diff --git a/sig-architecture/concepts-and-designs/pluggable-architecture-zh.md b/sig-architecture/concepts-and-designs/pluggable-architecture-zh.md new file mode 100644 index 00000000..30481d18 --- /dev/null +++ b/sig-architecture/concepts-and-designs/pluggable-architecture-zh.md @@ -0,0 +1,117 @@ +# Summary + +可插拔架构是 KubeSphere 4.0 中最重要的改动,目的是让 KubeSphere 可以动态的进行功能扩展,提供完善的插件机制便于第三方的应用接入,构建更加完善的生态。 + +- Data Management +- Project Management +- DevOps +- ... + +## Core Capabilities + +1. 前端插件化:前端项目支持插件化,可通过插件在各级导航栏插入新的功能入口,实现功能页面的动态添加。 +2. 后端插件化:后端支持 API 拓展机制,提供统一的 API 聚合,认证鉴权框架。 +3. 插件管理:提供可视化的插件管理机制,支持插件的安装、卸载、启用、停用、配置、升级 +4. 插件仓库:提供插件的打包、发布机制,提供内置的插件仓库。 +5. 插件框架:提供插件开发、打包、发布相关的脚手架,提供完善的插件开发文档。 + +## Architecture + +![plugin-arch](../images/pluggable-arch.png) + +## Frontend + +TBD + +## Backend + +后端的插件化主要包含 API 的注册、静态资源的代理两个部分,可以把 ks-apiserver 看作一个可拓展的 API 网关,由 ks-apiserver 提供统一的 API 认证鉴权能力,支持动态的 API 拓展。 + +![backend](../images/backend.svg) + +### Plugin Model + +**插件** 通过 CRD 进行定义,主要包含三个部分:`APIService`、`JSBundle` 和 `ReverseProxy`。 + +#### APIService + +APIService 是一种类似于 [K8s Aggregated API](https://kubernetes.io/docs/concepts/extend-kubernetes/api-extension/apiserver-aggregation/) 的一种 API 拓展机制,可以声明式的注册[资源型的 API](https://kubernetes.io/zh/docs/reference/using-api/api-concepts/),便于通过 [KubeSphere 的权限控制体系](#TODO)进行统一的 API 权限控制,一个插件中可以包含多个 APIService。 + +```yaml +apiVersion: extensions.kubesphere.io/v1alpha1 +kind: APIService +metadata: + name: v1alpha1.devops.kubesphere.io + annotations: + meta.helm.sh/release-name: devops-0.10.0 # 通过 Subscription 订阅插件之后,插件 chart 中包含的 APIService 通过 helm 创建出来 +spec: + group: devops.kubesphere.io # API Group + version: v1alpha1 # API Version + endpoint: https://ks-devops.kubesphere-devops-system.svc # backend + insecureSkipTLSVerify: true +status: + enabled: true +``` + +#### JSBundle + +JSBundle 定义了需要注入到前端框架中的 js bundle。为了便于开发,体积较小的 js 文件可以直接嵌入到 ConfigMap 或 Secret 中,体积较大的 js 文件则需要通过额外的后端服务来提供。插件被启用之后,ks-apiserver 会代理相关的静态资源请求,前端框架则借助此 API 动态的加载 js 文件。 + +```yaml +apiVersion: extensions.kubesphere.io/v1alpha1 +kind: JSBundle +metadata: + name: v1alpha1.devops.kubesphere.io + annotations: + meta.helm.sh/release-name: devops-0.10.0 +spec: + rawFrom: + url: https://ks-devops.kubesphere-devops-system.svc/dist/devops.kubesphere.io/v1alpha1/index.js + # configMapKeyRef: + # name: devops + # key: index.js + # namespace: kubesphere-devops-system + # secretKeyRef: + # name: + # key: + # namespace: kubesphere-devops-system + # TODO(@chenz24) +status: + enabled: true + link: /dist/devops.kubesphere.io/v1alpha1/index.js +``` + +#### ReverseProxy + +提供非资源型 API 的方向代理,可以用来代理一些静态的资源文件,支持路径的 Rewrite,支持请求头的注入。 + +API 的路径会在解析插件的时候就进行检查,避免冲突。 + +```yaml +apiVersion: extensions.kubesphere.io/v1alpha1 +kind: ReverseProxy +metadata: + name: devops.kubesphere.io +spec: + matcher: + - path: /res/devops.kubesphere.io/images/* + method: GET + upstream: + insecureSkipVerify: false + caBudle: <Base64Data> + backend: https://ks-devops.kubesphere-system.svc + healthCheck: + url: /healthz + interval: 15s + status: 200 + timeout: 15s + rewrite: + - '/old-prefix/* /new-prefix{path}' + header: + up: + - 'Foo: Bar' + down: + - 'Foo: Bar' +status: + enabled: true +``` \ No newline at end of file diff --git a/sig-architecture/concepts-and-designs/plugin-development-guide-zh.md b/sig-architecture/concepts-and-designs/plugin-development-guide-zh.md new file mode 100644 index 00000000..d202e2c3 --- /dev/null +++ b/sig-architecture/concepts-and-designs/plugin-development-guide-zh.md @@ -0,0 +1,107 @@ +# 插件开发指南 + +## 开发插件 + +### 项目初始化 + +1. 通过 CLI 创建一个项目脚手架 + +TBD + +### 前端页面的开发 + +1. 如何插入一个新的功能页面 +2. 前端设计风格指南 + +TBD + +### 后端 API 的开发 + +1. 后端 API 风格指南 +2. API 权限控制 + +TBD + +## 插件的打包与发布 + +插件开发完成之后,需要与依赖组件一起打包为 Helm Chart。 + +1. 一个插件打包为一个 Helm Chart +2. 一组插件打包为 Docker Iamge 之后可以进行发布 + +### Helm Chart 的目录结构 + +```bash +devops/ +├── .helmignore +├── Chart.yaml # Helm chart 基本信息 +├── LICENSE +├── README.md +├── values.yaml # 默认的配置信息 +├── charts/ +└── templates/ + ├── workloads.yaml # 需要部署的工作负载 + ├── services.yaml # 需要创建的 service + ├── extensions.yaml # 定义 APIService, JSBundle 用于注册 API 与 js 文件 + ├── roletemplates.yaml # 通过 role template CRD 动态注册权限控制项 + └── tests/ +dmp/ # 可以同时打包发布多个插件 +├── .helmignore +├── Chart.yaml +├── LICENSE +├── README.md +├── values.yaml +├── charts/ +└── templates/ + ├── workloads.yaml + ├── services.yaml + ├── extensions.yaml + ├── roletemplates.yaml + └── tests/ +Dockerfile # 将 charts 打包到 docker image 进行发布 +``` + +### Chart.yaml 的定义 + +```yaml +apiVersion: v2 +name: devops +version: v0.10.0 +kubeVersion: v1.17.0 +description: DevOps Plugin for KubeSphere. +type: application +keywords: + - DevOps +home: https://kubesphere.io +sources: + - https://github.com/kubesphere/ks-devops +dependencies: # chart 必要条件列表 (可选) + - name: jenkins + version: v0.0.1 + # repository: (可选)仓库URL () 或别名 ("@repo-name") + # condition: (可选) 解析为布尔值的yaml路径,用于启用/禁用chart (e.g. subchart1.enabled ) + # tags: (可选) + # - 用于一次启用/禁用 一组chart的tag + # import-values: (可选) + # - ImportValue 保存源值到导入父键的映射。每项可以是字符串或者一对子/父列表项 + # alias: (可选) chart中使用的别名。当你要多次添加相同的chart时会很有用 +maintainers: + - name: kubesphere + email: rick@Kubesphere.io + url: https://github.com/linuxsuren +icon: 'data:image/png;base64, PHN2ZyBoZWlnaHQ9IjUxMnB0IiB2aWV3Qm94PSIwIDAgNTEyIDUxMi4wMDEiIHdpZHRoPSI1MTJwdCIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIj48cGF0aCBkPSJtNTEyIDI1NmMwIDE0MS4zODY3MTktMTE0LjYxMzI4MSAyNTYtMjU2IDI1Ni0xNDEuMzgyODEyIDAtMjU2LTExNC42MTMyODEtMjU2LTI1NnMxMTQuNjE3MTg4LTI1NiAyNTYtMjU2YzE0MS4zODY3MTkgMCAyNTYgMTE0LjYxMzI4MSAyNTYgMjU2em0wIDAiIGZpbGw9IiM1YTU0ZTAiLz48cGF0aCBkPSJtNTEwLjkyOTY4OCAyNzkuMzQ3NjU2LTkxLjM1NTQ2OS05MS4zNTkzNzUtNy41OTc2NTcgMTAuMTA5Mzc1LTEwNC45ODA0NjgtMTA0Ljk4NDM3NS02NC4xODc1IDEyMi45MTAxNTctMTQ0LjAwNzgxMyAyNi44MzU5MzcgMTI1Ljk5MjE4OCAxMjUuOTkyMTg3LTY2LjI4OTA2MyA0Ni44MTY0MDcgOTYuMzIwMzEzIDk2LjMxNjQwNmMuMzk0NTMxLjAwMzkwNi43ODUxNTYuMDE1NjI1IDEuMTc1NzgxLjAxNTYyNSAxMzMuNTExNzE5IDAgMjQzLjEzMjgxMi0xMDIuMjE0ODQ0IDI1NC45Mjk2ODgtMjMyLjY1MjM0NHptMCAwIiBmaWxsPSIjMzgzOGJhIi8+PHBhdGggZD0ibTE4NCA1MDEuNzE4NzVjMjIuODM5ODQ0IDYuNjc5Njg4IDQ3IDEwLjI4MTI1IDcyIDEwLjI4MTI1czQ5LjE2MDE1Ni0zLjYwMTU2MiA3Mi0xMC4yODEyNXYtMTQyLjcxODc1aC0xNDR6bTAgMCIgZmlsbD0iI2ZmYmVhYSIvPjxwYXRoIGQ9Im0yNTUuOTA2MjUgMzU5djE1M2guMDkzNzVjMjUgMCA0OS4xNjAxNTYtMy42MDE1NjIgNzItMTAuMjgxMjV2LTE0Mi43MTg3NXptMCAwIiBmaWxsPSIjZmFhNjhlIi8+PHBhdGggZD0ibTM4NS4xMjUgMTY5LjkxNzk2OWgtMjU4LjI1Yy0yMy4xMjUgMC00MS44NzUgMTguNzQ2MDkzLTQxLjg3NSA0MS44NzUgMCAyMy4xMjUgMTguNzUgNDEuODc1IDQxLjg3NSA0MS44NzVoMzEuNjI4OTA2djE2MmgxOTQuOTkyMTg4di0xNjJoMzEuNjI4OTA2YzIzLjEyODkwNiAwIDQxLjg3NS0xOC43NSA0MS44NzUtNDEuODc1IDAtMjMuMTI4OTA3LTE4Ljc0NjA5NC00MS44NzUtNDEuODc1LTQxLjg3NXptMCAwIiBmaWxsPSIjZmZkYTAwIi8+PHBhdGggZD0ibTM4NS4xMjUgMTY5LjkxNzk2OWgtMTI5LjIxODc1djI0NS43NWg5Ny41ODk4NDR2LTE2MmgzMS42Mjg5MDZjMjMuMTI4OTA2IDAgNDEuODc1LTE4Ljc1IDQxLjg3NS00MS44NzUgMC0yMy4xMjg5MDctMTguNzQ2MDk0LTQxLjg3NS00MS44NzUtNDEuODc1em0wIDAiIGZpbGw9IiNmZmIwMDAiLz48cGF0aCBkPSJtMzIwLjMzMjAzMSAxMzIuMzMyMDMxYzAgMzUuNTMxMjUtMjguODAwNzgxIDY0LjMzMjAzMS02NC4zMzIwMzEgNjQuMzMyMDMxcy02NC4zMzIwMzEtMjguODAwNzgxLTY0LjMzMjAzMS02NC4zMzIwMzFjMC0zNS41MjczNDMgMjguODAwNzgxLTY0LjMzMjAzMSA2NC4zMzIwMzEtNjQuMzMyMDMxczY0LjMzMjAzMSAyOC44MDQ2ODggNjQuMzMyMDMxIDY0LjMzMjAzMXptMCAwIiBmaWxsPSIjZmZmIi8+PHBhdGggZD0ibTI1NiA2OGMtLjAzMTI1IDAtLjA2MjUuMDAzOTA2LS4wOTM3NS4wMDM5MDZ2MTI4LjY2MDE1NmguMDkzNzVjMzUuNTMxMjUgMCA2NC4zMzIwMzEtMjguODAwNzgxIDY0LjMzMjAzMS02NC4zMzIwMzEgMC0zNS41MjczNDMtMjguODAwNzgxLTY0LjMzMjAzMS02NC4zMzIwMzEtNjQuMzMyMDMxem0wIDAiIGZpbGw9IiNlOWVkZjUiLz48cGF0aCBkPSJtMjMzLjY2MDE1NiAxMzIuMzMyMDMxYzAgNy45MTQwNjMtNi40MTQwNjIgMTQuMzI4MTI1LTE0LjMyODEyNSAxNC4zMjgxMjUtNy45MTAxNTYgMC0xNC4zMjgxMjUtNi40MTQwNjItMTQuMzI4MTI1LTE0LjMyODEyNSAwLTcuOTE0MDYyIDYuNDE3OTY5LTE0LjMyODEyNSAxNC4zMjgxMjUtMTQuMzI4MTI1IDcuOTE0MDYzIDAgMTQuMzI4MTI1IDYuNDE0MDYzIDE0LjMyODEyNSAxNC4zMjgxMjV6bTAgMCIgZmlsbD0iI2ZlODIwNSIvPjxwYXRoIGQ9Im0zMDYuOTk2MDk0IDEzMi4zMzIwMzFjMCA3LjkxNDA2My02LjQxNDA2MyAxNC4zMjgxMjUtMTQuMzI4MTI1IDE0LjMyODEyNS03LjkxNDA2MyAwLTE0LjMyODEyNS02LjQxNDA2Mi0xNC4zMjgxMjUtMTQuMzI4MTI1IDAtNy45MTQwNjIgNi40MTQwNjItMTQuMzI4MTI1IDE0LjMyODEyNS0xNC4zMjgxMjUgNy45MTQwNjIgMCAxNC4zMjgxMjUgNi40MTQwNjMgMTQuMzI4MTI1IDE0LjMyODEyNXptMCAwIiBmaWxsPSIjZmU2YTE2Ii8+PC9zdmc+' +appVersion: v0.10.0 +annotations: + extensions.kubesphere.io/foo: bar # 额外的注释信息 +``` + +### 打包为 Docker Iamge 对插件进行分发 + +```dockerfile +FROM baseimage # Framwork 提供的 baseimage + +WORKDIR /charts +COPY . /charts +RUN helm index . +CMD ["serve"] # serve 一个 helm repo,并提供 grpc 接口,配合 Repository 实现 API Aggregation +``` diff --git a/sig-architecture/concepts-and-designs/plugin-management-zh.md b/sig-architecture/concepts-and-designs/plugin-management-zh.md new file mode 100644 index 00000000..36a56942 --- /dev/null +++ b/sig-architecture/concepts-and-designs/plugin-management-zh.md @@ -0,0 +1,133 @@ +### Plugin + +插件仓库部署完成后,plugin-controller-mamnager 会定时拉取最新的 Chart 解析后生成 Plugin 对象,以供订阅。 + +```yaml +apiVersion: extensions.kubesphere.io/v1alpha1 +kind: Plugin +metadata: + name: devops + labels: + extensions.kubesphere.io/category=devops +status: + phase: deployed + currentVersion: v0.10.1 + versions: + - description: DevOps plugin for KubeSphere. + keywords: + - devops + maintainers: + - email: devops.kubesphere.io + name: kubesphere + repo: builtin + version: 0.10.0 + minKubeVersion: 1.17.0 + - description: DevOps plugin for KubeSphere. + keywords: + - devops + maintainers: + - email: devops.kubesphere.io + name: kubesphere + repo: builtin + version: 0.10.1 + minKubeVersion: 1.17.0 +``` + + + +### PluginVersion + +插件可以同时存在多个版本,插件名称在同一个 Repo 中是唯一值 + +```yaml +apiVersion: extensions.kubesphere.io/v1alpha1 +kind: PluginVersion +metadata: + name: devops-v0.10.1 +spec: + description: DevOps plugin for KubeSphere. + keywords: + - devops + maintainers: + - email: devops.kubesphere.io + name: kubesphere + repo: builtin + version: 0.10.0 + minKubeVersion: 1.17.0 + files: + - NOTES.yaml + - templates/deployments.yaml +``` + +### PluginVersion Files + +Aggregated API,用于从 Repo 中直接加载 Helm Chart 中的数据 + +文件列表 + +``` +$ kubectl get --raw=/apis/packages.extensions.kubesphere.io/v1alpha1/pluginversions/devops-0.10.0/files +[ + "Chart.yaml", + "README.md", + "templates/NOTES.txt", + "templates/deployment.yaml", + "templates/hpa.yaml", + "templates/ingress.yaml", + "templates/service.yaml", + "templates/serviceaccount.yaml", + "templates/tests/test-connection.yaml", + "values.yaml" +]% +``` + +获取单个文件 + +``` +$ kubectl get --raw=/apis/packages.extensions.kubesphere.io/v1alpha1/pluginversions/xxx/files\?name=values.yaml +# Default values for test. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + +replicaCount: 1 + +image: + repository: nginx + pullPolicy: IfNotPresent + # Overrides the image tag whose default is the chart appVersion. + tag: "" + +imagePullSecrets: [] +nameOverride: "" +fullnameOverride: "" +``` + +### Subscription + +通过订阅的方式安装插件,通过 Subscription 来控制安装卸载,启用、停用,状态同步,版本升级。 + +```yaml +apiVersion: extensions.kubesphere.io/v1alpha1 +kind: Subscription +metadata: + name: devops-0.10.0 +spec: + enabled: true + plugin: + name: devops + version: 0.10.0 # 通过更新版本触发 upgrade, rollback + targetNamespace: kubesphere-devops-system + config: + foo: bar # 插件的配置信息 +status: + phase: deployed # unknown, superseded, failed, uninstalling, pending-install, pending-upgrade 或 pending-rollback +``` + + +### Upgrade + +TBD + +### Dependency + +TBD \ No newline at end of file diff --git a/sig-architecture/concepts-and-designs/plugin-repository-zh.md b/sig-architecture/concepts-and-designs/plugin-repository-zh.md new file mode 100644 index 00000000..72a0253f --- /dev/null +++ b/sig-architecture/concepts-and-designs/plugin-repository-zh.md @@ -0,0 +1,35 @@ +# 插件仓库 + +当我们通过 Docker Image 对 Helm Chart 进行打包的插件进行打包之后,可以将这个 Repo 部署到集群中 + +### Repository + +定义 Repository 用于加载打包为 Docker Image 的插件,创建好 Repository 对象后,plugin-controller-manager 会部署该 Docker Image,以提供 Helm Repo(HTTP)、Plugin(Aggregated API) 相关的 API。 + +```yaml +apiVersion: extensions.kubesphere.io/v1alpha1 +kind: Repository +metadata: + name: builtin +spec: + image: docker.io/kubespheredev/builtin:latest # 内置的仓库 + displayName: Builtin Repository + publisher: admin@kubesphere.io + updateStrategy: # 仓库的更新策略 + registryPoll: + interval: 10m +``` + +plugin-controller-manager 会部署 `docker.io/kubespheredev/builtin:latest`,并创建 builtin.kubesphere-system.svc 这个 Service,定时从 helm repo 拉取 Helm Chart, 读取 Helm Chart 中的元数据,进行数据校验,同时写入 Plugin、PluginVersion 对象,通过 Aggregated API 实现 pluginversions/files 这个 Aggregated API。 + +### Category + +```yaml +apiVersion: extensions.kubesphere.io/v1alpha1 +kind: Category +metadata: + name: devops +spec: + displayName: "DevOps" + description: "DevOps" +``` diff --git a/sig-architecture/images/backend.svg b/sig-architecture/images/backend.svg new file mode 100644 index 00000000..c48d1663 --- /dev/null +++ b/sig-architecture/images/backend.svg @@ -0,0 +1,4 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- Do not edit this file with editors other than diagrams.net --> +<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd"> +<svg xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" version="1.1" width="1902px" height="852px" viewBox="-0.5 -0.5 1902 852" content="<mxfile host="app.diagrams.net" modified="2021-12-21T10:29:57.596Z" agent="5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/96.0.4664.110 Safari/537.36" etag="YaQbJi0Hb2oYkKbKYZ4o" version="15.9.6" type="google"><diagram id="vKN-n06WEtU0aiU7Nuyo" name="第 1 页">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</diagram></mxfile>" style="background-color: rgb(42, 42, 42);"><defs/><g><path d="M 690 511.7 L 800 511.7 L 800 546.7 L 790 561.7 L 690 561.7 Z" fill="rgb(42, 42, 42)" stroke="rgb(240, 240, 240)" stroke-miterlimit="10" pointer-events="all"/><path d="M 800 511.7 L 1235 511.7 L 1235 795 L 690 795 L 690 561.7" fill="none" stroke="rgb(240, 240, 240)" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 108px; height: 1px; padding-top: 537px; margin-left: 691px;"><div data-drawio-colors="color: rgb(240, 240, 240); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 8px; font-family: Helvetica; color: rgb(240, 240, 240); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"><font style="font-size: 8px">plugin-controller</font></div></div></div></foreignObject><text x="745" y="539" fill="rgb(240, 240, 240)" font-family="Helvetica" font-size="8px" text-anchor="middle">plugin-controller</text></switch></g><path d="M 690 93.75 L 800 93.75 L 800 128.75 L 790 143.75 L 690 143.75 Z" fill="rgb(42, 42, 42)" stroke="rgb(240, 240, 240)" stroke-miterlimit="10" pointer-events="all"/><path d="M 800 93.75 L 1235 93.75 L 1235 455 L 690 455 L 690 143.75" fill="none" stroke="rgb(240, 240, 240)" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 108px; height: 1px; padding-top: 119px; margin-left: 691px;"><div data-drawio-colors="color: rgb(240, 240, 240); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 8px; font-family: Helvetica; color: rgb(240, 240, 240); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;"><font style="font-size: 8px">ks-apiserver</font></div></div></div></foreignObject><text x="745" y="121" fill="rgb(240, 240, 240)" font-family="Helvetica" font-size="8px" text-anchor="middle">ks-apiserver</text></switch></g><path d="M 715 155 L 775 155 L 775 170 L 765 185 L 715 185 Z" fill="rgb(42, 42, 42)" stroke="rgb(240, 240, 240)" stroke-miterlimit="10" pointer-events="all"/><path d="M 775 155 L 1195 155 L 1195 445 L 715 445 L 715 185" fill="none" stroke="rgb(240, 240, 240)" stroke-miterlimit="10" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 58px; height: 1px; padding-top: 170px; margin-left: 716px;"><div data-drawio-colors="color: rgb(240, 240, 240); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 8px; font-family: Helvetica; color: rgb(240, 240, 240); line-height: 1.2; pointer-events: all; white-space: normal; overflow-wrap: normal;">filters</div></div></div></foreignObject><text x="745" y="172" fill="rgb(240, 240, 240)" font-family="Helvetica" font-size="8px" text-anchor="middle">filters</text></switch></g><rect x="715" y="203.75" width="480" height="61.25" fill="rgb(42, 42, 42)" stroke="rgb(240, 240, 240)" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 234px; margin-left: 955px;"><div data-drawio-colors="color: rgb(240, 240, 240); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 8px; font-family: Helvetica; color: rgb(240, 240, 240); line-height: 1.2; pointer-events: all; white-space: nowrap;">RequestInfo</div></div></div></foreignObject><text x="955" y="237" fill="rgb(240, 240, 240)" font-family="Helvetica" font-size="8px" text-anchor="middle">RequestInfo</text></switch></g><path d="M 715 295 L 665 295 L 665 246 L 621.37 246" fill="none" stroke="rgb(240, 240, 240)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 616.12 246 L 623.12 242.5 L 621.37 246 L 623.12 249.5 Z" fill="rgb(240, 240, 240)" stroke="rgb(240, 240, 240)" stroke-miterlimit="10" pointer-events="all"/><rect x="715" y="265" width="480" height="60" fill="rgb(42, 42, 42)" stroke="rgb(240, 240, 240)" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 295px; margin-left: 955px;"><div data-drawio-colors="color: rgb(240, 240, 240); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 8px; font-family: Helvetica; color: rgb(240, 240, 240); line-height: 1.2; pointer-events: all; white-space: nowrap;">Authentication</div></div></div></foreignObject><text x="955" y="297" fill="rgb(240, 240, 240)" font-family="Helvetica" font-size="8px" text-anchor="middle">Authentication</text></switch></g><path d="M 1195 355 L 1308.63 355" fill="none" stroke="rgb(240, 240, 240)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 1313.88 355 L 1306.88 358.5 L 1308.63 355 L 1306.88 351.5 Z" fill="rgb(240, 240, 240)" stroke="rgb(240, 240, 240)" stroke-miterlimit="10" pointer-events="all"/><rect x="715" y="325" width="480" height="60" fill="rgb(42, 42, 42)" stroke="rgb(240, 240, 240)" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 355px; margin-left: 955px;"><div data-drawio-colors="color: rgb(240, 240, 240); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 8px; font-family: Helvetica; color: rgb(240, 240, 240); line-height: 1.2; pointer-events: all; white-space: nowrap;">Authorization</div></div></div></foreignObject><text x="955" y="357" fill="rgb(240, 240, 240)" font-family="Helvetica" font-size="8px" text-anchor="middle">Authorization</text></switch></g><path d="M 1195 234.38 L 1312.76 234.38" fill="none" stroke="rgb(240, 240, 240)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 1300.88 240.88 L 1313.88 234.38 L 1300.88 227.88" fill="none" stroke="rgb(240, 240, 240)" stroke-miterlimit="10" pointer-events="all"/><rect x="1315" y="172.19" width="180" height="124.37" fill="rgb(42, 42, 42)" stroke="rgb(240, 240, 240)" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 182px; height: 124px; padding-top: 172px; margin-left: 1315px;"><div data-drawio-colors="color: rgb(240, 240, 240); " style="box-sizing: border-box; font-size: 0px; text-align: left; width: 180px; height: 124px; overflow: hidden;"><div style="display: inline-block; font-size: 8px; font-family: Helvetica; color: rgb(240, 240, 240); line-height: 1.2; pointer-events: all; width: 100%; height: 100%; white-space: nowrap;"><p style="margin: 6px 0px 0px ; text-align: center"><b>RequestInfo</b></p><hr /><p style="margin: 0px 0px 0px 8px">+ API Group<br />+ API Version</p><p style="margin: 0px 0px 0px 8px">+ Resources</p><p style="margin: 0px 0px 0px 8px">+ Resource Name</p><p style="margin: 0px 0px 0px 8px">+ Path</p><p style="margin: 0px 0px 0px 8px">+ Scope</p></div></div></div></foreignObject><text x="1315" y="237" fill="rgb(240, 240, 240)" font-family="Helvetica" font-size="8px">RequestInfo...</text></switch></g><path d="M 1475 176.19 L 1491 176.19 L 1491 196.19 L 1475 196.19 L 1475 192.19 L 1471 192.19 L 1471 188.19 L 1475 188.19 L 1475 184.19 L 1471 184.19 L 1471 180.19 L 1475 180.19 Z" fill="rgb(42, 42, 42)" stroke="rgb(240, 240, 240)" stroke-miterlimit="10" pointer-events="all"/><path d="M 1475 180.19 L 1479 180.19 L 1479 184.19 L 1475 184.19 M 1475 188.19 L 1479 188.19 L 1479 192.19 L 1475 192.19" fill="none" stroke="rgb(240, 240, 240)" stroke-miterlimit="10" pointer-events="all"/><path d="M 321.37 255.06 L 350 255.1 L 385 255" fill="none" stroke="rgb(240, 240, 240)" stroke-miterlimit="10" pointer-events="stroke"/><path d="M 316.12 255.05 L 323.12 251.56 L 321.37 255.06 L 323.11 258.56 Z" fill="rgb(240, 240, 240)" stroke="rgb(240, 240, 240)" stroke-miterlimit="10" pointer-events="all"/><rect x="135" y="209.75" width="180" height="90.6" fill="rgb(42, 42, 42)" stroke="rgb(240, 240, 240)" pointer-events="all"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe flex-start; width: 182px; height: 91px; padding-top: 210px; margin-left: 135px;"><div data-drawio-colors="color: rgb(240, 240, 240); " style="box-sizing: border-box; font-size: 0px; text-align: left; width: 180px; height: 91px; overflow: hidden;"><div style="display: inline-block; font-size: 8px; font-family: Helvetica; color: rgb(240, 240, 240); line-height: 1.2; pointer-events: all; width: 100%; height: 100%; white-space: nowrap;"><p style="margin: 0px ; margin-top: 6px ; text-align: center"><b>UserInfo</b></p><hr /><p style="margin: 0px ; margin-left: 8px">+ Username<br />+ User Group</p><p style="margin: 0px ; margin-left: 8px">+ Extras</p><p style="margin: 0px ; margin-left: 8px"><br /></p></div></div></div></foreignObject><text x="135" y="257" fill="rgb(240, 240, 240)" font-family="Helvetica" font-size="8px">UserInfo...</text></switch></g><path d="M 295 213.75 L 311 213.75 L 311 233.75 L 295 233.75 L 295 229.75 L 291 229.75 L 291 225.75 L 295 225.75 L 295 221.75 L 291 221.75 L 291 217.75 L 295 217.75 Z" fill="rgb(42, 42, 42)" stroke="rgb(240, 240, 240)" stroke-miterlimit="10" pointer-events="all"/><path d="M 295 217.75 L 299 217.75 L 299 221.75 L 295 221.75 M 295 225.75 L 299 225.75 L 299 229.75 L 295 229.75" fill="none" stroke="rgb(240, 240, 240)" stroke-miterlimit="10" pointer-events="all"/><path d="M 385 165 L 485 165 L 485 180 L 475 195 L 385 195 Z" fill="rgb(42, 42, 42)" stroke="rgb(240, 240, 240)" stroke-miterlimit="10" pointer-events="none"/><path d="M 485 165 L 615 165 L 615 345.04 L 385 345.04 L 385 195" fill="none" stroke="rgb(240, 240, 240)" stroke-miterlimit="10" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 98px; height: 1px; padding-top: 180px; margin-left: 386px;"><div data-drawio-colors="color: rgb(240, 240, 240); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 8px; font-family: Helvetica; color: rgb(240, 240, 240); line-height: 1.2; pointer-events: none; white-space: normal; overflow-wrap: normal;"><span style="font-size: 8px">Authenticators</span></div></div></div></foreignObject><text x="435" y="182" fill="rgb(240, 240, 240)" font-family="Helvetica" font-size="8px" text-anchor="middle">Authenticators</text></switch></g><rect x="385" y="279.25" width="230" height="69.25" fill="rgb(42, 42, 42)" stroke="rgb(240, 240, 240)" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 314px; margin-left: 500px;"><div data-drawio-colors="color: rgb(240, 240, 240); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 8px; font-family: Helvetica; color: rgb(240, 240, 240); line-height: 1.2; pointer-events: none; white-space: nowrap;">Password Authenticator</div></div></div></foreignObject><text x="500" y="316" fill="rgb(240, 240, 240)" font-family="Helvetica" font-size="8px" text-anchor="middle">Password Authenticator</text></switch></g><rect x="385" y="212.81" width="230" height="66.44" fill="rgb(42, 42, 42)" stroke="rgb(240, 240, 240)" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 246px; margin-left: 500px;"><div data-drawio-colors="color: rgb(240, 240, 240); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 8px; font-family: Helvetica; color: rgb(240, 240, 240); line-height: 1.2; pointer-events: none; white-space: nowrap;">OAuth Authenticator</div></div></div></foreignObject><text x="500" y="248" fill="rgb(240, 240, 240)" font-family="Helvetica" font-size="8px" text-anchor="middle">OAuth Authenticator</text></switch></g><path d="M 1495 355 L 1565 355 L 1565 284.3 L 1628.63 284.25" fill="none" stroke="rgb(240, 240, 240)" stroke-miterlimit="10" pointer-events="none"/><path d="M 1633.88 284.25 L 1626.88 287.76 L 1628.63 284.25 L 1626.88 280.76 Z" fill="rgb(240, 240, 240)" stroke="rgb(240, 240, 240)" stroke-miterlimit="10" pointer-events="none"/><path d="M 1495 355 L 1628.63 355" fill="none" stroke="rgb(240, 240, 240)" stroke-miterlimit="10" pointer-events="none"/><path d="M 1633.88 355 L 1626.88 358.5 L 1628.63 355 L 1626.88 351.5 Z" fill="rgb(240, 240, 240)" stroke="rgb(240, 240, 240)" stroke-miterlimit="10" pointer-events="none"/><rect x="1315" y="325" width="180" height="60" fill="rgb(42, 42, 42)" stroke="rgb(240, 240, 240)" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 178px; height: 1px; padding-top: 355px; margin-left: 1316px;"><div data-drawio-colors="color: rgb(240, 240, 240); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 8px; font-family: Helvetica; color: rgb(240, 240, 240); line-height: 1.2; pointer-events: none; white-space: normal; overflow-wrap: normal;">RBAC Authorizer</div></div></div></foreignObject><text x="1405" y="357" fill="rgb(240, 240, 240)" font-family="Helvetica" font-size="8px" text-anchor="middle">RBAC Authorizer</text></switch></g><path d="M 1755 284.25 L 1805 284.3 L 1805 25 L 225 25 L 225 203.38" fill="none" stroke="rgb(240, 240, 240)" stroke-miterlimit="10" pointer-events="none"/><path d="M 225 208.63 L 221.5 201.63 L 225 203.38 L 228.5 201.63 Z" fill="rgb(240, 240, 240)" stroke="rgb(240, 240, 240)" stroke-miterlimit="10" pointer-events="none"/><rect x="1635" y="254.25" width="120" height="60" fill="rgb(42, 42, 42)" stroke="rgb(240, 240, 240)" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 284px; margin-left: 1636px;"><div data-drawio-colors="color: rgb(240, 240, 240); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 8px; font-family: Helvetica; color: rgb(240, 240, 240); line-height: 1.2; pointer-events: none; white-space: normal; overflow-wrap: normal;">User/Group</div></div></div></foreignObject><text x="1695" y="287" fill="rgb(240, 240, 240)" font-family="Helvetica" font-size="8px" text-anchor="middle">User/Group</text></switch></g><path d="M 1755 355 L 1755 360 L 1875 360 L 1875 213 L 1495 213 L 1495 228.01" fill="none" stroke="rgb(240, 240, 240)" stroke-miterlimit="10" pointer-events="none"/><path d="M 1495 233.26 L 1491.5 226.26 L 1495 228.01 L 1498.5 226.26 Z" fill="rgb(240, 240, 240)" stroke="rgb(240, 240, 240)" stroke-miterlimit="10" pointer-events="none"/><rect x="1635" y="325" width="120" height="60" fill="rgb(42, 42, 42)" stroke="rgb(240, 240, 240)" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 118px; height: 1px; padding-top: 355px; margin-left: 1636px;"><div data-drawio-colors="color: rgb(240, 240, 240); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 8px; font-family: Helvetica; color: rgb(240, 240, 240); line-height: 1.2; pointer-events: none; white-space: normal; overflow-wrap: normal;">Role</div></div></div></foreignObject><text x="1695" y="357" fill="rgb(240, 240, 240)" font-family="Helvetica" font-size="8px" text-anchor="middle">Role</text></switch></g><path d="M 715 415 L 665 415 L 665 469.5 L 621.37 469.46" fill="none" stroke="rgb(240, 240, 240)" stroke-miterlimit="10" pointer-events="none"/><path d="M 616.12 469.45 L 623.12 465.96 L 621.37 469.46 L 623.11 472.96 Z" fill="rgb(240, 240, 240)" stroke="rgb(240, 240, 240)" stroke-miterlimit="10" pointer-events="none"/><rect x="715" y="385" width="480" height="60" fill="rgb(42, 42, 42)" stroke="rgb(240, 240, 240)" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 415px; margin-left: 955px;"><div data-drawio-colors="color: rgb(240, 240, 240); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 8px; font-family: Helvetica; color: rgb(240, 240, 240); line-height: 1.2; pointer-events: none; white-space: nowrap;">Dispatch</div></div></div></foreignObject><text x="955" y="417" fill="rgb(240, 240, 240)" font-family="Helvetica" font-size="8px" text-anchor="middle">Dispatch</text></switch></g><path d="M 385 355 L 485 355 L 485 370 L 475 385 L 385 385 Z" fill="rgb(42, 42, 42)" stroke="rgb(240, 240, 240)" stroke-miterlimit="10" pointer-events="none"/><path d="M 485 355 L 615 355 L 615 573 L 385 573 L 385 385" fill="none" stroke="rgb(240, 240, 240)" stroke-miterlimit="10" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 98px; height: 1px; padding-top: 370px; margin-left: 386px;"><div data-drawio-colors="color: rgb(240, 240, 240); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 8px; font-family: Helvetica; color: rgb(240, 240, 240); line-height: 1.2; pointer-events: none; white-space: normal; overflow-wrap: normal;"><span style="font-size: 8px">Dispatchers</span></div></div></div></foreignObject><text x="435" y="372" fill="rgb(240, 240, 240)" font-family="Helvetica" font-size="8px" text-anchor="middle">Dispatchers</text></switch></g><rect x="385" y="458.4" width="230" height="56.6" fill="rgb(42, 42, 42)" stroke="rgb(240, 240, 240)" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 487px; margin-left: 500px;"><div data-drawio-colors="color: rgb(240, 240, 240); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 8px; font-family: Helvetica; color: rgb(240, 240, 240); line-height: 1.2; pointer-events: none; white-space: nowrap;">APIServiceDispatcher</div></div></div></foreignObject><text x="500" y="489" fill="rgb(240, 240, 240)" font-family="Helvetica" font-size="8px" text-anchor="middle">APIServiceDispatcher</text></switch></g><rect x="385" y="401.79" width="230" height="56.6" fill="rgb(42, 42, 42)" stroke="rgb(240, 240, 240)" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 430px; margin-left: 500px;"><div data-drawio-colors="color: rgb(240, 240, 240); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 8px; font-family: Helvetica; color: rgb(240, 240, 240); line-height: 1.2; pointer-events: none; white-space: nowrap;">MultiClusterDispatcher</div></div></div></foreignObject><text x="500" y="432" fill="rgb(240, 240, 240)" font-family="Helvetica" font-size="8px" text-anchor="middle">MultiClusterDispatcher</text></switch></g><rect x="385" y="515" width="230" height="56.6" fill="rgb(42, 42, 42)" stroke="rgb(240, 240, 240)" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 543px; margin-left: 500px;"><div data-drawio-colors="color: rgb(240, 240, 240); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 8px; font-family: Helvetica; color: rgb(240, 240, 240); line-height: 1.2; pointer-events: none; white-space: nowrap;">StaticResourceDispatcher</div></div></div></foreignObject><text x="500" y="546" fill="rgb(240, 240, 240)" font-family="Helvetica" font-size="8px" text-anchor="middle">StaticResourceDispatcher</text></switch></g><rect x="55" y="405.09" width="260" height="50" fill="rgb(42, 42, 42)" stroke="rgb(240, 240, 240)" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 430px; margin-left: 185px;"><div data-drawio-colors="color: rgb(240, 240, 240); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 8px; font-family: Helvetica; color: rgb(240, 240, 240); line-height: 1.2; pointer-events: none; white-space: nowrap;">/kapis/clusters/{cluster}</div></div></div></foreignObject><text x="185" y="432" fill="rgb(240, 240, 240)" font-family="Helvetica" font-size="8px" text-anchor="middle">/kapis/clusters/{cluster}</text></switch></g><path d="M 385 430.09 L 321.37 430.09" fill="none" stroke="rgb(240, 240, 240)" stroke-miterlimit="10" pointer-events="none"/><path d="M 316.12 430.09 L 323.12 426.59 L 321.37 430.09 L 323.12 433.59 Z" fill="rgb(240, 240, 240)" stroke="rgb(240, 240, 240)" stroke-miterlimit="10" pointer-events="none"/><rect x="55" y="461.7" width="260" height="50" fill="rgb(42, 42, 42)" stroke="rgb(240, 240, 240)" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 258px; height: 1px; padding-top: 487px; margin-left: 56px;"><div data-drawio-colors="color: rgb(240, 240, 240); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 8px; font-family: Helvetica; color: rgb(240, 240, 240); line-height: 1.2; pointer-events: none; white-space: normal; overflow-wrap: normal;">/kapis/group.klubesphere.io/v1alpha2</div></div></div></foreignObject><text x="185" y="489" fill="rgb(240, 240, 240)" font-family="Helvetica" font-size="8px" text-anchor="middle">/kapis/group.klubesphere.io/v1alpha2</text></switch></g><rect x="705" y="585" width="510" height="190" fill="rgb(42, 42, 42)" stroke="rgb(240, 240, 240)" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe flex-start; width: 512px; height: 190px; padding-top: 585px; margin-left: 705px;"><div data-drawio-colors="color: rgb(240, 240, 240); background-color: rgb(42, 42, 42); border-color: rgb(240, 240, 240); " style="box-sizing: border-box; font-size: 0px; text-align: left; width: 510px; height: 190px; background-color: rgb(42, 42, 42); border: 1px solid rgb(240, 240, 240); overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(240, 240, 240); line-height: 1.2; pointer-events: none; width: 100%; height: 100%; white-space: nowrap;"><p style="margin: 0px ; margin-top: 4px ; text-align: center"><b>Plugin</b></p><hr size="1" /><div style="height: 2px"><div>apiVersion: extensions.kubesphere.io/v1alpha1</div><div>kind: Plugin</div><div>...</div></div></div></div></div></foreignObject><text x="705" y="597" fill="rgb(240, 240, 240)" font-family="Helvetica" font-size="12px">Plugin...</text></switch></g><path d="M 718.63 715 L 25 715 L 25 486.7 L 55 486.7" fill="none" stroke="rgb(240, 240, 240)" stroke-miterlimit="10" pointer-events="none"/><path d="M 723.88 715 L 716.88 718.5 L 718.63 715 L 716.88 711.5 Z" fill="rgb(240, 240, 240)" stroke="rgb(240, 240, 240)" stroke-miterlimit="10" pointer-events="none"/><rect x="725" y="675" width="140" height="80" fill="rgb(42, 42, 42)" stroke="rgb(240, 240, 240)" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe flex-start; width: 142px; height: 80px; padding-top: 675px; margin-left: 725px;"><div data-drawio-colors="color: rgb(240, 240, 240); background-color: rgb(42, 42, 42); border-color: rgb(240, 240, 240); " style="box-sizing: border-box; font-size: 0px; text-align: left; width: 140px; height: 80px; background-color: rgb(42, 42, 42); border: 1px solid rgb(240, 240, 240); overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(240, 240, 240); line-height: 1.2; pointer-events: none; width: 100%; height: 100%; white-space: nowrap;"><p style="margin: 0px ; margin-top: 4px ; text-align: center"><b>APIService</b></p><hr size="1" /><div style="height: 2px"><div>apiVersion: extensions.kubesphere.io/v1alpha1</div><div>kind: APIService</div><div>...</div></div></div></div></div></foreignObject><text x="725" y="687" fill="rgb(240, 240, 240)" font-family="Helvetica" font-size="12px">APIService...</text></switch></g><path d="M 960 761.37 L 960 825 L 185 825 L 185 568.3" fill="none" stroke="rgb(240, 240, 240)" stroke-miterlimit="10" pointer-events="none"/><path d="M 960 756.12 L 963.5 763.12 L 960 761.37 L 956.5 763.12 Z" fill="rgb(240, 240, 240)" stroke="rgb(240, 240, 240)" stroke-miterlimit="10" pointer-events="none"/><rect x="890" y="675" width="140" height="80" fill="rgb(42, 42, 42)" stroke="rgb(240, 240, 240)" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe flex-start; width: 142px; height: 80px; padding-top: 675px; margin-left: 890px;"><div data-drawio-colors="color: rgb(240, 240, 240); background-color: rgb(42, 42, 42); border-color: rgb(240, 240, 240); " style="box-sizing: border-box; font-size: 0px; text-align: left; width: 140px; height: 80px; background-color: rgb(42, 42, 42); border: 1px solid rgb(240, 240, 240); overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(240, 240, 240); line-height: 1.2; pointer-events: none; width: 100%; height: 100%; white-space: nowrap;"><p style="margin: 0px ; margin-top: 4px ; text-align: center"><b>JSBundle</b></p><hr size="1" /><div style="height: 2px"><div>apiVersion: extensions.kubesphere.io/v1alpha1</div><div>kind: JSBundle</div><div>...</div></div></div></div></div></foreignObject><text x="890" y="687" fill="rgb(240, 240, 240)" font-family="Helvetica" font-size="12px">JSBundle...</text></switch></g><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 1px; height: 1px; padding-top: 455px; margin-left: 950px;"><div data-drawio-colors="color: rgb(240, 240, 240); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 28px; font-family: Helvetica; color: rgb(240, 240, 240); line-height: 1.2; pointer-events: none; white-space: nowrap;">...</div></div></div></foreignObject><text x="950" y="463" fill="rgb(240, 240, 240)" font-family="Helvetica" font-size="28px" text-anchor="middle">...</text></switch></g><rect x="55" y="518.3" width="260" height="50" fill="rgb(42, 42, 42)" stroke="rgb(240, 240, 240)" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe center; justify-content: unsafe center; width: 258px; height: 1px; padding-top: 543px; margin-left: 56px;"><div data-drawio-colors="color: rgb(240, 240, 240); " style="box-sizing: border-box; font-size: 0px; text-align: center;"><div style="display: inline-block; font-size: 8px; font-family: Helvetica; color: rgb(240, 240, 240); line-height: 1.2; pointer-events: none; white-space: normal; overflow-wrap: normal;">/dist/group.kubesphere.io/v1alpha2/index.js</div></div></div></foreignObject><text x="185" y="546" fill="rgb(240, 240, 240)" font-family="Helvetica" font-size="8px" text-anchor="middle">/dist/group.kubesphere.io/v1alpha2/index.js</text></switch></g><path d="M 385 486.7 L 321.37 486.7" fill="none" stroke="rgb(240, 240, 240)" stroke-miterlimit="10" pointer-events="none"/><path d="M 316.12 486.7 L 323.12 483.2 L 321.37 486.7 L 323.12 490.2 Z" fill="rgb(240, 240, 240)" stroke="rgb(240, 240, 240)" stroke-miterlimit="10" pointer-events="none"/><path d="M 385 543.3 L 321.37 543.3" fill="none" stroke="rgb(240, 240, 240)" stroke-miterlimit="10" pointer-events="none"/><path d="M 316.12 543.3 L 323.12 539.8 L 321.37 543.3 L 323.12 546.8 Z" fill="rgb(240, 240, 240)" stroke="rgb(240, 240, 240)" stroke-miterlimit="10" pointer-events="none"/><rect x="1055" y="675" width="140" height="80" fill="rgb(42, 42, 42)" stroke="rgb(240, 240, 240)" pointer-events="none"/><g transform="translate(-0.5 -0.5)"><switch><foreignObject pointer-events="none" width="100%" height="100%" requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility" style="overflow: visible; text-align: left;"><div xmlns="http://www.w3.org/1999/xhtml" style="display: flex; align-items: unsafe flex-start; justify-content: unsafe flex-start; width: 142px; height: 80px; padding-top: 675px; margin-left: 1055px;"><div data-drawio-colors="color: rgb(240, 240, 240); background-color: rgb(42, 42, 42); border-color: rgb(240, 240, 240); " style="box-sizing: border-box; font-size: 0px; text-align: left; width: 140px; height: 80px; background-color: rgb(42, 42, 42); border: 1px solid rgb(240, 240, 240); overflow: hidden;"><div style="display: inline-block; font-size: 12px; font-family: Helvetica; color: rgb(240, 240, 240); line-height: 1.2; pointer-events: none; width: 100%; height: 100%; white-space: nowrap;"><p style="margin: 0px ; margin-top: 4px ; text-align: center"><b>ReverseProxy</b></p><hr size="1" /><div style="height: 2px"><div>apiVersion: extensions.kubesphere.io/v1alpha1</div><div>kind: ReverseProxy</div><div>...</div></div></div></div></div></foreignObject><text x="1055" y="687" fill="rgb(240, 240, 240)" font-family="Helvetica" font-size="12px">ReverseProxy...</text></switch></g></g><switch><g requiredFeatures="http://www.w3.org/TR/SVG11/feature#Extensibility"/><a transform="translate(0,-5)" xlink:href="https://www.diagrams.net/doc/faq/svg-export-text-problems" target="_blank"><text text-anchor="middle" font-size="10px" x="50%" y="100%">Viewer does not support full SVG 1.1</text></a></switch></svg> \ No newline at end of file diff --git a/sig-architecture/images/pluggable-arch.png b/sig-architecture/images/pluggable-arch.png new file mode 100644 index 00000000..4eab6109 Binary files /dev/null and b/sig-architecture/images/pluggable-arch.png differ