Browse Source

feat: support upgrade interfaces

Yeuoly 9 months ago
parent
commit
d36dece0af

+ 56 - 0
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")

+ 24 - 0
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"},
+        )

+ 68 - 0
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,15 +79,77 @@ 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:
         """
         Upload plugin package files