def update_application(self): if self.run_plan: current_backends = [bc.backend for bc in self.run_plan.backends] scheduler = Scheduler() new_backends = scheduler.find_backends(self.run_plan) if not new_backends: log.error(_("Can't update '{name}', no backend " "available").format(name=self.name)) return updated_backends = [] for backend_conf in new_backends: if backend_conf.backend in current_backends: # replace backend settings with updated version self.run_plan.update( pull__backends__backend=backend_conf.backend) self.run_plan.update(push__backends=backend_conf) updated_backends.append(backend_conf.backend) else: # add backend to run plan if not already there ApplicationRunPlan.objects( id=self.run_plan.id, backends__backend__nin=[ backend_conf.backend]).update_one( push__backends=backend_conf) log.info(_("Starting {name} on backend {backend}").format( name=self.name, backend=backend_conf.backend.name)) ApplicationFlag.objects( pending_backends__ne=backend_conf.backend, application=self, name=IsStartingFlag.name).update_one( add_to_set__pending_backends=backend_conf.backend, upsert=True) if updated_backends: ApplicationFlag.objects( application=self, name=NeedsRestartFlag.name).update_one( set__pending_backends=updated_backends, upsert=True) for backend in current_backends: if backend not in [bc.backend for bc in new_backends]: log.info(_("Stopping {name} on old backend " "{backend}").format(name=self.name, backend=backend.name)) ApplicationFlag.objects( pending_backends__ne=backend, application=self, name=NeedsStoppingFlag.name).update_one( add_to_set__pending_backends=backend, upsert=True)
def handle_task(self): task_handled = super(Command, self).handle_task() if task_handled: return task_handled if self.last_app_check and self.last_app_check >= ( datetime.now() - timedelta(seconds=60)): return False self.last_app_check = datetime.now() for app in ApplicationRunPlan.objects( backends__backend=self.backend).distinct('application'): if app.flags: continue if not self.is_application_running(app): log.info(_("Application {name} is not running, " "starting").format(name=app.name)) ApplicationFlag.objects( application=app, name=IsStartingFlag.name).update_one( add_to_set__pending_backends=self.backend, upsert=True) elif not self.is_vassal_config_valid(app): log.info(_("Application {name} vassal config is invalid, " "restarting").format(name=app.name)) ApplicationFlag.objects( application=app, name=NeedsRestartFlag.name).update_one( add_to_set__pending_backends=self.backend, upsert=True) else: run_plan = app.run_plan if run_plan and not run_plan.is_valid(): log.info(_("Application {name} run plan is invalid, " "rescheduling").format(name=app.name)) ApplicationFlag.objects( application=app, name=NeedsReschedulingFlag.name).update_one( unset__pending=True, upsert=True)
def limits_usage(self): ret = {'running_apps': 0, 'workers': 0} for arp in ApplicationRunPlan.objects( application__in=Application.objects(owner=self)): ret['running_apps'] += 1 ret['workers'] += arp.workers_max return ret
def test_run_plan_migration(self): backend_settings = BackendRunPlanSettings(backend=self.backend, package=self.pkg, socket=8080, stats=9090, workers_min=1, workers_max=4) run_plan = ApplicationRunPlan(application=self.app, backends=[backend_settings], workers_min=1, workers_max=4, memory_per_worker=128, max_log_size=1) run_plan.save() self.app.reload() self.assertEqual(self.app.run_plan, None) self.assertEqual(call_command('migrate_db'), None) self.app.reload() self.assertEqual(self.app.run_plan, run_plan) run_plan.delete()
def create_run_plan_pkg_list(request): create_app(request) create_pkg_list(request) create_backend(request) create_router(request) backend_settings = BackendRunPlanSettings( backend=request.instance.backend, package=request.instance.pkg_list[0], socket=8080, stats=9090, workers_min=1, workers_max=4) run_plan = ApplicationRunPlan(application=request.instance.app, backends=[backend_settings], workers_min=1, workers_max=4, memory_per_worker=128, max_log_size=1) run_plan.save() request.instance.app.update(set__run_plan=run_plan) request.instance.app.reload() def cleanup(): run_plan.delete() request.addfinalizer(cleanup) request.instance.run_plan = run_plan
def clean(self): workers_min = self.cleaned_data.get('workers_min') workers_max = self.cleaned_data.get('workers_max') if not self.instance.id: apps_running = self.user.limits_usage['running_apps'] apps_limit = self.user.limits['running_apps'] if apps_limit and apps_running >= apps_limit: raise forms.ValidationError( _("Already running maximum allowed applications " "({count}), can't start another one").format( count=apps_running)) if workers_min is None or workers_max is None: return self.cleaned_data if workers_min > workers_max: raise forms.ValidationError(_("Minimum workers number cannot be" "lower than maximum")) workers_used = self.user.limits_usage['workers'] if self.instance.id: run_plan = ApplicationRunPlan.objects(id=self.instance.id).first() workers_used -= run_plan.workers_max workers_limit = self.user.limits['workers'] if workers_limit: workers_available = max(workers_limit - workers_used, 0) if workers_min > workers_available: raise forms.ValidationError(_( "Only {available} workers available, cannot set " "{workers} as minimum ").format( available=workers_available, workers=workers_min)) if workers_max > workers_available: raise forms.ValidationError(_( "Only {available} workers available, cannot set " "{workers} as maximum ").format( available=workers_available, workers=workers_max)) return self.cleaned_data
def run_plans(self): """ Returns the list of application run plans scheduled to be running on this backend. """ return ApplicationRunPlan.objects(backends__backend=self)
def running_applications(self): return [arp.application for arp in ApplicationRunPlan.objects( application__in=Application.objects(owner=self))]
def migrate_run_plans(self): for run_plan in ApplicationRunPlan.objects(): if not run_plan.application.run_plan: log.info("Migrating run plan for %s" % run_plan.application.name) run_plan.application.update(set__run_plan=run_plan)