def __init__(self, short_id=None, headless=True): self.headless = headless self.short_id = None self.build_id = None self._browser = None self._code_build_Jupyter = None self._jupyter_cell = None self._jupyter_web = None self._jupyter_api = None self._server_details = None self._needs_login = True self.jupyter_helper = CodeBuild_Jupyter_Helper() self.execute_python_file = 'notebooks/setup/gsbot-invoke.ipynb' if short_id: self.set_build_from_short_id(short_id)
def run(event, context): try: repo_name = event.get('repo_name') channel = event.get('channel') team_id = event.get('team_id') user = event.get('user') server_size = event.get('server_size', 'small') slack_message( f":point_right: Hi <@{user}>, starting Jupyter server for you with the repo `{repo_name}` with server size `{server_size}`.\n :information_source: This should take between 60 and 150 seconds", [], channel, team_id) from osbot_jupyter.api.CodeBuild_Jupyter_Helper import CodeBuild_Jupyter_Helper login_url = CodeBuild_Jupyter_Helper( ).start_build_for_repo_and_wait_for_jupyter_load( repo_name=repo_name, user=user, server_size=server_size) if login_url: slack_message( ":point_right: Server started ok, please use this link to open it:\n {0}" .format(login_url), [], channel, team_id) else: slack_message( ":red_circle: Could not find server (or it took too long to start). Please check that the repo `{0}` exists." .format(repo_name), [], channel, team_id) except Exception as error: slack_message( f":red_circle: Something went wrong when starting the {repo_name} Jupyter notebook: {0}" .format(error), [], channel, team_id) return "{0}".format(error)
def servers(team_id=None, channel=None, params=None): text = ":point_right: Here are the running servers:" servers_text = "" attachments = [] for build_id,build in CodeBuild_Jupyter_Helper().get_active_builds().items(): #print(build_id) build_info = build.build_info() Dev.pprint(build_info) variables = {} for variable in build_info.get('environment').get('environmentVariables'): variables[variable.get('name')] = variable.get('value') repo_name = variables.get('repo_name') user = variables.get('user') timeout = build_info.get('timeoutInMinutes') small_id = build_id[-5:] server_url = build.url() if server_url is None: user_text = "(server booting up)" else: user_text = "<{0}|open>".format(server_url) # servers_text += "*{0}*: booting up\n".format(repo_name, server_url) #else: time = "{0}".format(build_info.get('startTime').strftime("%H:%M")) servers_text += "*{1}*: {2} (id: `{0}`, user: <@{3}>, started: {4}, timeout: {5})\n".format( small_id, repo_name,user_text,user,time, timeout) if servers_text: attachments.append({"text":servers_text, 'color': 'good'}) slack_message(text, attachments, channel, team_id) else: slack_message(":information_source: there are no servers running! Why don't you start one using the command `jupyter start {repo name}` ", [], channel, team_id)
def test_create(self): headless = False file = '/tmp/active_jupyter_server.yml' api = CodeBuild_Jupyter_Helper() #result = api.start_build_and_wait_for_jupyter_load() #build_id = api.get_active_build_id() config = api.save_active_server_details(file) #Dev.pprint(result.build_status()) #Dev.pprint(build_id) Dev.pprint(config) jp_web = Jupyter_Web(token=config.get('token'), server=config.get('server'), headless=headless) jp_web.login() jp_api = Jupyter_API(token=config.get('token'), server=config.get('server'), headless=headless)
def test_start_new_build(self): self.build_id = CodeBuild_Jupyter_Helper().start_build_and_wait_for_jupyter_load().build_id print(self.build_id) self.api = CodeBuild_Jupyter(build_id=self.build_id) self.result = self.api.url()
def setUp(self): super().setUp() self.api = CodeBuild_Jupyter_Helper() self.result = None
class test_CodeBuild_Jupyter_Helper(Test_Helper): def setUp(self): super().setUp() self.api = CodeBuild_Jupyter_Helper() self.result = None def tearDown(self): if self.result: Dev.pprint(self.result) def test_get_active_build_id(self): self.result = self.api.get_active_build_id() def test_get_active_builds(self): builds = self.api.get_active_builds() print() for id, build in builds.items(): #assert build.build_status() == 'IN_PROGRESS' #assert build.build_phase() == 'BUILD' # need to improve the resilience of this test print(id, build.build_status(), build.build_phase()) def test_start_build(self): result = self.api.start_build() Dev.pprint(result.build_info()) def test_start_build_and_wait_for_jupyter_load(self): result = self.api.start_build_and_wait_for_jupyter_load() Dev.pprint(result.build_status()) def test_start_build_for_repo__server_size(self): repo = 'gs-notebook-gscs' self.api.start_build_for_repo(repo, server_size='small') self.api.start_build_for_repo(repo, server_size='medium') self.api.start_build_for_repo(repo, server_size='large') def test_start_build_for_repo_and_wait_for_jupyter_load(self): repo = 'gwbot-jupyter-notebooks' self.result = self.api.start_build_for_repo_and_wait_for_jupyter_load( repo) def test_stop_all_active(self): result = CodeBuild_Jupyter_Helper().stop_all_active() Dev.pprint("stopped builds {0}".format(result)) def test_save_active_server_details(self): tmp_file = '/tmp/active_jupyter_server.yml' self.result = self.api.save_active_server_details(tmp_file) def test_gw_repo_start_build_for_repo__server_size(self): repo_name = 'gwbot-jupyter-notebooks' self.result = self.api.start_build_for_repo(repo_name, server_size='medium')
def test_stop_all_active(self): result = CodeBuild_Jupyter_Helper().stop_all_active() Dev.pprint("stopped builds {0}".format(result))
class Live_Notebook: def __init__(self, short_id=None, headless=True): self.headless = headless self.short_id = None self.build_id = None self._browser = None self._code_build_Jupyter = None self._jupyter_cell = None self._jupyter_web = None self._jupyter_api = None self._server_details = None self._needs_login = True self.jupyter_helper = CodeBuild_Jupyter_Helper() self.execute_python_file = 'notebooks/setup/gsbot-invoke.ipynb' if short_id: self.set_build_from_short_id(short_id) # global objects def browser( self ): # we have make sure there is only one instance of browser created if self._browser is None: from osbot_browser.browser.Browser_Lamdba_Helper import Browser_Lamdba_Helper browser_helper = Browser_Lamdba_Helper( headless=self.headless).setup() self._browser = browser_helper.api_browser return self._browser def jupyter_cell(self): if self._jupyter_cell is None: server, token = self.server_details() self._jupyter_cell = Jupyter_Web_Cell(server=server, token=token, headless=self.headless, browser=self.browser()) return self._jupyter_cell def jupyter_web(self): if self._jupyter_web is None: server, token = self.server_details() self._jupyter_web = Jupyter_Web(server=server, token=token, headless=self.headless, browser=self.browser()) return self._jupyter_web def jupyter_api(self): if self._jupyter_api is None: server, token = self.server_details() self._jupyter_api = Jupyter_API(server=server, token=token) return self._jupyter_api # config methods def set_build_id(self, build_id): self.build_id = build_id return self def set_build_from_short_id(self, short_id): if short_id and type(short_id) is str: active_builds = self.jupyter_helper.get_active_builds() if active_builds: for build_id, build in active_builds.items(): if short_id in build_id: # search on build_id self.build_id = build_id self.short_id = short_id return self repo_name = build.build_environment_variables().get( 'repo_name') # search on repo_name if short_id in repo_name: self.build_id = build_id self.short_id = build_id # in this case use the actual build id as the short id return self return None def code_build_Jupyter(self): if self._code_build_Jupyter is None and self.build_id: self._code_build_Jupyter = CodeBuild_Jupyter(self.build_id) return self._code_build_Jupyter # # NOT WORKING IN LAMBDA (I think it is because the Javascript is not being executed ok) # def execute_python(self, python_code,keep_contents=True, target=None): # jp_web = self.jupyter_web() # jp_cell = self.jupyter_cell() # the prob is the browser object is being created twice # if target is None: # target = self.execute_python_file # if (target in jp_web.url()) is False: # jp_web.open(target) # if not keep_contents: # jp_cell.clear() # jp_cell.execute(python_code) # #jp_cell.new() # #jp_cell.text('some content') # return jp_cell.output_wait_for_data() def server_details(self): if self._server_details is None: if self.code_build_Jupyter(): self._server_details = self.code_build_Jupyter( ).get_server_details_from_logs() return self._server_details # api Methods def files(self, path=''): text_body = "" data = self.jupyter_api().contents(path) if data is None: text_title = ":red_circle: Folder `{0}` not found in server `{1}`".format( path, self.short_id) else: if path == '': path = '/' files = [] folders = [] text_title = ":point_right: Here are the files and folders for `{0}` in the server `{1}`".format( path, data.get('type'), self.short_id) for item in data.get('content'): url = "{0}/tree/{1}".format(self.jupyter_api().server, item.get('path')) url_preview = "{0}/{1}".format( self.jupyter_web().server, self.jupyter_web().resolve_url_notebook_preview( item.get('path'))) if item.get('type') == 'directory': #folders.append("<{0}|{1}> (<{2}|preview>)".format(url,item.get('name'), url_preview)) folders.append("<{0}|{1}>".format(url, item.get('name'))) else: files.append( " - {0} (<{1}|edit> , <{2}|preview>)\n".format( item.get('name'), url, url_preview)) #files.append("<{0}|{1}>".format(url,item.get('name'))) if files: text_body += '*Files:* \n{0}\n\n'.format(''.join(files)) if folders: text_body += '*Folders:* {0}'.format(' , '.join(folders)) return text_title, text_body def screenshot(self, path=None, width=None, height=None, delay=None, apply_ui_fixes=True): jupyter_web = self.login() (jupyter_web.open(path).browser_size(width, height).wait_seconds(delay)) jupyter_web.ui_add_jquery() if apply_ui_fixes: jupyter_web.ui_css_fixes(width) if path and 'osbot-no-code' in path: jupyter_web.ui_hide_input_boxes() return jupyter_web.screenshot_base64() def login(self): if self._needs_login is True: self.jupyter_web().login() self._needs_login = False return self.jupyter_web() def stop(self): return self.code_build_Jupyter().code_build.codebuild.stop_build( id=self.build_id).get('build') def execute_python_in_notebook(self, target_notebook, code, source_event): self.login() self.jupyter_web().open(target_notebook) self.jupyter_cell().wait_seconds(1) # refactor with better method self.jupyter_cell().new_top() \ .to_markdown() \ .text("### Code above requested by: \n ```{0}```".format(source_event)) \ .execute() result = self.jupyter_cell().execute_python( code).output_wait_for_data() self.jupyter_cell().save_notebook() return result def get_python_invoke_file(self): today = '{0}'.format(datetime.date.today().strftime('%d-%b-%y')) target_notebook = 'users/gsbot/invoke-{0}.ipynb'.format(today) created = False if self.jupyter_api().contents( target_notebook) is None: # we need to create the file self.jupyter_api().notebook_create(target_notebook) created = True target_notebook = "notebooks/{0}".format(target_notebook) return target_notebook, created
def stop_all(*params): return CodeBuild_Jupyter_Helper().stop_all_active()
def codebuild(self): server, token = CodeBuild_Jupyter_Helper().get_active_server_details() self.server = server self.token = token return self
def test_stop_build(self): code_build_helper = CodeBuild_Jupyter_Helper() self.result = code_build_helper.stop_all_active()