Exemplo n.º 1
0
 def test_gather_basic_deployment_info_for_api_validates(self):
     directory = get_api_path("flask")
     server = RSConnectServer("https://www.bogus.com", "bogus")
     with self.assertRaises(RSConnectException):
         gather_basic_deployment_info_for_api(server, None, directory, "bogus:bogus:bogus", False, 0, "bogus")
     with self.assertRaises(RSConnectException):
         gather_basic_deployment_info_for_api(server, None, directory, "app:app", False, 0, "")
Exemplo n.º 2
0
 def test_verify_server(self):
     with self.assertRaises(RSConnectException):
         _verify_server(RSConnectServer("fake-url", None))
Exemplo n.º 3
0
 def test_deploy_python_api_validates(self):
     directory = get_api_path("flask")
     server = RSConnectServer("https://www.bogus.com", "bogus")
     with self.assertRaises(RSConnectException):
         deploy_python_api(server, directory, [], [], "bogus")
Exemplo n.º 4
0
    def post(self, action):
        data = self.get_json_body()

        if action == "verify_server":
            server_address = data["server_address"]
            api_key = data["api_key"]
            disable_tls_check = data["disable_tls_check"]
            cadata = data.get("cadata", None)

            canonical_address = None
            result = None
            try:
                canonical_address, result = test_server(
                    RSConnectServer(server_address, api_key, disable_tls_check,
                                    cadata))
            except SSLError as exc:
                if exc.reason == "UNKNOWN_PROTOCOL":
                    raise web.HTTPError(
                        400,
                        'Received an "SSL:UNKNOWN_PROTOCOL" error when trying to connect securely '
                        + "to the RStudio Connect server.\n" +
                        '* Try changing "https://" in the "Server Address" field to "http://".\n'
                        +
                        "* If the condition persists, contact your RStudio Connect server "
                        + "administrator.",
                    )
                raise web.HTTPError(
                    400,
                    "A TLS error occurred when trying to reach the RStudio Connect server.\n"
                    +
                    "* Ensure that the server address you entered is correct.\n"
                    +
                    "* Ask your RStudio Connect administrator if you need a certificate bundle and\n"
                    +
                    '  upload it using "Upload TLS Certificate Bundle" below.',
                )
            except Exception as err:
                self.log.exception(
                    "Unable to verify that the provided server is running RStudio Connect"
                )
                raise web.HTTPError(
                    400,
                    "Unable to verify that the provided server is running RStudio Connect: %s"
                    % err,
                )
            if canonical_address is not None:
                uri = canonical_address.url
                try:
                    verify_api_key(
                        RSConnectServer(uri, api_key, disable_tls_check,
                                        cadata))
                    address_hash = md5(server_address)
                    self.finish(
                        json.dumps({
                            "status":
                            "Provided server is running RStudio Connect",
                            "address_hash": address_hash,
                            "server_address": canonical_address.url,
                        }))
                except RSConnectException:
                    raise web.HTTPError(
                        401, "Unable to verify the provided API key")
            return

        if action == "app_search":
            uri = data["server_address"]
            api_key = data["api_key"]
            title = data["notebook_title"]
            app_id = data.get("app_id")
            disable_tls_check = data["disable_tls_check"]
            cadata = data.get("cadata", None)

            try:
                server = RSConnectServer(uri, api_key, disable_tls_check,
                                         cadata)
                retval = override_title_search(server, app_id, title)
            except RSConnectException as exc:
                raise web.HTTPError(400, exc.message)
            self.finish(json.dumps(retval))
            return

        if action == "deploy":
            uri = data["server_address"]
            app_id = data.get("app_id")
            nb_title = data["notebook_title"]
            nb_name = data["notebook_name"]
            nb_path = unquote_plus(data["notebook_path"].strip("/"))
            api_key = data["api_key"]
            app_mode = data["app_mode"]
            environment_dict = data.get("environment")
            disable_tls_check = data["disable_tls_check"]
            cadata = data.get("cadata", None)
            extra_files = data.get("files", [])
            hide_all_input = data.get("hide_all_input", False)
            hide_tagged_input = data.get("hide_tagged_input", False)

            model = self.contents_manager.get(path=nb_path)
            if model["type"] != "notebook":
                # not a notebook
                raise web.HTTPError(400, "Not a notebook: %s" % nb_path)

            if not hasattr(self.contents_manager, "_get_os_path"):
                raise web.HTTPError(
                    400, "Notebook does not live on a mounted filesystem")

            os_path = self.contents_manager._get_os_path(nb_path)

            if app_mode == "static":
                try:
                    bundle = make_notebook_html_bundle(
                        os_path,
                        sys.executable,
                        hide_all_input=hide_all_input,
                        hide_tagged_input=hide_tagged_input)
                except Exception as exc:
                    self.log.exception("Bundle creation failed")
                    raise web.HTTPError(500,
                                        "Bundle creation failed: %s" % exc)
            elif app_mode == "jupyter-static":
                if not environment_dict:
                    raise web.HTTPError(
                        400,
                        "environment is required for jupyter-static app_mode")

                try:
                    bundle = make_notebook_source_bundle(
                        os_path,
                        Environment(**environment_dict),
                        extra_files,
                        hide_all_input=hide_all_input,
                        hide_tagged_input=hide_tagged_input,
                    )
                except Exception as exc:
                    self.log.exception("Bundle creation failed")
                    raise web.HTTPError(500,
                                        "Bundle creation failed: %s" % exc)
            else:
                raise web.HTTPError(
                    400,
                    'Invalid app_mode: %s, must be "static" or "jupyter-static"'
                    % app_mode,
                )

            try:
                server = RSConnectServer(uri, api_key, disable_tls_check,
                                         cadata)
                with RSConnect(server) as api_client:
                    retval = api_client.deploy(app_id, nb_name, nb_title,
                                               nb_title is not None, bundle)
                    retval["cookies"] = server.cookie_jar.as_dict()
            except RSConnectException as exc:
                raise web.HTTPError(400, exc.message)

            self.finish(json.dumps(retval))
            return

        if action == "app_get":
            uri = data["server_address"]
            api_key = data["api_key"]
            app_id = data["app_id"]
            disable_tls_check = data["disable_tls_check"]
            cadata = data.get("cadata", None)

            try:
                server = RSConnectServer(uri, api_key, disable_tls_check,
                                         cadata)
                with RSConnect(server) as api_client:
                    retval = api_client.app_get(app_id)
            except RSConnectException as exc:
                raise web.HTTPError(400, exc.message)
            self.finish(json.dumps(retval))
            return

        if action == "get_log":
            uri = data["server_address"]
            api_key = data["api_key"]
            task_id = data["task_id"]
            last_status = data["last_status"]
            cookie_source = data.get("cookies", {})
            disable_tls_check = data["disable_tls_check"]
            cadata = data.get("cadata", None)

            try:
                rs_connect_server = RSConnectServer(uri, api_key,
                                                    disable_tls_check, cadata)
                rs_connect_server.cookie_jar = CookieJar.from_dict(
                    cookie_source)
                with RSConnect(rs_connect_server) as api_client:
                    retval = api_client.task_get(task_id, last_status)
                rs_connect_server.handle_bad_response(retval)
            except RSConnectException as exc:
                raise web.HTTPError(400, exc.message)
            self.finish(json.dumps(retval))
            return

        if action == "app_config":
            uri = data["server_address"]
            api_key = data["api_key"]
            app_id = data["app_id"]
            disable_tls_check = data["disable_tls_check"]
            cadata = data.get("cadata", None)

            try:
                server = RSConnectServer(uri, api_key, disable_tls_check,
                                         cadata)
                with RSConnect(server) as api_client:
                    retval = api_client.app_config(app_id)
                server.handle_bad_response(retval)
            except RSConnectException as exc:
                raise web.HTTPError(400, exc.message)
            self.finish(json.dumps(retval))
            return

        if action == "write_manifest":
            environment_dict = data["environment"]
            nb_path = unquote_plus(data["notebook_path"].strip("/"))
            relative_dir = dirname(nb_path)
            os_path = self.contents_manager._get_os_path(nb_path)
            output_dir = dirname(os_path)
            nb_name = os.path.basename(os_path)
            created, skipped = write_manifest(relative_dir, nb_name,
                                              Environment(**environment_dict),
                                              output_dir)
            self.finish(json.dumps({"created": created, "skipped": skipped}))
            return

        if action == "get_python_settings":
            uri = data["server_address"]
            api_key = data["api_key"]
            disable_tls_check = data["disable_tls_check"]
            cadata = data.get("cadata", None)

            try:
                server = RSConnectServer(uri, api_key, disable_tls_check,
                                         cadata)
                with RSConnect(server) as api_client:
                    retval = api_client.python_settings()
                server.handle_bad_response(retval)
            except RSConnectException as exc:
                raise web.HTTPError(400, exc.message)
            self.finish(json.dumps(retval))
            return
