From d36dece0afdc34734f42dabce73b9994c7a996f9 Mon Sep 17 00:00:00 2001 From: Yeuoly Date: Fri, 25 Oct 2024 18:56:38 +0800 Subject: [PATCH] feat: support upgrade interfaces --- api/controllers/console/workspace/plugin.py | 56 +++++++++++++++++ api/core/plugin/manager/plugin.py | 24 ++++++++ api/services/plugin/plugin_service.py | 68 +++++++++++++++++++++ 3 files changed, 148 insertions(+) diff --git a/api/controllers/console/workspace/plugin.py b/api/controllers/console/workspace/plugin.py index a858f7a0ed..b3333f67e0 100644 --- a/api/controllers/console/workspace/plugin.py +++ b/api/controllers/console/workspace/plugin.py @@ -280,6 +280,60 @@ class PluginDeleteInstallTaskItemApi(Resource): return {"success": PluginService.delete_install_task_item(tenant_id, task_id, identifier)} +class PluginUpgradeFromMarketplaceApi(Resource): + @setup_required + @login_required + @account_initialization_required + def post(self): + user = current_user + if not user.is_admin_or_owner: + raise Forbidden() + + tenant_id = user.current_tenant_id + + parser = reqparse.RequestParser() + parser.add_argument("original_plugin_unique_identifier", type=str, required=True, location="json") + parser.add_argument("new_plugin_unique_identifier", type=str, required=True, location="json") + args = parser.parse_args() + + return jsonable_encoder( + PluginService.upgrade_plugin_with_marketplace( + tenant_id, args["original_plugin_unique_identifier"], args["new_plugin_unique_identifier"] + ) + ) + + +class PluginUpgradeFromGithubApi(Resource): + @setup_required + @login_required + @account_initialization_required + def post(self): + user = current_user + if not user.is_admin_or_owner: + raise Forbidden() + + tenant_id = user.current_tenant_id + + parser = reqparse.RequestParser() + parser.add_argument("original_plugin_unique_identifier", type=str, required=True, location="json") + parser.add_argument("new_plugin_unique_identifier", type=str, required=True, location="json") + parser.add_argument("repo", type=str, required=True, location="json") + parser.add_argument("version", type=str, required=True, location="json") + parser.add_argument("package", type=str, required=True, location="json") + args = parser.parse_args() + + return jsonable_encoder( + PluginService.upgrade_plugin_with_github( + tenant_id, + args["original_plugin_unique_identifier"], + args["new_plugin_unique_identifier"], + args["repo"], + args["version"], + args["package"], + ) + ) + + class PluginUninstallApi(Resource): @setup_required @login_required @@ -305,6 +359,8 @@ api.add_resource(PluginUploadFromPkgApi, "/workspaces/current/plugin/upload/pkg" api.add_resource(PluginUploadFromGithubApi, "/workspaces/current/plugin/upload/github") api.add_resource(PluginInstallFromPkgApi, "/workspaces/current/plugin/install/pkg") api.add_resource(PluginInstallFromGithubApi, "/workspaces/current/plugin/install/github") +api.add_resource(PluginUpgradeFromMarketplaceApi, "/workspaces/current/plugin/upgrade/marketplace") +api.add_resource(PluginUpgradeFromGithubApi, "/workspaces/current/plugin/upgrade/github") api.add_resource(PluginInstallFromMarketplaceApi, "/workspaces/current/plugin/install/marketplace") api.add_resource(PluginFetchManifestApi, "/workspaces/current/plugin/fetch-manifest") api.add_resource(PluginFetchInstallTasksApi, "/workspaces/current/plugin/tasks") diff --git a/api/core/plugin/manager/plugin.py b/api/core/plugin/manager/plugin.py index 6200d5380b..7075117e66 100644 --- a/api/core/plugin/manager/plugin.py +++ b/api/core/plugin/manager/plugin.py @@ -141,3 +141,27 @@ class PluginInstallationManager(BasePluginManager): }, headers={"Content-Type": "application/json"}, ) + + def upgrade_plugin( + self, + tenant_id: str, + original_plugin_unique_identifier: str, + new_plugin_unique_identifier: str, + source: PluginInstallationSource, + meta: dict, + ) -> PluginInstallTaskStartResponse: + """ + Upgrade a plugin. + """ + return self._request_with_plugin_daemon_response( + "POST", + f"plugin/{tenant_id}/management/upgrade", + PluginInstallTaskStartResponse, + data={ + "original_plugin_unique_identifier": original_plugin_unique_identifier, + "new_plugin_unique_identifier": new_plugin_unique_identifier, + "source": source, + "meta": meta, + }, + headers={"Content-Type": "application/json"}, + ) diff --git a/api/services/plugin/plugin_service.py b/api/services/plugin/plugin_service.py index 294cab9139..e9ef18ee97 100644 --- a/api/services/plugin/plugin_service.py +++ b/api/services/plugin/plugin_service.py @@ -58,11 +58,17 @@ class PluginService: @staticmethod def fetch_plugin_manifest(tenant_id: str, plugin_unique_identifier: str) -> PluginDeclaration: + """ + Fetch plugin manifest + """ manager = PluginInstallationManager() return manager.fetch_plugin_manifest(tenant_id, plugin_unique_identifier) @staticmethod def fetch_install_tasks(tenant_id: str, page: int, page_size: int) -> Sequence[PluginInstallTask]: + """ + Fetch plugin installation tasks + """ manager = PluginInstallationManager() return manager.fetch_plugin_installation_tasks(tenant_id, page, page_size) @@ -73,14 +79,76 @@ class PluginService: @staticmethod def delete_install_task(tenant_id: str, task_id: str) -> bool: + """ + Delete a plugin installation task + """ manager = PluginInstallationManager() return manager.delete_plugin_installation_task(tenant_id, task_id) @staticmethod def delete_install_task_item(tenant_id: str, task_id: str, identifier: str) -> bool: + """ + Delete a plugin installation task item + """ manager = PluginInstallationManager() return manager.delete_plugin_installation_task_item(tenant_id, task_id, identifier) + @staticmethod + def upgrade_plugin_with_marketplace( + tenant_id: str, original_plugin_unique_identifier: str, new_plugin_unique_identifier: str + ): + """ + Upgrade plugin with marketplace + """ + if original_plugin_unique_identifier == new_plugin_unique_identifier: + raise ValueError("you should not upgrade plugin with the same plugin") + + # check if plugin pkg is already downloaded + manager = PluginInstallationManager() + + try: + manager.fetch_plugin_manifest(tenant_id, new_plugin_unique_identifier) + # already downloaded, skip + except Exception: + # plugin not installed, download and upload pkg + pkg = download_plugin_pkg(new_plugin_unique_identifier) + manager.upload_pkg(tenant_id, pkg, verify_signature=True) + + return manager.upgrade_plugin( + tenant_id, + original_plugin_unique_identifier, + new_plugin_unique_identifier, + PluginInstallationSource.Marketplace, + { + "plugin_unique_identifier": new_plugin_unique_identifier, + }, + ) + + @staticmethod + def upgrade_plugin_with_github( + tenant_id: str, + original_plugin_unique_identifier: str, + new_plugin_unique_identifier: str, + repo: str, + version: str, + package: str, + ): + """ + Upgrade plugin with github + """ + manager = PluginInstallationManager() + return manager.upgrade_plugin( + tenant_id, + original_plugin_unique_identifier, + new_plugin_unique_identifier, + PluginInstallationSource.Github, + { + "repo": repo, + "version": version, + "package": package, + }, + ) + @staticmethod def upload_pkg(tenant_id: str, pkg: bytes, verify_signature: bool = False) -> PluginUploadResponse: """