Exemplo n.º 1
0
    def test_source_bundle1(self):
        self.maxDiff = 5000
        directory = get_dir("pip1")
        nb_path = join(directory, "dummy.ipynb")

        # Note that here we are introspecting the environment from within
        # the test environment. Don't do this in the production code, which
        # runs in the notebook server. We need the introspection to run in
        # the kernel environment and not the notebook server environment.
        environment = detect_environment(directory)
        with make_notebook_source_bundle(
                nb_path,
                environment) as bundle, tarfile.open(mode="r:gz",
                                                     fileobj=bundle) as tar:

            names = sorted(tar.getnames())
            self.assertEqual(names, [
                "dummy.ipynb",
                "manifest.json",
                "requirements.txt",
            ])

            reqs = tar.extractfile("requirements.txt").read()
            self.assertEqual(reqs, b"numpy\npandas\nmatplotlib\n")

            manifest = json.loads(
                tar.extractfile("manifest.json").read().decode("utf-8"))

            # don't check locale value, just require it be present
            del manifest["locale"]
            del manifest["python"]["package_manager"]["version"]

            if sys.version_info[0] == 2:
                ipynb_hash = u"38aa30662bc16e91e6804cf21d7722f7"
            else:
                ipynb_hash = u"36873800b48ca5ab54760d60ba06703a"

            # noinspection SpellCheckingInspection
            self.assertEqual(
                manifest,
                {
                    u"version": 1,
                    u"metadata": {
                        u"appmode": u"jupyter-static",
                        u"entrypoint": u"dummy.ipynb",
                    },
                    u"python": {
                        u"version": self.python_version(),
                        u"package_manager": {
                            u"name": u"pip",
                            u"package_file": u"requirements.txt",
                        },
                    },
                    u"files": {
                        u"dummy.ipynb": {
                            u"checksum": ipynb_hash,
                        },
                        u"requirements.txt": {
                            u"checksum": u"5f2a5e862fe7afe3def4a57bb5cfb214"
                        },
                    },
                },
            )
Exemplo n.º 2
0
    def test_source_bundle2(self):
        self.maxDiff = 5000
        directory = get_dir("pip2")
        nb_path = join(directory, "dummy.ipynb")

        # Note that here we are introspecting the environment from within
        # the test environment. Don't do this in the production code, which
        # runs in the notebook server. We need the introspection to run in
        # the kernel environment and not the notebook server environment.
        environment = detect_environment(directory)

        with make_notebook_source_bundle(
                nb_path, environment,
                extra_files=["data.csv"
                             ]) as bundle, tarfile.open(mode="r:gz",
                                                        fileobj=bundle) as tar:

            names = sorted(tar.getnames())
            self.assertEqual(names, [
                "data.csv",
                "dummy.ipynb",
                "manifest.json",
                "requirements.txt",
            ])

            reqs = tar.extractfile("requirements.txt").read()

            # these are the dependencies declared in our setup.py
            self.assertIn(b"six", reqs)

            manifest = json.loads(
                tar.extractfile("manifest.json").read().decode("utf-8"))

            # don't check requirements.txt since we don't know the checksum
            del manifest["files"]["requirements.txt"]

            # also don't check locale value, just require it be present
            del manifest["locale"]
            del manifest["python"]["package_manager"]["version"]

            if sys.version_info[0] == 2:
                ipynb_hash = u"38aa30662bc16e91e6804cf21d7722f7"
            else:
                ipynb_hash = u"36873800b48ca5ab54760d60ba06703a"

            # noinspection SpellCheckingInspection
            self.assertEqual(
                manifest,
                {
                    u"version": 1,
                    u"metadata": {
                        u"appmode": u"jupyter-static",
                        u"entrypoint": u"dummy.ipynb",
                    },
                    u"python": {
                        u"version": self.python_version(),
                        u"package_manager": {
                            u"name": u"pip",
                            u"package_file": u"requirements.txt",
                        },
                    },
                    u"files": {
                        u"dummy.ipynb": {
                            u"checksum": ipynb_hash,
                        },
                        u"data.csv": {
                            u"checksum": u"f2bd77cc2752b3efbb732b761d2aa3c3"
                        },
                    },
                },
            )
Exemplo n.º 3
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