Exemplo n.º 5
0
 def setUp(self):
     self.server_store = ServerStore()
     self.server_store.set("connect", "https://connect.remote:6443", "apiKey", insecure=True)
     self.server = RSConnectServer("https://connect.remote:6443", "apiKey", True, None)
     self.build_store = ContentBuildStore(self.server)
     self.build_store._set("rsconnect_build_running", False)
     self.build_store._set(
         "rsconnect_content",
         {
             "c96db3f3-87a1-4df5-9f58-eb109c397718": {
                 "guid": "c96db3f3-87a1-4df5-9f58-eb109c397718",
                 "bundle_id": "177",
                 "title": "orphan-proc-shiny-test",
                 "name": "orphan-proc-shiny-test",
                 "app_mode": "shiny",
                 "content_url": "https://connect.remote:6443/content/c96db3f3-87a1-4df5-9f58-eb109c397718/",
                 "dashboard_url": "https://connect.remote:6443/connect/#/apps/c96db3f3-87a1-4df5-9f58-eb109c397718",
                 "created_time": "2021-11-04T18:07:12Z",
                 "last_deployed_time": "2021-11-10T19:10:56Z",
                 "owner_guid": "edf26318-0027-4d9d-bbbb-54703ebb1855",
                 "rsconnect_build_status": "NEEDS_BUILD",
             },
             "fe673896-f92a-40cc-be4c-e4872bb90a37": {
                 "guid": "fe673896-f92a-40cc-be4c-e4872bb90a37",
                 "bundle_id": "185",
                 "title": "interactive-rmd",
                 "name": "interactive-rmd",
                 "app_mode": "rmd-shiny",
                 "content_url": "https://connect.remote:6443/content/fe673896-f92a-40cc-be4c-e4872bb90a37/",
                 "dashboard_url": "https://connect.remote:6443/connect/#/apps/fe673896-f92a-40cc-be4c-e4872bb90a37",
                 "created_time": "2021-11-15T15:37:53Z",
                 "last_deployed_time": "2021-11-15T15:37:57Z",
                 "owner_guid": "edf26318-0027-4d9d-bbbb-54703ebb1855",
                 "rsconnect_build_status": "ERROR",
             },
             "a0b6b5a2-5fbe-4293-8310-4f80054bc24f": {
                 "guid": "a0b6b5a2-5fbe-4293-8310-4f80054bc24f",
                 "bundle_id": "184",
                 "title": "stock-report-jupyter",
                 "name": "stock-report-jupyter",
                 "app_mode": "jupyter-static",
                 "content_url": "https://connect.remote:6443/content/a0b6b5a2-5fbe-4293-8310-4f80054bc24f/",
                 "dashboard_url": "https://connect.remote:6443/connect/#/apps/a0b6b5a2-5fbe-4293-8310-4f80054bc24f",
                 "created_time": "2021-11-15T15:27:18Z",
                 "last_deployed_time": "2021-11-15T15:35:27Z",
                 "owner_guid": "edf26318-0027-4d9d-bbbb-54703ebb1855",
                 "rsconnect_build_status": "RUNNING",
             },
             "23315cc9-ed2a-40ad-9e99-e5e49066531a": {
                 "guid": "23315cc9-ed2a-40ad-9e99-e5e49066531a",
                 "bundle_id": "180",
                 "title": "static-rmd",
                 "name": "static-rmd2",
                 "app_mode": "rmd-static",
                 "content_url": "https://connect.remote:6443/content/23315cc9-ed2a-40ad-9e99-e5e49066531a/",
                 "dashboard_url": "https://connect.remote:6443/connect/#/apps/23315cc9-ed2a-40ad-9e99-e5e49066531a",
                 "created_time": "2021-11-15T15:20:58Z",
                 "last_deployed_time": "2021-11-15T15:25:31Z",
                 "owner_guid": "edf26318-0027-4d9d-bbbb-54703ebb1855",
                 "rsconnect_build_status": "COMPLETE",
                 "rsconnect_last_build_time": "2021-12-13T18:10:38Z",
                 "rsconnect_last_build_log": "/logs/localhost_3939/23315cc9-ed2a-40ad-9e99-e5e49066531a/ZUf44zVWHjODv1Rq.log",
                 "rsconnect_build_task_result": {
                     "id": "ZUf44zVWHjODv1Rq",
                     "user_id": 1,
                     "result": {"type": "", "data": None},
                     "finished": True,
                     "code": 0,
                     "error": "",
                 },
             },
             "015143da-b75f-407c-81b1-99c4a724341e": {
                 "guid": "015143da-b75f-407c-81b1-99c4a724341e",
                 "bundle_id": "176",
                 "title": "plumber-async",
                 "name": "plumber-async",
                 "app_mode": "api",
                 "content_url": "https://connect.remote:6443/content/015143da-b75f-407c-81b1-99c4a724341e/",
                 "dashboard_url": "https://connect.remote:6443/connect/#/apps/015143da-b75f-407c-81b1-99c4a724341e",
                 "created_time": "2021-11-01T20:43:32Z",
                 "last_deployed_time": "2021-11-03T17:48:59Z",
                 "owner_guid": "edf26318-0027-4d9d-bbbb-54703ebb1855",
                 "rsconnect_build_status": "NEEDS_BUILD",
             },
         },
     )