def api_updateFolder(): #TODO(robnagler) Folder should have a serial, or should it be on data req = http_request.parse_post() o = srschema.parse_folder(req.req_data['oldName']) if o == '/': raise sirepo.util.Error( 'cannot rename root ("/") folder', 'old folder is root req={}', req, ) n = srschema.parse_folder(req.req_data['newName']) if n == '/': raise sirepo.util.Error( 'cannot rename folder to root ("/")', 'new folder is root req={}', req, ) for r in simulation_db.iterate_simulation_datafiles( req.type, _simulation_data_iterator): f = r.models.simulation.folder l = o.lower() if f.lower() == o.lower(): r.models.simulation.folder = n elif f.lower().startswith(o.lower() + '/'): r.models.simulation.folder = n + f[len():] else: continue simulation_db.save_simulation_json(r) return http_reply.gen_json_ok()
def api_copyNonSessionSimulation(): req = http_request.parse_post(id=True, template=True) simulation_db.verify_app_directory(req.type) src = pkio.py_path( simulation_db.find_global_simulation( req.type, req.id, checked=True, ), ) data = simulation_db.open_json_file( req.type, src.join(simulation_db.SIMULATION_DATA_FILE), ) data.pkdel('report') data.models.simulation.isExample = False data.models.simulation.outOfSessionSimulationId = req.id res = _save_new_and_reply(data) sirepo.sim_data.get_class(req.type).lib_files_from_other_user( data, simulation_db.lib_dir_from_sim_dir(src), ) target = simulation_db.simulation_dir(req.type, data.models.simulation.simulationId) #TODO(robnagler) does not work, supervisor needs to be notified to # copy the simulation state. # if hasattr(req.template, 'copy_related_files'): # req.template.copy_related_files(data, str(src), str(target)) return res
def api_runCancel(): jid = None try: req = http_request.parse_post(id=True, model=True, check_sim_exists=True) jid = req.sim_data.parse_jid(req.req_data) # TODO(robnagler) need to have a way of listing jobs # Don't bother with cache_hit check. We don't have any way of canceling # if the parameters don't match so for now, always kill. #TODO(robnagler) mutex required if runner.job_is_processing(jid): run_dir = simulation_db.simulation_run_dir(req.req_data) # Write first, since results are write once, and we want to # indicate the cancel instead of the termination error that # will happen as a result of the kill. try: simulation_db.write_result({'state': 'canceled'}, run_dir=run_dir) except Exception as e: if not pykern.pkio.exception_is_not_found(e): raise # else: run_dir may have been deleted runner.job_kill(jid) # TODO(robnagler) should really be inside the template (t.cancel_simulation()?) # the last frame file may not be finished, remove it t = sirepo.template.import_module(req.req_data) if hasattr(t, 'remove_last_frame'): t.remove_last_frame(run_dir) except Exception as e: pkdlog('ignoring exception={} jid={} stack={}', e, jid, pkdexc()) # Always true from the client's perspective return http_reply.gen_json({'state': 'canceled'})
def api_copySimulation(): """Takes the specified simulation and returns a newly named copy with the suffix ( X)""" req = http_request.parse_post(id=True, folder=True, name=True) d = simulation_db.read_simulation_json(req.type, sid=req.id) d.models.simulation.pkupdate( name=req.name, folder=req.folder, isExample=False, outOfSessionSimulationId='', ) return _save_new_and_reply(d)
def api_listSimulations(): req = http_request.parse_post() simulation_db.verify_app_directory(req.type) return http_reply.gen_json( sorted( simulation_db.iterate_simulation_datafiles( req.type, simulation_db.process_simulation_list, req.req_data.get('search'), ), key=lambda row: row['name'], ))
def api_newSimulation(): req = http_request.parse_post(template=True, folder=True, name=True) d = simulation_db.default_data(req.type) #TODO(pjm): update fields from schema values across new_simulation_data values d.models.simulation.pkupdate( name=req.name, folder=req.folder, notes=req.req_data.get('notes', ''), ) if hasattr(req.template, 'new_simulation'): req.template.new_simulation(d, req.req_data) return _save_new_and_reply(d)
def api_saveSimulationData(): # do not fixup_old_data yet req = http_request.parse_post(id=True, template=True) d = req.req_data simulation_db.validate_serial(d) d = simulation_db.fixup_old_data(d)[0] if hasattr(req.template, 'prepare_for_save'): d = req.template.prepare_for_save(d) d = simulation_db.save_simulation_json(d) return api_simulationData( d.simulationType, d.models.simulation.simulationId, )
def api_deleteFile(): req = http_request.parse_post(filename=True, file_type=True) e = _simulations_using_file(req) if len(e): return http_reply.gen_json({ 'error': 'File is in use in other simulations.', 'fileList': e, 'fileName': req.filename, }) # Will not remove resource (standard) lib files pkio.unchecked_remove(_lib_file_write_path(req)) return http_reply.gen_json_ok()
def api_newSimulation(): req = http_request.parse_post(template=True, folder=True, name=True) d = simulation_db.default_data(req.type) d.models.simulation.pkupdate( {k: v for k, v in req.req_data.items() if k in d.models.simulation}) d.models.simulation.pkupdate( name=req.name, folder=req.folder, ) if hasattr(req.template, 'new_simulation'): req.template.new_simulation(d, req.req_data) return _save_new_and_reply(d)
def api_runSimulation(): req = http_request.parse_post(id=True, model=True, fixup_old_data=True, check_sim_exists=True) res = _simulation_run_status(req, quiet=True) if ((not res['state'] in _RUN_STATES and (res['state'] != 'completed' or req.req_data.get('forceRun', False))) or res.get('parametersChanged', True)): try: _start_simulation(req.req_data) except runner.Collision: pkdlog('{}: runner.Collision, ignoring start', _reqd(req).jid) res = _simulation_run_status(req) return http_reply.gen_json(res)
def api_getApplicationData(filename=None): """Get some data from the template Args: filename (str): if supplied, result is file attachment Returns: response: may be a file or JSON """ req = http_request.parse_post(template=True, filename=filename or None) with simulation_db.tmp_dir() as d: res = req.template.get_application_data(req.req_data, tmp_dir=d) if 'filename' in req: assert isinstance(res, pkconst.PY_PATH_LOCAL_TYPE), \ '{}: template did not return a file'.format(res) return http_reply.gen_file_as_attachment(res, filename=req.filename) return http_reply.gen_json(res)
def api_authEmailLogin(): """Start the login process for the user. User has sent an email, which needs to be verified. """ req = http_request.parse_post() email = _parse_email(req.req_data) with auth_db.thread_lock: u = AuthEmailUser.search_by(unverified_email=email) if not u: u = AuthEmailUser(unverified_email=email) u.create_token() u.save() return _send_login_email( u, uri_router.uri_for_api( 'authEmailAuthorized', dict(simulation_type=req.type, token=u.token), ), )
def api_getApplicationData(filename=None): """Get some data from the template Args: filename (str): if supplied, result is file attachment Returns: response: may be a file or JSON """ req = http_request.parse_post(template=True, filename=filename or None) with simulation_db.tmp_dir() as d: assert 'method' in req.req_data res = req.template.get_application_data(req.req_data, tmp_dir=d) assert res != None, f'unhandled application data method: {req.req_data.method}' if 'filename' in req and isinstance(res, pkconst.PY_PATH_LOCAL_TYPE): return http_reply.gen_file_as_attachment( res, filename=req.filename, content_type=req.req_data.get('contentType', None)) return http_reply.gen_json(res)
def api_deleteSimulation(): req = http_request.parse_post(id=True) simulation_db.delete_simulation(req.type, req.id) return http_reply.gen_json_ok()
def api_runStatus(): return http_reply.gen_json( _simulation_run_status( http_request.parse_post(id=True, model=True, check_sim_exists=True), ), )