def _wait_for_session_backup(sessname): cont = JBoxContainer.get_by_name(sessname) if (cont is not None) and JBoxd._is_scheduled( JBoxAsyncJob.CMD_BACKUP_CLEANUP, (cont.dockid, )): JBoxd.log_debug("Waiting for backup of session %s", sessname) return False return True
def chk_and_launch_docker(self, sessname, creds, authtok, user_id): cont = JBoxContainer.get_by_name(sessname) nhops = int(self.get_argument('h', 0)) self.log_debug("got hop " + repr(nhops) + " for session " + repr(sessname)) self.log_debug("have existing container for " + repr(sessname) + ": " + repr(None != cont)) if cont is not None: self.log_debug("container running: " + str(cont.is_running())) if ((None == cont) or (not cont.is_running())) and (not CloudHelper.should_accept_session()): if None != cont: cont.backup() cont.delete() self.clear_container_cookies() self.set_header('Connection', 'close') self.request.connection.no_keep_alive = True if nhops > self.config('numhopmax', 0): self.rendertpl("index.tpl", cfg=self.config(), state=self.state( error="Maximum number of JuliaBox instances active. Please try after sometime.", success='')) else: self.redirect('/?h=' + str(nhops + 1)) else: cont = JBoxContainer.launch_by_name(sessname, user_id, True) (shellport, uplport, ipnbport) = cont.get_host_ports() sign = signstr(sessname + str(shellport) + str(uplport) + str(ipnbport), self.config("sesskey")) self.set_container_cookies({ "sessname": sessname, "hostshell": shellport, "hostupload": uplport, "hostipnb": ipnbport, "sign": sign }) self.set_lb_tracker_cookie() self.rendertpl("ipnbsess.tpl", sessname=sessname, cfg=self.config(), creds=creds, authtok=authtok, user_id=user_id)
def get(self): sessname = unquote(self.get_cookie("sessname")) jbox_cookie = self.get_session_cookie() if (None == sessname) or (len(sessname) == 0) or (None == jbox_cookie): self.send_error() return user_id = jbox_cookie['u'] user = JBoxUserV2(user_id) is_admin = sessname in self.config("admin_sessnames", []) manage_containers = is_admin or user.has_role(JBoxUserV2.ROLE_MANAGE_CONTAINERS) show_report = is_admin or user.has_role(JBoxUserV2.ROLE_ACCESS_STATS) cont = JBoxContainer.get_by_name(sessname) if cont is None: self.send_error() return if self.handle_if_logout(cont): return if self.handle_if_stats(is_admin or show_report): return if self.handle_if_show_cfg(is_admin): return if self.handle_if_instance_info(is_admin): return if self.handle_switch_julia_img(user): return juliaboxver, _upgrade_available = self.get_upgrade_available(cont) jimg_type = 0 if user.has_resource_profile(JBoxUserV2.RES_PROF_JULIA_PKG_PRECOMP): jimg_type = JBoxUserV2.RES_PROF_JULIA_PKG_PRECOMP d = dict( manage_containers=manage_containers, show_report=show_report, sessname=sessname, user_id=user_id, created=isodate.datetime_isoformat(cont.time_created()), started=isodate.datetime_isoformat(cont.time_started()), allowed_till=isodate.datetime_isoformat((cont.time_started() + timedelta(seconds=self.config('expire')))), mem=cont.get_memory_allocated(), cpu=cont.get_cpu_allocated(), disk=cont.get_disk_allocated(), expire=self.config('expire'), juliaboxver=juliaboxver, jimg_type=jimg_type ) self.rendertpl("ipnbadmin.tpl", d=d, cfg=self.config())
def do_monitor_loading(self, user_id): sessname = unique_sessname(user_id) self.log_debug("Monitoring loading of session [%s] user[%s]...", sessname, user_id) cont = JBoxContainer.get_by_name(sessname) if (cont is None) or (not cont.is_running()): loading_step = int(self.get_cookie("loading", 0)) if loading_step > 30: self.log_error("Could not start instance. Session [%s] for user [%s] didn't load.", sessname, user_id) self.clear_container_cookies() self.rendertpl("index.tpl", cfg=self.config(), state=self.state( error='Could not start your instance! Please try again.', pending_activation=False, user_id=user_id)) return else: loading_step += 1 self.set_cookie("loading", str(loading_step)) self.rendertpl("loading.tpl", user_id=user_id) else: if self.config("gauth"): jbuser = JBoxUserV2(user_id) creds = jbuser.get_gtok() if creds is not None: try: creds_json = json.loads(base64.b64decode(creds)) creds_json = self.renew_creds(creds_json) authtok = creds_json['access_token'] except: self.log_warn("stale stored creds. will renew on next use. user: "******"sesskey")) self.clear_cookie("loading") self.set_container_cookies({ "sessname": sessname, "hostshell": shellport, "hostupload": uplport, "hostipnb": ipnbport, "sign": sign }) self.set_lb_tracker_cookie() self.rendertpl("ipnbsess.tpl", sessname=sessname, cfg=self.config(), creds=creds, authtok=authtok, user_id=user_id)
def try_launch_container(cls, user_id): sessname = unique_sessname(user_id) cont = JBoxContainer.get_by_name(sessname) cls.log_debug("have existing container for %s: %r", sessname, None != cont) if cont is not None: cls.log_debug("container running: %r", cont.is_running()) if ((cont is None) or (not cont.is_running())) and (not CloudHost.should_accept_session()): if cont is not None: cont.async_backup_and_cleanup() return False JBoxContainer.async_launch_by_name(sessname, user_id, True) return True
def chk_and_launch_docker(self, sessname, creds, authtok, user_id): cont = JBoxContainer.get_by_name(sessname) nhops = int(self.get_argument('h', 0)) self.log_debug("got hop " + repr(nhops) + " for session " + repr(sessname)) self.log_debug("have existing container for " + repr(sessname) + ": " + repr(None != cont)) if cont is not None: self.log_debug("container running: " + str(cont.is_running())) if ((None == cont) or (not cont.is_running())) and ( not CloudHelper.should_accept_session()): if None != cont: cont.backup() cont.delete() self.clear_container_cookies() self.set_header('Connection', 'close') self.request.connection.no_keep_alive = True if nhops > self.config('numhopmax', 0): self.rendertpl( "index.tpl", cfg=self.config(), state=self.state( error= "Maximum number of JuliaBox instances active. Please try after sometime.", success='')) else: self.redirect('/?h=' + str(nhops + 1)) else: cont = JBoxContainer.launch_by_name(sessname, True) (shellport, uplport, ipnbport) = cont.get_host_ports() sign = signstr( sessname + str(shellport) + str(uplport) + str(ipnbport), self.config("sesskey")) self.set_container_cookies({ "sessname": sessname, "hostshell": shellport, "hostupload": uplport, "hostipnb": ipnbport, "sign": sign }) self.set_lb_tracker_cookie() self.rendertpl("ipnbsess.tpl", sessname=sessname, cfg=self.config(), creds=creds, authtok=authtok, user_id=user_id)
def do_monitor_loading_ajax(self, user_id): sessname = unique_sessname(user_id) self.log_debug("AJAX monitoring loading of session [%s] user[%s]...", sessname, user_id) cont = JBoxContainer.get_by_name(sessname) if (cont is None) or (not cont.is_running()): loading_step = int(self.get_cookie("loading", 0)) if loading_step > 30: self.log_error("Could not start instance. Session [%s] for user [%s] didn't load.", sessname, user_id) self.write({'code': -1}) return loading_step += 1 self.set_cookie("loading", str(loading_step)) self.write({'code': 0}) else: self.write({'code': 1})
def do_monitor_loading_ajax(self, user_id): sessname = unique_sessname(user_id) self.log_debug("AJAX monitoring loading of session [%s] user[%s]...", sessname, user_id) cont = JBoxContainer.get_by_name(sessname) if (cont is None) or (not cont.is_running()): loading_step = int(self.get_cookie("loading", 0)) if loading_step > 30: self.write({'code': -1}) return loading_step += 1 self.set_cookie("loading", str(loading_step)) self.write({'code': 0}) else: self.write({'code': 1})
def try_launch_container(cls, user_id): sessname = unique_sessname(user_id) cont = JBoxContainer.get_by_name(sessname) cls.log_debug("have existing container for %s: %r", sessname, None != cont) if cont is not None: cls.log_debug("container running: %r", cont.is_running()) is_leader = is_proposed_cluster_leader() if ((cont is None) or (not cont.is_running())) and ( not CloudHost.should_accept_session(is_leader)): if cont is not None: cont.async_backup_and_cleanup() return False JBoxContainer.async_launch_by_name(sessname, user_id, True) return True
def post(self): self.log_debug("Homework handler got POST request") sessname = unquote(self.get_cookie("sessname")) jbox_cookie = self.get_session_cookie() if (None == sessname) or (len(sessname) == 0) or (None == jbox_cookie): self.log_info( "Homework handler got invalid sessname[%r] or cookie[%r]", sessname, jbox_cookie) self.send_error() return user_id = jbox_cookie['u'] user = JBoxUserV2(user_id) is_admin = sessname in self.config( "admin_sessnames", []) or user.has_role(JBoxUserV2.ROLE_SUPER) course_owner = is_admin or user.has_role(JBoxUserV2.ROLE_OFFER_COURSES) cont = JBoxContainer.get_by_name(sessname) self.log_info("user_id[%r], is_admin[%r], course_owner[%r]", user_id, is_admin, course_owner) if cont is None: self.log_info("user_id[%r] container not found", user_id) self.send_error() return courses_offered = user.get_courses_offered() if self.handle_if_check(user_id): return if self.handle_create_course(user_id): return if self.handle_get_metadata(is_admin, courses_offered): return if course_owner and self.handle_if_report(user_id, is_admin, courses_offered): return self.log_error("no handlers found") # only AJAX requests responded to self.send_error()
def try_launch_container(cls, user_id, max_hop=False): sessname = unique_sessname(user_id) cont = JBoxContainer.get_by_name(sessname) cls.log_debug("have existing container for %s: %r", sessname, None != cont) if cont is not None: cls.log_debug("container running: %r", cont.is_running()) if max_hop: self_load = CloudHost.get_instance_stats(CloudHost.instance_id(), 'Load') if self_load < 100: JBoxContainer.async_launch_by_name(sessname, user_id, True) return True is_leader = is_proposed_cluster_leader() if ((cont is None) or (not cont.is_running())) and (not CloudHost.should_accept_session(is_leader)): if cont is not None: cont.async_backup_and_cleanup() return False JBoxContainer.async_launch_by_name(sessname, user_id, True) return True
def post(self): self.log_debug("Homework handler got POST request") sessname = unquote(self.get_cookie("sessname")) jbox_cookie = self.get_session_cookie() if (None == sessname) or (len(sessname) == 0) or (None == jbox_cookie): self.log_info("Homework handler got invalid sessname[%r] or cookie[%r]", sessname, jbox_cookie) self.send_error() return user_id = jbox_cookie['u'] user = JBoxUserV2(user_id) is_admin = sessname in self.config("admin_sessnames", []) or user.has_role(JBoxUserV2.ROLE_SUPER) course_owner = is_admin or user.has_role(JBoxUserV2.ROLE_OFFER_COURSES) cont = JBoxContainer.get_by_name(sessname) self.log_info("user_id[%r], is_admin[%r], course_owner[%r]", user_id, is_admin, course_owner) if cont is None: self.log_info("user_id[%r] container not found", user_id) self.send_error() return courses_offered = user.get_courses_offered() if self.handle_if_check(user_id): return if self.handle_create_course(user_id): return if self.handle_get_metadata(is_admin, courses_offered): return if course_owner and self.handle_if_report(user_id, is_admin, courses_offered): return self.log_error("no handlers found") # only AJAX requests responded to self.send_error()
def _wait_for_session_backup(sessname): cont = JBoxContainer.get_by_name(sessname) if (cont is not None) and JBoxd._is_scheduled(JBoxAsyncJob.CMD_BACKUP_CLEANUP, (cont.dockid,)): return False return True
def get(self): sessname = unquote(self.get_cookie("sessname")) jbox_cookie = AuthHandler.get_session_cookie(self) if (None == sessname) or (len(sessname) == 0) or (None == jbox_cookie): self.send_error() return user_id = jbox_cookie['u'] cont = JBoxContainer.get_by_name(sessname) if cont is None: self.send_error() return juliaboxver, upgrade_available = self.get_upgrade_available(cont) if self.do_upgrade(cont, upgrade_available): response = {'code': 0, 'data': ''} self.write(response) return user = JBoxUserV2(user_id) show_report = (sessname in self.config("report_sessnames", []) or user.get_role() == JBoxUserV2.ROLE_REPORT) admin_user = (sessname in self.config("admin_sessnames", []) or user.get_role() == JBoxUserV2.ROLE_ADMIN) show_report = show_report or admin_user sections = [] loads = [] report = {} report_span = 'day' if admin_user: sections, loads = self.admin_stats() if show_report: today = datetime.now() if self.get_argument('range', 'day') == 'week': dates = [today - timedelta(days=i) for i in range(6, -1, -1)] report_span = 'week' else: dates = [today] report = JBoxAccountingV2.get_stats(dates) d = dict(admin_user=admin_user, show_report=show_report, report_span=report_span, sessname=sessname, user_id=user_id, created=isodate.datetime_isoformat(cont.time_created()), started=isodate.datetime_isoformat(cont.time_started()), allowed_till=isodate.datetime_isoformat( (cont.time_started() + timedelta(seconds=self.config('expire')))), mem=cont.get_memory_allocated(), cpu=cont.get_cpu_allocated(), disk=cont.get_disk_allocated(), expire=self.config('expire'), sections=sections, loads=loads, report=report, juliaboxver=juliaboxver, upgrade_available=upgrade_available) self.rendertpl("ipnbadmin.tpl", d=d, cfg=self.config())
def get(self): sessname = unquote(self.get_cookie("sessname")) jbox_cookie = self.get_session_cookie() if (None == sessname) or (len(sessname) == 0) or (None == jbox_cookie): self.send_error() return user_id = jbox_cookie['u'] user = JBoxUserV2(user_id) is_admin = sessname in self.config("admin_sessnames", []) manage_containers = is_admin or user.has_role( JBoxUserV2.ROLE_MANAGE_CONTAINERS) show_report = is_admin or user.has_role(JBoxUserV2.ROLE_ACCESS_STATS) cont = JBoxContainer.get_by_name(sessname) if cont is None: self.send_error() return if self.handle_if_logout(cont): return if self.handle_if_stats(is_admin): return if self.handle_if_show_cfg(is_admin): return if self.handle_if_instance_info(is_admin): return juliaboxver, _upgrade_available = self.get_upgrade_available(cont) sections = [] report = {} report_span = 'day' if manage_containers: sections = self.do_containers() if show_report: today = datetime.now() if self.get_argument('range', 'day') == 'week': dates = [today - timedelta(days=i) for i in range(6, -1, -1)] report_span = 'week' else: dates = [today] report = JBoxAccountingV2.get_stats(dates) d = dict(manage_containers=manage_containers, show_report=show_report, report_span=report_span, sessname=sessname, user_id=user_id, created=isodate.datetime_isoformat(cont.time_created()), started=isodate.datetime_isoformat(cont.time_started()), allowed_till=isodate.datetime_isoformat( (cont.time_started() + timedelta(seconds=self.config('expire')))), mem=cont.get_memory_allocated(), cpu=cont.get_cpu_allocated(), disk=cont.get_disk_allocated(), expire=self.config('expire'), sections=sections, report=report, juliaboxver=juliaboxver) self.rendertpl("ipnbadmin.tpl", d=d, cfg=self.config())
def get(self): sessname = unquote(self.get_cookie("sessname")) jbox_cookie = self.get_session_cookie() if (None == sessname) or (len(sessname) == 0) or (None == jbox_cookie): self.send_error() return user_id = jbox_cookie['u'] user = JBoxUserV2(user_id) is_admin = sessname in self.config("admin_sessnames", []) manage_containers = is_admin or user.has_role(JBoxUserV2.ROLE_MANAGE_CONTAINERS) show_report = is_admin or user.has_role(JBoxUserV2.ROLE_ACCESS_STATS) cont = JBoxContainer.get_by_name(sessname) if cont is None: self.send_error() return if self.handle_if_logout(cont): return if self.handle_if_stats(is_admin): return if self.handle_if_show_cfg(is_admin): return if self.handle_if_instance_info(is_admin): return juliaboxver, _upgrade_available = self.get_upgrade_available(cont) sections = [] report = {} report_span = 'day' if manage_containers: sections = self.do_containers() if show_report: today = datetime.now() if self.get_argument('range', 'day') == 'week': dates = [today - timedelta(days=i) for i in range(6, -1, -1)] report_span = 'week' else: dates = [today] report = JBoxAccountingV2.get_stats(dates) d = dict( manage_containers=manage_containers, show_report=show_report, report_span=report_span, sessname=sessname, user_id=user_id, created=isodate.datetime_isoformat(cont.time_created()), started=isodate.datetime_isoformat(cont.time_started()), allowed_till=isodate.datetime_isoformat((cont.time_started() + timedelta(seconds=self.config('expire')))), mem=cont.get_memory_allocated(), cpu=cont.get_cpu_allocated(), disk=cont.get_disk_allocated(), expire=self.config('expire'), sections=sections, report=report, juliaboxver=juliaboxver ) self.rendertpl("ipnbadmin.tpl", d=d, cfg=self.config())
def get(self): sessname = unquote(self.get_cookie("sessname")) jbox_cookie = AuthHandler.get_session_cookie(self) if (None == sessname) or (len(sessname) == 0) or (None == jbox_cookie): self.send_error() return user_id = jbox_cookie['u'] cont = JBoxContainer.get_by_name(sessname) if cont is None: self.send_error() return juliaboxver, upgrade_available = self.get_upgrade_available(cont) if self.do_upgrade(cont, upgrade_available): response = {'code': 0, 'data': ''} self.write(response) return user = JBoxUserV2(user_id) show_report = (sessname in self.config("report_sessnames", []) or user.get_role() == JBoxUserV2.ROLE_REPORT) admin_user = (sessname in self.config("admin_sessnames", []) or user.get_role() == JBoxUserV2.ROLE_ADMIN) show_report = show_report or admin_user sections = [] loads = [] report = {} report_span = 'day' if admin_user: sections, loads = self.admin_stats() if show_report: today = datetime.now() if self.get_argument('range', 'day') == 'week': dates = [today - timedelta(days=i) for i in range(6, -1, -1)] report_span = 'week' else: dates = [today] report = JBoxAccountingV2.get_stats(dates) d = dict( admin_user=admin_user, show_report=show_report, report_span=report_span, sessname=sessname, user_id=user_id, created=isodate.datetime_isoformat(cont.time_created()), started=isodate.datetime_isoformat(cont.time_started()), allowed_till=isodate.datetime_isoformat((cont.time_started() + timedelta(seconds=self.config('expire')))), mem=cont.get_memory_allocated(), cpu=cont.get_cpu_allocated(), disk=cont.get_disk_allocated(), expire=self.config('expire'), sections=sections, loads=loads, report=report, juliaboxver=juliaboxver, upgrade_available=upgrade_available ) self.rendertpl("ipnbadmin.tpl", d=d, cfg=self.config())
def get(self): sessname = unquote(self.get_cookie("sessname")) jbox_cookie = AuthHandler.get_session_cookie(self) if (None == sessname) or (len(sessname) == 0) or (None == jbox_cookie): self.send_error() return user_id = jbox_cookie['u'] cont = JBoxContainer.get_by_name(sessname) if cont is None: self.send_error() return juliaboxver, upgrade_available = self.get_upgrade_available(cont) if self.do_upgrade(cont, upgrade_available): response = {'code': 0, 'data': ''} self.write(response) return user = JBoxUserV2(user_id) is_admin = sessname in self.config("admin_sessnames", []) manage_containers = is_admin or user.has_role( JBoxUserV2.ROLE_MANAGE_CONTAINERS) show_report = is_admin or user.has_role(JBoxUserV2.ROLE_ACCESS_STATS) invites_perm = is_admin or user.has_role( JBoxUserV2.ROLE_MANAGE_INVITES) sections = [] loads = [] report = {} report_span = 'day' invites_info = [] action = self.get_argument("action", None) #invite_code = self.request.get("invite_code", None) if action == "invites_report" and invites_perm: self.write( dict(code=0, data=[obj for obj in JBoxInvite.table().scan()])) return if manage_containers: sections, loads = self.do_containers() if show_report: today = datetime.now() if self.get_argument('range', 'day') == 'week': dates = [today - timedelta(days=i) for i in range(6, -1, -1)] report_span = 'week' else: dates = [today] report = JBoxAccountingV2.get_stats(dates) d = dict(manage_containers=manage_containers, show_report=show_report, invites_perm=invites_perm, report_span=report_span, sessname=sessname, user_id=user_id, created=isodate.datetime_isoformat(cont.time_created()), started=isodate.datetime_isoformat(cont.time_started()), allowed_till=isodate.datetime_isoformat( (cont.time_started() + timedelta(seconds=self.config('expire')))), mem=cont.get_memory_allocated(), cpu=cont.get_cpu_allocated(), disk=cont.get_disk_allocated(), expire=self.config('expire'), sections=sections, loads=loads, report=report, juliaboxver=juliaboxver, upgrade_available=upgrade_available) self.rendertpl("ipnbadmin.tpl", d=d, cfg=self.config())
def do_monitor_loading(self, user_id): sessname = unique_sessname(user_id) self.log_debug("Monitoring loading of session [%s] user[%s]...", sessname, user_id) cont = JBoxContainer.get_by_name(sessname) if (cont is None) or (not cont.is_running()): loading_step = int(self.get_cookie("loading", 0)) if loading_step > 30: self.log_error( "Could not start instance. Session [%s] for user [%s] didn't load.", sessname, user_id) self.clear_container_cookies() self.rendertpl( "index.tpl", cfg=self.config(), state=self.state( error= 'Could not start your instance! Please try again.', pending_activation=False, user_id=user_id)) return else: loading_step += 1 self.set_cookie("loading", str(loading_step)) self.rendertpl("loading.tpl", user_id=user_id) else: if self.config("gauth"): jbuser = JBoxUserV2(user_id) creds = jbuser.get_gtok() if creds is not None: try: creds_json = json.loads(base64.b64decode(creds)) creds_json = self.renew_creds(creds_json) authtok = creds_json['access_token'] except: self.log_warn( "stale stored creds. will renew on next use. user: "******"sesskey")) self.clear_cookie("loading") self.set_container_cookies({ "sessname": sessname, "hostshell": shellport, "hostupload": uplport, "hostipnb": ipnbport, "sign": sign }) self.set_lb_tracker_cookie() self.rendertpl("ipnbsess.tpl", sessname=sessname, cfg=self.config(), creds=creds, authtok=authtok, user_id=user_id)
def get(self): sessname = unquote(self.get_cookie("sessname")) jbox_cookie = AuthHandler.get_session_cookie(self) if (None == sessname) or (len(sessname) == 0) or (None == jbox_cookie): self.send_error() return user_id = jbox_cookie['u'] cont = JBoxContainer.get_by_name(sessname) if cont is None: self.send_error() return juliaboxver, upgrade_available = self.get_upgrade_available(cont) if self.do_upgrade(cont, upgrade_available): response = {'code': 0, 'data': ''} self.write(response) return user = JBoxUserV2(user_id) is_admin = sessname in self.config("admin_sessnames", []) manage_containers = is_admin or user.has_role(JBoxUserV2.ROLE_MANAGE_CONTAINERS) show_report = is_admin or user.has_role(JBoxUserV2.ROLE_ACCESS_STATS) invites_perm = is_admin or user.has_role(JBoxUserV2.ROLE_MANAGE_INVITES) sections = [] loads = [] report = {} report_span = 'day' invites_info = [] action = self.get_argument("action", None) #invite_code = self.request.get("invite_code", None) if action == "invites_report" and invites_perm: self.write(dict( code=0, data=[obj for obj in JBoxInvite.table().scan()])) return if manage_containers: sections, loads = self.do_containers() if show_report: today = datetime.now() if self.get_argument('range', 'day') == 'week': dates = [today - timedelta(days=i) for i in range(6, -1, -1)] report_span = 'week' else: dates = [today] report = JBoxAccountingV2.get_stats(dates) d = dict( manage_containers=manage_containers, show_report=show_report, invites_perm=invites_perm, report_span=report_span, sessname=sessname, user_id=user_id, created=isodate.datetime_isoformat(cont.time_created()), started=isodate.datetime_isoformat(cont.time_started()), allowed_till=isodate.datetime_isoformat((cont.time_started() + timedelta(seconds=self.config('expire')))), mem=cont.get_memory_allocated(), cpu=cont.get_cpu_allocated(), disk=cont.get_disk_allocated(), expire=self.config('expire'), sections=sections, loads=loads, report=report, juliaboxver=juliaboxver, upgrade_available=upgrade_available ) self.rendertpl("ipnbadmin.tpl", d=d, cfg=self.config())