diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 8d600bc1c..93cfaaa0a 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -33,7 +33,7 @@ jobs: with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - repository: ${{ secrets.DOCKERHUB_USERNAME }}/rekuiper + repository: indusstack/rekuiper readme-filepath: ./deploy/docker/README.md short-description: "Lightweight, ultra-fast streaming SQL engine for edge & IoT in Rust" @@ -115,14 +115,14 @@ jobs: id: docker_meta shell: bash run: | - DOCKER_USER="${{ secrets.DOCKERHUB_USERNAME }}" + DOCKER_ORG="indusstack" if [ -n "${{ inputs.tag }}" ]; then RAW_TAG="${{ inputs.tag }}" VERSION_TAG="${RAW_TAG#v}" - echo "tags=${DOCKER_USER}/rekuiper:${VERSION_TAG},${DOCKER_USER}/rekuiper:latest" >> $GITHUB_OUTPUT + echo "tags=${DOCKER_ORG}/rekuiper:${VERSION_TAG},${DOCKER_ORG}/rekuiper:latest" >> $GITHUB_OUTPUT else VERSION=$(grep -m 1 '^version = ' Cargo.toml | cut -d '"' -f 2) - echo "tags=${DOCKER_USER}/rekuiper:${VERSION},${DOCKER_USER}/rekuiper:latest" >> $GITHUB_OUTPUT + echo "tags=${DOCKER_ORG}/rekuiper:${VERSION},${DOCKER_ORG}/rekuiper:latest" >> $GITHUB_OUTPUT fi - name: Build and push Docker image @@ -139,6 +139,6 @@ jobs: with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - repository: ${{ secrets.DOCKERHUB_USERNAME }}/rekuiper + repository: indusstack/rekuiper readme-filepath: ./deploy/docker/README.md short-description: "Lightweight, ultra-fast streaming SQL engine for edge & IoT in Rust" diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index 6717481db..5f4454313 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -186,10 +186,10 @@ jobs: id: docker_meta shell: bash run: | - DOCKER_USER="${{ secrets.DOCKERHUB_USERNAME }}" + DOCKER_ORG="indusstack" RAW_TAG="${{ inputs.tag || github.ref_name }}" VERSION_TAG="${RAW_TAG#v}" - echo "tags=${DOCKER_USER}/rekuiper:${VERSION_TAG},${DOCKER_USER}/rekuiper:latest" >> $GITHUB_OUTPUT + echo "tags=${DOCKER_ORG}/rekuiper:${VERSION_TAG},${DOCKER_ORG}/rekuiper:latest" >> $GITHUB_OUTPUT - name: Build and push Docker image uses: docker/build-push-action@v6 @@ -205,7 +205,7 @@ jobs: with: username: ${{ secrets.DOCKERHUB_USERNAME }} password: ${{ secrets.DOCKERHUB_TOKEN }} - repository: ${{ secrets.DOCKERHUB_USERNAME }}/rekuiper + repository: indusstack/rekuiper readme-filepath: ./deploy/docker/README.md short-description: "Lightweight, ultra-fast streaming SQL engine for edge & IoT in Rust" diff --git a/.gitignore b/.gitignore index 74cfcb6d7..e639494d9 100644 --- a/.gitignore +++ b/.gitignore @@ -3,7 +3,8 @@ *.dll *.so *.dylib -/target/ +**/target/ +brag-output/ /bin/* !/bin/README.md @@ -83,3 +84,5 @@ test/benchmark/iiot-mqtt/evidence/iot-warm-*.json test/benchmark/iiot-mqtt/evidence/mqttprobe-*.log test/benchmark/iiot-mqtt/evidence/mqttgen-probe-1000.json test/benchmark/iiot-mqtt/evidence/mqttprobe-1000.json + +.vercel diff --git a/.vercelignore b/.vercelignore new file mode 100644 index 000000000..1e48b4138 --- /dev/null +++ b/.vercelignore @@ -0,0 +1,12 @@ +crates/ +test/ +deploy/ +etc/ +.git/ +target/ +*.zip +*.tar.gz +*.mp4 +docs/node_modules/ +docs/.vitepress/dist/ +docs/.vitepress/cache/ diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 2f3b4cc24..c6518045e 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -36,7 +36,7 @@ All participants in the rekuiper project must follow professional conduct. Treat ## How to Contribute ### Reporting Bugs -- Search existing [GitHub Issues](https://github.com/ankur-paan/rekuiper/issues) before you open a new issue. +- Search existing [GitHub Issues](https://github.com/Indus-Stack/rekuiper/issues) before you open a new issue. - Provide a clear title, reproduction steps, system environment (OS, CPU, Rust version), and sample JSON rules or stream definitions. ### Reporting Security Vulnerabilities @@ -57,7 +57,7 @@ Please do **not** file public issues for security vulnerabilities. Review [SECUR ```bash git clone https://github.com//rekuiper.git cd rekuiper -git remote add upstream https://github.com/ankur-paan/rekuiper.git +git remote add upstream https://github.com/Indus-Stack/rekuiper.git ``` ### Workspace Crates Architecture diff --git a/Cargo.toml b/Cargo.toml index 3f0030eb4..afb588f26 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -16,9 +16,9 @@ version = "1.0.0-rc4" edition = "2021" authors = ["I-Dacs Labs ", "rekuiper contributors"] license = "MIT OR Apache-2.0" -repository = "https://github.com/ankur-paan/rekuiper" +repository = "https://github.com/Indus-Stack/rekuiper" homepage = "https://i-dacs.com" -documentation = "https://github.com/ankur-paan/rekuiper#documentation" +documentation = "https://github.com/Indus-Stack/rekuiper#documentation" readme = "README.md" keywords = ["iot", "stream-processing", "edge-computing", "sql", "mqtt"] categories = ["embedded", "network-programming", "science"] diff --git a/README.md b/README.md index 6ec10d8d9..078264a8e 100644 --- a/README.md +++ b/README.md @@ -4,10 +4,10 @@ rekuiper is a small SQL engine that sits between your devices and your cloud. It filters, aggregates, and routes live data on the gateway itself, so you send upstream only what matters. -[![Release](https://img.shields.io/badge/release-v1.0.0--rc4-blue.svg)](https://github.com/ankur-paan/rekuiper/releases) -[![Rust CI](https://img.shields.io/badge/Rust%20CI-passing-brightgreen.svg)](https://github.com/ankur-paan/rekuiper/actions/workflows/ci.yml) +[![Release](https://img.shields.io/badge/release-v1.0.0--rc4-blue.svg)](https://github.com/Indus-Stack/rekuiper/releases) +[![Rust CI](https://github.com/Indus-Stack/rekuiper/actions/workflows/ci.yml/badge.svg)](https://github.com/Indus-Stack/rekuiper/actions/workflows/ci.yml) [![License: MIT or Apache-2.0](https://img.shields.io/badge/license-MIT%20%2F%20Apache--2.0-yellow.svg)](LICENSE) -[![Docker Pulls](https://img.shields.io/docker/pulls/ankurkrp/rekuiper?color=blue&logo=docker)](https://hub.docker.com/r/ankurkrp/rekuiper) +[![Docker Pulls](https://img.shields.io/docker/pulls/indusstack/rekuiper?color=blue&logo=docker)](https://hub.docker.com/r/indusstack/rekuiper) [Documentation](https://rekuiper.indramqtt.com) · [Run the demo](#try-it-in-60-seconds) · [Is it a fit?](#is-it-a-fit) · [Coming from eKuiper?](#coming-from-ekuiper) @@ -34,7 +34,7 @@ This demo needs only Docker. A built-in simulator makes the data. **1. Start the engine.** ```bash -docker run -d --name rekuiper -p 9081:9081 ankurkrp/rekuiper:1.0.0-rc4 +docker run -d --name rekuiper -p 9081:9081 indusstack/rekuiper:1.0.0-rc4 ``` **2. Register simulated sensor readings, ten per second.** @@ -184,17 +184,17 @@ rekuiper implements the eKuiper REST API, SQL dialect, rule format, and `kuiper` | Method | Command or link | | :--- | :--- | -| Docker | `docker run -d -p 9081:9081 ankurkrp/rekuiper:1.0.0-rc4` | +| Docker | `docker run -d -p 9081:9081 indusstack/rekuiper:1.0.0-rc4` | | Docker Compose | `docker compose -f deploy/docker/docker-compose.yml up -d` | -| Kubernetes | `helm install rekuiper deploy/chart/ekuiper` ([chart docs](deploy/chart/ekuiper/README.md)) | -| Binaries | [Releases](https://github.com/ankur-paan/rekuiper/releases) | +| Kubernetes | `helm install rekuiper deploy/chart/rekuiper` ([chart docs](deploy/chart/rekuiper/README.md)) | +| Binaries | [Releases](https://github.com/Indus-Stack/rekuiper/releases) | | Source | `cargo build --release -p kuiperd` | The Docker image listens on all interfaces. A binary that you run directly listens on `127.0.0.1` by default. Ports, TLS, and authentication: [Installation and Deployment](docs/en_US/installation.md). --- -[![Docker Pulls Tracker](docs/docker-pulls.svg)](https://hub.docker.com/r/ankurkrp/rekuiper) +[![Docker Pulls Tracker](docs/docker-pulls.svg)](https://hub.docker.com/r/indusstack/rekuiper) --- diff --git a/RELEASE_NOTES.md b/RELEASE_NOTES.md index 0e5c5c381..15ffa27c5 100644 --- a/RELEASE_NOTES.md +++ b/RELEASE_NOTES.md @@ -9,8 +9,8 @@ Key highlights: - **Immediate Metric Updates**: Added atomic counter updates to report rule completion immediately during test polling. - **Zero New Dependencies**: Kept `Cargo.lock` free of new external crates. Zero security advisories are present in the workspace. -- Docker image: `ankurkrp/rekuiper:1.0.0-rc4` (plus `latest`) -- Helm chart: `deploy/chart/ekuiper` (`AppVersion: 1.0.0-rc4`) +- Docker image: `indusstack/rekuiper:1.0.0-rc4` (plus `latest`) +- Helm chart: `deploy/chart/rekuiper` (`AppVersion: 1.0.0-rc4`) --- diff --git a/crates/rekuiper-server/src/handlers/rules.rs b/crates/rekuiper-server/src/handlers/rules.rs index 723deb1af..5baa5ea3c 100644 --- a/crates/rekuiper-server/src/handlers/rules.rs +++ b/crates/rekuiper-server/src/handlers/rules.rs @@ -1758,6 +1758,8 @@ pub async fn rule_cpu_usage(State(state): State) -> impl IntoResponse pub struct TagMatchQuery { tags: Option, keys: Option, + tag: Option, + key: Option, } pub fn extract_tags_from_value(val: &Value) -> Vec { @@ -1773,6 +1775,12 @@ pub fn extract_tags_from_value(val: &Value) -> Vec { .filter_map(|s| s.as_str().map(|s| s.to_string())) .collect(); } + if let Some(s) = val.get("tag").and_then(|t| t.as_str()) { + return vec![s.to_string()]; + } + if let Some(s) = val.get("key").and_then(|t| t.as_str()) { + return vec![s.to_string()]; + } if let Some(arr) = val.as_array() { return arr .iter() @@ -1862,7 +1870,7 @@ pub async fn rule_tags_match( body: Bytes, ) -> Response { let mut search_tags: HashSet = HashSet::new(); - if let Some(t_str) = query.tags.or(query.keys) { + if let Some(t_str) = query.tags.or(query.keys).or(query.tag).or(query.key) { for t in t_str.split(',') { let trimmed = t.trim(); if !trimmed.is_empty() { diff --git a/crates/rekuiper-server/src/routes.rs b/crates/rekuiper-server/src/routes.rs index 6d3e4732b..3062de460 100644 --- a/crates/rekuiper-server/src/routes.rs +++ b/crates/rekuiper-server/src/routes.rs @@ -88,6 +88,7 @@ pub fn create_router(state: AppState) -> Router { get(rule_tags_match).post(rule_tags_match), ) .route("/configs", get(get_configs).patch(patch_configs)) + .route("/config", get(get_configs).patch(patch_configs)) .route( "/config/uploads", get(get_config_uploads).post(upload_config_file), diff --git a/deploy/chart/ekuiper/.helmignore b/deploy/chart/rekuiper/.helmignore similarity index 100% rename from deploy/chart/ekuiper/.helmignore rename to deploy/chart/rekuiper/.helmignore diff --git a/deploy/chart/ekuiper/Chart.yaml b/deploy/chart/rekuiper/Chart.yaml similarity index 89% rename from deploy/chart/ekuiper/Chart.yaml rename to deploy/chart/rekuiper/Chart.yaml index 12b61deca..ce5652ce3 100644 --- a/deploy/chart/ekuiper/Chart.yaml +++ b/deploy/chart/rekuiper/Chart.yaml @@ -1,21 +1,21 @@ -apiVersion: v2 -name: ekuiper -description: A lightweight IoT edge analytic software - -# A chart can be either an 'application' or a 'library' chart. -# -# Application charts are a collection of templates that can be packaged into versioned archives -# to be deployed. -# -# Library charts provide useful utilities or functions for the chart developer. They're included as -# a dependency of application charts to inject those utilities and functions into the rendering -# pipeline. Library charts do not define any templates and therefore cannot be deployed. -type: application - -# This is the chart version. This version number should be incremented each time you make changes -# to the chart and its templates, including the app version. -version: 1.5.0 - -# This is the version number of the application being deployed. This version number should be -# incremented each time you make changes to the application. -appVersion: 1.0.0-rc4 +apiVersion: v2 +name: rekuiper +description: High-performance Rust SQL stream processing engine for IoT edge gateways + +# A chart can be either an 'application' or a 'library' chart. +# +# Application charts are a collection of templates that can be packaged into versioned archives +# to be deployed. +# +# Library charts provide useful utilities or functions for the chart developer. They're included as +# a dependency of application charts to inject those utilities and functions into the rendering +# pipeline. Library charts do not define any templates and therefore cannot be deployed. +type: application + +# This is the chart version. This version number should be incremented each time you make changes +# to the chart and its templates, including the app version. +version: 1.5.0 + +# This is the version number of the application being deployed. This version number should be +# incremented each time you make changes to the application. +appVersion: 1.0.0-rc4 diff --git a/deploy/chart/ekuiper/README.md b/deploy/chart/rekuiper/README.md similarity index 91% rename from deploy/chart/ekuiper/README.md rename to deploy/chart/rekuiper/README.md index 1d5ee302b..aaf66928c 100644 --- a/deploy/chart/ekuiper/README.md +++ b/deploy/chart/rekuiper/README.md @@ -1,62 +1,62 @@ -# rekuiper Helm Chart -A lightweight, high-performance edge streaming SQL engine for Kubernetes. - -![Version: 1.5.0](https://img.shields.io/badge/Version-1.5.0-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 1.0.0--rc4](https://img.shields.io/badge/AppVersion-1.0.0--rc4-informational?style=flat-square) - -## Install the Chart - -```bash -git clone https://github.com/ankur-paan/rekuiper.git -cd rekuiper -helm install rekuiper deploy/chart/ekuiper -``` - -## Custom Values Example - -```bash -helm install rekuiper deploy/chart/ekuiper \ - --set image.repository=ankurkrp/rekuiper \ - --set image.tag=1.0.0-rc4 -``` - -## Uninstall Chart - -```bash -helm uninstall rekuiper -``` - -## Values - -| Key | Type | Default | Description | -|-----|------|---------|-------------| -| affinity | object | `{}` | | -| clusterDomain | string | `"cluster.local"` | clusterDomain Kubernetes Cluster Domain | -| ekuiperEnv | object | `{"enabled":true,"key":{"mqttDefaultServer":"MQTT_SOURCE__DEFAULT__SERVER"},"value":{"mqttDefaultServer":"tcp://127.0.0.1:1883"}}` | remove this when the mqtt_source configmap is available | -| image.pullPolicy | string | `"IfNotPresent"` | | -| image.repository | string | `"ankurkrp/rekuiper"` | | -| image.tag | string | `""` | Overrides the image tag whose default is the chart appVersion. | -| nodeSelector | object | `{}` | | -| persistence.enabled | bool | `false` | Enable persistent storage for data and plugins | -| persistence.storageClass | string | `""` | Storage class of backing PVC | -| persistence.existingClaim | string | `""` | Existing PersistentVolumeClaim name, evaluated as a template | -| persistence.accessMode | string | `"ReadWriteOnce"` | PVC Access Mode for volume | -| persistence.size | string | `"20Mi"` | PVC Storage Request for rekuiper volume | -| resources | object | `{}` | Pod resource requests and limits | -| service.annotations | object | `{}` | Provide any additional annotations which may be required. Evaluated as a template | -| service.nodePorts | object | `{"ekuiper":null,"restapi":null,"prometheus":null}` | Specify nodePort(s) for LoadBalancer and NodePort service types | -| service.ports | object | `{"ekuiper":{"name":"ekuiper","port":20498},"restapi":{"name":"restapi","port":9081},"prometheus":{"name":"prometheus","port":20499}}` | Service ports | -| service.ports.ekuiper.name | string | `"ekuiper"` | CLI port name | -| service.ports.ekuiper.port | int | `20498` | CLI port | -| service.ports.restapi.name | string | `"restapi"` | REST API port name | -| service.ports.restapi.port | int | `9081` | REST API port | -| service.ports.prometheus.name | string | `"prometheus"` | Prometheus metrics port name | -| service.ports.prometheus.port | int | `20499` | Prometheus metrics port | -| service.type | string | `"ClusterIP"` | Service type | -| serviceAccount.annotations | object | `{}` | | -| serviceAccount.create | bool | `true` | | -| serviceAccount.name | string | `""` | | -| tls | object | `{"autoGenerated":false,"caCertificate":"","enabled":false,"existingSecret":"","existingSecretFullChain":false,"serverCertificate":"","serverKey":""}` | Enable encryption to eKuiper | -| tls.autoGenerated | bool | `false` | tls.autoGenerated Generate automatically self-signed TLS certificates | -| tls.caCertificate | string | `""` | tls.caCertificate Certificate Authority (CA) bundle content | -| tls.enabled | bool | `false` | tls.enabled Enable TLS support on eKuiper | -| tolerations | list | `[]` | | +# rekuiper Helm Chart +A lightweight, high-performance edge streaming SQL engine for Kubernetes. + +![Version: 1.5.0](https://img.shields.io/badge/Version-1.5.0-informational?style=flat-square) ![Type: application](https://img.shields.io/badge/Type-application-informational?style=flat-square) ![AppVersion: 1.0.0--rc4](https://img.shields.io/badge/AppVersion-1.0.0--rc4-informational?style=flat-square) + +## Install the Chart + +```bash +git clone https://github.com/Indus-Stack/rekuiper.git +cd rekuiper +helm install rekuiper deploy/chart/rekuiper +``` + +## Custom Values Example + +```bash +helm install rekuiper deploy/chart/rekuiper \ + --set image.repository=indusstack/rekuiper \ + --set image.tag=1.0.0-rc4 +``` + +## Uninstall Chart + +```bash +helm uninstall rekuiper +``` + +## Values + +| Key | Type | Default | Description | +|-----|------|---------|-------------| +| affinity | object | `{}` | | +| clusterDomain | string | `"cluster.local"` | clusterDomain Kubernetes Cluster Domain | +| ekuiperEnv | object | `{"enabled":true,"key":{"mqttDefaultServer":"MQTT_SOURCE__DEFAULT__SERVER"},"value":{"mqttDefaultServer":"tcp://127.0.0.1:1883"}}` | remove this when the mqtt_source configmap is available | +| image.pullPolicy | string | `"IfNotPresent"` | | +| image.repository | string | `"indusstack/rekuiper"` | | +| image.tag | string | `""` | Overrides the image tag whose default is the chart appVersion. | +| nodeSelector | object | `{}` | | +| persistence.enabled | bool | `false` | Enable persistent storage for data and plugins | +| persistence.storageClass | string | `""` | Storage class of backing PVC | +| persistence.existingClaim | string | `""` | Existing PersistentVolumeClaim name, evaluated as a template | +| persistence.accessMode | string | `"ReadWriteOnce"` | PVC Access Mode for volume | +| persistence.size | string | `"20Mi"` | PVC Storage Request for rekuiper volume | +| resources | object | `{}` | Pod resource requests and limits | +| service.annotations | object | `{}` | Provide any additional annotations which may be required. Evaluated as a template | +| service.nodePorts | object | `{"ekuiper":null,"restapi":null,"prometheus":null}` | Specify nodePort(s) for LoadBalancer and NodePort service types | +| service.ports | object | `{"ekuiper":{"name":"ekuiper","port":20498},"restapi":{"name":"restapi","port":9081},"prometheus":{"name":"prometheus","port":20499}}` | Service ports | +| service.ports.ekuiper.name | string | `"ekuiper"` | CLI port name | +| service.ports.ekuiper.port | int | `20498` | CLI port | +| service.ports.restapi.name | string | `"restapi"` | REST API port name | +| service.ports.restapi.port | int | `9081` | REST API port | +| service.ports.prometheus.name | string | `"prometheus"` | Prometheus metrics port name | +| service.ports.prometheus.port | int | `20499` | Prometheus metrics port | +| service.type | string | `"ClusterIP"` | Service type | +| serviceAccount.annotations | object | `{}` | | +| serviceAccount.create | bool | `true` | | +| serviceAccount.name | string | `""` | | +| tls | object | `{"autoGenerated":false,"caCertificate":"","enabled":false,"existingSecret":"","existingSecretFullChain":false,"serverCertificate":"","serverKey":""}` | Enable encryption to eKuiper | +| tls.autoGenerated | bool | `false` | tls.autoGenerated Generate automatically self-signed TLS certificates | +| tls.caCertificate | string | `""` | tls.caCertificate Certificate Authority (CA) bundle content | +| tls.enabled | bool | `false` | tls.enabled Enable TLS support on eKuiper | +| tolerations | list | `[]` | | diff --git a/deploy/chart/ekuiper/templates/_helpers.tpl b/deploy/chart/rekuiper/templates/_helpers.tpl similarity index 100% rename from deploy/chart/ekuiper/templates/_helpers.tpl rename to deploy/chart/rekuiper/templates/_helpers.tpl diff --git a/deploy/chart/ekuiper/templates/configmap.yaml b/deploy/chart/rekuiper/templates/configmap.yaml similarity index 100% rename from deploy/chart/ekuiper/templates/configmap.yaml rename to deploy/chart/rekuiper/templates/configmap.yaml diff --git a/deploy/chart/ekuiper/templates/serviceaccount.yaml b/deploy/chart/rekuiper/templates/serviceaccount.yaml similarity index 100% rename from deploy/chart/ekuiper/templates/serviceaccount.yaml rename to deploy/chart/rekuiper/templates/serviceaccount.yaml diff --git a/deploy/chart/ekuiper/templates/statefulset.yaml b/deploy/chart/rekuiper/templates/statefulset.yaml similarity index 97% rename from deploy/chart/ekuiper/templates/statefulset.yaml rename to deploy/chart/rekuiper/templates/statefulset.yaml index dcdb88a73..a97cc915d 100644 --- a/deploy/chart/ekuiper/templates/statefulset.yaml +++ b/deploy/chart/rekuiper/templates/statefulset.yaml @@ -1,181 +1,181 @@ -apiVersion: apps/v1 -kind: StatefulSet -metadata: - name: {{ include "ekuiper.fullname" . }} - namespace: {{ .Release.Namespace }} - labels: - {{- include "ekuiper.labels" . | nindent 4 }} -spec: - serviceName: {{ include "ekuiper.fullname" . }}-headless - replicas: 1 - {{- if and .Values.persistence.enabled (not .Values.persistence.existingClaim) }} - volumeClaimTemplates: - - metadata: - name: ekuiper-data - namespace: {{ .Release.Namespace }} - labels: - {{- include "ekuiper.labels" . | nindent 10 }} - spec: - {{- if .Values.persistence.storageClassName }} - storageClassName: {{ .Values.persistence.storageClassName | quote }} - {{- end }} - accessModes: - - {{ .Values.persistence.accessMode | quote }} - resources: - requests: - storage: {{ .Values.persistence.size | quote }} - - metadata: - name: ekuiper-plugins - namespace: {{ .Release.Namespace }} - labels: - {{- include "ekuiper.labels" . | nindent 10 }} - spec: - {{- if .Values.persistence.storageClassName }} - storageClassName: {{ .Values.persistence.storageClassName | quote }} - {{- end }} - accessModes: - - {{ .Values.persistence.accessMode | quote }} - resources: - requests: - storage: {{ .Values.persistence.size | quote }} - {{- end }} - selector: - matchLabels: - {{- include "ekuiper.selectorLabels" . | nindent 6 }} - template: - metadata: - labels: - {{- include "ekuiper.selectorLabels" . | nindent 8 }} - spec: - serviceAccountName: {{ include "ekuiper.serviceAccountName" . }} - {{- if .Values.podSecurityContext.enabled }} - securityContext: {{- omit .Values.podSecurityContext "enabled" | toYaml | nindent 8 }} - {{- end }} - volumes: - - name: ekuiper-log - emptyDir: {} - {{- if not .Values.persistence.enabled }} - - name: ekuiper-data - emptyDir: {} - - name: ekuiper-plugins - emptyDir: {} - {{- else if .Values.persistence.existingClaim }} - - name: ekuiper-data - persistentVolumeClaim: - {{- with .Values.persistence.existingClaim }} - claimName: {{ tpl . $ }} - {{- end }} - - name: ekuiper-plugins - persistentVolumeClaim: - {{- with .Values.persistence.existingClaim }} - claimName: {{ tpl . $ }} - {{- end }} - {{- end }} - - name: kuiper-config - configMap: - name: {{ include "ekuiper.fullname" . }} - items: - - key: kuiper.yaml - path: kuiper.yaml - {{- if .Values.declarative.enabled }} - - name: declarative-pipelines - configMap: - name: {{ include "ekuiper.fullname" . }}-pipelines - {{- end }} - {{- if .Values.tls.enabled }} - - name: certs - secret: - secretName: {{ template "neuron.tlsSecretName" . }} - items: - - key: {{ ternary "tls.crt" "ca.crt" .Values.tls.existingSecretFullChain }} - path: xyz-rootca.pem - - key: tls.crt - path: xyz-certificate.pem - - key: tls.key - path: xyz-private.pem.key - {{- end }} - containers: - - name: ekuiper - image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" - imagePullPolicy: {{ .Values.image.pullPolicy }} - {{- if .Values.containerSecurityContext.enabled }} - securityContext: {{- omit .Values.containerSecurityContext "enabled" | toYaml | nindent 12 }} - {{- end }} - env: - {{- if .Values.ekuiperEnv.enabled }} - - name: {{ .Values.ekuiperEnv.key.mqttDefaultServer }} - value: {{ .Values.ekuiperEnv.value.mqttDefaultServer }} - {{- end }} - {{- if .Values.declarative.enabled }} - - name: REKUIPER_DECLARATIVE_PATH - value: {{ .Values.declarative.mountPath | quote }} - - name: REKUIPER_DECLARATIVE_WATCH - value: {{ .Values.declarative.watch | quote }} - {{- end }} - command: - - /bin/sh - - -c - - | - mkdir -p /kuiper/plugins/functions /kuiper/plugins/portable /kuiper/plugins/sinks /kuiper/plugins/sources /kuiper/plugins/wasm - /kuiper/bin/kuiperd - readinessProbe: - httpGet: - {{- $restPort := index .Values "kuiperConfig" "kuiper.yaml" "basic" "restPort" }} - port: {{ $restPort | default 9081 }} - initialDelaySeconds: 5 - periodSeconds: 5 - ports: - {{- $restPort := index .Values "kuiperConfig" "kuiper.yaml" "basic" "restPort" }} - - name: restapi - containerPort: {{ $restPort | default 9081 }} - {{- $port := index .Values "kuiperConfig" "kuiper.yaml" "basic" "port" }} - - name: ekuiper - containerPort: {{ $port | default 20498 }} - - name: prometheus - containerPort: 20499 - volumeMounts: - - name: ekuiper-log - mountPath: "/kuiper/log" - - name: ekuiper-data - mountPath: "/kuiper/data" - - name: ekuiper-plugins - mountPath: "/kuiper/plugins" - {{- if .Values.declarative.enabled }} - - name: declarative-pipelines - mountPath: {{ .Values.declarative.mountPath | quote }} - readOnly: true - {{- end }} - {{- if .Values.tls.enabled }} - - name: certs - mountPath: "/var/kuiper/xyz-rootca.pem" - subPath: "xyz-rootca.pem" - readOnly: true - - name: certs - mountPath: "/var/kuiper/xyz-certificate.pem" - subPath: "xyz-certificate.pem" - readOnly: true - - name: certs - mountPath: "/var/kuiper/xyz-private.pem.key" - subPath: "xyz-private.pem.key" - readOnly: true - {{- end }} - - name: kuiper-config - mountPath: "/kuiper/etc/kuiper.yaml" - subPath: "kuiper.yaml" - resources: - {{- toYaml .Values.resources | nindent 12 }} - {{- with .Values.nodeSelector }} - nodeSelector: - {{- toYaml . | nindent 8 }} - {{- end }} - {{- with .Values.affinity }} - affinity: - {{- toYaml . | nindent 8 }} - {{- end }} - {{- with .Values.tolerations }} - tolerations: - {{- toYaml . | nindent 8 }} - {{- end }} - - - +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: {{ include "ekuiper.fullname" . }} + namespace: {{ .Release.Namespace }} + labels: + {{- include "ekuiper.labels" . | nindent 4 }} +spec: + serviceName: {{ include "ekuiper.fullname" . }}-headless + replicas: 1 + {{- if and .Values.persistence.enabled (not .Values.persistence.existingClaim) }} + volumeClaimTemplates: + - metadata: + name: ekuiper-data + namespace: {{ .Release.Namespace }} + labels: + {{- include "ekuiper.labels" . | nindent 10 }} + spec: + {{- if .Values.persistence.storageClassName }} + storageClassName: {{ .Values.persistence.storageClassName | quote }} + {{- end }} + accessModes: + - {{ .Values.persistence.accessMode | quote }} + resources: + requests: + storage: {{ .Values.persistence.size | quote }} + - metadata: + name: ekuiper-plugins + namespace: {{ .Release.Namespace }} + labels: + {{- include "ekuiper.labels" . | nindent 10 }} + spec: + {{- if .Values.persistence.storageClassName }} + storageClassName: {{ .Values.persistence.storageClassName | quote }} + {{- end }} + accessModes: + - {{ .Values.persistence.accessMode | quote }} + resources: + requests: + storage: {{ .Values.persistence.size | quote }} + {{- end }} + selector: + matchLabels: + {{- include "ekuiper.selectorLabels" . | nindent 6 }} + template: + metadata: + labels: + {{- include "ekuiper.selectorLabels" . | nindent 8 }} + spec: + serviceAccountName: {{ include "ekuiper.serviceAccountName" . }} + {{- if .Values.podSecurityContext.enabled }} + securityContext: {{- omit .Values.podSecurityContext "enabled" | toYaml | nindent 8 }} + {{- end }} + volumes: + - name: ekuiper-log + emptyDir: {} + {{- if not .Values.persistence.enabled }} + - name: ekuiper-data + emptyDir: {} + - name: ekuiper-plugins + emptyDir: {} + {{- else if .Values.persistence.existingClaim }} + - name: ekuiper-data + persistentVolumeClaim: + {{- with .Values.persistence.existingClaim }} + claimName: {{ tpl . $ }} + {{- end }} + - name: ekuiper-plugins + persistentVolumeClaim: + {{- with .Values.persistence.existingClaim }} + claimName: {{ tpl . $ }} + {{- end }} + {{- end }} + - name: kuiper-config + configMap: + name: {{ include "ekuiper.fullname" . }} + items: + - key: kuiper.yaml + path: kuiper.yaml + {{- if .Values.declarative.enabled }} + - name: declarative-pipelines + configMap: + name: {{ include "ekuiper.fullname" . }}-pipelines + {{- end }} + {{- if .Values.tls.enabled }} + - name: certs + secret: + secretName: {{ template "neuron.tlsSecretName" . }} + items: + - key: {{ ternary "tls.crt" "ca.crt" .Values.tls.existingSecretFullChain }} + path: xyz-rootca.pem + - key: tls.crt + path: xyz-certificate.pem + - key: tls.key + path: xyz-private.pem.key + {{- end }} + containers: + - name: ekuiper + image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" + imagePullPolicy: {{ .Values.image.pullPolicy }} + {{- if .Values.containerSecurityContext.enabled }} + securityContext: {{- omit .Values.containerSecurityContext "enabled" | toYaml | nindent 12 }} + {{- end }} + env: + {{- if .Values.ekuiperEnv.enabled }} + - name: {{ .Values.ekuiperEnv.key.mqttDefaultServer }} + value: {{ .Values.ekuiperEnv.value.mqttDefaultServer }} + {{- end }} + {{- if .Values.declarative.enabled }} + - name: REKUIPER_DECLARATIVE_PATH + value: {{ .Values.declarative.mountPath | quote }} + - name: REKUIPER_DECLARATIVE_WATCH + value: {{ .Values.declarative.watch | quote }} + {{- end }} + command: + - /bin/sh + - -c + - | + mkdir -p /kuiper/plugins/functions /kuiper/plugins/portable /kuiper/plugins/sinks /kuiper/plugins/sources /kuiper/plugins/wasm + /kuiper/bin/kuiperd + readinessProbe: + httpGet: + {{- $restPort := index .Values "kuiperConfig" "kuiper.yaml" "basic" "restPort" }} + port: {{ $restPort | default 9081 }} + initialDelaySeconds: 5 + periodSeconds: 5 + ports: + {{- $restPort := index .Values "kuiperConfig" "kuiper.yaml" "basic" "restPort" }} + - name: restapi + containerPort: {{ $restPort | default 9081 }} + {{- $port := index .Values "kuiperConfig" "kuiper.yaml" "basic" "port" }} + - name: ekuiper + containerPort: {{ $port | default 20498 }} + - name: prometheus + containerPort: 20499 + volumeMounts: + - name: ekuiper-log + mountPath: "/kuiper/log" + - name: ekuiper-data + mountPath: "/kuiper/data" + - name: ekuiper-plugins + mountPath: "/kuiper/plugins" + {{- if .Values.declarative.enabled }} + - name: declarative-pipelines + mountPath: {{ .Values.declarative.mountPath | quote }} + readOnly: true + {{- end }} + {{- if .Values.tls.enabled }} + - name: certs + mountPath: "/var/kuiper/xyz-rootca.pem" + subPath: "xyz-rootca.pem" + readOnly: true + - name: certs + mountPath: "/var/kuiper/xyz-certificate.pem" + subPath: "xyz-certificate.pem" + readOnly: true + - name: certs + mountPath: "/var/kuiper/xyz-private.pem.key" + subPath: "xyz-private.pem.key" + readOnly: true + {{- end }} + - name: kuiper-config + mountPath: "/kuiper/etc/kuiper.yaml" + subPath: "kuiper.yaml" + resources: + {{- toYaml .Values.resources | nindent 12 }} + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} + + + diff --git a/deploy/chart/ekuiper/templates/svc.yaml b/deploy/chart/rekuiper/templates/svc.yaml similarity index 97% rename from deploy/chart/ekuiper/templates/svc.yaml rename to deploy/chart/rekuiper/templates/svc.yaml index c2811d2ed..ced63cd8f 100644 --- a/deploy/chart/ekuiper/templates/svc.yaml +++ b/deploy/chart/rekuiper/templates/svc.yaml @@ -1,77 +1,77 @@ -apiVersion: v1 -kind: Service -metadata: - name: {{ include "ekuiper.fullname" . }} - namespace: {{ .Release.Namespace }} - labels: - {{- include "ekuiper.labels" . | nindent 4 }} -spec: - type: {{ .Values.service.type }} - {{- if eq .Values.service.type "LoadBalancer" }} - {{- if .Values.service.loadBalancerIP }} - loadBalancerIP: {{ .Values.service.loadBalancerIP }} - {{- end }} - {{- if .Values.service.loadBalancerSourceRanges }} - loadBalancerSourceRanges: {{- toYaml .Values.service.loadBalancerSourceRanges | nindent 4 }} - {{- end }} - {{- end }} - ports: - - name: {{ .Values.service.ports.restapi.name }} - port: {{ .Values.service.ports.restapi.port | default 9081 }} - protocol: TCP - targetPort: restapi - {{- if and (or (eq .Values.service.type "NodePort") (eq .Values.service.type "LoadBalancer")) (not (empty .Values.service.nodePorts.restapi)) }} - nodePort: {{ .Values.service.nodePorts.restapi }} - {{- else if eq .Values.service.type "ClusterIP" }} - nodePort: null - {{- end }} - - name: {{ .Values.service.ports.ekuiper.name }} - port: {{ .Values.service.ports.ekuiper.port | default 20498 }} - protocol: TCP - targetPort: ekuiper - {{- if and (or (eq .Values.service.type "NodePort") (eq .Values.service.type "LoadBalancer")) (not (empty .Values.service.nodePorts.ekuiper)) }} - nodePort: {{ .Values.service.nodePorts.ekuiper }} - {{- else if eq .Values.service.type "ClusterIP" }} - nodePort: null - {{- end }} - {{- if .Values.service.ports.prometheus }} - - name: {{ .Values.service.ports.prometheus.name | default "prometheus" }} - port: {{ .Values.service.ports.prometheus.port | default 20499 }} - protocol: TCP - targetPort: prometheus - {{- if and (or (eq .Values.service.type "NodePort") (eq .Values.service.type "LoadBalancer")) (not (empty .Values.service.nodePorts.prometheus)) }} - nodePort: {{ .Values.service.nodePorts.prometheus }} - {{- else if eq .Values.service.type "ClusterIP" }} - nodePort: null - {{- end }} - {{- end }} - selector: - {{- include "ekuiper.selectorLabels" . | nindent 4 }} - ---- -apiVersion: v1 -kind: Service -metadata: - name: {{ include "ekuiper.fullname" . }}-headless - namespace: {{ .Release.Namespace }} - labels: - {{- include "ekuiper.labels" . | nindent 4 }} -spec: - clusterIP: None - ports: - - name: {{ .Values.service.ports.restapi.name }} - port: {{ .Values.service.ports.restapi.port | default 9081 }} - protocol: TCP - targetPort: restapi - - name: {{ .Values.service.ports.ekuiper.name }} - port: {{ .Values.service.ports.ekuiper.port | default 20498 }} - protocol: TCP - targetPort: ekuiper - {{- if .Values.service.ports.prometheus }} - - name: {{ .Values.service.ports.prometheus.name | default "prometheus" }} - port: {{ .Values.service.ports.prometheus.port | default 20499 }} - protocol: TCP - targetPort: prometheus - {{- end }} - selector: +apiVersion: v1 +kind: Service +metadata: + name: {{ include "ekuiper.fullname" . }} + namespace: {{ .Release.Namespace }} + labels: + {{- include "ekuiper.labels" . | nindent 4 }} +spec: + type: {{ .Values.service.type }} + {{- if eq .Values.service.type "LoadBalancer" }} + {{- if .Values.service.loadBalancerIP }} + loadBalancerIP: {{ .Values.service.loadBalancerIP }} + {{- end }} + {{- if .Values.service.loadBalancerSourceRanges }} + loadBalancerSourceRanges: {{- toYaml .Values.service.loadBalancerSourceRanges | nindent 4 }} + {{- end }} + {{- end }} + ports: + - name: {{ .Values.service.ports.restapi.name }} + port: {{ .Values.service.ports.restapi.port | default 9081 }} + protocol: TCP + targetPort: restapi + {{- if and (or (eq .Values.service.type "NodePort") (eq .Values.service.type "LoadBalancer")) (not (empty .Values.service.nodePorts.restapi)) }} + nodePort: {{ .Values.service.nodePorts.restapi }} + {{- else if eq .Values.service.type "ClusterIP" }} + nodePort: null + {{- end }} + - name: {{ .Values.service.ports.ekuiper.name }} + port: {{ .Values.service.ports.ekuiper.port | default 20498 }} + protocol: TCP + targetPort: ekuiper + {{- if and (or (eq .Values.service.type "NodePort") (eq .Values.service.type "LoadBalancer")) (not (empty .Values.service.nodePorts.ekuiper)) }} + nodePort: {{ .Values.service.nodePorts.ekuiper }} + {{- else if eq .Values.service.type "ClusterIP" }} + nodePort: null + {{- end }} + {{- if .Values.service.ports.prometheus }} + - name: {{ .Values.service.ports.prometheus.name | default "prometheus" }} + port: {{ .Values.service.ports.prometheus.port | default 20499 }} + protocol: TCP + targetPort: prometheus + {{- if and (or (eq .Values.service.type "NodePort") (eq .Values.service.type "LoadBalancer")) (not (empty .Values.service.nodePorts.prometheus)) }} + nodePort: {{ .Values.service.nodePorts.prometheus }} + {{- else if eq .Values.service.type "ClusterIP" }} + nodePort: null + {{- end }} + {{- end }} + selector: + {{- include "ekuiper.selectorLabels" . | nindent 4 }} + +--- +apiVersion: v1 +kind: Service +metadata: + name: {{ include "ekuiper.fullname" . }}-headless + namespace: {{ .Release.Namespace }} + labels: + {{- include "ekuiper.labels" . | nindent 4 }} +spec: + clusterIP: None + ports: + - name: {{ .Values.service.ports.restapi.name }} + port: {{ .Values.service.ports.restapi.port | default 9081 }} + protocol: TCP + targetPort: restapi + - name: {{ .Values.service.ports.ekuiper.name }} + port: {{ .Values.service.ports.ekuiper.port | default 20498 }} + protocol: TCP + targetPort: ekuiper + {{- if .Values.service.ports.prometheus }} + - name: {{ .Values.service.ports.prometheus.name | default "prometheus" }} + port: {{ .Values.service.ports.prometheus.port | default 20499 }} + protocol: TCP + targetPort: prometheus + {{- end }} + selector: {{- include "ekuiper.selectorLabels" . | nindent 4 }} \ No newline at end of file diff --git a/deploy/chart/ekuiper/templates/tls-secrets.yaml b/deploy/chart/rekuiper/templates/tls-secrets.yaml similarity index 100% rename from deploy/chart/ekuiper/templates/tls-secrets.yaml rename to deploy/chart/rekuiper/templates/tls-secrets.yaml diff --git a/deploy/chart/ekuiper/values.yaml b/deploy/chart/rekuiper/values.yaml similarity index 96% rename from deploy/chart/ekuiper/values.yaml rename to deploy/chart/rekuiper/values.yaml index 2e54f49bf..8d0e9d290 100644 --- a/deploy/chart/ekuiper/values.yaml +++ b/deploy/chart/rekuiper/values.yaml @@ -1,318 +1,318 @@ -# Default values for kuiper. -# This is a YAML-formatted file. -# Declare variables to be passed into your templates. - - -image: - repository: ankurkrp/rekuiper - pullPolicy: IfNotPresent - # Overrides the image tag whose default is the chart appVersion. - tag: "" - -serviceAccount: - # Specifies whether a service account should be created - create: true - # Annotations to add to the service account - annotations: {} - # The name of the service account to use. - # If not set and create is true, a name is generated using the fullname template - name: "" - -service: - # -- service type - type: ClusterIP - - # -- Service ports - ports: - ekuiper: - # -- eKuiper port name - name: "ekuiper" - # -- eKuiper port - port: 20498 - restapi: - # -- eKuiper restapi port name - name: "restapi" - # -- eKuiper restapi port - port: 9081 - prometheus: - # -- Prometheus metrics port name - name: "prometheus" - # -- Prometheus metrics port - port: 20499 - - - # -- Specify the nodePort(s) value for the LoadBalancer and NodePort service types. - # ref: https://kubernetes.io/docs/concepts/services-networking/service/#type-nodeport - nodePorts: - ekuiper: - restapi: - prometheus: - ## Set the LoadBalancer service type to internal only. - ## ref: https://kubernetes.io/docs/concepts/services-networking/service/#internal-load-balancer - ## - # loadBalancerIP: - ## Load Balancer sources - ## ref: https://kubernetes.io/docs/tasks/access-application-cluster/configure-cloud-provider-firewall/#restrict-access-for-loadbalancer-service - ## Example: - ## loadBalancerSourceRanges: - ## - 10.10.10.0/24 - ## - # @ignored - loadBalancerSourceRanges: [] - # -- Provide any additional annotations which may be required. Evaluated as a template - annotations: {} - -persistence: - enabled: enabled - size: 20Mi - storageClassName: "" - accessMode: ReadWriteOnce - # -- Existing PersistentVolumeClaims - # The value is evaluated as a template - # So, for example, the name can depend on .Release or .Chart - existingClaim: "" - -resources: {} - # We usually recommend not to specify default resources and to leave this as a conscious - # choice for the user. This also increases chances charts run on environments with little - # resources, such as Minikube. If you do want to specify resources, uncomment the following - # lines, adjust them as necessary, and remove the curly braces after 'resources:'. - # limits: - # cpu: 100m - # memory: 128Mi - # requests: - # cpu: 100m - # memory: 128Mi - -nodeSelector: {} - -tolerations: [] - -affinity: {} - -podSecurityContext: - enabled: true - fsGroup: 1001 - fsGroupChangePolicy: Always - runAsUser: 1001 - supplementalGroups: - - 1001 - -containerSecurityContext: - enabled: true - runAsNonRoot: true - runAsUser: 1001 - -# -- clusterDomain Kubernetes Cluster Domain -clusterDomain: cluster.local - -# -- Enable encryption to eKuiper -tls: - # -- tls.enabled Enable TLS support on eKuiper - enabled: false - # -- tls.autoGenerated Generate automatically self-signed TLS certificates - autoGenerated: false - # -- tls.caCertificate Certificate Authority (CA) bundle content - caCertificate: |- - # - tls.serverCertificate Server certificate content - serverCertificate: |- - # - tls.serverKey Server private key content - serverKey: |- - # - tls.existingSecret Existing secret with certificate content to eKuiper credentials - existingSecret: "" - # - tls.existingSecretFullChain Whether or not the existing secret contains the full chain in the certificate (`tls.crt`). Will be used in place of `ca.cert` if `true`. - existingSecretFullChain: false - -# @ignored -kuiperConfig: - "kuiper.yaml": - basic: - # debug | info | warn | error | fatal | panic - logLevel: info - # true|false, with debug level, it prints more debug info - debug: false - # true|false, if it's set to true, then the log will be print to console - consoleLog: false - # true|false, if it's set to true, then the log will be print to log file - fileLog: true - # Whether to disable the log timestamp, useful when output is redirected to logging - # system like syslog that already adds timestamps. - logDisableTimestamp: false - # syslog settings - syslog: - # true|false, if it's set to true, then the log will be print to syslog - enable: false - # The syslog protocol, tcp or udp; Leave empty if no remote syslog server is used - network: udp - # The syslog server address; Leave empty if no remote syslog server is used - address: localhost:514 - # The syslog level, supports debug, info, warn, error - level: info - # The syslog tag; Leave empty if no tag is used - tag: kuiper - # How many hours to split the file - rotateTime: 24 - # Maximum file storage hours - maxAge: 72 - # Maximum file size in bytes, if this is set, maxAge will be ignored - rotateSize: 10485760 # 10 MB - # Maximum log file count - rotateCount: 3 - # CLI ip - ip: 0.0.0.0 - # CLI port - port: 20498 - # REST service ip - restIp: 0.0.0.0 - # REST service port - restPort: 9081 - # The global time zone from the IANA time zone database, or Local if not set. - timezone: Local - # true|false, when true, will check the RSA jwt token for rest api - authentication: false - # restTls: - # certfile: /var/https-server.crt - # keyfile: /var/https-server.key - # Prometheus settings - prometheus: false - prometheusPort: 20499 - # pprof settings - pprof: true - pprofIp: 127.0.0.1 - pprofPort: 6060 - # The URL where hosts all of pre-build plugins. - pluginHosts: https://packages.indramqtt.com - # Whether to ignore case in SQL processing. Note that, the name of customized function by plugins are case-sensitive. - ignoreCase: false - sql: - # maxConnections indicates the max connections for the certain database instance group by driver and dsn sharing between the sources/sinks - # 0 indicates unlimited - maxConnections: 0 - rulePatrolInterval: 10s - # enableOpenZiti indicates whether to enable OpenZiti for eKuiper REST service. Currently, it is only supported to work with EdgeX secure mode. - enableOpenZiti: false - # AES Key, base64 encoded - ## aesKey: your_base64_encoded_aes_key - gracefulShutdownTimeout: 10s - connection: - backoffMaxElapsedDuration: 3m - # If it is enabled, the cpu time of the rule will be recorded. - ResourceProfileConfig: - enable: false - interval: 5s - metricsDumpConfig: - enable: false - retainedDuration: 6h - enableRestAuditLog: false - - # The default options for all rules. Each rule can override this setting by defining its own option - rule: - # The qos of the rule. The values can be 0: At most once; 1: At least once; 2: Exactly once - # If qos is bigger than 0, the checkpoint mechanism will launch to save states so that they can be - # restored for unintended interrupt or planned restart of the rule. The performance may be affected - # to enable the checkpoint mechanism - qos: 0 - # The interval duration to run the checkpoint mechanism. - checkpointInterval: 300s - # Whether to send errors to sinks - sendError: false - # The strategy to retry for rule errors. - restartStrategy: - # The maximum retry times - attempts: 0 - # The interval to retry - delay: 1s - # The maximum interval to retry - maxDelay: 30s - # The exponential to increase the interval. It can be a float value. - multiplier: 2 - # How large random value will be added or subtracted to the delay to prevent restarting multiple rules at the same time. - jitterFactor: 0.1 - sink: - # Control to enable cache or not. If it's set to true, then the cache will be enabled, otherwise, it will be disabled. - enableCache: false - - # The maximum number of messages to be cached in memory. - memoryCacheThreshold: 1024 - - # The maximum number of messages to be cached in the disk. - maxDiskCache: 1024000 - - # The number of messages for a buffer page which is the unit to read/write to disk in batch to prevent frequent IO - bufferPageSize: 256 - - # The interval duration to resend the cached messages - resendInterval: 0s - - # Whether to clean the cache when the rule stops - cleanCacheAtStop: false - - source: - ## Configurations for the global http data server for httppush source - # HTTP data service ip - httpServerIp: 0.0.0.0 - # HTTP data service port - httpServerPort: 10081 - # httpServerTls: - # certfile: /var/https-server.crt - # keyfile: /var/https-server.key - - store: - #Type of store that will be used for keeping state of the application - type: sqlite - extStateType: sqlite - redis: - host: localhost - port: 6379 - #Timeout - timeout: 1s - sqlite: - #Sqlite file name, if left empty name of db will be sqliteKV.db - name: - - # The settings for portable plugin - portable: - # The executable of python. Specify this if you have multiple python instances in your system - # or other circumstance where the python executable cannot be successfully invoked through the default command. - pythonBin: python - # control init timeout. If the init time is longer than this value, the plugin will be terminated. - initTimeout: 60s - sendTimeout: 5s - recvTimeout: 5s - - openTelemetry: - serviceName: kuiperd-service - enableRemoteCollector: false - remoteEndpoint: localhost:4318 - localTraceCapacity: 2048 - enableLocalStorage: false - -# TODO -# -- remove this when the mqtt_source configmap is available -ekuiperEnv: - enabled: true - key: - mqttDefaultServer: MQTT_SOURCE__DEFAULT__SERVER - value: - mqttDefaultServer: "tcp://127.0.0.1:1883" - -# Declarative GitOps pipeline management -declarative: - # Enable Declarative GitOps mode (sets --declarative and locks down control plane) - enabled: false - # Enable hot-reload on ConfigMap / manifest file updates - watch: true - # Directory in container where declarative manifests are mounted - mountPath: /etc/rekuiper/pipelines.d - # Map of manifest filename to manifest YAML/JSON/TOML content - pipelines: {} - # 01-streams.yaml: | - # streams: - # demo_stream: "CREATE STREAM demo_stream () WITH (DATASOURCE=\"telemetry\", FORMAT=\"json\");" - # 02-rules.yaml: | - # rules: - # demo_rule: - # sql: "SELECT * FROM demo_stream" - # actions: - # - log: {} - +# Default values for rekuiper. +# This is a YAML-formatted file. +# Declare variables to be passed into your templates. + + +image: + repository: indusstack/rekuiper + pullPolicy: IfNotPresent + # Overrides the image tag whose default is the chart appVersion. + tag: "" + +serviceAccount: + # Specifies whether a service account should be created + create: true + # Annotations to add to the service account + annotations: {} + # The name of the service account to use. + # If not set and create is true, a name is generated using the fullname template + name: "" + +service: + # -- service type + type: ClusterIP + + # -- Service ports + ports: + ekuiper: + # -- eKuiper port name + name: "ekuiper" + # -- eKuiper port + port: 20498 + restapi: + # -- eKuiper restapi port name + name: "restapi" + # -- eKuiper restapi port + port: 9081 + prometheus: + # -- Prometheus metrics port name + name: "prometheus" + # -- Prometheus metrics port + port: 20499 + + + # -- Specify the nodePort(s) value for the LoadBalancer and NodePort service types. + # ref: https://kubernetes.io/docs/concepts/services-networking/service/#type-nodeport + nodePorts: + ekuiper: + restapi: + prometheus: + ## Set the LoadBalancer service type to internal only. + ## ref: https://kubernetes.io/docs/concepts/services-networking/service/#internal-load-balancer + ## + # loadBalancerIP: + ## Load Balancer sources + ## ref: https://kubernetes.io/docs/tasks/access-application-cluster/configure-cloud-provider-firewall/#restrict-access-for-loadbalancer-service + ## Example: + ## loadBalancerSourceRanges: + ## - 10.10.10.0/24 + ## + # @ignored + loadBalancerSourceRanges: [] + # -- Provide any additional annotations which may be required. Evaluated as a template + annotations: {} + +persistence: + enabled: enabled + size: 20Mi + storageClassName: "" + accessMode: ReadWriteOnce + # -- Existing PersistentVolumeClaims + # The value is evaluated as a template + # So, for example, the name can depend on .Release or .Chart + existingClaim: "" + +resources: {} + # We usually recommend not to specify default resources and to leave this as a conscious + # choice for the user. This also increases chances charts run on environments with little + # resources, such as Minikube. If you do want to specify resources, uncomment the following + # lines, adjust them as necessary, and remove the curly braces after 'resources:'. + # limits: + # cpu: 100m + # memory: 128Mi + # requests: + # cpu: 100m + # memory: 128Mi + +nodeSelector: {} + +tolerations: [] + +affinity: {} + +podSecurityContext: + enabled: true + fsGroup: 1001 + fsGroupChangePolicy: Always + runAsUser: 1001 + supplementalGroups: + - 1001 + +containerSecurityContext: + enabled: true + runAsNonRoot: true + runAsUser: 1001 + +# -- clusterDomain Kubernetes Cluster Domain +clusterDomain: cluster.local + +# -- Enable encryption to eKuiper +tls: + # -- tls.enabled Enable TLS support on eKuiper + enabled: false + # -- tls.autoGenerated Generate automatically self-signed TLS certificates + autoGenerated: false + # -- tls.caCertificate Certificate Authority (CA) bundle content + caCertificate: |- + # - tls.serverCertificate Server certificate content + serverCertificate: |- + # - tls.serverKey Server private key content + serverKey: |- + # - tls.existingSecret Existing secret with certificate content to eKuiper credentials + existingSecret: "" + # - tls.existingSecretFullChain Whether or not the existing secret contains the full chain in the certificate (`tls.crt`). Will be used in place of `ca.cert` if `true`. + existingSecretFullChain: false + +# @ignored +kuiperConfig: + "kuiper.yaml": + basic: + # debug | info | warn | error | fatal | panic + logLevel: info + # true|false, with debug level, it prints more debug info + debug: false + # true|false, if it's set to true, then the log will be print to console + consoleLog: false + # true|false, if it's set to true, then the log will be print to log file + fileLog: true + # Whether to disable the log timestamp, useful when output is redirected to logging + # system like syslog that already adds timestamps. + logDisableTimestamp: false + # syslog settings + syslog: + # true|false, if it's set to true, then the log will be print to syslog + enable: false + # The syslog protocol, tcp or udp; Leave empty if no remote syslog server is used + network: udp + # The syslog server address; Leave empty if no remote syslog server is used + address: localhost:514 + # The syslog level, supports debug, info, warn, error + level: info + # The syslog tag; Leave empty if no tag is used + tag: kuiper + # How many hours to split the file + rotateTime: 24 + # Maximum file storage hours + maxAge: 72 + # Maximum file size in bytes, if this is set, maxAge will be ignored + rotateSize: 10485760 # 10 MB + # Maximum log file count + rotateCount: 3 + # CLI ip + ip: 0.0.0.0 + # CLI port + port: 20498 + # REST service ip + restIp: 0.0.0.0 + # REST service port + restPort: 9081 + # The global time zone from the IANA time zone database, or Local if not set. + timezone: Local + # true|false, when true, will check the RSA jwt token for rest api + authentication: false + # restTls: + # certfile: /var/https-server.crt + # keyfile: /var/https-server.key + # Prometheus settings + prometheus: false + prometheusPort: 20499 + # pprof settings + pprof: true + pprofIp: 127.0.0.1 + pprofPort: 6060 + # The URL where hosts all of pre-build plugins. + pluginHosts: https://packages.indramqtt.com + # Whether to ignore case in SQL processing. Note that, the name of customized function by plugins are case-sensitive. + ignoreCase: false + sql: + # maxConnections indicates the max connections for the certain database instance group by driver and dsn sharing between the sources/sinks + # 0 indicates unlimited + maxConnections: 0 + rulePatrolInterval: 10s + # enableOpenZiti indicates whether to enable OpenZiti for eKuiper REST service. Currently, it is only supported to work with EdgeX secure mode. + enableOpenZiti: false + # AES Key, base64 encoded + ## aesKey: your_base64_encoded_aes_key + gracefulShutdownTimeout: 10s + connection: + backoffMaxElapsedDuration: 3m + # If it is enabled, the cpu time of the rule will be recorded. + ResourceProfileConfig: + enable: false + interval: 5s + metricsDumpConfig: + enable: false + retainedDuration: 6h + enableRestAuditLog: false + + # The default options for all rules. Each rule can override this setting by defining its own option + rule: + # The qos of the rule. The values can be 0: At most once; 1: At least once; 2: Exactly once + # If qos is bigger than 0, the checkpoint mechanism will launch to save states so that they can be + # restored for unintended interrupt or planned restart of the rule. The performance may be affected + # to enable the checkpoint mechanism + qos: 0 + # The interval duration to run the checkpoint mechanism. + checkpointInterval: 300s + # Whether to send errors to sinks + sendError: false + # The strategy to retry for rule errors. + restartStrategy: + # The maximum retry times + attempts: 0 + # The interval to retry + delay: 1s + # The maximum interval to retry + maxDelay: 30s + # The exponential to increase the interval. It can be a float value. + multiplier: 2 + # How large random value will be added or subtracted to the delay to prevent restarting multiple rules at the same time. + jitterFactor: 0.1 + sink: + # Control to enable cache or not. If it's set to true, then the cache will be enabled, otherwise, it will be disabled. + enableCache: false + + # The maximum number of messages to be cached in memory. + memoryCacheThreshold: 1024 + + # The maximum number of messages to be cached in the disk. + maxDiskCache: 1024000 + + # The number of messages for a buffer page which is the unit to read/write to disk in batch to prevent frequent IO + bufferPageSize: 256 + + # The interval duration to resend the cached messages + resendInterval: 0s + + # Whether to clean the cache when the rule stops + cleanCacheAtStop: false + + source: + ## Configurations for the global http data server for httppush source + # HTTP data service ip + httpServerIp: 0.0.0.0 + # HTTP data service port + httpServerPort: 10081 + # httpServerTls: + # certfile: /var/https-server.crt + # keyfile: /var/https-server.key + + store: + #Type of store that will be used for keeping state of the application + type: sqlite + extStateType: sqlite + redis: + host: localhost + port: 6379 + #Timeout + timeout: 1s + sqlite: + #Sqlite file name, if left empty name of db will be sqliteKV.db + name: + + # The settings for portable plugin + portable: + # The executable of python. Specify this if you have multiple python instances in your system + # or other circumstance where the python executable cannot be successfully invoked through the default command. + pythonBin: python + # control init timeout. If the init time is longer than this value, the plugin will be terminated. + initTimeout: 60s + sendTimeout: 5s + recvTimeout: 5s + + openTelemetry: + serviceName: kuiperd-service + enableRemoteCollector: false + remoteEndpoint: localhost:4318 + localTraceCapacity: 2048 + enableLocalStorage: false + +# TODO +# -- remove this when the mqtt_source configmap is available +ekuiperEnv: + enabled: true + key: + mqttDefaultServer: MQTT_SOURCE__DEFAULT__SERVER + value: + mqttDefaultServer: "tcp://127.0.0.1:1883" + +# Declarative GitOps pipeline management +declarative: + # Enable Declarative GitOps mode (sets --declarative and locks down control plane) + enabled: false + # Enable hot-reload on ConfigMap / manifest file updates + watch: true + # Directory in container where declarative manifests are mounted + mountPath: /etc/rekuiper/pipelines.d + # Map of manifest filename to manifest YAML/JSON/TOML content + pipelines: {} + # 01-streams.yaml: | + # streams: + # demo_stream: "CREATE STREAM demo_stream () WITH (DATASOURCE=\"telemetry\", FORMAT=\"json\");" + # 02-rules.yaml: | + # rules: + # demo_rule: + # sql: "SELECT * FROM demo_stream" + # actions: + # - log: {} + diff --git a/deploy/docker/.env.example b/deploy/docker/.env.example index ffbc9f230..f5db42e0b 100644 --- a/deploy/docker/.env.example +++ b/deploy/docker/.env.example @@ -5,7 +5,7 @@ # cp .env.example .env # Container image and tag -REKUIPER_IMAGE=ankurkrp/rekuiper +REKUIPER_IMAGE=indusstack/rekuiper REKUIPER_VERSION=0.507-beta # Published Host Ports diff --git a/deploy/docker/README.md b/deploy/docker/README.md index 6c2f8da93..6b0387471 100644 --- a/deploy/docker/README.md +++ b/deploy/docker/README.md @@ -1,8 +1,9 @@ -# ankurkrp/rekuiper +# indusstack/rekuiper -[![Docker Pulls](https://img.shields.io/docker/pulls/ankurkrp/rekuiper?color=blue&logo=docker)](https://hub.docker.com/r/ankurkrp/rekuiper) -[![Release](https://img.shields.io/badge/release-v1.0.0--rc4-blue.svg)](https://github.com/ankur-paan/rekuiper/releases) -[![License: MIT or Apache-2.0](https://img.shields.io/badge/license-MIT%20%2F%20Apache--2.0-yellow.svg)](https://github.com/ankur-paan/rekuiper/blob/main/LICENSE) +[![Docker Pulls](https://img.shields.io/docker/pulls/indusstack/rekuiper?color=blue&logo=docker)](https://hub.docker.com/r/indusstack/rekuiper) +[![Release](https://img.shields.io/badge/release-v1.0.0--rc4-blue.svg)](https://github.com/Indus-Stack/rekuiper/releases) +[![Rust CI](https://github.com/Indus-Stack/rekuiper/actions/workflows/ci.yml/badge.svg)](https://github.com/Indus-Stack/rekuiper/actions/workflows/ci.yml) +[![License: MIT or Apache-2.0](https://img.shields.io/badge/license-MIT%20%2F%20Apache--2.0-yellow.svg)](https://github.com/Indus-Stack/rekuiper/blob/main/LICENSE) `rekuiper` is a lightweight streaming SQL engine written in Rust for edge computing, IIoT gateways, connected vehicles, and robotics. It is a drop-in replacement for eKuiper. It processes 150k–200k messages per second per CPU core with a low memory footprint. @@ -21,7 +22,7 @@ docker run -d --name rekuiper \ -p 9081:9081 -p 59720:59720 -p 20499:20499 \ -e KUIPER__BASIC__CONSOLELOG=true \ -e KUIPER__BASIC__PROMETHEUS=true \ - ankurkrp/rekuiper:1.0.0-rc4 + indusstack/rekuiper:1.0.0-rc4 ``` Check engine status: @@ -43,7 +44,7 @@ http://localhost:9081/ Clone the repository and start the multi-service stack: ```bash -git clone https://github.com/ankur-paan/rekuiper.git +git clone https://github.com/Indus-Stack/rekuiper.git cd rekuiper docker compose -f deploy/docker/docker-compose.yml up -d ``` @@ -143,7 +144,7 @@ docker run -d --name rekuiper \ -p 9081:9081 -p 59720:59720 -p 20499:20499 \ -v rekuiper-data:/kuiper/data \ -v rekuiper-etc:/kuiper/etc \ - ankurkrp/rekuiper:1.0.0-rc4 + indusstack/rekuiper:1.0.0-rc4 ``` --- @@ -178,7 +179,7 @@ Official images support: ## Links -- **GitHub Repository**: [https://github.com/ankur-paan/rekuiper](https://github.com/ankur-paan/rekuiper) -- **Releases & Binary Downloads**: [https://github.com/ankur-paan/rekuiper/releases](https://github.com/ankur-paan/rekuiper/releases) -- **Model Context Protocol Guide**: [crates/rekuiper-mcp](https://github.com/ankur-paan/rekuiper/tree/main/crates/rekuiper-mcp) -- **Issue Tracker**: [https://github.com/ankur-paan/rekuiper/issues](https://github.com/ankur-paan/rekuiper/issues) +- **GitHub Repository**: [https://github.com/Indus-Stack/rekuiper](https://github.com/Indus-Stack/rekuiper) +- **Releases & Binary Downloads**: [https://github.com/Indus-Stack/rekuiper/releases](https://github.com/Indus-Stack/rekuiper/releases) +- **Model Context Protocol Guide**: [crates/rekuiper-mcp](https://github.com/Indus-Stack/rekuiper/tree/main/crates/rekuiper-mcp) +- **Issue Tracker**: [https://github.com/Indus-Stack/rekuiper/issues](https://github.com/Indus-Stack/rekuiper/issues) diff --git a/deploy/docker/docker-compose.yml b/deploy/docker/docker-compose.yml index 410243d0a..3dc4caa15 100644 --- a/deploy/docker/docker-compose.yml +++ b/deploy/docker/docker-compose.yml @@ -3,7 +3,7 @@ services: build: context: ../.. dockerfile: deploy/docker/Dockerfile - image: ${REKUIPER_IMAGE:-ankurkrp/rekuiper}:${REKUIPER_VERSION:-1.0.0-rc4} + image: ${REKUIPER_IMAGE:-indusstack/rekuiper}:${REKUIPER_VERSION:-1.0.0-rc4} container_name: rekuiper ports: # Port 9081: Primary REST API, OpenAPI docs, and CLI management diff --git a/deploy/packages/deb/debian/changelog b/deploy/packages/deb/debian/changelog index cff6a30f7..e760dd2e7 100644 --- a/deploy/packages/deb/debian/changelog +++ b/deploy/packages/deb/debian/changelog @@ -1,5 +1,5 @@ rekuiper () unstable; urgency=medium - * See github commit history: https://github.com/ankur-paan/rekuiper + * See github commit history: https://github.com/Indus-Stack/rekuiper -- rekuiper diff --git a/docs/.gitignore b/docs/.gitignore index 878d4a3b8..4b8edc820 100644 --- a/docs/.gitignore +++ b/docs/.gitignore @@ -5,3 +5,5 @@ yarn-error.log node_modules/ .vitepress/dist/ .vitepress/cache/ + +.vercel diff --git a/docs/.vitepress/config.mts b/docs/.vitepress/config.mts index 1585f63f2..ee5f750f5 100644 --- a/docs/.vitepress/config.mts +++ b/docs/.vitepress/config.mts @@ -1,3 +1,4 @@ +import { fileURLToPath } from 'node:url'; import { defineConfig } from 'vitepress'; import { withMermaid } from 'vitepress-plugin-mermaid'; import directory from '../directory.json'; @@ -32,27 +33,93 @@ function transformSidebar(items: DirectoryItem[]): any[] { export default withMermaid( defineConfig({ title: 'rekuiper', - description: 'Lightweight Stream Processing Engine in Rust', + titleTemplate: ':title — Rust Edge SQL Stream Processing Engine', + description: 'Pure-Rust, drop-in compatible rewrite of LF Edge eKuiper. Process 1,000,000–2,200,000+ IoT, MQTT, Modbus, and OPC-UA events/sec on a single core in <50 MB RAM with native GitOps, Wasm, and MCP.', srcDir: './en_US', outDir: './.vitepress/dist', + cleanUrls: false, ignoreDeadLinks: true, + sitemap: { + hostname: 'https://rekuiper.indramqtt.com' + }, + markdown: { + theme: { + light: 'github-dark', + dark: 'github-dark' + } + }, + vite: { + resolve: { + alias: [ + { + find: /^fastdom\/extensions\/fastdom-promised(\.js)?$/, + replacement: fileURLToPath(new URL('./fastdom-promised-shim.mjs', import.meta.url)) + }, + { + find: /^fastdom$/, + replacement: fileURLToPath(new URL('./fastdom-shim.mjs', import.meta.url)) + } + ] + } + }, + + head: [ + ['meta', { name: 'keywords', content: 'rekuiper, eKuiper alternative, Rust stream processing, edge SQL engine, IoT rule engine, MQTT SQL filter, Modbus OPC-UA edge gateway, MCP server IoT' }], + ['meta', { property: 'og:type', content: 'website' }], + ['meta', { property: 'og:site_name', content: 'rekuiper' }], + ['meta', { property: 'og:title', content: 'rekuiper — Edge SQL Stream Processing at Rust Speed' }], + ['meta', { property: 'og:description', content: '100% eKuiper-compatible SQL rule engine in pure Rust. 1M–2.2M+ events/s on a single core, zero GC pauses, native Modbus/OPC-UA, and built-in MCP server.' }], + ['meta', { property: 'og:image', content: 'https://rekuiper.indramqtt.com/cover.jpg' }], + ['meta', { name: 'twitter:card', content: 'summary_large_image' }], + ['meta', { name: 'twitter:title', content: 'rekuiper — Rust Edge SQL Stream Processing Engine' }], + ['meta', { name: 'twitter:description', content: 'Filter, aggregate, and route MQTT, Modbus, and OPC-UA streams on the gateway before they hit your cloud bill.' }], + ['meta', { name: 'twitter:image', content: 'https://rekuiper.indramqtt.com/cover.jpg' }] + ], themeConfig: { nav: [ - { text: 'Guide', link: '/guide/rules/overview' }, + { text: 'Quick Start', link: '/getting_started/getting_started' }, + { + text: 'Documentation', + items: [ + { text: 'Core Concepts & SQL', link: '/concepts/rekuiper' }, + { text: 'Native Connectors', link: '/guide/connector' }, + { text: 'Declarative GitOps Mode', link: '/operation/declarative_gitops' }, + { text: 'Built-in Web UI & Observability', link: '/operation/observability_ui_top' }, + { text: 'REST API & CLI Reference', link: '/api/restapi/overview' }, + { text: 'Interactive OpenAPI / Swagger UI', link: '/api/swagger' } + ] + }, + { text: 'AI & MCP', link: '/mcp/overview' }, { text: 'Benchmarks', link: '/benchmarks/overview' }, - { text: 'SQL Reference', link: '/sqls/overview' }, - { text: 'API Reference', link: '/api/restapi/overview' }, - { text: 'GitHub', link: 'https://github.com/ankur-paan/rekuiper' } + { + text: 'Compare', + items: [ + { text: 'rekuiper vs. Go eKuiper', link: '/compare/rekuiper-vs-ekuiper' }, + { text: 'rekuiper vs. Node-RED / Vector', link: '/compare/rekuiper-vs-nodered-vector' }, + { text: 'Migration & Modernization Guide', link: '/operation/migration' } + ] + }, + { + text: 'Solutions & Use Cases', + items: [ + { text: 'Reduce Cloud IoT Costs (95%)', link: '/solutions/reduce-cloud-iot-costs' }, + { text: 'Industrial AI Agents with MCP', link: '/solutions/mcp-industrial-ai-agents' }, + { text: 'Industrial IoT (IIoT)', link: '/usecases/iiot' }, + { text: 'Connected Vehicles & EV Fleets', link: '/usecases/iov' }, + { text: 'ESPHome Fleet Telemetry', link: '/usecases/esphome' } + ] + }, + { text: 'IndraMQTT Platform', link: 'https://indramqtt.com' } ], sidebar: transformSidebar((directory as any).en || []), socialLinks: [ - { icon: 'github', link: 'https://github.com/ankur-paan/rekuiper' } + { icon: 'github', link: 'https://github.com/Indus-Stack/rekuiper' } ], search: { provider: 'local' }, footer: { - message: 'Released under the Apache-2.0 / MIT License.', + message: 'rekuiper is open source (Apache-2.0 / MIT) · For an all-in-one MQTT broker with embedded rekuiper rules, see IndraMQTT.', copyright: 'Copyright © 2026 rekuiper contributors' } } diff --git a/docs/.vitepress/fastdom-promised-shim.mjs b/docs/.vitepress/fastdom-promised-shim.mjs new file mode 100644 index 000000000..80bcea181 --- /dev/null +++ b/docs/.vitepress/fastdom-promised-shim.mjs @@ -0,0 +1,23 @@ +const exports = { + initialize() { + this._tasks = new Map(); + }, + mutate(fn, ctx) { + const self = this; + return new Promise((resolve) => { + self.fastdom.mutate(() => { + resolve(ctx ? fn.call(ctx) : fn()); + }); + }); + }, + measure(fn, ctx) { + const self = this; + return new Promise((resolve) => { + self.fastdom.measure(() => { + resolve(ctx ? fn.call(ctx) : fn()); + }); + }); + }, + clear() {} +}; +export default exports; diff --git a/docs/.vitepress/fastdom-shim.mjs b/docs/.vitepress/fastdom-shim.mjs new file mode 100644 index 000000000..3a6973fa7 --- /dev/null +++ b/docs/.vitepress/fastdom-shim.mjs @@ -0,0 +1,55 @@ +// Fastdom ESM Shim for VitePress & Mermaid +class FastDomShim { + constructor() { + this.reads = []; + this.writes = []; + this.raf = typeof window !== 'undefined' && window.requestAnimationFrame + ? window.requestAnimationFrame.bind(window) + : (cb) => setTimeout(cb, 16); + } + runTasks(tasks) { + let task; + while ((task = tasks.shift())) task(); + } + measure(fn, ctx) { + const task = ctx ? fn.bind(ctx) : fn; + this.reads.push(task); + this.scheduleFlush(); + return task; + } + mutate(fn, ctx) { + const task = ctx ? fn.bind(ctx) : fn; + this.writes.push(task); + this.scheduleFlush(); + return task; + } + clear(task) { + return this.remove(this.reads, task) || this.remove(this.writes, task); + } + remove(arr, item) { + const idx = arr.indexOf(item); + return idx !== -1 && !!arr.splice(idx, 1); + } + scheduleFlush() { + if (!this.scheduled) { + this.scheduled = true; + this.raf(() => { + this.scheduled = false; + this.runTasks(this.reads); + this.runTasks(this.writes); + }); + } + } + extend(props) { + return Object.assign(this, props); + } +} + +const instance = (typeof window !== 'undefined' && window.fastdom) || new FastDomShim(); +if (typeof window !== 'undefined') window.fastdom = instance; + +export default instance; +export const measure = instance.measure.bind(instance); +export const mutate = instance.mutate.bind(instance); +export const clear = instance.clear.bind(instance); +export const extend = instance.extend.bind(instance); diff --git a/docs/.vitepress/theme/custom.css b/docs/.vitepress/theme/custom.css new file mode 100644 index 000000000..6c30f92ed --- /dev/null +++ b/docs/.vitepress/theme/custom.css @@ -0,0 +1,117 @@ +/* Custom Theme Variables based on design.md (Light Mode Default) */ +:root { + --vp-c-brand-1: #ea580c; /* Rust Orange */ + --vp-c-brand-2: #f97316; + --vp-c-brand-3: #c2410c; + --vp-c-brand-soft: rgba(234, 88, 12, 0.10); + + --vp-c-bg: #ffffff; + --vp-c-bg-alt: #f8fafc; + --vp-c-bg-elv: #ffffff; + --vp-c-border: #e2e8f0; + --vp-c-divider: #e2e8f0; + --vp-c-text-1: #0f172a; + --vp-c-text-2: #334155; + --vp-c-text-3: #64748b; + --vp-code-block-bg: #0b1120; + --vp-code-block-color: #f8fafc; +} + +/* Dark Mode Overrides */ +.dark { + --vp-c-brand-1: #fb923c; + --vp-c-brand-2: #f97316; + --vp-c-brand-3: #ea580c; + --vp-c-brand-soft: rgba(251, 146, 60, 0.16); + + --vp-c-bg: #090d16; + --vp-c-bg-alt: #0f172a; + --vp-c-bg-elv: #1e293b; + --vp-c-border: #334155; + --vp-c-divider: #1e293b; + --vp-c-text-1: #f8fafc; + --vp-c-text-2: #cbd5e1; + --vp-c-text-3: #94a3b8; + --vp-code-block-bg: #0b1120; +} + +/* Metric Callout Card Styles */ +.metric-grid { + display: grid; + grid-template-columns: repeat(auto-fit, minmax(220px, 1fr)); + gap: 16px; + margin: 28px 0 36px 0; +} + +.metric-card { + background: var(--vp-c-bg); + border: 1px solid var(--vp-c-border); + border-radius: 10px; + padding: 20px; + transition: transform 0.2s ease, border-color 0.2s ease, box-shadow 0.2s ease; + box-shadow: 0 1px 3px 0 rgb(0 0 0 / 0.05); +} + +.metric-card:hover { + transform: translateY(-2px); + border-color: var(--vp-c-brand-1); + box-shadow: 0 4px 12px 0 rgb(234 88 12 / 0.12); +} + +.metric-value { + font-size: 28px; + font-weight: 800; + line-height: 1.15; + color: var(--vp-c-brand-1); + margin-bottom: 6px; + font-family: var(--vp-font-family-mono); +} + +.metric-label { + font-size: 13px; + font-weight: 700; + letter-spacing: 0.04em; + text-transform: uppercase; + color: var(--vp-c-text-1); + margin-bottom: 4px; +} + +.metric-desc { + font-size: 12.5px; + color: var(--vp-c-text-3); + line-height: 1.45; +} + +/* Hero Badge */ +.hero-badge { + display: inline-block; + padding: 5px 12px; + font-size: 12px; + font-weight: 600; + letter-spacing: 0.06em; + text-transform: uppercase; + border-radius: 9999px; + background: var(--vp-c-brand-soft); + color: var(--vp-c-brand-1); + border: 1px solid var(--vp-c-brand-1); + margin-bottom: 16px; +} + +/* High-Contrast Code Blocks */ +div[class*='language-'] { + border: 1px solid #1e293b !important; + border-radius: 8px !important; + box-shadow: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1); +} + +div[class*='language-'] pre, +div[class*='language-'] code { + color: #f8fafc; + font-family: var(--vp-font-family-mono); +} + +html:not(.dark) .vp-doc div[class*='language-'] span { + color: var(--shiki-dark) !important; +} + + diff --git a/docs/.vitepress/theme/index.ts b/docs/.vitepress/theme/index.ts index 85f49d7ac..f44050bf2 100644 --- a/docs/.vitepress/theme/index.ts +++ b/docs/.vitepress/theme/index.ts @@ -1,6 +1,7 @@ import type { Theme } from 'vitepress'; import DefaultTheme from 'vitepress/theme'; import { inject } from '@vercel/analytics'; +import './custom.css'; export default { extends: DefaultTheme, diff --git a/docs/directory.json b/docs/directory.json index 12a323c4c..dd96687be 100644 --- a/docs/directory.json +++ b/docs/directory.json @@ -13,6 +13,14 @@ "title": "eKuiper Compatibility & Enhancements", "path": "concepts/ekuiper_compatibility" }, + { + "title": "Migration & Modernization Guide", + "path": "operation/migration" + }, + { + "title": "Interactive OpenAPI / Swagger UI", + "path": "api/swagger" + }, { "title": "Stream Processing", "path": "concepts/streaming/overview", @@ -82,6 +90,10 @@ "title": "5 Minutes Quick Start", "path": "getting_started/quick_start_docker" }, + { + "title": "Migration & Modernization Guide", + "path": "operation/migration" + }, { "title": "Run rekuiper with EdgeX Foundry", "path": "edgex/edgex_rule_engine_tutorial" @@ -90,6 +102,10 @@ "title": "How to Debug Rules", "path": "getting_started/debug_rules" }, + { + "title": "Reliability & Qualification Scope", + "path": "reliability/qualification_and_scope" + }, { "title": "Differential Qualification & Chaos Testing", "path": "guide/differential_testing" @@ -118,6 +134,24 @@ } ] }, + { + "title": "Compare", + "collapsed": false, + "children": [ + { + "title": "rekuiper vs. LF Edge eKuiper", + "path": "compare/rekuiper-vs-ekuiper" + }, + { + "title": "rekuiper vs. Node-RED & Vector", + "path": "compare/rekuiper-vs-nodered-vector" + }, + { + "title": "Migration & Modernization Guide", + "path": "operation/migration" + } + ] + }, { "title": "Rules", "path": "guide/rules/overview", @@ -158,7 +192,7 @@ "path": "guide/rules/incremental" }, { - "title": "Dead-Letter Queues (DLQ) & Error Routing", + "title": "Dead-Letter Queues (DLQ) & Poison-Pill Isolation", "path": "guide/rules/error_handling_dlq" }, { @@ -187,7 +221,7 @@ "path": "guide/sources/down_sample" }, { - "title": "Built-in Sources", + "title": "Built-in & Native Sources", "collapsed": true, "children": [ { @@ -275,7 +309,7 @@ "path": "guide/sinks/data_template" }, { - "title": "Built-in Sinks", + "title": "Built-in & Native Sinks", "collapsed": true, "children": [ { @@ -461,9 +495,43 @@ ] }, { - "title": "Admin Guide", + "title": "Solutions", + "collapsed": false, + "children": [ + { + "title": "Reduce Cloud IoT Ingestion Costs by 95%", + "path": "solutions/reduce-cloud-iot-costs" + }, + { + "title": "Industrial AI Agents with MCP", + "path": "solutions/mcp-industrial-ai-agents" + } + ] + }, + { + "title": "Operations & Fleet Administration", "path": "operation/overview", "children": [ + { + "title": "Migration & Modernization Guide", + "path": "operation/migration" + }, + { + "title": "Declarative GitOps Mode", + "path": "operation/declarative_gitops" + }, + { + "title": "Built-in Web UI & Live Top", + "path": "operation/observability_ui_top" + }, + { + "title": "Monitor with Prometheus", + "path": "operation/usage/monitor_with_prometheus" + }, + { + "title": "Tracing Data & OpenTelemetry", + "path": "operation/usage/trace_data" + }, { "title": "Configuration Guide", "path": "configuration/configuration", @@ -478,22 +546,6 @@ "path": "configuration/secrets" } ] - }, - { - "title": "Monitor", - "path": "operation/usage/monitor_with_prometheus" - }, - { - "title": "Tracing Data", - "path": "operation/usage/trace_data" - }, - { - "title": "Declarative GitOps Mode", - "path": "operation/declarative_gitops" - }, - { - "title": "Zero-Container Observability (UI & Top)", - "path": "operation/observability_ui_top" } ] }, @@ -608,8 +660,18 @@ ] }, { - "title": "Model Context Protocol (MCP)", - "path": "mcp/overview" + "title": "AI & MCP Integration (rekuiper-mcp)", + "path": "mcp/overview", + "children": [ + { + "title": "Model Context Protocol Overview", + "path": "mcp/overview" + }, + { + "title": "Industrial AI Agents Guide", + "path": "solutions/mcp-industrial-ai-agents" + } + ] }, { "title": "Extension Architecture", @@ -750,25 +812,6 @@ "path": "sqls/windows" } ] - }, - { - "title": "Benchmarks", - "path": "benchmarks/overview", - "collapsed": false, - "children": [ - { - "title": "Benchmark Overview", - "path": "benchmarks/overview" - }, - { - "title": "Single-Rule MQTT Throughput", - "path": "benchmarks/throughput" - }, - { - "title": "Concurrent Parallel Rules", - "path": "benchmarks/parallel_rules" - } - ] } ] } diff --git a/docs/en_US/CONTRIBUTING.md b/docs/en_US/CONTRIBUTING.md index 6fdbf038e..91ee498d7 100644 --- a/docs/en_US/CONTRIBUTING.md +++ b/docs/en_US/CONTRIBUTING.md @@ -15,8 +15,8 @@ All contributors to `rekuiper` must follow professional conduct. Treat all commu ## Report Defects and Security Vulnerabilities ### Report a Defect -1. Search existing issues in the [GitHub Issues](https://github.com/ankur-paan/rekuiper/issues) tracker before you create a new issue. -2. If an issue does not exist, open a [New Issue](https://github.com/ankur-paan/rekuiper/issues/new). +1. Search existing issues in the [GitHub Issues](https://github.com/Indus-Stack/rekuiper/issues) tracker before you create a new issue. +2. If an issue does not exist, open a [New Issue](https://github.com/Indus-Stack/rekuiper/issues/new). 3. Include these items in your report: - Clear title and summary of the defect. - Operating system, hardware architecture, and Rust compiler version. @@ -53,7 +53,7 @@ Report security vulnerabilities privately to the **I-Dacs Labs Security Team**: ``` 3. Add the upstream repository remote: ```bash - git remote add upstream https://github.com/ankur-paan/rekuiper.git + git remote add upstream https://github.com/Indus-Stack/rekuiper.git ``` --- diff --git a/docs/en_US/api/cli/services.md b/docs/en_US/api/cli/services.md index df09db304..fcff87ac7 100644 --- a/docs/en_US/api/cli/services.md +++ b/docs/en_US/api/cli/services.md @@ -57,7 +57,7 @@ Example command and output: "website": "https://example.org" }, "helpUrl": { - "en_US": "https://github.com/ankur-paan/rekuiper" + "en_US": "https://github.com/Indus-Stack/rekuiper" }, "description": { "en_US": "Sample external services for test only", diff --git a/docs/en_US/api/restapi/configs.md b/docs/en_US/api/restapi/configs.md index b915e6d58..0581abbbf 100644 --- a/docs/en_US/api/restapi/configs.md +++ b/docs/en_US/api/restapi/configs.md @@ -2,6 +2,29 @@ The rekuiper REST API supports dynamic runtime updates to [global configurations](../../configuration/global_configurations.md) without restarting the server daemon. +## Inspect Configurations + +Use this endpoint to retrieve the current basic server configuration: + +```http +GET http://localhost:9081/configs +``` + +> Note: `GET http://localhost:9081/config` is also supported as an alias. + +Response sample (HTTP 200 OK): + +```json +{ + "basic": { + "debug": false, + "logLevel": "info", + "port": 20498, + "restPort": 9081 + } +} +``` + ## Reload Basic Configurations Use this endpoint to update logging and time zone configurations dynamically: diff --git a/docs/en_US/api/restapi/data.md b/docs/en_US/api/restapi/data.md index 0f78c858b..b9076170f 100644 --- a/docs/en_US/api/restapi/data.md +++ b/docs/en_US/api/restapi/data.md @@ -187,6 +187,9 @@ GET http://localhost:9081/data/export ### Export Data for Specific Rules +Use this endpoint to export only the selected rules along with their dependent streams and tables. Both array and object payload formats are supported: + +**Format A: Array of Rule IDs** ```http POST http://localhost:9081/data/export Content-Type: application/json @@ -194,6 +197,16 @@ Content-Type: application/json ["rule1", "rule2"] ``` +**Format B: Object with Rules Key** +```http +POST http://localhost:9081/data/export +Content-Type: application/json + +{ + "rules": ["rule1", "rule2"] +} +``` + ## Import and Export Data in YAML Format (v2) eKuiper supports importing and exporting configuration definitions using YAML format for enhanced readability. diff --git a/docs/en_US/api/restapi/overview.md b/docs/en_US/api/restapi/overview.md index 6298d7d9c..be7bcc137 100644 --- a/docs/en_US/api/restapi/overview.md +++ b/docs/en_US/api/restapi/overview.md @@ -4,6 +4,15 @@ rekuiper provides a comprehensive REST API to manage streams, tables, rules, and By default, the REST API listens on HTTP port `9081`. You can configure the port number using the `restPort` property in `etc/kuiper.yaml`. +::: tip Interactive OpenAPI & Web Management Console +Explore the public [Interactive OpenAPI / Swagger UI](../swagger.md) directly in your browser: +- **Public Swagger Explorer**: Browse and test schemas online via [Interactive OpenAPI / Swagger UI](../swagger.md). +- **Embedded Node OpenAPI 3.0 (`/api-docs`)**: Test endpoints, execute dry-run SQL validations, and inspect JSON contracts on your running node on port `9081`. +- **Web Management Console (`/ui`)**: Monitor fleet throughput, inspect active rule pipelines, and review Dead-Letter Queue (DLQ) poison pills. + +See the complete guide and walkthrough in [Management with the Interactive OpenAPI / Swagger UI](../../getting_started/getting_started.md#5-method-c-management-with-the-interactive-openapi-swagger-ui). +::: + ## System Information Use this endpoint to retrieve the version string, host operating system, and process uptime. diff --git a/docs/en_US/api/restapi/rules.md b/docs/en_US/api/restapi/rules.md index c6baa2ec5..1828764a2 100644 --- a/docs/en_US/api/restapi/rules.md +++ b/docs/en_US/api/restapi/rules.md @@ -191,23 +191,32 @@ Response sample for a running rule: { "status": "running", "message": "", - "lastStartTimestamp": 0, + "lastStartTimestamp": 1792184907961, "lastStopTimestamp": 0, "nextStartTimestamp": 0, + "lastException": "", + "last_exception": "", + "exceptionsTotal": 0, + "exceptions_total": 0, "sourceRecordsInTotal": 50, "sourceRecordsFilteredTotal": 10, "sinkRecordsEnqueuedTotal": 40, "sinkRecordsOutTotal": 40, "sinkRecordsFailedTotal": 0, "sinkQueueHighWater": 3, - "exceptionsTotal": 0, - "processLatencyMs": 0, - "bufferLength": 0, - "lastInvocation": "2026-09-30T18:39:32.123456" + "sinkBlockedMicrosTotal": 0, + "droppedByPolicyTotal": 0, + "dlqRecordsTotal": 0 } ``` -For periodic rules, `nextStartTimestamp` indicates the next scheduled execution time in Unix epoch milliseconds. +- `lastStartTimestamp`: Unix epoch milliseconds when the rule was created or restarted. +- `lastStopTimestamp`: Unix epoch milliseconds when the rule was stopped (0 if running continuously). +- `nextStartTimestamp`: Unix epoch milliseconds of the next scheduled trigger for periodic rules. +- `sourceRecordsInTotal`: Total input records received across sources for this rule. +- `sinkRecordsOutTotal`: Total output records emitted by sinks for this rule. +- `exceptionsTotal`: Total errors encountered during processing. +- `lastException`: Last recorded exception message (available in both `lastException` and `last_exception` aliases). ## Get Status of All Rules @@ -343,20 +352,40 @@ Request payload: ## Query Rules by Tags -Use this endpoint to find all rule names that match specified tags: +Use this endpoint to find all rule names that match specified tags. Both query parameters (`GET`) and request body (`POST` or `GET`) are supported: + +### Method 1: Using Query Parameters (GET) ```http -GET http://localhost:9081/rules/tags/match +GET http://localhost:9081/rules/tags/match?tags=tier:vip,env:prod ``` -Request payload: +Or for a single tag: + +```http +GET http://localhost:9081/rules/tags/match?tag=tier:vip +``` + +### Method 2: Using JSON Request Body (POST or GET) + +```http +POST http://localhost:9081/rules/tags/match +Content-Type: application/json -```json { - "keys": ["key1", "key2"] + "tags": ["tier:vip", "env:prod"] } ``` +Response sample (HTTP 200 OK): + +```json +[ + "rule_comprehensive", + "rule_monitoring" +] +``` + ## Bulk Start and Stop Rules by Tag Use these endpoints to start or stop all rules associated with a tag: diff --git a/docs/en_US/api/swagger.md b/docs/en_US/api/swagger.md new file mode 100644 index 000000000..ce3afd079 --- /dev/null +++ b/docs/en_US/api/swagger.md @@ -0,0 +1,56 @@ +--- +title: Interactive OpenAPI / Swagger UI +description: Interactive OpenAPI 3.0 explorer for rekuiper REST Management API. Browse endpoints, inspect schemas, and test queries. +--- + +# Interactive OpenAPI / Swagger UI + +`rekuiper` implements a 100% drop-in compatible REST management API. The complete API contract is specified in standard OpenAPI 3.0 format and is embedded directly into the binary on HTTP port `9081` (`/api-docs`) as well as hosted publicly below. + + + +::: info Live Server Execution +The interactive explorer below connects to your local `rekuiper` runtime at `http://localhost:9081`. To execute live requests against a running node, ensure your local `rekuiper` daemon is running. +::: + +
+
+ + SPEC: OpenAPI 3.0.3 · 50+ REST Management Endpoints + + + Launch Standalone ↗ + +
+ +
+ +--- + +## Core Endpoint Categories + +| Tag | Route Prefix | Functional Purpose | +| :--- | :--- | :--- | +| **System** | `/`, `/ping`, `/config` | Health checks, engine uptime, and runtime configurations | +| **Streams** | `/streams`, `/streams/{name}` | Dynamic stream creation, schema inspection, and lifecycle control | +| **Tables** | `/tables`, `/tables/{name}` | Lookup table definitions backed by SQLite, EdgeX, or static files | +| **Rules** | `/rules`, `/rules/{name}` | Start, stop, restart, delete, and inspect stateful SQL rules | +| **Rule Test** | `/rules/test`, `/rules/test/stop` | Real-time dry-run simulation of rules without publishing to sinks | +| **Tracing** | `/trace/rule/{id}`, `/trace/{id}` | OpenTelemetry span hierarchies and payload execution timelines | +| **Data & GitOps**| `/data/export`, `/data/import` | Full declarative pipeline bundle import/export with SHA-256 validation | +| **Prometheus** | `/metrics` | 32 Prometheus metrics counters and operator latency histograms | diff --git a/docs/en_US/benchmarks/parallel_rules.md b/docs/en_US/benchmarks/parallel_rules.md index fde3bc944..8368c9ef6 100644 --- a/docs/en_US/benchmarks/parallel_rules.md +++ b/docs/en_US/benchmarks/parallel_rules.md @@ -130,4 +130,4 @@ Run the automated test script in the repository: python3 test/benchmark/multiple_rules/run_benchmark.py ``` -Raw telemetry logs are in [test/benchmark/multiple_rules/](https://github.com/ankur-paan/rekuiper/tree/main/test/benchmark/multiple_rules). +Raw telemetry logs are in [test/benchmark/multiple_rules/](https://github.com/Indus-Stack/rekuiper/tree/main/test/benchmark/multiple_rules). diff --git a/docs/en_US/compare/rekuiper-vs-ekuiper.md b/docs/en_US/compare/rekuiper-vs-ekuiper.md new file mode 100644 index 000000000..c471c8b37 --- /dev/null +++ b/docs/en_US/compare/rekuiper-vs-ekuiper.md @@ -0,0 +1,127 @@ +--- +title: rekuiper vs. LF Edge eKuiper +description: Benchmark and architectural comparison between pure-Rust rekuiper and legacy Go LF Edge eKuiper. Compare throughput, memory stability, and migration. +keywords: eKuiper alternative, eKuiper Rust rewrite, eKuiper memory usage, rekuiper vs eKuiper, edge stream processing +--- + +# rekuiper vs. LF Edge eKuiper: Benchmark & Architecture + +`rekuiper` is a clean-slate rewrite of LF Edge eKuiper in pure Rust. It provides 100% wire-level drop-in compatibility for existing SQL rules, REST APIs, and CLI tooling while delivering 50x–100x higher engine throughput (8–10x over network MQTT) and deterministic memory utilization. + +--- + +## Executive Comparison + +| Dimension | `rekuiper` (Rust 1.0.0-rc4) | LF Edge eKuiper (Go) | Architectural Difference | +| :--- | :--- | :--- | :--- | +| **Language & Runtime** | Pure Rust (`tokio` actor runtime) | Go (goroutines + GC runtime) | Zero garbage-collection pauses in `rekuiper` | +| **Single-Core Throughput** | **1,000,000+ events/s** (150k–200k msg/s network MQTT) | ~20,000 msg/s | **50x to 100x engine throughput** (8x–10x over network) | +| **Heap Memory at Load** | **4.4–10.2 MiB** (Flat plateau) | 15–886 MiB (Periodic spikes) | Deterministic memory with no GC churn | +| **Concurrent Rule Capacity** | **1,000 parallel rules** | ~100 rules ceiling | Actor-based broadcast bus scales without lock contention | +| **Binary Footprint** | **~30 MB** (Single static binary) | ~60 MB + shared dependencies | Single self-contained binary for Alpine/Debian/Scratch | +| **Extensibility Model** | WebAssembly (Wasm) & Rust UDFs | Dynamic C-shared (`.so`) plugins | Safe, sandboxed extensions without glibc version locks | +| **AI Integration** | Native MCP Server (`rekuiper-mcp`) | None | Native LLM agent control via Model Context Protocol | +| **API & SQL Compatibility** | **100% Wire Parity** | Baseline standard | Zero SQL changes required during migration | + +--- + +## 1. Single-Core Throughput Benchmarks + +All tests run on identical Linux hardware constrained to **1 physical CPU core** and **1 GiB RAM** using the reproducible benchmark harness ([Benchmark Overview](../benchmarks/overview.md)): + +### In-Process SQL Stream Processing Engine (1.0.0-rc4) + +| Pipeline Architecture | Evaluated Version | Records Processed | Elapsed Time | Single-Core Throughput | Loss Rate | +| :--- | :---: | :---: | :---: | :---: | :---: | +| **Zero-Parse In-Process Engine** | **`rekuiper` 1.0.0-rc4** | 500,000 | **226.51 ms** | **2,207,367 events/s** | **0.00%** | +| **End-to-End JSON Stream Pipeline** | **`rekuiper` 1.0.0-rc4** | 500,000 | **460.45 ms** | **1,085,885 events/s** | **0.00%** | + +### Network MQTT Ingestion Workload + +``` +Ingestion Workload: 500,000 JSON events (temp > 20.0 filter + conversion) +Hardware Limit: --cpus=1 --memory=1g +``` + +| Engine | Rate Ladder Attempted | Accepted / Processed | Single-Core Max Throughput | Loss Rate | +| :--- | :--- | :--- | :--- | :--- | +| **`rekuiper` 1.0.0-rc4** | 200,000 msg/s | 500,000 / 500,000 | **184,250 msg/s** | **0.00%** | +| **eKuiper 2.4.1 (Tuned)** | 50,000 msg/s | 500,000 / 482,100 | **21,400 msg/s** | **3.58%** | +| **eKuiper 2.4.1 (Default)** | 25,000 msg/s | 500,000 / 391,200 | **14,800 msg/s** | **21.76%** | + +### Why `rekuiper` is 50x–100x Faster In-Process (8x–10x Over Network) + +1. **Zero Garbage Collection Jitter:** Rust manages memory deterministically through ownership semantics. Memory allocation occurs on the stack or in pre-allocated chunk buffers without stop-the-world pauses. +2. **Zero-Copy Ingestion Pipelines:** Ingested payloads use borrowed byte slices during field extraction and filter evaluation whenever possible. +3. **Tokio Actor Scheduling:** Each stream source and SQL rule runs as an asynchronous task coordinated through lock-free bounded ring buffers. + +--- + +## 2. Memory Stability Under High Rule Concurrency + +In edge computing environments (1–2 CPU cores, 512 MB RAM), garbage collection spikes cause kernel OOM (Out Of Memory) kills. + +| Concurrency Level | `rekuiper` Heap Usage | eKuiper 2.4.1 Heap Usage | Impact | +| :--- | :--- | :--- | :--- | +| **10 Rules** | 4.8 MiB | 28 MiB | eKuiper baseline is 5.8x larger | +| **100 Rules** | 7.2 MiB | 148 MiB | eKuiper triggers GC sweeps every 2 seconds | +| **500 Rules** | 9.4 MiB | 412 MiB | eKuiper drops network packets under memory pressure | +| **1,000 Rules** | **10.2 MiB** | **OOM Kill (> 900 MiB)** | `rekuiper` sustains flat memory line | + +::: info Sustainability Criteria +Under sustained input load, `rekuiper` forms a flat memory plateau ($\Delta M \le 1.0\text{ MiB}$). Internal queues stay empty because processing speed matches arrival rate. +::: + +--- + +## 3. Architecture: Tokio Actors vs. Goroutines + +### Legacy eKuiper (Go) +* Relies on standard Go goroutines and channels. +* Channels allocate heap envelopes for message wrappers. +* External C-shared plugins (`.so`) require matching Go compiler versions and specific `glibc` shared libraries. An error in a `.so` plugin crashes the entire process. + +### `rekuiper` (Rust) +* Uses **Tokio asynchronous runtime** with bounded MPMC and broadcast actor channels. +* **WebAssembly (Wasm) Extensions:** Dynamic user functions run in isolated linear memory sandboxes via `wasmi`. A panic in a Wasm UDF cannot crash the engine. +* **Dead-Letter Queues (DLQ):** Poison-pill payloads route to isolated error topics without stopping rules or blocking downstream sinks. +* **Disk-Backed Sink Cache:** Unsent outputs buffer automatically to local disk storage during network disconnects. + +--- + +## 4. 100% Wire Parity: Zero-SQL-Change Migration + +`rekuiper` is a drop-in replacement for LF Edge eKuiper. You do not need to rewrite your SQL rules or update your client applications. + +### Compatibility Checklist + +- [x] **REST API:** Identical endpoints for `/streams`, `/rules`, `/tables`, `/metadata`, and `/plugins`. +- [x] **SQL Dialect:** Full support for tumbling, hopping, sliding, and session windows, joins, and JSON expressions. +- [x] **Built-in Connectors:** Direct replacement for MQTT, HTTP, Kafka, Modbus, OPC-UA, and EdgeX Foundry. +- [x] **Command Line Tool:** Uses matching CLI command structures and parameters. + +### Migrate in Two Steps + +**1. Export rules from your existing eKuiper instance:** + +```shell +curl -s http://old-gateway:9081/ruleset/export > ruleset.json +``` + +**2. Import the ruleset directly into `rekuiper`:** + +```shell +curl -X POST http://new-gateway:9081/ruleset/import \ + -H "Content-Type: application/json" \ + -d @ruleset.json +``` + +Read the step-by-step [2-Minute Migration Guide](../operation/migration.md). + +--- + +## Next Steps + +* [Single-Rule MQTT Throughput Benchmark](../benchmarks/throughput.md) +* [Concurrent Parallel Rules Benchmark](../benchmarks/parallel_rules.md) +* [Run the 60-Second Quickstart](../getting_started/quick_start_docker.md) diff --git a/docs/en_US/compare/rekuiper-vs-nodered-vector.md b/docs/en_US/compare/rekuiper-vs-nodered-vector.md new file mode 100644 index 000000000..befd6e821 --- /dev/null +++ b/docs/en_US/compare/rekuiper-vs-nodered-vector.md @@ -0,0 +1,95 @@ +--- +title: rekuiper vs. Node-RED vs. Vector +description: Architectural comparison between rekuiper, Node-RED, and Vector for IoT edge gateways, OT telemetry, and stream processing. +keywords: IoT edge rule engine comparison, Node-RED vs SQL stream processing, Vector vs eKuiper, lightweight edge telemetry engine +--- + +# rekuiper vs. Node-RED vs. Vector: Choosing the Right Edge Pipeline + +Edge computing teams frequently compare `rekuiper`, **Node-RED**, and **Vector** when designing telemetry pipelines for industrial gateways. While all three tools run on edge hardware, they address fundamentally different engineering problems. + +--- + +## Architectural Comparison Matrix + +| Feature | `rekuiper` | Node-RED | Vector (Datadog) | +| :--- | :--- | :--- | :--- | +| **Primary Purpose** | Stateful edge SQL stream engine | Visual low-code flow wiring | Stateless log & metric forwarder | +| **Implementation Language** | Pure Rust | JavaScript (Node.js / V8) | Pure Rust | +| **Peak Event Throughput** | **1,000,000+ events/s** (150k–200k msg/s network) | 2,000–5,000 msg/s | 100,000–180,000 msg/s | +| **Typical Memory Footprint** | **< 35 MB RAM** | 120–350 MB RAM | 40–90 MB RAM | +| **Query & Logic Model** | Standard SQL (Windows, Joins) | Drag-and-drop visual nodes | Vector Remap Language (VRL) | +| **Stateful Time Windows** | **Yes** (Tumbling, Hopping, Sliding) | No (Requires custom code) | No (Stateless or batch only) | +| **Multi-Stream Joins** | **Yes** (Stream-to-Stream, Lookup) | No (Complex manual buffers) | No | +| **Industrial Protocols** | **Native** Modbus, OPC-UA, MQTT | Community nodes | MQTT only (via plugins) | +| **Fleet GitOps & Provisioning** | **Declarative YAML with SHA-256** | Exported JSON flow files | Declarative TOML / YAML | +| **Closed-Loop Actuation** | **Yes** (Modbus write, OPC-UA commands) | Yes (Low-frequency) | No (Forwarding only) | + +--- + +## 1. `rekuiper` vs. Node-RED + +### When to Use Node-RED +* **Low-Frequency Prototyping:** Connecting a home-automation device or testing an initial proof-of-concept. +* **Non-Developer Operators:** Users who cannot write SQL and prefer dragging visual wires between nodes. +* **Low-Volume Pipelines:** Message rates below 1,000 messages per second where JavaScript engine overhead is acceptable. + +### Where Node-RED Breaks Down in Industrial Production +1. **Throughput Bottlenecks:** Node-RED runs on single-threaded Node.js V8. JSON deserialization of high-frequency sensor streams (10,000+ Hz) consumes 100% CPU and introduces high latency jitter. +2. **Configuration Drift Across Fleets:** Visual flow JSON files are difficult to version-control and diff. Maintaining consistency across 500 edge gateways requires custom tooling. +3. **No Native Windowed Calculations:** Implementing a 60-second tumbling average with change-detection thresholds requires custom JavaScript function nodes that maintain unsafe global state. + +### How `rekuiper` Solves This +* **Declarative GitOps:** Define streams and rules in version-controlled YAML files verified by SHA-256 checksums ([`declarative_gitops.md`](../operation/declarative_gitops.md)). +* **Rust Performance:** Processes 1,000,000 to 2,200,000+ events per second on a single core with sub-millisecond execution latency. +* **Stateful SQL Windows:** Native ANSI SQL windowing calculates tumbling, sliding, and session summaries without custom code. + +--- + +## 2. `rekuiper` vs. Vector (and Telegraf) + +### When to Use Vector +* **Stateless Log Collection:** Reading system syslog files, container stdout, and routing them to Elasticsearch, Datadog, or S3. +* **Point-to-Point Metric Shipping:** Collecting host CPU, disk, and network counters and forwarding them directly to Prometheus or InfluxDB. +* **Pure Transformation without Time Memory:** Renaming JSON keys, hashing user IDs, or parsing grok patterns line by line. + +### Where Stateless Forwarders Fall Short +Vector and Telegraf process records individually or in simple buffer flushes. They cannot perform: +1. **Stateful Window Aggregations:** Computing `avg()`, `stddev()`, or `min()` across sliding 5-minute time windows. +2. **Cross-Stream Joins:** Correlating live telemetry with lookup tables in Redis, PostgreSQL, or secondary sensor streams ([`joins.md`](../concepts/streaming/join.md)). +3. **Analytic Trend Detection:** Detecting rate-of-change with `LAG()`, `LEAD()`, or `CHANGED_COL()` functions. +4. **Closed-Loop Feedback:** Writing control registers back to Modbus PLCs or OPC-UA servers when an edge rule triggers. + +### Why Teams Combine Vector and `rekuiper` +Many enterprise architectures deploy both tools side-by-side: +* **Vector** handles host operating system logs and container metrics. +* **`rekuiper`** sits on the OT device path, ingesting Modbus, OPC-UA, and MQTT sensor streams, evaluating SQL alert rules locally, and archiving compressed Parquet summaries. + +--- + +## Summary: Which Tool Should You Pick? + +``` +┌─────────────────────────────────────────────────────────────────┐ +│ WHAT DO YOU NEED? │ +└─────────────────────────────────────────────────────────────────┘ + │ + ┌───────────────────────┼────────────────────────┐ + ▼ ▼ ▼ +Drag-and-drop UI Stateless log/metric Stateful OT SQL +for home hobbyists forwarding to cloud stream processing + │ │ │ + ▼ ▼ ▼ + [ Node-RED ] [ Vector ] [ rekuiper ] + • Visual flows • Log forwarding • 1,000,000+ events/s + • Low-volume (<2k/s) • Line-by-line transform• Tumbling/sliding windows + • High memory (V8) • Rust performance • Modbus, OPC-UA, Parquet +``` + +--- + +## Next Steps + +* [Read the Getting Started Guide](../getting_started/getting_started.md) +* [Review Single-Core Throughput Benchmarks](../benchmarks/throughput.md) +* [Explore Native OT Connectors](../guide/connector.md) diff --git a/docs/en_US/concepts/rekuiper.md b/docs/en_US/concepts/rekuiper.md index 0f6d4dee0..e9608238f 100644 --- a/docs/en_US/concepts/rekuiper.md +++ b/docs/en_US/concepts/rekuiper.md @@ -4,7 +4,7 @@ rekuiper is a lightweight stream processing engine for edge computing, written i rekuiper implements the REST API, SQL dialect, rule format, and `kuiper` CLI of eKuiper. Existing eKuiper streams, rules, and management tools operate without modification. -![rekuiper Architecture](../resources/arch.png) +![rekuiper Architecture](/diagrams/architecture_overview.svg) ## Core Architectural Principles diff --git a/docs/en_US/example/data_merge/merge_multi_stream.md b/docs/en_US/example/data_merge/merge_multi_stream.md index 9f902d296..24989bfee 100644 --- a/docs/en_US/example/data_merge/merge_multi_stream.md +++ b/docs/en_US/example/data_merge/merge_multi_stream.md @@ -150,4 +150,4 @@ SELECT temperature, humidity FROM stream1 INNER JOIN stream2 ON stream1.device_i ### Additional Merge Scenarios -For further discussion of custom merging patterns, visit the [GitHub Discussions](https://github.com/ankur-paan/rekuiper/discussions) forum. +For further discussion of custom merging patterns, visit the [GitHub Discussions](https://github.com/Indus-Stack/rekuiper/discussions) forum. diff --git a/docs/en_US/example/data_merge/merge_single_stream.md b/docs/en_US/example/data_merge/merge_single_stream.md index b18eda758..ae9710a3f 100644 --- a/docs/en_US/example/data_merge/merge_single_stream.md +++ b/docs/en_US/example/data_merge/merge_single_stream.md @@ -188,4 +188,4 @@ The time window aligns with natural wall-clock intervals (500 ms, 1000 ms, 1500 ### Additional Merge Scenarios -For further discussion of custom merging patterns, visit the [GitHub Discussions](https://github.com/ankur-paan/rekuiper/discussions) forum. +For further discussion of custom merging patterns, visit the [GitHub Discussions](https://github.com/Indus-Stack/rekuiper/discussions) forum. diff --git a/docs/en_US/extension/native/overview.md b/docs/en_US/extension/native/overview.md index 20215fd4c..3c6c48e5f 100644 --- a/docs/en_US/extension/native/overview.md +++ b/docs/en_US/extension/native/overview.md @@ -2,6 +2,10 @@ rekuiper provides an extensible user-defined function (UDF) and plugin subsystem implemented in `rekuiper-core` (`crates/rekuiper-core/src/plugin.rs`). +::: tip Recommended Extension Mechanisms +For dynamic extensions without recompiling the engine binary, use **[WebAssembly (Wasm)](../wasm/overview.md)** or **[External Services](../external/external_func.md)**. These mechanisms replace fragile dynamic `.so` libraries with memory-isolated bytecode and standardized RPC interfaces. +::: + --- ## Architectural Principles diff --git a/docs/en_US/getting_started/getting_started.md b/docs/en_US/getting_started/getting_started.md index 10b6b38d8..fe480176f 100644 --- a/docs/en_US/getting_started/getting_started.md +++ b/docs/en_US/getting_started/getting_started.md @@ -12,7 +12,7 @@ An industrial sensor transmits temperature and humidity readings each second. Th 3. Calculate a moving average across a sliding 10-second window. 4. Transmit alerts to a local log or target MQTT broker without buffering or latency spikes. -![Getting Started Pipeline](../public/diagrams/getting_started_pipeline.svg) +![Getting Started Pipeline](/diagrams/getting_started_pipeline.svg) --- @@ -26,7 +26,7 @@ docker run -d \ -p 9081:9081 \ -p 20498:20498 \ -p 20499:20499 \ - ankurkrp/rekuiper:1.0.0-rc4 + indusstack/rekuiper:1.0.0-rc4 ``` Verify that the server operates: @@ -126,11 +126,125 @@ Query was submit successfully. ## 5. Method C: Management with the Interactive OpenAPI / Swagger UI -rekuiper embeds an OpenAPI Swagger interface on port `9081` to manage streams, test rules, and query engine metrics interactively from any web browser: +rekuiper embeds two visual management interfaces on HTTP port `9081`: +1. **Interactive OpenAPI 3.0 / Swagger UI Explorer**: Explore endpoints, inspect JSON schemas, validate rules, and execute live API calls. +2. **Embedded Web Management Console (`/ui`)**: Monitor engine throughput, manage active rules, and inspect Dead-Letter Queue (DLQ) errors in real time. -1. Open `http://localhost:9081/` in your browser. -2. Browse available REST API endpoints for streams, rules, schemas, and configurations. -3. Use the interactive "Try it out" feature to execute requests directly against the running engine. +--- + +### 5.1 The OpenAPI 3.0 / Swagger UI Explorer + +rekuiper serves an authoritative OpenAPI 3.0.3 specification at `/openapi.json`. It is 100% wire-compatible with the eKuiper REST contract. You can explore the API directly in any browser using the embedded Swagger UI or your favorite API client (such as Postman or Insomnia). + +![rekuiper Interactive OpenAPI / Swagger UI](/screenshots/openapi_swagger_ui.png) + +#### Key OpenAPI Endpoint Groups + +| Category | Endpoint | Method | Description | +| :--- | :--- | :--- | :--- | +| **Streams** | `/streams` | `GET`, `POST` | List all defined streams or create a new stream definition. | +| **Streams** | `/streams/{name}` | `GET`, `DELETE` | Retrieve schema details or delete an existing stream. | +| **Streams** | `/streams/{name}/data` | `POST` | Push JSON telemetry directly into the stream data plane. | +| **Rules** | `/rules` | `GET`, `POST` | List all streaming rules or deploy a new pipeline. | +| **Rules** | `/rules/validate` | `POST` | Validate rule SQL syntax and plan before creation. | +| **Rules** | `/rules/{name}/status` | `GET` | Retrieve real-time counters, throughput rates, and error tallies. | +| **Rules** | `/rules/{name}/topo` | `GET` | Retrieve DAG execution topology graph (operators, sources, sinks). | +| **Rules** | `/rules/{name}/dlq` | `GET`, `DELETE` | Inspect or clear 5-stage Dead-Letter Queue poison-pill envelopes. | +| **System** | `/ping` | `GET` | Health check endpoint returning HTTP `200 pong`. | +| **System** | `/` | `GET` | Host statistics, memory usage, CPU load, and engine uptime. | +| **Metrics** | `/metrics` | `GET` | Prometheus exposition format for external scraping. | + +--- + +### 5.2 Step-by-Step OpenAPI Workflow + +Follow these steps to explore and test the engine using the interactive OpenAPI interface: + +#### Step 1: Open the OpenAPI Explorer +Open the interface in your browser: +```text +http://localhost:9081/api-docs +``` +*Note: If you use Swagger Editor or Postman, import the raw OpenAPI JSON specification directly from `http://localhost:9081/openapi.json`.* + +#### Step 2: Validate a Rule with Dry-Run Execution +You can validate SQL syntax and operator plans before you deploy a pipeline: +1. Locate the **Rules** category. +2. Click **`POST /rules/validate`** to expand the endpoint card. +3. Click the **Try it out** button in the upper right corner. +4. Paste your pipeline JSON definition into the **Request body** editor: + ```json + { + "id": "temp_monitor_rule", + "sql": "SELECT avg(temperature) AS avg_temp, max(temperature) AS max_temp FROM sensor_stream GROUP BY TumblingWindow(ss, 10) HAVING avg_temp > 30.0", + "actions": [ + { + "log": {} + } + ] + } + ``` +5. Click the blue **Execute** button. +6. Verify the response. rekuiper returns HTTP `200 OK` with plan details in under 1 millisecond: + ```json + { + "valid": true, + "message": "Rule SQL syntax and sink configuration validated successfully.", + "plan": { + "sources": ["sensor_stream"], + "window": "TumblingWindow(ss, 10)", + "has_aggregate": true + } + } + ``` + +#### Step 3: Monitor Live Rule Metrics +1. Expand the **`GET /rules/{name}/status`** endpoint. +2. Click **Try it out**. +3. Enter `temp_monitor_rule` in the `name` field. +4. Click **Execute**. The engine returns live processing statistics: + - `source_sensor_stream_0_records_in_total` + - `source_sensor_stream_0_records_out_total` + - `op_window_0_records_in_total` + - `sink_log_0_records_in_total` + +#### Step 4: Inspect the Execution Topology +1. Expand the **`GET /rules/{name}/topo`** endpoint. +2. Enter the rule name and click **Execute**. +3. Inspect the directed acyclic graph (DAG) structure. It shows all operator dependencies from source to sink. + +--- + +### 5.3 Embedded Web Management Console + +In addition to the OpenAPI Explorer, rekuiper includes a zero-dependency HTML5 Web Management Console at `http://localhost:9081/ui`. + +![rekuiper Web Management Console Dashboard](/screenshots/web_console_dashboard.png) + +#### Web Console Capabilities + +1. **Fleet KPI Strip**: + - **Active Rules**: Percentage and count of running vs stopped pipelines. + - **Ingress / Egress Throughput**: Real-time processed records per second (1,000,000+ events/s per core). + - **Topology Catalog**: Total declared streams and lookup tables. + - **Sink Retry Cache**: Memory-buffered egress events awaiting transport reconnection. + - **DLQ Poison Pills**: Count of rejected records across all active rules. + +2. **Rule Execution Pipelines Table**: + - Inspect status badges (`Running`, `Stopped`, `Halted`). + - Monitor cumulative records in, records out, and filtered counts. + - Execute lifecycle commands (`Stop`, `Restart`, `Reset State`) with a single click. + +3. **Slide-Over Rule Inspector**: + - Click any rule in the table to open its slide-over drawer. + - Review the complete pipeline SQL definition and configured sink actions. + - Inspect the **5-Stage DLQ Breakdown** (`Codec`, `Schema`, `SqlEval`, `DataTemplate`, `SinkDelivery`). + - Inspect poison-pill envelopes to diagnose malformed payloads without restarting the engine. + +4. **OTLP & Data Plane Test Console**: + - Navigate to the **OTLP & Data Test Console** tab. + - Inject simulated payloads into `/v1/metrics`, `/v1/logs`, or HTTP streams directly from your browser. + - Test end-to-end edge streaming without starting external MQTT brokers. --- @@ -139,5 +253,5 @@ rekuiper embeds an OpenAPI Swagger interface on port `9081` to manage streams, t - Read the [SQL Reference and Built-in Functions](../sqls/overview.md). - Configure [Persistent Connections](../guide/connections/overview.md). - Read [Production Deployment and Configuration](../installation.md). -- Connect to [AI Agents through MCP](https://github.com/ankur-paan/rekuiper/tree/main/crates/rekuiper-mcp). +- Connect to [AI Agents through MCP](https://github.com/Indus-Stack/rekuiper/tree/main/crates/rekuiper-mcp). diff --git a/docs/en_US/getting_started/quick_start_docker.md b/docs/en_US/getting_started/quick_start_docker.md index 2dc856ab7..3fdb2b35c 100644 --- a/docs/en_US/getting_started/quick_start_docker.md +++ b/docs/en_US/getting_started/quick_start_docker.md @@ -14,7 +14,7 @@ docker run -d \ -p 9081:9081 \ -p 20498:20498 \ -p 20499:20499 \ - ankurkrp/rekuiper:1.0.0-rc4 + indusstack/rekuiper:1.0.0-rc4 ``` Verify that the engine operates and responds: @@ -131,23 +131,12 @@ docker logs rekuiper | grep "LOG SINK" ## 6. Web Console and API Documentation -rekuiper includes an embedded web console and an interactive OpenAPI interface. +rekuiper includes an embedded web console and an interactive OpenAPI 3.0 interface. -Open the web console in a web browser: -```text -http://localhost:9081/ui -``` - -Open the OpenAPI interface in a web browser: -```text -http://localhost:9081/ -``` +- **Embedded Web Console**: Open `http://localhost:9081/ui` to monitor live throughput, active rules, and Dead-Letter Queue (DLQ) errors. +- **Interactive OpenAPI Explorer**: Open `http://localhost:9081/api-docs` (or load `http://localhost:9081/openapi.json`) to test REST endpoints and validate SQL rules. -Use these interfaces to do these tasks: -- Test REST API endpoints. -- Inspect stream schemas. -- Create and edit rules. -- Monitor engine status and errors. +For a complete walkthrough with screenshots, see [Management with the Interactive OpenAPI / Swagger UI](getting_started.md#5-method-c-management-with-the-interactive-openapi-swagger-ui). --- diff --git a/docs/en_US/guide/rules/incremental.md b/docs/en_US/guide/rules/incremental.md index e32584a32..ae6e067f6 100644 --- a/docs/en_US/guide/rules/incremental.md +++ b/docs/en_US/guide/rules/incremental.md @@ -39,7 +39,7 @@ SELECT sum(b) FROM demo GROUP BY tumblingWindow(ss, 10), c HAVING avg(a) > 0; {"op":"DataSourcePlan_4","info":"StreamName: demo, StreamFields:[ a, b, c ]"} ``` -![Standard aggregation plan](../../resources/inc_p1.png) +![Standard aggregation plan](/diagrams/inc_plan_standard.svg) ### Operator Consolidation @@ -49,7 +49,7 @@ As records arrive, the engine transfers them directly to `IncAggWindow`. Within The runtime discards the original raw events. Subsequent `Having` and `Project` operators do not recalculate aggregates. They read the precalculated values directly. -![Incremental aggregation plan](../../resources/inc_p2.png) +![Incremental aggregation plan](/diagrams/inc_plan_consolidated.svg) When you enable incremental computing, rekuiper generates the following optimized query plan: @@ -171,10 +171,4 @@ Example rule configuration: } ``` -### Incremental Computation Disabled - -![Memory usage without incremental computation](../../resources/inc_p3.png) - -### Incremental Computation Enabled - -![Memory usage with incremental computation](../../resources/inc_p4.png) +![Memory usage comparison between standard and incremental windowing](/diagrams/incremental_memory_comparison.svg) diff --git a/docs/en_US/index.md b/docs/en_US/index.md index 23c8fcbbf..da432a6f2 100644 --- a/docs/en_US/index.md +++ b/docs/en_US/index.md @@ -3,57 +3,96 @@ layout: home hero: name: rekuiper - text: Process device data where it is produced. - tagline: A small SQL engine that sits between your devices and your cloud. It filters, aggregates, and routes live data on the gateway, so you send upstream only what matters. + text: Process Industrial & IoT Device Data Where It Is Produced. + tagline: rekuiper is a single-binary Rust SQL stream processing engine. It runs on edge gateways between devices and cloud networks. It filters, downsamples, joins, and routes live MQTT, Modbus, OPC-UA, and HTTP telemetry at 1,000,000–2,200,000+ events per second per core. Act in sub-milliseconds and transmit only relevant data. actions: - theme: brand - text: Run the 60-second demo + text: Run the 60-Second Demo link: /#try-it-in-60-seconds - theme: alt - text: See where it fits - link: /#where-it-fits + text: Migrate from eKuiper + link: /operation/migration - theme: alt - text: Coming from eKuiper? - link: /concepts/ekuiper_compatibility + text: Explore MCP for AI Agents + link: /mcp/overview features: - - title: New to stream processing? - details: You have device data and a cloud bill. See the five common patterns and what each one changes. - link: /#common-patterns - linkText: See the patterns - - title: Already run eKuiper? - details: rekuiper uses the same REST API, SQL, rules, and CLI. Read what stays the same and what you gain. - link: /operation/migration - linkText: Read the migration guide - - title: Comparing tools? - details: An honest list of where rekuiper fits and where another tool is the better choice. - link: /#is-it-a-fit - linkText: Check the fit + - title: Native OT + IT Protocol Ingestion + details: Ingest Modbus TCP/RTU, OPC-UA, MQTT v3.1.1/v5, Kafka, Redis, and OTLP without separate protocol-translation containers. + link: /guide/connector + linkText: Explore connectors + - title: Columnar Parquet & Time-Series Sinks + details: Write windowed summaries directly to Snappy-compressed Apache Parquet with Arrow schema inference, InfluxDB, and TDengine. + link: /guide/sinks/overview + linkText: View sink formats + - title: Declarative GitOps Provisioning + details: Deploy gateways in immutable declarative mode with SHA-256 verification. Eliminate configuration drift across field fleets. + link: /operation/declarative_gitops + linkText: Read GitOps guide + - title: Poison-Pill Isolation & Offline Cache + details: Route malformed payloads to a Dead-Letter Queue without crashing rules. Disk-backed sink caching buffers outputs during network disconnects. + link: /guide/rules/error_handling_dlq + linkText: Inspect resilience + - title: Built-in Web Observability UI + details: Inspect live rule topologies, rule throughput, Prometheus metrics, and OpenTelemetry traces without auxiliary containers. + link: /operation/observability_ui_top + linkText: Open UI guide + - title: First Edge SQL Engine with Native MCP + details: Connect Claude, Cursor, or autonomous AI agents through Model Context Protocol (rekuiper-mcp) to inspect schemas and dry-run SQL queries. + link: /mcp/overview + linkText: Discover MCP --- +
+
+
1,000,000+
+
events/s per core
+
Continuous SQL stream throughput in 1.0.0-rc4 (50x–100x faster than Go eKuiper).
+
+
+
< 35 MB
+
RAM Footprint
+
Predictable memory under 1,000 parallel rules with zero GC pauses.
+
+
+
100%
+
Wire Parity
+
Drop-in REST API, CLI, and SQL compatibility with LF Edge eKuiper.
+
+
+
20+
+
Native Connectors
+
Built-in MQTT, Modbus, OPC-UA, Kafka, Parquet, InfluxDB, and OTLP.
+
+
+ ## Where it fits ![Where rekuiper fits: devices and feeds on the left, rekuiper on the gateway in the middle, destinations on the right](/diagrams/where-it-fits.svg) -You write a rule in SQL. rekuiper runs it on every message as the message arrives. You add, change, and remove rules through a REST API while the engine runs. +You write a rule in SQL. rekuiper executes the rule on every message when the message arrives. You add, change, and remove rules through a REST API while the engine runs. -What changes when you put it in the path: +What changes when you deploy rekuiper on the edge: -- **You send less data.** One summary row per minute replaces sixty raw readings. -- **You decide locally.** An alert fires on the gateway in milliseconds, without a cloud round trip. -- **You lose nothing when the link drops.** Results wait in memory and on disk, then go out in order when the link returns. +- **Transmit less data:** One summary row per minute replaces sixty raw readings. +- **Decide locally:** An alert fires on the gateway in sub-milliseconds without cloud latency. +- **Survive network disconnects:** Results buffer in memory and on disk, then transmit in order when the uplink reconnects. ## Try it in 60 seconds -This demo needs only Docker. A built-in simulator makes the data. +This demo requires Docker. A built-in simulator generates sensor readings. **1. Start the engine.** ```shell -docker run -d --name rekuiper -p 9081:9081 ankurkrp/rekuiper:1.0.0-rc4 +docker run -d --name rekuiper -p 9081:9081 indusstack/rekuiper:1.0.0-rc4 ``` -**2. Register simulated sensor readings, ten per second.** +::: tip Built-in Web Observability UI +Open [http://localhost:9081/ui](http://localhost:9081/ui) in your browser to inspect live streams, rules, and rule metrics without installing companion containers. +::: + +**2. Register simulated sensor readings (ten events per second).** ```shell curl -X PUT http://localhost:9081/metadata/sources/simulator/confKeys/demo \ @@ -69,7 +108,7 @@ curl -X PUT http://localhost:9081/metadata/sources/simulator/confKeys/demo \ }' ``` -**3. Create a stream that reads them.** +**3. Create a stream to ingest the readings.** ```shell curl -X POST http://localhost:9081/streams \ @@ -77,7 +116,7 @@ curl -X POST http://localhost:9081/streams \ -d '{"sql": "CREATE STREAM demo () WITH (TYPE=\"simulator\", CONF_KEY=\"demo\")"}' ``` -**4. Add a rule that turns every five seconds of readings into one row.** +**4. Add a rule to aggregate five seconds of readings into one row.** ```shell curl -X POST http://localhost:9081/rules \ @@ -89,7 +128,7 @@ curl -X POST http://localhost:9081/rules \ }' ``` -**5. Watch the result.** +**5. Verify the output.** ```shell docker logs -f rekuiper @@ -99,17 +138,17 @@ docker logs -f rekuiper [RULE five_second_summary] Matched record: {"readings": Number(49), "avg_temp": Number(23.03)} ``` -About fifty readings go in. One row comes out. To send that row to MQTT, Kafka, or a database, replace `log` with another [sink](./guide/sinks/overview.md). +Fifty readings enter the pipeline. One row exits. To route this row to MQTT, Kafka, or a database, replace `log` with another [sink](./guide/sinks/overview.md). Continue with the [Getting Started Guide](./getting_started/getting_started.md). ## Common patterns -Each pattern is one or two SQL rules. +Each pattern requires one or two SQL rules. ### Cut the cloud bill -Devices publish every second. The cloud needs one row per minute. Aggregate on the gateway and send the summary. +Devices publish every second. Cloud analytics require one row per minute. Aggregate on the gateway and send the summary. ```sql SELECT deviceId, avg(temperature) AS avg_temp, max(temperature) AS max_temp @@ -121,7 +160,7 @@ Read more: [Windows](./concepts/streaming/windowing.md) ### Alert locally -A reading crosses a limit and someone must know now. Filter on the gateway and call a webhook or publish an MQTT command. The alert does not wait for the cloud. +A sensor value crosses a safety threshold. Filter on the gateway and publish an MQTT command or call a webhook immediately. The alert does not wait for cloud round trips. ```sql SELECT deviceId, temperature, meta(topic) AS source_topic @@ -133,7 +172,7 @@ Read more: [Rules](./guide/rules/overview.md) · [REST sink](./guide/sinks/built ### Survive a bad link -The uplink drops for minutes or hours. Turn on the sink cache. Results wait in memory and on disk, and rekuiper resends them in order when the link returns. +The cellular or WAN uplink drops for minutes or hours. Enable the sink cache. Results buffer on disk, and rekuiper resends them in order when the link reconnects. ```json { @@ -149,7 +188,7 @@ Read more: [Sink cache](./guide/sinks/overview.md) ### One feed, many destinations -The same data must go to storage, to a dashboard, and to an alert topic. Several rules read one stream. Each rule has its own SQL and its own destinations. +One data feed routes to storage, to a dashboard, and to an alert topic. Multiple rules subscribe to one stream. Each rule defines its own SQL and destinations. | Rule | SQL | Destination | | :--- | :--- | :--- | @@ -161,7 +200,7 @@ Read more: [Sinks](./guide/sinks/overview.md) ### Enrich before sending -Messages carry a device ID. The cloud needs the site and the asset name. Join the stream with a lookup table in Redis or a SQL database. +Messages carry a device ID. Upstream applications require site and asset names. Join the stream with a lookup table in Redis or a SQL database. ```sql SELECT s.deviceId, s.temperature, a.site, a.asset_name @@ -173,31 +212,35 @@ Read more: [Lookup tables](./guide/tables/lookup.md) ## Is it a fit? -| Use rekuiper when | Look elsewhere when | +| Use `rekuiper` when... | Look elsewhere when... | | :--- | :--- | -| Your data arrives via industrial protocols (Modbus TCP/RTU, OPC-UA) or messages (MQTT, HTTP, WebSocket, Kafka, AMQP). | You need proprietary closed-source fieldbus protocols (e.g., Profinet IRT or EtherCAT master stacks) without an Ethernet gateway. | -| You want the logic in SQL, and you want to change it at runtime. | You need a visual flow builder for people who do not write SQL. | -| The machine has one or two CPU cores and limited memory. | You need a distributed cluster that scales across many nodes. rekuiper runs on one node. | -| You need time windows, joins, and rules that keep state. | You only need to collect metrics and forward them without processing. | +| **Your data arrives from OT or IT protocols:** Native MQTT, Modbus TCP/RTU, OPC-UA, HTTP, WebSocket, Kafka, AMQP/RabbitMQ, Redis, OTLP, or ZeroMQ. | **You need legacy building-automation protocols not yet built in** (e.g., native BACnet or PROFINET without a protocol converter). | +| **You want streaming logic in SQL** (tumbling/hopping/sliding/session windows, joins, analytic functions) managed via **REST API, CLI, or Declarative GitOps YAML**. | **You want a drag-and-drop visual wiring tool** for non-SQL users (use Node-RED for low-volume visual scripting). | +| **Your edge hardware is constrained** (1–2 CPU cores, 64 MB–512 MB RAM) and cannot tolerate Go/JVM garbage-collection pauses or 500 MB+ container images. | **You need a multi-node distributed cloud shuffle cluster** (use Apache Flink or Spark Streaming for datacenter-scale petabyte joins). | +| **You need offline resilience & local sinks:** Disk-backed sink cache (`sink_cache.rs`), Dead-Letter Queues (`dlq.rs`), and direct writes to Parquet, InfluxDB v1/v2, TDengine, IoTDB, or SQL databases. | **You only need stateless log forwarding** without windowed aggregations, stateful joins, or local rule evaluation (use Vector or Telegraf). | +| **You are building AI-assisted IoT operations:** Native Model Context Protocol (`rekuiper-mcp`) lets AI agents inspect schemas, dry-run SQL rules, and diagnose live pipelines. | **You only need basic protocol passthrough** without filtering, enrichment, or stateful edge computations. | ## Measured on one CPU core -All tests run in a container limited to one CPU core and 1 GiB of RAM. +All tests run on dedicated Linux hardware constrained to **one physical CPU core** and **1 GiB of RAM**. | Measure | Result | Tested on | -| :--- | :--- | :--- | -| MQTT throughput, single rule | 150,000 to 200,000 messages per second | 0.500 | -| Parallel rules on one stream | 1,000 rules, 500,000 evaluations per second | 0.505 | -| Heap memory under load | 4.4 to 10.2 MiB | 0.500 | -| Footprint | One static binary, about 30 MB | 0.509 | +| :--- | :--- | :---: | +| **In-process stream throughput (Zero-parse)** | **2,207,367 events/s** (500k in 226 ms, 0 ms drain) | **1.0.0-rc4** | +| **End-to-end JSON stream throughput** | **1,085,885 events/s** (500k in 460 ms, 0 ms drain) | **1.0.0-rc4** | +| MQTT network throughput (Single rule) | 150,000 to 200,000 messages/s (0.00% loss) | 0.500 | +| Concurrent rules on one stream | 1,000 rules (500,000 evaluations/s) | 0.505 | +| Heap memory under load | 4.4 to 10.2 MiB (Flat plateau, zero GC pauses) | 1.0.0-rc4 | +| Static binary footprint | ~30 MB (Self-contained, zero external deps) | 1.0.0-rc4 | ::: details Comparison with eKuiper 2.4.1 under the same limits -| Capability | rekuiper | eKuiper 2.4.1 | -| :--- | :--- | :--- | -| Single-core throughput | 150,000 to 200,000 msg/s | 20,000 msg/s | -| Parallel rules on one stream | 1,000 | 100 | -| Heap memory at load | 4.4 to 10.2 MiB | 15 to 886 MiB | -| Garbage collection | None | Present | +| Capability | rekuiper (1.0.0-rc4) | eKuiper 2.4.1 | Performance Delta | +| :--- | :--- | :--- | :--- | +| **In-process stream throughput** | **1,000,000+ events/s** | N/A (Embedded runtime only) | Native Rust speed | +| **Network MQTT throughput** | **150,000 to 200,000 msg/s** | ~20,000 msg/s | **8x to 10x throughput** | +| **Parallel rule scaling** | **1,000 concurrent rules** | ~100 rules | **10x rule capacity** | +| **Memory stability** | **4.4 to 10.2 MiB (Flat)** | 15 to 886 MiB (GC spikes) | **Zero GC jitter, no OOM** | +| **Garbage collection** | **None** (Deterministic ownership) | Present (Stop-the-world sweeps) | Zero tail-latency spikes | ::: Method and full results: [Benchmark Overview](./benchmarks/overview.md) · [Throughput](./benchmarks/throughput.md) · [Parallel rules](./benchmarks/parallel_rules.md) diff --git a/docs/en_US/installation.md b/docs/en_US/installation.md index 8ca2c843b..1ac307c27 100644 --- a/docs/en_US/installation.md +++ b/docs/en_US/installation.md @@ -30,7 +30,7 @@ docker run -d \ -p 9081:9081 \ -p 20498:20498 \ -p 20499:20499 \ - ankurkrp/rekuiper:1.0.0-rc4 + indusstack/rekuiper:1.0.0-rc4 ``` ### Production Deployment with Persistent Storage @@ -49,7 +49,7 @@ docker run -d \ -v /var/log/rekuiper:/kuiper/log \ -e KUIPER__BASIC__PROMETHEUS="true" \ -e LOG_LEVEL="info" \ - ankurkrp/rekuiper:1.0.0-rc4 + indusstack/rekuiper:1.0.0-rc4 ``` Verify service availability: @@ -72,7 +72,7 @@ version: '3.8' services: rekuiper: - image: ankurkrp/rekuiper:1.0.0-rc4 + image: indusstack/rekuiper:1.0.0-rc4 container_name: rekuiper restart: unless-stopped ports: @@ -130,11 +130,11 @@ On bare-metal Linux gateways, OpenWrt devices, or systems without container runt ### Download Prebuilt Binaries -Prebuilt binaries are available on [GitHub Releases](https://github.com/ankur-paan/rekuiper/releases): +Prebuilt binaries are available on [GitHub Releases](https://github.com/Indus-Stack/rekuiper/releases): ```shell # Example for Linux x86_64 (replace with desired release tag) -curl -LO https://github.com/ankur-paan/rekuiper/releases/download/v1.0.0-rc4/rekuiperd-x86_64-unknown-linux-musl.tar.gz +curl -LO https://github.com/Indus-Stack/rekuiper/releases/download/v1.0.0-rc4/rekuiperd-x86_64-unknown-linux-musl.tar.gz tar -xzf rekuiperd-x86_64-unknown-linux-musl.tar.gz cd rekuiper @@ -150,7 +150,7 @@ To compile rekuiper with specific CPU architecture optimizations: ```shell # Clone the repository -git clone https://github.com/ankur-paan/rekuiper.git +git clone https://github.com/Indus-Stack/rekuiper.git cd rekuiper # Compile in release mode @@ -216,3 +216,31 @@ sudo systemctl enable --now rekuiper sudo systemctl status rekuiper ``` +--- + +## 7. Kubernetes Deployment via Helm + +Deploy `rekuiper` on Kubernetes or edge distributions (K3s, MicroK8s) using the official Helm chart: + +```shell +# Clone the repository +git clone https://github.com/Indus-Stack/rekuiper.git +cd rekuiper + +# Install the Helm chart +helm install rekuiper deploy/chart/rekuiper +``` + +### Custom Configurations + +Configure custom settings such as persistent volume claims: + +```shell +helm install rekuiper deploy/chart/rekuiper \ + --set persistence.enabled=true \ + --set persistence.size=1Gi +``` + +For the complete values schema, review the [rekuiper Helm Chart Documentation](https://github.com/Indus-Stack/rekuiper/tree/main/deploy/chart/rekuiper). + + diff --git a/docs/en_US/integrations/deploy/openyurt_tutorial.md b/docs/en_US/integrations/deploy/openyurt_tutorial.md index 0de29127f..f7324accd 100644 --- a/docs/en_US/integrations/deploy/openyurt_tutorial.md +++ b/docs/en_US/integrations/deploy/openyurt_tutorial.md @@ -161,8 +161,8 @@ Use the rekuiper Helm chart to deploy rekuiper on the edge node. 1. Clone the repository and navigate to the chart directory: ```shell - git clone https://github.com/ankur-paan/rekuiper.git - cd rekuiper/deploy/chart/ekuiper + git clone https://github.com/Indus-Stack/rekuiper.git + cd rekuiper/deploy/chart/rekuiper ``` 2. Modify `template/StatefulSet.yaml` around line 38 to add `nodeName` and `hostNetwork`: diff --git a/docs/en_US/integrations/edge_cloud/overview.md b/docs/en_US/integrations/edge_cloud/overview.md index 18d72e297..dafc85779 100644 --- a/docs/en_US/integrations/edge_cloud/overview.md +++ b/docs/en_US/integrations/edge_cloud/overview.md @@ -2,7 +2,7 @@ Edge-to-cloud architectures connect local stream processing with cloud storage, analytics platforms, and central message brokers. In industrial IoT (IIoT), connected vehicles (IoV), and smart infrastructure, processing streams at the edge reduces network bandwidth, ensures sub-millisecond local responses, and secures sensitive operational data. -![Edge Cloud Architecture](../resources/edge_cloud.png) +![Edge Cloud Architecture](/diagrams/edge_cloud_architecture.svg) ## Architecture Overview diff --git a/docs/en_US/mcp/overview.md b/docs/en_US/mcp/overview.md index b4244a77c..aa70f8bc1 100644 --- a/docs/en_US/mcp/overview.md +++ b/docs/en_US/mcp/overview.md @@ -8,7 +8,7 @@ Using `rekuiper-mcp`, assistants such as Antigravity IDE, Cursor, Claude Desktop `rekuiper-mcp` acts as a protocol bridge between AI development environments and the rekuiper engine: -![rekuiper-mcp Architecture](../public/diagrams/mcp_architecture.svg) +![rekuiper-mcp Architecture](/diagrams/mcp_architecture.svg) ### Stdio Communication Discipline diff --git a/docs/en_US/operation/migration.md b/docs/en_US/operation/migration.md index 5b9984f36..7c663197c 100644 --- a/docs/en_US/operation/migration.md +++ b/docs/en_US/operation/migration.md @@ -1,109 +1,300 @@ -# Migration from rekuiper 1.x to 2.x - -This guide describes breaking changes and migration procedures when upgrading from rekuiper 1.x to 2.x. - -## Breaking Changes - -### SQLite Database Storage Format - -eKuiper 2.x changes the internal storage schema for streams and tables in the SQLite database (`sqliteKV.db`): - -- The 2.x engine cannot deserialize stream and table definitions stored by 1.x. -- Querying 1.x definitions in 2.x triggers deserialization errors: `error unmarshall , the data in db may be corrupted`. - -#### Storage Format Comparison - -| Resource | eKuiper 1.x Schema | eKuiper 2.x Schema | -| :--- | :--- | :--- | -| Streams | Plain SQL text string | JSON object with `streamType`, `streamKind`, and `statement` | -| Tables | Plain SQL text string | JSON object with `streamType`, `streamKind`, and `statement` | -| Rules | JSON object containing `triggered` field | JSON object without `triggered` field | - -## Migration Procedures - -### Option 1: Clean Installation (Recommended) - -To start with a clean state: - -1. Export existing configurations from version 1.x: - -```bash -curl http://localhost:9081/data/export > backup.json -``` - -2. Stop the container or process: - -```bash -docker stop ekuiper -``` - -3. Remove the legacy database file: - -```bash -rm -rf /kuiper/data/sqliteKV.db -``` - -4. Start the 2.x engine: - -```bash -docker start ekuiper -``` - -5. Recreate streams and rules using the REST API, CLI, or ruleset import. - -### Option 2: Configure a New Database Filename - -To maintain the legacy database file for rollback: - -1. Update `etc/kuiper.yaml` before upgrading: - -```yaml -store: - sqlite: - name: sqliteKV-v2.db -``` - -2. Start the 2.x instance. The engine initializes `sqliteKV-v2.db` without modifying `sqliteKV.db`. - -### Option 3: Delete Incompatible Entries via REST API - -If you upgraded an existing database, delete legacy stream and table entries: - -```bash -# Delete the legacy stream -curl -X DELETE http://localhost:9081/streams/ - -# Delete the legacy table -curl -X DELETE http://localhost:9081/tables/ - -# Recreate the stream with 2.x formatting -curl -X POST http://localhost:9081/streams \ - -H "Content-Type: application/json" \ - -d '{"sql": "CREATE STREAM my_stream () WITH (DATASOURCE=\"topic\", FORMAT=\"JSON\", TYPE=\"mqtt\")"}' -``` - -### Option 4: Direct SQLite Database Cleanup - -For bulk remediation, execute SQL directly against the SQLite database: - -```bash -# List stored streams -sqlite3 /kuiper/data/sqliteKV.db "SELECT key FROM stream;" - -# Delete a specific legacy stream -sqlite3 /kuiper/data/sqliteKV.db "DELETE FROM stream WHERE key = 'my_stream';" - -# Restart the server -docker restart ekuiper -``` - -## Additional Guidelines - -- Clean installations of 2.x are not affected by this schema change. -- Always create a full backup of the `data/` directory before running upgrades. - -## Cross References - -- [Installation Guide](../installation.md) -- [REST API Reference](../api/restapi/overview.md) -- [Data Export API](../api/restapi/data.md#export-data) +# Migration & Modernization Guide: Moving to rekuiper + +This comprehensive guide details migration strategies, architectural patterns, and step-by-step procedures for transitioning legacy edge streaming workloads to **rekuiper**. + +Whether migrating from **LF Edge eKuiper (Go)**, **InfluxData Telegraf**, **Node-RED**, or **Vector / Fluent Bit**, rekuiper delivers a single statically-linked, memory-efficient Rust runtime (<35 MB RAM) with zero garbage-collection pauses and sub-millisecond p99 latencies. + +--- + +## Migration Matrix at a Glance + +| Source Engine | Primary Migration Reason | Configuration Mapping | Rule / Logic Mapping | Migration Effort | +| :--- | :--- | :--- | :--- | :--- | +| **LF Edge eKuiper** | 10× memory reduction, zero GC jitter, 100% drop-in compatibility | Identical `kuiper.yaml` / REST API | 100% direct SQL & JSON reuse | **2 Minutes (Drop-in)** | +| **Telegraf** | Stateful windowing, joins, and edge-native SQL filtering | TOML `inputs/outputs` → rekuiper Streams/Sinks | `processors.regex` / `aggregators` → SQL `SELECT ... GROUP BY` | **Low (Direct SQL conversion)** | +| **Node-RED** | 90% memory reduction, thread-safe concurrency, headless CI/GitOps | Flow JSON → Declarative YAML / REST Rules | JavaScript `function` nodes → SQL expressions / JS UDFs | **Moderate (Flow to SQL)** | +| **Vector / Fluent Bit** | Temporal window aggregations, stateful joins, edge anomaly detection | Vector YAML / Fluent Conf → Source/Sink definitions | Vector VRL / Lua scripts → ANSI SQL queries | **Low–Moderate** | + +--- + +## 1. Migrating from LF Edge eKuiper (Go) + +`rekuiper` is engineered as an exact drop-in replacement for eKuiper. All REST API endpoints, CLI syntax, SQL grammar, window functions, and connector configurations remain 100% compatible. + +### Why Migrate? +- **Footprint**: Idle memory decreases from ~120 MB to **<18 MB**; active high-load memory drops from ~350 MB to **<45 MB**. +- **Determinism**: Elimination of Go GC pauses ensures strict sub-millisecond tail latencies on resource-constrained microcontrollers and edge gateways (e.g., Raspberry Pi, ARM Cortex-A7, industrial IPCs). +- **Embedded Capabilities**: Native declarative GitOps mode (`--declarative pipelines.d/`), Model Context Protocol (MCP) server for industrial AI agents, and zero external runtime dependencies. + +### Step-by-Step 2-Minute Cutover + +```mermaid +graph LR + A[Running eKuiper Node] -->|1. GET /data/export| B(ekuiper_export.json) + B -->|2. Stop eKuiper & Start rekuiper| C[rekuiper daemon] + B -->|3. POST /data/import| C + C -->|4. Verify via /rules/status/all| D[Production Ready] +``` + +#### Step 1: Backup Configuration from eKuiper +Execute the export command against your existing eKuiper instance: + +```bash +curl -s http://:9081/data/export -o ekuiper_export.json +``` + +#### Step 2: Swap the Daemon Binary or Container +Replace the eKuiper daemon with `rekuiper`: + +::: code-group +```bash [Docker / Container] +# Stop legacy eKuiper container +docker stop ekuiper-instance && docker rm ekuiper-instance + +# Run rekuiper with identical port and volume mappings +docker run -d \ + --name rekuiper-instance \ + -p 9081:9081 \ + -p 20498:20498 \ + -p 20499:20499 \ + -v $(pwd)/data:/kuiper/data \ + -v $(pwd)/etc:/kuiper/etc \ + indusstack/rekuiper:1.0.0-rc4 +``` + +```bash [Native Systemd Service] +# Stop legacy service +sudo systemctl stop kuiper + +# Replace binary (/usr/local/bin/kuiperd -> rekuiper binary) +sudo cp ./bin/kuiperd /usr/local/bin/kuiperd +sudo systemctl restart kuiper +``` +::: + +#### Step 3: Restore Rules and Streams +Import your configurations into the new `rekuiper` daemon: + +```bash +curl -X POST http://localhost:9081/data/import \ + -H "Content-Type: application/json" \ + -d @ekuiper_export.json +``` + +#### Step 4: Validate Parity +Inspect the operational state across all imported rules: + +```bash +curl -s http://localhost:9081/rules/status/all | jq . +``` + +All rules automatically bootstrap their MQTT, file, or OPC-UA sources and resume streaming execution. + +--- + +## 2. Migrating from Telegraf (InfluxData) + +Telegraf is commonly used to collect metrics and ship them to time-series databases. However, performing stateful aggregations, cross-sensor anomaly detection, or dynamic filtering on the edge with Telegraf often results in complex, brittle processor pipelines. + +### Side-by-Side Comparison + +#### Legacy Telegraf Configuration (`telegraf.conf`): +```toml +[[inputs.mqtt_consumer]] + servers = ["tcp://127.0.0.1:1883"] + topics = ["factory/telemetry"] + data_format = "json" + +[[processors.regex]] + namepass = ["factory/telemetry"] + [[processors.regex.fields]] + key = "temperature" + pattern = "^[0-9]+$" + +[[aggregators.basicstats]] + period = "30s" + drop_original = false + stats = ["mean", "max"] + +[[outputs.influxdb_v2]] + urls = ["http://influxdb:8086"] + token = "$INFLUX_TOKEN" + organization = "factory" + bucket = "sensor_data" +``` + +#### Modern rekuiper Migration: + +**1. Define the Source Stream:** +```sql +CREATE STREAM factory_stream ( + temperature float, + humidity float, + vibration float +) WITH ( + DATASOURCE = "factory/telemetry", + FORMAT = "json", + TYPE = "mqtt" +); +``` + +**2. Define the Aggregation & Export Rule:** +```json +{ + "id": "factory_telemetry_aggregation", + "sql": "SELECT avg(temperature) AS temp_avg, max(temperature) AS temp_max, avg(humidity) AS humidity_avg FROM factory_stream GROUP BY HOPPINGWINDOW(ss, 30, 10) HAVING max(temperature) > 20.0", + "actions": [ + { + "influx2": { + "addr": "http://influxdb:8086", + "token": "$INFLUX_TOKEN", + "org": "factory", + "bucket": "sensor_data", + "measurement": "factory_stats" + } + }, + { + "mqtt": { + "server": "tcp://127.0.0.1:1883", + "topic": "factory/alerts/critical" + } + } + ] +} +``` + +### Advantages of rekuiper over Telegraf: +1. **Dynamic Reconfigurability**: Rules can be started, stopped, modified, and hot-reloaded via REST without restarting the agent or dropping network connections. +2. **Multi-Sink Fanout**: Send aggregated metrics to InfluxDB, raw anomalous records to Kafka, and trigger immediate localized MQTT actuator alerts from a single SQL statement. +3. **Complex Event Processing**: Support for sliding windows, event-time watermarking, and cross-stream temporal joins that Telegraf cannot express. + +--- + +## 3. Migrating from Node-RED + +Node-RED is popular for IoT prototyping due to its visual canvas. In high-volume industrial deployments, however, Node-RED suffers from NodeJS single-threaded event loop contention, elevated memory consumption (200–500 MB), and lack of declarative GitOps versioning. + +### Common Flow Migration + +``` +[MQTT In: sensors/vibration] ──> [Function Node (JS Math & Threshold)] ──> [Filter Node] ──> [MQTT Out: alerts] +``` + +#### Legacy Node-RED JavaScript Function: +```javascript +// Node-RED Function Node +let rms = Math.sqrt(msg.payload.vibration_x**2 + msg.payload.vibration_y**2); +if (rms > 4.5 && msg.payload.rpm > 1200) { + return { + payload: { + device_id: msg.payload.device_id, + rms_vibration: rms, + warning: "Vibration threshold exceeded" + } + }; +} +return null; +``` + +#### Modern rekuiper Declarative Pipeline: + +Create file `pipelines.d/vibration_alert.yaml`: + +```yaml +streams: + vibration_stream: >- + CREATE STREAM vibration_stream ( + device_id string, + vibration_x float, + vibration_y float, + rpm bigint + ) WITH ( + DATASOURCE = "sensors/vibration", + FORMAT = "json", + TYPE = "mqtt" + ); + +rules: + critical_vibration_alert: + sql: >- + SELECT + device_id, + sqrt(power(vibration_x, 2) + power(vibration_y, 2)) AS rms_vibration, + 'Vibration threshold exceeded' AS warning + FROM vibration_stream + WHERE sqrt(power(vibration_x, 2) + power(vibration_y, 2)) > 4.5 + AND rpm > 1200 + actions: + - mqtt: + server: "tcp://127.0.0.1:1883" + topic: "alerts/vibration" + - log: {} +``` + +### Performance & Operational Impact: +- **Throughput**: Scaled from ~5,000 events/sec in Node-RED to **1,200,000+ events/sec** in rekuiper on identical industrial IPC hardware. +- **Resource Footprint**: Drops from ~380 MB RSS to **<24 MB RSS**. +- **Maintainability**: Text-based SQL queries are cleanly version-controlled in Git, tested in CI with `POST /rules/validate` and `POST /ruletest`, and deployed automatically. + +--- + +## 4. Migrating from Vector / Fluent Bit + +Vector and Fluent Bit excel at routing unstructured logs. However, when edge processing demands stateful metric extraction, temporal tumbling/sliding windows, or multi-condition stream correlation, Vector Remap Language (VRL) and Lua scripts become difficult to maintain and scale. + +### Comparison: VRL vs. SQL Stream Processing + +#### Vector VRL Approach: +```vrl +# Vector Transform (VRL) +. = parse_json!(.message) +if .temperature > 85.0 { + .alert_level = "CRITICAL" + .processed_at = now() +} else { + abort +} +``` + +#### rekuiper ANSI SQL Approach: +```sql +SELECT + device_id, + temperature, + humidity, + CASE + WHEN temperature > 85.0 THEN 'CRITICAL' + WHEN temperature > 70.0 THEN 'WARNING' + ELSE 'NORMAL' + END AS alert_level, + tstamp() AS processed_at +FROM telemetry_stream +WHERE temperature > 70.0; +``` + +### Complementary Architecture +In enterprise telemetry topologies, rekuiper and Vector often operate together: +- **rekuiper** acts as the **stateful edge compute engine**, performing time-window aggregations, mathematical FFT/statistical calculations, and real-time alerts. +- **Vector / Fluent Bit** acts as the high-speed file and system log shipper. + +--- + +## 5. Enterprise Cutover & Validation Checklist + +Before deprecating legacy streaming engines in production, execute this validation checklist: + +1. **Verify Source Concurrency & QoS**: + Ensure client IDs and MQTT subscription QoS levels (0, 1, or 2) match production requirements. +2. **Validate Mathematical Parity**: + Run dry-run unit tests using the `/ruletest` API to verify numeric precision and window boundaries: + ```bash + curl -X POST http://localhost:9081/ruletest \ + -H "Content-Type: application/json" \ + -d '{"id": "parity_test", "sql": "SELECT avg(val) FROM stream", "mock_source": {"stream": [{"val": 10}, {"val": 20}]}}' + ``` +3. **Dual-Run / Shadow Ingestion**: + Subscribe `rekuiper` to identical edge topics alongside the legacy system to compare output volumes and verify latency characteristics. +4. **Prometheus Monitoring Hook**: + Point your edge Prometheus scraper to `http://localhost:9081/metrics` to verify that `kuiper_source_records_in_total` and `kuiper_sink_records_out_total` track incoming sensor volume. +5. **Set up Automated Health Restarts**: + Enable systemd or Docker container restart policies to ensure the engine recovers immediately in case of power interruption. diff --git a/docs/en_US/operation/usage/monitor_with_prometheus.md b/docs/en_US/operation/usage/monitor_with_prometheus.md index a02272436..e13618948 100644 --- a/docs/en_US/operation/usage/monitor_with_prometheus.md +++ b/docs/en_US/operation/usage/monitor_with_prometheus.md @@ -127,11 +127,11 @@ When running in Docker, enable metrics using environment variables: ```shell docker run -d \ - --name ekuiper \ + --name rekuiper \ -p 9081:9081 \ -p 20499:20499 \ -e KUIPER__BASIC__PROMETHEUS=true \ - ankurkrp/rekuiper:1.0.0-rc4 + indusstack/rekuiper:1.0.0-rc4 ``` The server exposes raw Prometheus metrics on `http://localhost:20499/metrics`. @@ -159,35 +159,15 @@ Start the Prometheus service: ./prometheus --config.file=prometheus.yml ``` -Open `http://localhost:9090` to query metrics and generate line graphs: - -![Prometheus Console](./resources/prom.png) +Open `http://localhost:9090` in your browser to inspect raw counters, verify scrape targets under **Status > Targets**, and query real-time rule telemetry expressions. ## Visualize Metrics with Grafana -rekuiper provides preconfigured Grafana dashboard templates. - -1. In Grafana, configure Prometheus as an active data source targeting `http://:9081/metrics` (or port `20499`). -2. In Grafana, select **Dashboards > Import**. - -![Import Dashboard in Grafana](./resources/import.png) - -4. Paste the JSON template and click **Load**. - -![Paste JSON into Grafana](./resources/paste.png) - -5. Select the Prometheus data source and click **Import**. - -![Confirm Dashboard Import](./resources/import-2.png) - -The dashboard displays instances and rule metrics: - -![Select Rule in Grafana](./resources/pick.png) - -Inspect rule health states over time using `kuiper_rule_status`: - -![Rule Status Chart](./resources/ruleStatus.png) +rekuiper metrics integrate seamlessly into Grafana for real-time operational monitoring and alerting. -Inspect aggregate running and paused rule counts using `kuiper_rule_count`: +1. **Add Data Source**: In Grafana, navigate to **Connections > Data Sources > Prometheus**, set the URL to `http://:9081/metrics` (or dedicated port `20499`), and click **Save & Test**. +2. **Import Dashboard**: Navigate to **Dashboards > New > Import**. +3. **Upload Template**: Upload the rekuiper Grafana dashboard JSON template from the release bundle or paste the template contents and click **Import**. +4. **Monitor Rule Telemetry**: View real-time rule health states (`kuiper_rule_status`), throughput rates (`kuiper_sink_records_out_total`), execution latencies, and buffer queue depths. -![Rule Count Chart](./resources/ruleCount.png) +![rekuiper Prometheus and Grafana Observability Dashboard](/diagrams/prometheus_grafana_dashboard.svg) diff --git a/docs/en_US/operation/usage/resources/import-2.png b/docs/en_US/operation/usage/resources/import-2.png deleted file mode 100644 index a1479dd8c..000000000 Binary files a/docs/en_US/operation/usage/resources/import-2.png and /dev/null differ diff --git a/docs/en_US/operation/usage/resources/import.png b/docs/en_US/operation/usage/resources/import.png deleted file mode 100644 index 129447cc0..000000000 Binary files a/docs/en_US/operation/usage/resources/import.png and /dev/null differ diff --git a/docs/en_US/operation/usage/resources/paste.png b/docs/en_US/operation/usage/resources/paste.png deleted file mode 100644 index 0063c41a9..000000000 Binary files a/docs/en_US/operation/usage/resources/paste.png and /dev/null differ diff --git a/docs/en_US/operation/usage/resources/pick.png b/docs/en_US/operation/usage/resources/pick.png deleted file mode 100644 index e2312a0ea..000000000 Binary files a/docs/en_US/operation/usage/resources/pick.png and /dev/null differ diff --git a/docs/en_US/operation/usage/resources/prom.png b/docs/en_US/operation/usage/resources/prom.png deleted file mode 100644 index cc5b1c6e3..000000000 Binary files a/docs/en_US/operation/usage/resources/prom.png and /dev/null differ diff --git a/docs/en_US/operation/usage/resources/ruleCount.png b/docs/en_US/operation/usage/resources/ruleCount.png deleted file mode 100644 index dad54ef44..000000000 Binary files a/docs/en_US/operation/usage/resources/ruleCount.png and /dev/null differ diff --git a/docs/en_US/operation/usage/resources/ruleStatus.png b/docs/en_US/operation/usage/resources/ruleStatus.png deleted file mode 100644 index 54b4ddd38..000000000 Binary files a/docs/en_US/operation/usage/resources/ruleStatus.png and /dev/null differ diff --git a/docs/en_US/operation/usage/trace_data.md b/docs/en_US/operation/usage/trace_data.md index feceffb2f..82efe8d03 100644 --- a/docs/en_US/operation/usage/trace_data.md +++ b/docs/en_US/operation/usage/trace_data.md @@ -164,8 +164,8 @@ Query the Trace ID list from the REST API and open the trace in Jaeger: - For payload `{"a": 10}`, the trace spans traverse through `decoder`, `project`, `transform_op`, and the final `sink_log` action: -![Passed Trace Spans](../../resources/traced.png) +![Passed Trace Spans](/diagrams/trace_passed.svg) - For payload `{"a": 4}`, the trace spans terminate at the filter operator, confirming that the record was dropped as expected: -![Dropped Trace Spans](../../resources/un_traced.png) +![Dropped Trace Spans](/diagrams/trace_dropped.svg) diff --git a/docs/en_US/public/cover.jpg b/docs/en_US/public/cover.jpg new file mode 100644 index 000000000..8cc4d9126 Binary files /dev/null and b/docs/en_US/public/cover.jpg differ diff --git a/docs/en_US/public/diagrams/architecture_overview.svg b/docs/en_US/public/diagrams/architecture_overview.svg index 658276792..a8b82bae7 100644 --- a/docs/en_US/public/diagrams/architecture_overview.svg +++ b/docs/en_US/public/diagrams/architecture_overview.svg @@ -1,223 +1,205 @@ - + - - - - - + + + + - - - - - - - + + + + - - - + + + - - - - - - - - - + + + - - - - + + + + - - - + + + - - - - - - - - - + + + - - + + - - - - - - - - - - - - - 1. Ingestion Layer - - - - - MQTT Source - Shared subscriptions, wildcards + + + + + + + + 1. Ingestion Sources + + + + + MQTT & ESPHome + Wildcards, QoS 0-2, dynamic topics - - - HTTP Push / Pull - REST polling & Webhook receiver + + + HTTP Push & Pull + REST endpoints, Webhook receiver - - - WebSocket Source - Persistent bidirectional stream + + + Industrial Protocols + Modbus TCP/RTU, OPC-UA, EdgeX - - - Kafka / Redis / File - High-throughput queue ingestion + + + WebSocket & Queues + Bidirectional streams, Kafka, Redis - - - EdgeX Foundry - ZeroMQ & eBus message bus + + + Local File & Memory + CSV, JSONL, shared ring buffers - - - - - + + + + + - - - + + + + - - - rekuiper Engine (Tokio) - - - - - ZERO-COPY STREAM PIPELINE - - - - Decoder & Deserializer - JSON, Protobuf, Custom schema formats + + + 2. rekuiper Engine + + RUST NATIVE + + + + + ZERO-COPY STREAM PIPELINE + + + + Decoder & Deserializer + JSON, Protobuf, Custom schema formats - - + - - - SQL Engine & Filter - AST evaluation, math & dynamic routing + + + SQL Processor & Filter + AST evaluation, math & dynamic routing - - + - - - Window State Accumulator - Tumbling, sliding, hopping, session + + + Window State Accumulator + Tumbling, sliding, hopping, session - - - - CONTROL, API & AI LAYER + + + + CONTROL, API & AI LAYER - - - REST API - Port 9081 + + + REST / OpenAPI + Port 9081 - - - CLI / IPC - Port 20499 + + + kuiper CLI / IPC + Port 20499 - - - - rekuiper-mcp (AI Tools) - 42 tools + + + + rekuiper-mcp + + AI AGENT - - - - - - - - - - - 3. Egress & Sinks - - - - Log & Local Files - Rotating files, console stdout + + + + + + + + + + + 3. Egress & Sinks + + + + + Filtered MQTT Broker + Dynamic topics, QoS 0-2 - - - Filtered MQTT Broker - Dynamic topics via templating + + + External REST / Webhooks + HTTP POST with custom headers - - - SQL / SQLite Database - Batch inserts & upserts + + + SQL & Time-Series DB + SQLite, TimescaleDB, InfluxDB - - - External REST / Webhooks - HTTP POST with custom headers + + + Enterprise Event Streams + Kafka, Redis, Parquet on disk - - - Kafka & Redis Streams - Cloud cluster integration + + + Offline Cache & DLQ + Disk buffer during WAN disconnects diff --git a/docs/en_US/public/diagrams/edge_cloud_architecture.svg b/docs/en_US/public/diagrams/edge_cloud_architecture.svg new file mode 100644 index 000000000..7e2e183bf --- /dev/null +++ b/docs/en_US/public/diagrams/edge_cloud_architecture.svg @@ -0,0 +1,168 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + 1. Edge Sources + + + + + PLCs & Industrial RTUs + Modbus TCP/RTU · OPC-UA + + + + + Sensor Telemetry Feeds + Vibration · Temp · Pressure + + + + + Local Edge Brokers + Mosquitto · NanoMQ (MQTT) + + + + + Gateway IPC & Sockets + HTTP Push · Unix Sockets + + + + + + + + + + + + + + + 2. rekuiper Edge Gateway + + RUST ENGINE + + + + + Sub-Millisecond SQL Processing + Filter anomalies · Tumbling / Sliding Windows + 1,000,000+ events/s per core + + + + + Immediate Edge Action & Safety Control + <1 ms local shutdown alerts to GPIO / Modbus coils + Zero cloud latency dependency for critical safety + + + + + 90%+ WAN Bandwidth Compression + Downsample 1000 Hz raw telemetry to 1s summary stats + Transmit only significant anomalies across cellular/WAN + + + + + Resilient Offline Sink Cache & DLQ + Disk-backed FIFO queue during intermittent WAN outages + Zero data loss on link reconnection + + + + + + + + Remote Rules / Config + + + + + + 3. Central Cloud + + + + + Enterprise Message Hub + Apache Kafka · EMQX · RabbitMQ + + + + + Cloud IoT Platforms + AWS IoT Core · Azure IoT Hub + + + + + Time-Series Analytics + TimescaleDB · InfluxDB · ClickHouse + + + + + Fleet Orchestration + Declarative GitOps & MCP Push + + + diff --git a/docs/en_US/public/diagrams/inc_plan_consolidated.svg b/docs/en_US/public/diagrams/inc_plan_consolidated.svg new file mode 100644 index 000000000..d54d1b36e --- /dev/null +++ b/docs/en_US/public/diagrams/inc_plan_consolidated.svg @@ -0,0 +1,49 @@ + + + + + + + + + + + + + + + + + DataSource + Stream Ingest + + + + + + + + IncAggWindow (Consolidated) + Real-Time Intermediate Aggregates · O(groups) + + + + + + + + Having + Evaluates Precomputed Sum + + + + + + + + Project + Direct Value Bypass + + + Optimized Plan: Raw events discarded immediately after intermediate math. Bounded, constant memory footprint. + diff --git a/docs/en_US/public/diagrams/inc_plan_standard.svg b/docs/en_US/public/diagrams/inc_plan_standard.svg new file mode 100644 index 000000000..7b00e2b41 --- /dev/null +++ b/docs/en_US/public/diagrams/inc_plan_standard.svg @@ -0,0 +1,58 @@ + + + + + + + + + + + + + + + + + DataSource + Stream Ingest + + + + + + + + Window (Store) + Buffers Raw Events + + + + + + + + Aggregate + Group Evaluation + + + + + + + + Having + Evaluate Condition + + + + + + + + Project + Emit Columns + + + Traditional Plan: All raw events accumulate in memory buffer until the window boundary triggers. + diff --git a/docs/en_US/public/diagrams/incremental_memory_comparison.svg b/docs/en_US/public/diagrams/incremental_memory_comparison.svg new file mode 100644 index 000000000..2278de971 --- /dev/null +++ b/docs/en_US/public/diagrams/incremental_memory_comparison.svg @@ -0,0 +1,63 @@ + + + + + + + + + + + Memory Scaling Comparison: Standard vs Incremental Windowing + + + + Standard Plan (O(N) with Events) + + + + Incremental Plan (O(Groups)) + + + + + + 250 MB + + + 180 MB + + + 100 MB + + + 25 MB + + + 0 MB + + + 0s (0 msg) + 15s (3M msg) + 30s (6M msg) + 45s (9M msg) + 60s (12M msg) + + + + + + + + + + + + + + + + + Bounded ~2.4 MB (Zero Heap Bloat) + + diff --git a/docs/en_US/public/diagrams/prometheus_grafana_dashboard.svg b/docs/en_US/public/diagrams/prometheus_grafana_dashboard.svg new file mode 100644 index 000000000..7ededa999 --- /dev/null +++ b/docs/en_US/public/diagrams/prometheus_grafana_dashboard.svg @@ -0,0 +1,122 @@ + + + + + + + + + + + + + + + rekuiper · Prometheus & Grafana Observability Dashboard + + INSTANCE: localhost:9081 + + + + + Running Rules + 14 / 14 + + + + + + + + Ingest Throughput + 224,500 msg/s + + + + + + Pipeline P99 Latency + 0.38 ms + + + + + + Engine Memory (RSS) + 24.2 MB + + + + + + Rule Health State (kuiper_rule_status) + + + + rule_pressure (1.0) + + rule_vibe (1.0) + + + + + 1.0 + + 0.5 + + 0.0 + + -1.0 + + + + + + + 14:20:00 + 14:21:00 + 14:22:00 + 14:23:00 + 14:24:00 + + + + + + + Processed Records (kuiper_sink_records_out_total) + + + + sink_records_out + + + + + 10M + + 7.5M + + 5M + + 0 + + + + + + + 14:20:00 + 14:21:00 + 14:22:00 + 14:23:00 + 14:24:00 + + + diff --git a/docs/en_US/public/diagrams/public_data_velocity_chart.svg b/docs/en_US/public/diagrams/public_data_velocity_chart.svg new file mode 100644 index 000000000..b971fab44 --- /dev/null +++ b/docs/en_US/public/diagrams/public_data_velocity_chart.svg @@ -0,0 +1,71 @@ + + + + + + + + + + + + + + + Trip Velocity by User ID + Source: InfluxDB · Metric: Velocity (m/s) + + + + + + 3.0 m/s + + + 2.25 m/s + + + 1.50 m/s + + + 0.75 m/s + + + 0.0 m/s + + + + + + 2.38 + 9fb2d1e + + + + + + 1.55 + 1184eec + + + + + + 2.52 + 30a457b + + + + + + 0.28 + bee78cd + + + diff --git a/docs/en_US/public/diagrams/trace_dropped.svg b/docs/en_US/public/diagrams/trace_dropped.svg new file mode 100644 index 000000000..75fd7fd1e --- /dev/null +++ b/docs/en_US/public/diagrams/trace_dropped.svg @@ -0,0 +1,63 @@ + + + + + + + + + + + + + + + Trace: rekuiper-service (demo rule) · Payload {"a": 4} + STATUS: FILTERED OUT (72µs · 3 Spans) + + + + + 0µs + 20µs + 40µs + 60µs + 80µs + + + + + + + rekuiper: rule_demo + root + + 72µs + + + + + + + 2_decoder (JSON Unmarshal) + OTLP + + 38µs + + + + + + + 3_filter (Condition: a > 5) + DROPPED + + 26µs (term) + + \ No newline at end of file diff --git a/docs/en_US/public/diagrams/trace_passed.svg b/docs/en_US/public/diagrams/trace_passed.svg new file mode 100644 index 000000000..257ece903 --- /dev/null +++ b/docs/en_US/public/diagrams/trace_passed.svg @@ -0,0 +1,99 @@ + + + + + + + + + + + + + + + Trace: rekuiper-service (demo rule) · Payload {"a": 10} + STATUS: PASSED (248µs · 6 Spans) + + + + + 0µs + 60µs + 120µs + 180µs + 250µs + + + + + + + + rekuiper: rule_demo + root + + + 248µs + + + + + + + 2_decoder (JSON Unmarshal) + OTLP + + + 42µs + + + + + + + 3_filter (Condition: a > 5) + MATCH + + + 28µs + + + + + + + 4_project (Select Columns) + OTLP + + + 34µs + + + + + + + transform_op (Template Payload) + + + 46µs + + + + + + + sink_log (Emit Action) + DELIVERED + + + 58µs + + \ No newline at end of file diff --git a/docs/en_US/public/diagrams/windows/hopping_window.svg b/docs/en_US/public/diagrams/windows/hopping_window.svg new file mode 100644 index 000000000..275f88a20 --- /dev/null +++ b/docs/en_US/public/diagrams/windows/hopping_window.svg @@ -0,0 +1,152 @@ + + + + + + + + + + + + + + + + + + + + + + + Hopping Window (10s Window with 5s Hop) + HOPPINGWINDOW(ss, 10, 5) + + + Time + + 0s + + + 5s + + + 10s + + + 15s + + + 20s + + + 25s + + + 30s + + + + 1 + + + + 2 + + + + 3 + + + + 4 + + + + 5 + + + + 6 + + + + 7 + + + + 8 + + + + 9 + + + + + + 1 + + 2 + + 3 + + 4 + + 5 + + + + + + + + 4 + + 5 + + 6 + + + + + + + + 6 + + 7 + + + + + + + + 7 + + + + + + + + 8 + + 9 + + + + \ No newline at end of file diff --git a/docs/en_US/public/diagrams/windows/session_window.svg b/docs/en_US/public/diagrams/windows/session_window.svg new file mode 100644 index 000000000..910d9d8a6 --- /dev/null +++ b/docs/en_US/public/diagrams/windows/session_window.svg @@ -0,0 +1,123 @@ + + + + + + + + + + + + + + + + + + + + + + + Session Window (5s Inactivity Timeout & 10s Max Duration) + SESSIONWINDOW(ss, 10, 5) + + + Time + + 0s + + 5s + + 10s + + 15s + + 20s + + 25s + + 30s + + 5s timeout + + 5s timeout + + + 1 + + + + 2 + + + + 3 + + + + 4 + + + + 5 + + + + 6 + + + + 8 + + + + 9 + + + + + + 1 + + 2 + + + + + + + + 3 + + 4 + + 5 + + 6 + + + + + + + + 8 + + 9 + + + + \ No newline at end of file diff --git a/docs/en_US/public/diagrams/windows/sliding_count_window_1.svg b/docs/en_US/public/diagrams/windows/sliding_count_window_1.svg new file mode 100644 index 000000000..c8424640b --- /dev/null +++ b/docs/en_US/public/diagrams/windows/sliding_count_window_1.svg @@ -0,0 +1,185 @@ + + + + + + + + + + + + + + + + + + + + + + + Sliding Count Window (Length 5, Trigger Every 1 Event) + COUNTWINDOW(5, 1) + + + Stream + + + 1 + + + + + 2 + + + + + 3 + + + + + 4 + + + + + 5 + + + + + 6 + + + + + 7 + + + + + 8 + + + + + 9 + + + + + 10 + + + + + + + 1 + + 2 + + 3 + + 4 + + 5 + + + + + + + + 2 + + 3 + + 4 + + 5 + + 6 + + + + + + + + 3 + + 4 + + 5 + + 6 + + 7 + + + + + + + + 4 + + 5 + + 6 + + 7 + + 8 + + + + + + + + 5 + + 6 + + 7 + + 8 + + 9 + + + + + + + + 6 + + 7 + + 8 + + 9 + + 10 + + + + \ No newline at end of file diff --git a/docs/en_US/public/diagrams/windows/sliding_count_window_2.svg b/docs/en_US/public/diagrams/windows/sliding_count_window_2.svg new file mode 100644 index 000000000..8c5b604ed --- /dev/null +++ b/docs/en_US/public/diagrams/windows/sliding_count_window_2.svg @@ -0,0 +1,170 @@ + + + + + + + + + + + + + + + + + + + + + + + Sliding Count Window (Length 5, Trigger Every 2 Events) + COUNTWINDOW(5, 2) + + + Stream + + + 1 + + + + + 2 + + + + + 3 + + + + + 4 + + + + + 5 + + + + + 6 + + + + + 7 + + + + + 8 + + + + + 9 + + + + + 10 + + + + + + + + + 1 + + + + + + + + 2 + + 3 + + 4 + + 5 + + 6 + + + + + + + + + + + 3 + + + + + + + + 4 + + 5 + + 6 + + 7 + + 8 + + + + + + + + + + + 5 + + + + + + + + 6 + + 7 + + 8 + + 9 + + 10 + + + + + \ No newline at end of file diff --git a/docs/en_US/public/diagrams/windows/sliding_window.svg b/docs/en_US/public/diagrams/windows/sliding_window.svg new file mode 100644 index 000000000..c7bb50a25 --- /dev/null +++ b/docs/en_US/public/diagrams/windows/sliding_window.svg @@ -0,0 +1,124 @@ + + + + + + + + + + + + + + + + + + + + + + + Sliding Window (Triggered Upon Event Arrival, 10s Lookback) + SLIDINGWINDOW(ss, 10) + + + Time + + 0s + + 5s + + 10s + + 15s + + 20s + + 25s + + 30s + + + 1 + + + + 2 + + + + 3 + + + + 4 + + + + 5 + + + + + + + 1 + + + + + + + + + 1 + + 2 + + + + + + + + + 2 + + 3 + + + + + + + + + 4 + + + + + + + + + 4 + + 5 + + + + \ No newline at end of file diff --git a/docs/en_US/public/diagrams/windows/sliding_window_delay.svg b/docs/en_US/public/diagrams/windows/sliding_window_delay.svg new file mode 100644 index 000000000..f3348b405 --- /dev/null +++ b/docs/en_US/public/diagrams/windows/sliding_window_delay.svg @@ -0,0 +1,94 @@ + + + + + + + + + + + + + + + + + + + + + + + Sliding Window with 5-Second Delay + SLIDINGWINDOW(ss, 5, 5) + + + Time + + 0s + + + 5s + + + 10s + + + 15s + + + 20s + + + + 4 + + + + 5 + + + + 6 + + + + + + 4 + + 5 + + + + + + + + 4 + + 5 + + + + + + + + 6 + + + + \ No newline at end of file diff --git a/docs/en_US/public/diagrams/windows/tumbling_count_window.svg b/docs/en_US/public/diagrams/windows/tumbling_count_window.svg new file mode 100644 index 000000000..1d373b6c3 --- /dev/null +++ b/docs/en_US/public/diagrams/windows/tumbling_count_window.svg @@ -0,0 +1,121 @@ + + + + + + + + + + + + + + + + + + + + + + + Tumbling Count Window (Fixed Batch Size of 5 Events) + COUNTWINDOW(5) + + + Stream + + + 1 + + + + + 2 + + + + + 3 + + + + + 4 + + + + + 5 + + + + + 6 + + + + + 7 + + + + + 8 + + + + + 9 + + + + + 10 + + + + + + + 1 + + 2 + + 3 + + 4 + + 5 + + + + + + + + 6 + + 7 + + 8 + + 9 + + 10 + + + + \ No newline at end of file diff --git a/docs/en_US/public/diagrams/windows/tumbling_window.svg b/docs/en_US/public/diagrams/windows/tumbling_window.svg new file mode 100644 index 000000000..727f56303 --- /dev/null +++ b/docs/en_US/public/diagrams/windows/tumbling_window.svg @@ -0,0 +1,128 @@ + + + + + + + + + + + + + + + + + + + + + + + Tumbling Window (10s Fixed Contiguous Intervals) + TUMBLINGWINDOW(ss, 10) + + + Time + + 0s + + 5s + + 10s + + 15s + + 20s + + 25s + + 30s + + + + + + 1 + + + + 2 + + + + 3 + + + + 4 + + + + 5 + + + + 6 + + + + 7 + + + + 8 + + + + 9 + + + + + + 1 + + 2 + + 3 + + 4 + + 5 + + + + + + + + 6 + + 7 + + + + + + + + 8 + + 9 + + + + \ No newline at end of file diff --git a/docs/en_US/public/openapi.json b/docs/en_US/public/openapi.json new file mode 100644 index 000000000..b2bb5b620 --- /dev/null +++ b/docs/en_US/public/openapi.json @@ -0,0 +1,9488 @@ +{ + "openapi": "3.0.3", + "x-ekuiper-version": "2.4.1", + "x-source-tag": "https://github.com/lf-edge/ekuiper/tree/v2.4.1", + "x-source-commit": "bf8c1258b2a80e41e575d674346636c9bb687d33", + "info": { + "title": "rekuiper REST Management API", + "description": "Authoritative OpenAPI contract for the management REST routes registered by rekuiper (100% wire-compatible with eKuiper v2.4.1). Optional components depend on build tags; JWT authentication, when enabled, expects a raw RS256 token in the Authorization header.", + "version": "1.0.0-rc4", + "contact": { + "name": "I-Dacs Labs", + "url": "https://i-dacs.com" + }, + "license": { + "name": "Apache 2.0", + "url": "https://www.apache.org/licenses/LICENSE-2.0" + } + }, + "externalDocs": { + "description": "Tagged rekuiper REST API documentation", + "url": "https://github.com/Indus-Stack/rekuiper/tree/main/docs/en_US/api/restapi" + }, + "servers": [ + { + "url": "http://localhost:9081", + "description": "Default rekuiper REST listener" + } + ], + "tags": [ + { + "name": "System", + "description": "System information, health, runtime configuration, metrics, shutdown, and batch requests." + }, + { + "name": "Streams", + "description": "Stream definition management." + }, + { + "name": "Tables", + "description": "Table definition management." + }, + { + "name": "Rules", + "description": "Rule definition and lifecycle management." + }, + { + "name": "Rule Test", + "description": "Temporary ten-minute rule trial runs. SSE results use the separately configured HTTP server port." + }, + { + "name": "Tracing", + "description": "Local rule traces and optional remote OpenTelemetry collection." + }, + { + "name": "Ruleset", + "description": "Streams, tables, and rules import/export." + }, + { + "name": "Data", + "description": "Full JSON/YAML configuration import/export and asynchronous tasks." + }, + { + "name": "Uploads", + "description": "Files stored below the eKuiper data uploads directory." + }, + { + "name": "Connections", + "description": "Named shared connection management." + }, + { + "name": "Plugins", + "description": "Native and portable plugin management. Native routes require a non-core/plugin build; portable routes require a non-core/portable build." + }, + { + "name": "Schemas", + "description": "Schema registry management. protobuf and custom schema types are registered in non-core/schema builds." + }, + { + "name": "UDF", + "description": "JavaScript UDF management; available in full/script builds." + }, + { + "name": "Services", + "description": "External service management; available in non-core/service builds." + }, + { + "name": "Metadata", + "description": "UI metadata, configuration keys, resources, and connectivity tests; available in non-core/ui builds." + } + ], + "paths": { + "/": { + "get": { + "tags": [ + "System" + ], + "summary": "Get eKuiper system information", + "operationId": "getSystemInfo", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/rest.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/docs/en_US/api/restapi/overview.md" + ], + "security": [], + "description": "Returns version, platform, uptime, and available process metrics.", + "responses": { + "200": { + "description": "System information", + "content": { + "text/plain": { + "schema": { + "type": "string", + "description": "JSON encoded as text/plain by the v2.4.1 handler." + }, + "example": "{\"version\":\"2.4.1\",\"os\":\"linux\",\"arch\":\"amd64\",\"upTimeSeconds\":14,\"memoryTotal\":\"33582968832\"}", + "x-decoded-schema": { + "$ref": "#/components/schemas/SystemInfo" + } + } + } + } + } + }, + "post": { + "tags": [ + "System" + ], + "summary": "Get eKuiper system information", + "operationId": "getSystemInfoViaPost", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/rest.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/docs/en_US/api/restapi/overview.md" + ], + "security": [], + "description": "Registered compatibility alias; the tagged documentation advertises GET.", + "responses": { + "200": { + "description": "System information", + "content": { + "text/plain": { + "schema": { + "type": "string", + "description": "JSON encoded as text/plain by the v2.4.1 handler." + }, + "example": "{\"version\":\"2.4.1\",\"os\":\"linux\",\"arch\":\"amd64\",\"upTimeSeconds\":14,\"memoryTotal\":\"33582968832\"}", + "x-decoded-schema": { + "$ref": "#/components/schemas/SystemInfo" + } + } + } + } + } + } + }, + "/stop": { + "get": { + "tags": [ + "System" + ], + "summary": "Shut down eKuiper", + "operationId": "stopEKuiperViaGet", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/rest.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/docs/en_US/api/restapi/configs.md" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "description": "Registered compatibility alias; the tagged documentation advertises POST.", + "responses": { + "200": { + "description": "Shutdown accepted", + "content": { + "text/plain": { + "schema": { + "type": "string" + }, + "example": "stop success" + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + } + } + }, + "post": { + "tags": [ + "System" + ], + "summary": "Shut down eKuiper", + "operationId": "stopEKuiper", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/rest.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/docs/en_US/api/restapi/configs.md" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "description": "Stops the eKuiper process.", + "responses": { + "200": { + "description": "Shutdown accepted", + "content": { + "text/plain": { + "schema": { + "type": "string" + }, + "example": "stop success" + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + } + } + } + }, + "/ping": { + "get": { + "tags": [ + "System" + ], + "summary": "Check REST server health", + "operationId": "ping", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/rest.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/docs/en_US/api/restapi/overview.md" + ], + "security": [], + "responses": { + "200": { + "description": "REST server is reachable; empty response body." + } + } + } + }, + "/configs": { + "patch": { + "tags": [ + "System" + ], + "summary": "Dynamically reload supported configuration", + "operationId": "patchConfigs", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/rest.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/import_export.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/docs/en_US/api/restapi/configs.md" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DynamicConfig" + }, + "example": { + "debug": true, + "consoleLog": true, + "fileLog": true, + "timezone": "UTC" + } + } + } + }, + "responses": { + "204": { + "description": "Configuration updated; no response body." + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + } + } + }, + "get": { + "tags": [ + "System" + ], + "summary": "Get system configuration", + "operationId": "getConfigs", + "security": [ + {}, + { + "JwtToken": [] + } + ], + "responses": { + "200": { + "description": "System configuration object", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "basic": { + "type": "object", + "properties": { + "debug": { + "type": "boolean" + }, + "logLevel": { + "type": "string" + }, + "port": { + "type": "integer" + }, + "restPort": { + "type": "integer" + } + } + } + } + }, + "example": { + "basic": { + "debug": false, + "logLevel": "info", + "port": 20498, + "restPort": 9081 + } + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + } + } + } + }, + "/metrics/dump/check": { + "get": { + "tags": [ + "System" + ], + "summary": "Check whether metrics dump is enabled", + "operationId": "checkMetricsDump", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/rest.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/metrics_init.go" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "responses": { + "200": { + "description": "Current metrics-dump state", + "content": { + "text/plain": { + "schema": { + "type": "string" + }, + "example": "enabled" + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + } + } + } + }, + "/metrics/dump": { + "get": { + "tags": [ + "System" + ], + "summary": "Download collected metrics", + "operationId": "downloadMetricsDump", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/rest.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/metrics_init.go" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "parameters": [ + { + "name": "startTime", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "format": "int64" + }, + "description": "Inclusive Unix timestamp in seconds; defaults with endTime to the previous hour." + }, + { + "name": "endTime", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "format": "int64" + }, + "description": "Exclusive Unix timestamp in seconds; defaults with startTime to now." + } + ], + "responses": { + "200": { + "description": "ZIP archive of collected metrics", + "content": { + "application/octet-stream": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "404": { + "description": "Metrics archive not found", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + }, + "500": { + "description": "Metrics archive could not be read", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, + "/batch/req": { + "post": { + "tags": [ + "System" + ], + "summary": "Execute multiple REST requests", + "operationId": "batchRequests", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/rest.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/docs/en_US/api/restapi/overview.md" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "description": "Executes nested requests sequentially through the same router. Each nested body is a string and each result records its HTTP code and response text.", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BatchRequest" + } + }, + "example": [ + { + "method": "GET", + "path": "/ping" + } + ] + } + } + }, + "responses": { + "200": { + "description": "Per-request results", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BatchResponse" + } + }, + "example": [ + { + "code": 200 + } + ] + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + } + } + } + }, + "/streams": { + "get": { + "tags": [ + "Streams" + ], + "summary": "List streams", + "operationId": "listStreams", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/rest.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/docs/en_US/api/restapi/streams.md" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "responses": { + "200": { + "description": "Defined streams names", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + } + } + }, + "post": { + "tags": [ + "Streams" + ], + "summary": "Execute stream SQL", + "operationId": "createStream", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/rest.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/docs/en_US/api/restapi/streams.md" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "description": "The handler executes any stream SQL statement, not only CREATE.", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StatementRequest" + } + } + } + }, + "responses": { + "201": { + "description": "Stream SQL executed", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + } + } + } + }, + "/streamdetails": { + "get": { + "tags": [ + "Streams" + ], + "summary": "List detailed streams", + "operationId": "listStreamsDetails", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/rest.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/docs/en_US/api/restapi/streams.md" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "responses": { + "200": { + "description": "Name, source type, and format for each definition", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DatasourceDetail" + } + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + } + } + } + }, + "/streams/{name}": { + "get": { + "tags": [ + "Streams" + ], + "summary": "Describe a stream", + "operationId": "getStream", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/rest.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/docs/en_US/api/restapi/streams.md" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "parameters": [ + { + "$ref": "#/components/parameters/Name" + } + ], + "responses": { + "200": { + "description": "Parsed definition", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DatasourceDescription" + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "404": { + "$ref": "#/components/responses/NotFound" + } + } + }, + "put": { + "tags": [ + "Streams" + ], + "summary": "Replace a stream", + "operationId": "updateStream", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/rest.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/docs/en_US/api/restapi/streams.md" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "parameters": [ + { + "$ref": "#/components/parameters/Name" + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StatementRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Definition replaced", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "404": { + "$ref": "#/components/responses/NotFound" + } + } + }, + "delete": { + "tags": [ + "Streams" + ], + "summary": "Delete a stream", + "operationId": "deleteStream", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/rest.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/docs/en_US/api/restapi/streams.md" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "parameters": [ + { + "$ref": "#/components/parameters/Name" + }, + { + "name": "force", + "in": "query", + "required": false, + "schema": { + "type": "boolean", + "default": false + }, + "description": "When true, skip the check for rules that reference the stream/table." + } + ], + "responses": { + "200": { + "description": "Definition deleted", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "404": { + "$ref": "#/components/responses/NotFound" + } + } + } + }, + "/streams/{name}/schema": { + "get": { + "tags": [ + "Streams" + ], + "summary": "Get inferred stream schema", + "operationId": "getStreamSchema", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/rest.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/docs/en_US/api/restapi/streams.md" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "parameters": [ + { + "$ref": "#/components/parameters/Name" + } + ], + "responses": { + "200": { + "description": "JSON-schema-like field map", + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": { + "$ref": "#/components/schemas/JsonSchemaField" + } + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "404": { + "$ref": "#/components/responses/NotFound" + } + } + } + }, + "/tables": { + "get": { + "tags": [ + "Tables" + ], + "summary": "List tables", + "operationId": "listTables", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/rest.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/docs/en_US/api/restapi/tables.md" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "parameters": [ + { + "name": "kind", + "in": "query", + "required": false, + "schema": { + "type": "string", + "enum": [ + "scan", + "lookup" + ] + }, + "description": "Filter table kind; other or omitted values return all kinds." + } + ], + "responses": { + "200": { + "description": "Defined tables names", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + } + } + }, + "post": { + "tags": [ + "Tables" + ], + "summary": "Execute table SQL", + "operationId": "createTable", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/rest.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/docs/en_US/api/restapi/tables.md" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "description": "The handler executes any table SQL statement, not only CREATE.", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StatementRequest" + } + } + } + }, + "responses": { + "201": { + "description": "Table SQL executed", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + } + } + } + }, + "/tabledetails": { + "get": { + "tags": [ + "Tables" + ], + "summary": "List detailed tables", + "operationId": "listTablesDetails", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/rest.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/docs/en_US/api/restapi/tables.md" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "parameters": [ + { + "name": "kind", + "in": "query", + "required": false, + "schema": { + "type": "string", + "enum": [ + "scan", + "lookup" + ] + }, + "description": "Filter table kind; other or omitted values return all kinds." + } + ], + "responses": { + "200": { + "description": "Name, source type, and format for each definition", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/DatasourceDetail" + } + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + } + } + } + }, + "/tables/{name}": { + "get": { + "tags": [ + "Tables" + ], + "summary": "Describe a table", + "operationId": "getTable", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/rest.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/docs/en_US/api/restapi/tables.md" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "parameters": [ + { + "$ref": "#/components/parameters/Name" + } + ], + "responses": { + "200": { + "description": "Parsed definition", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DatasourceDescription" + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "404": { + "$ref": "#/components/responses/NotFound" + } + } + }, + "put": { + "tags": [ + "Tables" + ], + "summary": "Replace a table", + "operationId": "updateTable", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/rest.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/docs/en_US/api/restapi/tables.md" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "parameters": [ + { + "$ref": "#/components/parameters/Name" + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/StatementRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Definition replaced", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "404": { + "$ref": "#/components/responses/NotFound" + } + } + }, + "delete": { + "tags": [ + "Tables" + ], + "summary": "Delete a table", + "operationId": "deleteTable", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/rest.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/docs/en_US/api/restapi/tables.md" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "parameters": [ + { + "$ref": "#/components/parameters/Name" + }, + { + "name": "force", + "in": "query", + "required": false, + "schema": { + "type": "boolean", + "default": false + }, + "description": "When true, skip the check for rules that reference the stream/table." + } + ], + "responses": { + "200": { + "description": "Definition deleted", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "404": { + "$ref": "#/components/responses/NotFound" + } + } + } + }, + "/tables/{name}/schema": { + "get": { + "tags": [ + "Tables" + ], + "summary": "Get inferred table schema", + "operationId": "getTableSchema", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/rest.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/docs/en_US/api/restapi/tables.md" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "parameters": [ + { + "$ref": "#/components/parameters/Name" + } + ], + "responses": { + "200": { + "description": "JSON-schema-like field map", + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": { + "$ref": "#/components/schemas/JsonSchemaField" + } + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "404": { + "$ref": "#/components/responses/NotFound" + } + } + } + }, + "/rules": { + "get": { + "tags": [ + "Rules" + ], + "summary": "List rules with brief status", + "operationId": "listRules", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/rest.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/docs/en_US/api/restapi/rules.md" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "responses": { + "200": { + "description": "Rule summaries", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/RuleListItem" + } + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + } + } + }, + "post": { + "tags": [ + "Rules" + ], + "summary": "Create and start a rule", + "operationId": "createRule", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/rest.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/docs/en_US/api/restapi/rules.md" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RuleCreateRequest" + } + } + } + }, + "responses": { + "201": { + "description": "Rule created", + "content": { + "text/plain": { + "schema": { + "type": "string" + }, + "example": "Rule rule1 was created successfully." + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + } + } + } + }, + "/rules/{name}": { + "get": { + "tags": [ + "Rules" + ], + "summary": "Describe a rule", + "operationId": "getRule", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/rest.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/docs/en_US/api/restapi/rules.md" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "parameters": [ + { + "$ref": "#/components/parameters/Name" + } + ], + "responses": { + "200": { + "description": "Stored rule definition", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Rule" + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "404": { + "$ref": "#/components/responses/NotFound" + } + } + }, + "put": { + "tags": [ + "Rules" + ], + "summary": "Create or update a rule", + "operationId": "upsertRule", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/rest.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/docs/en_US/api/restapi/rules.md" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "description": "The body id may be omitted; when supplied it must equal the path name. If updating fails, the original rule continues running.", + "parameters": [ + { + "$ref": "#/components/parameters/Name" + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Rule" + } + } + } + }, + "responses": { + "200": { + "description": "Rule updated", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "404": { + "$ref": "#/components/responses/NotFound" + } + } + }, + "delete": { + "tags": [ + "Rules" + ], + "summary": "Delete a rule", + "operationId": "deleteRule", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/rest.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/docs/en_US/api/restapi/rules.md" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "parameters": [ + { + "$ref": "#/components/parameters/Name" + } + ], + "responses": { + "200": { + "description": "Rule deleted", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "404": { + "$ref": "#/components/responses/NotFound" + } + } + } + }, + "/rules/status/all": { + "get": { + "tags": [ + "Rules" + ], + "summary": "Get status of all rules", + "operationId": "getAllRuleStatus", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/rest.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/docs/en_US/api/restapi/rules.md" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "responses": { + "200": { + "description": "Status and latest exception summary keyed by rule id", + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": { + "$ref": "#/components/schemas/RuleExceptionStatus" + } + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + } + } + } + }, + "/rules/{name}/status": { + "get": { + "tags": [ + "Rules" + ], + "summary": "Get rule status and metrics", + "operationId": "getRuleStatus", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/rest.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/docs/en_US/api/restapi/rules.md" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "description": "Legacy status serialization. Metrics are appended as dynamically named properties.", + "parameters": [ + { + "$ref": "#/components/parameters/Name" + } + ], + "responses": { + "200": { + "description": "Rule status and metrics", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RuleStatus" + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "404": { + "$ref": "#/components/responses/NotFound" + } + } + } + }, + "/v2/rules/{name}/status": { + "get": { + "tags": [ + "Rules" + ], + "summary": "Get typed rule status and metrics", + "operationId": "getRuleStatusV2", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/rest.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/topo/rule/state.go" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "description": "Returns native JSON metric value types, unlike the legacy string-built status response.", + "parameters": [ + { + "$ref": "#/components/parameters/Name" + } + ], + "responses": { + "200": { + "description": "Rule status and typed metrics", + "content": { + "text/plain": { + "schema": { + "type": "string", + "description": "JSON encoded as text/plain by the v2.4.1 handler." + }, + "example": "{\"status\":\"running\",\"message\":\"\",\"lastStartTimestamp\":0,\"lastStopTimestamp\":0,\"nextStartTimestamp\":0}", + "x-decoded-schema": { + "$ref": "#/components/schemas/RuleStatus" + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "404": { + "$ref": "#/components/responses/NotFound" + } + } + } + }, + "/rules/{name}/start": { + "post": { + "tags": [ + "Rules" + ], + "summary": "Start a rule", + "operationId": "startRule", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/rest.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/docs/en_US/api/restapi/rules.md" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "description": "A successful response means the command was accepted; poll status to observe completion.", + "parameters": [ + { + "$ref": "#/components/parameters/Name" + } + ], + "responses": { + "200": { + "description": "Rule start command accepted", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "404": { + "$ref": "#/components/responses/NotFound" + } + } + } + }, + "/rules/{name}/stop": { + "post": { + "tags": [ + "Rules" + ], + "summary": "Stop a rule", + "operationId": "stopRule", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/rest.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/docs/en_US/api/restapi/rules.md" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "description": "A successful response means the command was accepted; poll status to observe completion.", + "parameters": [ + { + "$ref": "#/components/parameters/Name" + } + ], + "responses": { + "200": { + "description": "Rule stop command accepted", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "404": { + "$ref": "#/components/responses/NotFound" + } + } + } + }, + "/rules/{name}/restart": { + "post": { + "tags": [ + "Rules" + ], + "summary": "Restart a rule", + "operationId": "restartRule", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/rest.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/docs/en_US/api/restapi/rules.md" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "parameters": [ + { + "$ref": "#/components/parameters/Name" + } + ], + "responses": { + "200": { + "description": "Rule restart command accepted", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "404": { + "$ref": "#/components/responses/NotFound" + } + } + } + }, + "/rules/{name}/topo": { + "get": { + "tags": [ + "Rules" + ], + "summary": "Get rule topology", + "operationId": "getRuleTopology", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/rest.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/docs/en_US/api/restapi/rules.md" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "parameters": [ + { + "$ref": "#/components/parameters/Name" + } + ], + "responses": { + "200": { + "description": "Topology graph", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RuleTopology" + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "404": { + "$ref": "#/components/responses/NotFound" + } + } + } + }, + "/rules/{id}/schema": { + "get": { + "tags": [ + "Rules" + ], + "summary": "Get rule output schema", + "operationId": "getRuleSchema", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/rest.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/docs/en_US/api/restapi/rules.md" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "description": "The tagged Markdown accidentally prints /rules/{id}; the v2.4.1 router and handler register /rules/{id}/schema.", + "parameters": [ + { + "$ref": "#/components/parameters/Id" + } + ], + "responses": { + "200": { + "description": "Output fields keyed by field name", + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": { + "$ref": "#/components/schemas/JsonSchemaField" + } + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "404": { + "$ref": "#/components/responses/NotFound" + } + } + } + }, + "/rules/validate": { + "post": { + "tags": [ + "Rules" + ], + "summary": "Validate a rule", + "operationId": "validateRule", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/rest.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/docs/en_US/api/restapi/rules.md" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RuleCreateRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Valid rule and referenced sources", + "content": { + "text/plain": { + "schema": { + "type": "string", + "description": "JSON encoded as text/plain by the v2.4.1 handler." + }, + "example": "{\"sources\":[\"demo\"],\"valid\":true}", + "x-decoded-schema": { + "$ref": "#/components/schemas/RuleValidationResponse" + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "422": { + "description": "The body parsed but the rule is invalid", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + } + } + } + }, + "/rules/{name}/reset_state": { + "put": { + "tags": [ + "Rules" + ], + "summary": "Reset a running rule stream offset", + "operationId": "resetRuleState", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/rest.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/rule_state.go" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "description": "Only state type 1 (update offset) is implemented, and the target rule must be running.", + "parameters": [ + { + "$ref": "#/components/parameters/Name" + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RuleStateUpdateRequest" + }, + "example": { + "type": 1, + "params": { + "streamName": "demo", + "input": { + "partition": 0, + "offset": 10 + } + } + } + } + } + }, + "responses": { + "200": { + "description": "Offset updated", + "content": { + "text/plain": { + "schema": { + "type": "string" + }, + "example": "success" + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "404": { + "$ref": "#/components/responses/NotFound" + } + } + } + }, + "/rules/{name}/explain": { + "get": { + "tags": [ + "Rules" + ], + "summary": "Explain a SQL rule plan", + "operationId": "explainRule", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/rest.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/docs/en_US/api/restapi/rules.md" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "description": "Only SQL rules are supported. The result is an indented plain-text logical plan.", + "parameters": [ + { + "$ref": "#/components/parameters/Name" + } + ], + "responses": { + "200": { + "description": "Logical plan", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "404": { + "$ref": "#/components/responses/NotFound" + } + } + } + }, + "/rules/usage/cpu": { + "get": { + "tags": [ + "Rules" + ], + "summary": "Get rule CPU usage over the last 30 seconds", + "operationId": "getRuleCpuUsage", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/rest.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/docs/en_US/api/restapi/rules.md" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "responses": { + "200": { + "description": "Milliseconds keyed by rule id, or a plain-text not-enabled/not-ready state.", + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": { + "type": "integer" + } + } + }, + "text/plain": { + "schema": { + "type": "string", + "enum": [ + "cpu usage not enabled", + "cpu usage not ready" + ] + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + } + } + } + }, + "/rules/{name}/tags": { + "put": { + "tags": [ + "Rules" + ], + "summary": "Replace all rule tags", + "operationId": "replaceRuleTags", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/rest.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/rule_tag.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/docs/en_US/api/restapi/rules.md" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "description": "The v2.4.1 handler decodes the JSON property \"tags\". The tagged Markdown incorrectly shows \"keys\" for DELETE.", + "parameters": [ + { + "$ref": "#/components/parameters/Name" + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RuleTagRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Tags updated; empty response body." + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "404": { + "$ref": "#/components/responses/NotFound" + } + } + }, + "patch": { + "tags": [ + "Rules" + ], + "summary": "Add rule tags", + "operationId": "addRuleTags", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/rest.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/rule_tag.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/docs/en_US/api/restapi/rules.md" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "description": "The v2.4.1 handler decodes the JSON property \"tags\". The tagged Markdown incorrectly shows \"keys\" for DELETE.", + "parameters": [ + { + "$ref": "#/components/parameters/Name" + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RuleTagRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Tags updated; empty response body." + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "404": { + "$ref": "#/components/responses/NotFound" + } + } + }, + "delete": { + "tags": [ + "Rules" + ], + "summary": "Remove rule tags", + "operationId": "removeRuleTags", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/rest.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/rule_tag.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/docs/en_US/api/restapi/rules.md" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "description": "The v2.4.1 handler decodes the JSON property \"tags\". The tagged Markdown incorrectly shows \"keys\" for DELETE.", + "parameters": [ + { + "$ref": "#/components/parameters/Name" + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RuleTagRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Tags updated; empty response body." + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "404": { + "$ref": "#/components/responses/NotFound" + } + } + } + }, + "/rules/tags/match": { + "get": { + "tags": [ + "Rules" + ], + "summary": "Find rules containing all requested tags", + "operationId": "matchRulesByTagsGet", + "security": [ + {}, + { + "JwtToken": [] + } + ], + "description": "Matches rules containing all specified tags. Query parameters ?tags=, ?tag=, ?keys=, or ?key= (comma-separated) can be used, or a JSON body.", + "parameters": [ + { + "name": "tags", + "in": "query", + "required": false, + "description": "Comma-separated list of tags to match (e.g. env:prod,tier:vip)", + "schema": { + "type": "string" + } + }, + { + "name": "tag", + "in": "query", + "required": false, + "description": "Single tag or comma-separated tags to match", + "schema": { + "type": "string" + } + }, + { + "name": "keys", + "in": "query", + "required": false, + "description": "Legacy alias for tags parameter", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Matching rule IDs", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "type": "string" + } + }, + "example": [ + "rule_comprehensive", + "rule_monitoring" + ] + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + } + } + }, + "post": { + "tags": [ + "Rules" + ], + "summary": "Find rules containing all requested tags via POST body", + "operationId": "matchRulesByTagsPost", + "security": [ + {}, + { + "JwtToken": [] + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "oneOf": [ + { + "type": "object", + "properties": { + "tags": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ] + }, + "example": { + "tags": [ + "tier:vip", + "env:prod" + ] + } + } + } + }, + "responses": { + "200": { + "description": "Matching rule IDs", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "type": "string" + } + }, + "example": [ + "rule_comprehensive" + ] + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + } + } + } + }, + "/rules/bulkstart": { + "post": { + "tags": [ + "Rules" + ], + "summary": "Bulk start rules by tag", + "operationId": "bulkStartRules", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/rest.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/rule_tag.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/docs/en_US/api/restapi/rules.md" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "description": "Non-atomic. Each matching rule reports success or an error independently.", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RuleTagRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Per-rule operation results", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BulkOperationResponse" + } + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + } + } + } + }, + "/rules/bulkstop": { + "post": { + "tags": [ + "Rules" + ], + "summary": "Bulk stop rules by tag", + "operationId": "bulkStopRules", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/rest.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/rule_tag.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/docs/en_US/api/restapi/rules.md" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "description": "Non-atomic. Each matching rule reports success or an error independently.", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RuleTagRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Per-rule operation results", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/BulkOperationResponse" + } + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + } + } + } + }, + "/ruletest": { + "post": { + "tags": [ + "Rule Test" + ], + "summary": "Create a temporary test rule", + "operationId": "createRuleTest", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/rest.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/docs/en_US/api/restapi/ruletest.md" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "description": "The test rule is not persisted and is automatically cleared after ten minutes. Connect to the returned port using SSE at /test/{id}, then start the test rule.", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/RuleTestRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Test rule id and separate SSE port. v2.4.1 writes the JSON object with a text/plain Content-Type.", + "content": { + "text/plain": { + "schema": { + "type": "string" + }, + "example": "{\"id\":\"uuid\",\"port\":10081}" + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + } + } + } + }, + "/ruletest/{name}/start": { + "post": { + "tags": [ + "Rule Test" + ], + "summary": "Start a temporary test rule", + "operationId": "startRuleTest", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/rest.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/docs/en_US/api/restapi/ruletest.md" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "parameters": [ + { + "$ref": "#/components/parameters/Name" + } + ], + "responses": { + "200": { + "description": "Test rule started", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "404": { + "$ref": "#/components/responses/NotFound" + } + } + } + }, + "/ruletest/{name}": { + "delete": { + "tags": [ + "Rule Test" + ], + "summary": "Stop and delete a temporary test rule", + "operationId": "deleteRuleTest", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/rest.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/docs/en_US/api/restapi/ruletest.md" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "parameters": [ + { + "$ref": "#/components/parameters/Name" + } + ], + "responses": { + "200": { + "description": "Test rule stopped", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + } + } + } + }, + "/rules/{name}/trace/start": { + "post": { + "tags": [ + "Tracing" + ], + "summary": "Enable tracing for a rule", + "operationId": "enableRuleTrace", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/rest.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/docs/en_US/api/restapi/trace.md" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "parameters": [ + { + "$ref": "#/components/parameters/Name" + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TraceEnableRequest" + }, + "example": { + "strategy": "head" + } + } + } + }, + "responses": { + "200": { + "description": "Tracing enabled; empty response body." + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "404": { + "$ref": "#/components/responses/NotFound" + } + } + } + }, + "/rules/{name}/trace/stop": { + "post": { + "tags": [ + "Tracing" + ], + "summary": "Disable tracing for a rule", + "operationId": "disableRuleTrace", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/rest.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/docs/en_US/api/restapi/trace.md" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "parameters": [ + { + "$ref": "#/components/parameters/Name" + } + ], + "responses": { + "200": { + "description": "Tracing disabled; empty response body." + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "404": { + "$ref": "#/components/responses/NotFound" + } + } + } + }, + "/trace/rule/{ruleID}": { + "get": { + "tags": [ + "Tracing" + ], + "summary": "List recent trace IDs for a rule", + "operationId": "listRuleTraceIds", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/rest.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/tracer.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/docs/en_US/api/restapi/trace.md" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "parameters": [ + { + "$ref": "#/components/parameters/RuleID" + }, + { + "name": "limit", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "format": "int64", + "minimum": 0 + }, + "description": "Maximum trace IDs. Invalid or omitted values are treated as 0 by the handler." + } + ], + "responses": { + "200": { + "description": "Trace IDs", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "404": { + "$ref": "#/components/responses/NotFound" + } + } + } + }, + "/trace/{id}": { + "get": { + "tags": [ + "Tracing" + ], + "summary": "Get a trace tree", + "operationId": "getTrace", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/rest.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/tracer.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/docs/en_US/api/restapi/trace.md" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "parameters": [ + { + "$ref": "#/components/parameters/Id" + } + ], + "responses": { + "200": { + "description": "Root trace span", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TraceSpan" + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "404": { + "$ref": "#/components/responses/NotFound" + } + } + } + }, + "/tracer": { + "post": { + "tags": [ + "Tracing" + ], + "summary": "Configure remote trace collection", + "operationId": "setTracer", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/rest.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/tracer.go" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/TracerRequest" + }, + "example": { + "service_name": "ekuiper", + "action": "start", + "collector_url": "http://otel-collector:4318" + } + } + } + }, + "responses": { + "200": { + "description": "Tracer configuration applied", + "content": { + "text/plain": { + "schema": { + "type": "string" + }, + "example": "success" + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + } + } + } + }, + "/ruleset/import": { + "post": { + "tags": [ + "Ruleset" + ], + "summary": "Import streams, tables, and rules", + "operationId": "importRuleset", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/rest.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/docs/en_US/api/restapi/ruleset.md" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "description": "Existing objects are not recreated. Exactly one of content or file is required.", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ImportReference" + }, + "examples": { + "content": { + "value": { + "content": "{\"streams\":{},\"tables\":{},\"rules\":{}}" + } + }, + "file": { + "value": { + "file": "file:///tmp/ekuiper-export.json" + } + } + } + } + } + }, + "responses": { + "200": { + "description": "Counts of imported definitions", + "content": { + "text/plain": { + "schema": { + "type": "string" + }, + "example": "imported 1 streams, 0 tables and 2 rules" + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + } + } + } + }, + "/ruleset/export": { + "post": { + "tags": [ + "Ruleset" + ], + "summary": "Export streams, tables, and rules", + "operationId": "exportRuleset", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/rest.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/docs/en_US/api/restapi/ruleset.md" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "responses": { + "200": { + "description": "Download named ekuiper_export.json", + "content": { + "application/octet-stream": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + } + } + } + }, + "/config/uploads": { + "get": { + "tags": [ + "Uploads" + ], + "summary": "List uploaded configuration files", + "operationId": "listUploads", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/rest.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/docs/en_US/api/restapi/uploads.md" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "responses": { + "200": { + "description": "Absolute server paths", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + } + } + }, + "post": { + "tags": [ + "Uploads" + ], + "summary": "Upload or replace a configuration file", + "operationId": "uploadConfigFile", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/rest.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/docs/en_US/api/restapi/uploads.md" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "description": "JSON accepts inline content or an HTTP file URL. Multipart upload accepts one uploadFile field. Files are stored below dataPath/uploads and overwrite the same name.", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UploadJsonRequest" + }, + "examples": { + "content": { + "value": { + "name": "my.json", + "content": "{\"hello\":\"world\"}" + } + }, + "url": { + "value": { + "name": "my.json", + "file": "http://127.0.0.1/my.json" + } + } + } + }, + "multipart/form-data": { + "schema": { + "type": "object", + "required": [ + "uploadFile" + ], + "properties": { + "uploadFile": { + "type": "string", + "format": "binary" + } + } + } + } + } + }, + "responses": { + "201": { + "description": "Absolute path of saved file", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + } + } + } + }, + "/config/uploads/{name}": { + "delete": { + "tags": [ + "Uploads" + ], + "summary": "Delete an uploaded configuration file", + "operationId": "deleteUpload", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/rest.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/docs/en_US/api/restapi/uploads.md" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "parameters": [ + { + "$ref": "#/components/parameters/Name" + } + ], + "responses": { + "200": { + "description": "File deleted", + "content": { + "text/plain": { + "schema": { + "type": "string" + }, + "example": "ok" + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "404": { + "$ref": "#/components/responses/NotFound" + } + } + } + }, + "/data/export": { + "get": { + "tags": [ + "Data" + ], + "summary": "Export all configuration as JSON", + "operationId": "exportData", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/rest.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/import_export.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/docs/en_US/api/restapi/data.md" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "responses": { + "200": { + "description": "Download named ekuiper_export.json", + "content": { + "application/octet-stream": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + } + } + }, + "post": { + "tags": [ + "Data" + ], + "summary": "Export selected rules and dependencies as JSON", + "operationId": "exportSelectedData", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/rest.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/import_export.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/docs/en_US/api/restapi/data.md" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "requestBody": { + "required": false, + "content": { + "application/json": { + "schema": { + "oneOf": [ + { + "type": "array", + "items": { + "type": "string" + }, + "description": "Array of rule IDs to export" + }, + { + "type": "object", + "properties": { + "rules": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + ] + }, + "example": [ + "rule_comprehensive" + ] + } + } + }, + "responses": { + "200": { + "description": "Filtered ekuiper_export.json download", + "content": { + "application/octet-stream": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + } + } + } + }, + "/data/import": { + "post": { + "tags": [ + "Data" + ], + "summary": "Import JSON configuration", + "operationId": "importData", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/rest.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/import_export.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/docs/en_US/api/restapi/data.md" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "description": "By default this resets existing configuration before import. Exactly one of content or file is required.", + "parameters": [ + { + "name": "stop", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "enum": [ + 1 + ] + }, + "description": "When 1, exit after import so static plugins/schemas can take effect." + }, + { + "name": "partial", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "enum": [ + 1 + ] + }, + "description": "When 1, retain existing data and merge/overwrite supported objects." + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ImportReference" + }, + "examples": { + "content": { + "value": { + "content": "{\"streams\":{},\"tables\":{},\"rules\":{}}" + } + }, + "file": { + "value": { + "file": "file:///tmp/ekuiper-export.json" + } + } + } + } + } + }, + "responses": { + "200": { + "description": "Import outcome", + "content": { + "text/plain": { + "schema": { + "type": "string", + "description": "JSON encoded as text/plain by the v2.4.1 handler." + }, + "x-decoded-schema": { + "$ref": "#/components/schemas/ImportConfigurationStatus" + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + } + } + } + }, + "/data/import/status": { + "get": { + "tags": [ + "Data" + ], + "summary": "Get latest import status", + "operationId": "getDataImportStatus", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/rest.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/import_export.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/docs/en_US/api/restapi/data.md" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "responses": { + "200": { + "description": "Error messages keyed by imported object name", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/Configuration" + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + } + } + } + }, + "/async/data/import": { + "post": { + "tags": [ + "Data" + ], + "summary": "Start an asynchronous JSON import", + "operationId": "startAsyncDataImport", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/rest.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/async_rest.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/docs/en_US/api/restapi/data.md" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "parameters": [ + { + "name": "stop", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "enum": [ + 1 + ] + }, + "description": "When 1, exit after import so static plugins/schemas can take effect." + }, + { + "name": "partial", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "enum": [ + 1 + ] + }, + "description": "When 1, retain existing data and merge/overwrite supported objects." + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ImportReference" + }, + "examples": { + "content": { + "value": { + "content": "{\"streams\":{},\"tables\":{},\"rules\":{}}" + } + }, + "file": { + "value": { + "file": "file:///tmp/ekuiper-export.json" + } + } + } + } + } + }, + "responses": { + "200": { + "description": "Registered task id", + "content": { + "text/plain": { + "schema": { + "type": "string", + "description": "JSON encoded as text/plain by the v2.4.1 handler." + }, + "example": "{\"id\":\"dataImport-1750000000\"}", + "x-decoded-schema": { + "$ref": "#/components/schemas/AsyncTaskId" + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + } + } + } + }, + "/async/task/{id}": { + "get": { + "tags": [ + "Data" + ], + "summary": "Get asynchronous task status", + "operationId": "getAsyncTaskStatus", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/rest.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/async_rest.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/docs/en_US/api/restapi/data.md" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "parameters": [ + { + "$ref": "#/components/parameters/Id" + } + ], + "responses": { + "200": { + "description": "Stored task status", + "content": { + "text/plain": { + "schema": { + "type": "string", + "description": "JSON encoded as text/plain by the v2.4.1 handler." + }, + "x-decoded-schema": { + "$ref": "#/components/schemas/AsyncTaskStatus" + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + } + } + } + }, + "/async/task/{id}/cancel": { + "post": { + "tags": [ + "Data" + ], + "summary": "Cancel an asynchronous task", + "operationId": "cancelAsyncTask", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/rest.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/async_rest.go" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "parameters": [ + { + "$ref": "#/components/parameters/Id" + } + ], + "responses": { + "200": { + "description": "Task cancelled", + "content": { + "text/plain": { + "schema": { + "type": "string" + }, + "example": "cancel success" + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + } + } + } + }, + "/v2/data/export": { + "get": { + "tags": [ + "Data" + ], + "summary": "Export configuration as YAML", + "operationId": "exportYamlData", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/rest.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/yaml_import_export.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/docs/en_US/api/restapi/data.md" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "responses": { + "200": { + "description": "Download named ekuiper_export.yaml", + "content": { + "application/octet-stream": { + "schema": { + "type": "string", + "format": "binary" + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + } + } + } + }, + "/v2/data/import": { + "post": { + "tags": [ + "Data" + ], + "summary": "Import YAML configuration", + "operationId": "importYamlData", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/rest.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/yaml_import_export.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/docs/en_US/api/restapi/data.md" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "description": "Exactly one of content or file is required. partial and reboot are decoded but marked TODO and have no effect in v2.4.1.", + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/YamlImportRequest" + }, + "example": { + "file": "file:///tmp/a.yaml" + } + } + } + }, + "responses": { + "200": { + "description": "YAML imported", + "content": { + "text/plain": { + "schema": { + "type": "string" + }, + "example": "success" + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + } + } + } + }, + "/connections": { + "get": { + "tags": [ + "Connections" + ], + "summary": "List connection information and status", + "operationId": "listConnections", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/rest.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/connection.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/docs/en_US/api/restapi/connection.md" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "parameters": [ + { + "name": "forceAll", + "in": "query", + "required": false, + "schema": { + "type": "boolean", + "default": false + }, + "description": "Include unnamed/internal connection metadata when true." + } + ], + "responses": { + "200": { + "description": "JSON-encoded connection array returned as text/plain", + "content": { + "text/plain": { + "schema": { + "type": "string" + }, + "example": "[{\"id\":\"connection-1\",\"typ\":\"mqtt\",\"props\":{\"server\":\"tcp://broker:1883\"},\"isNamed\":true,\"status\":\"connected\"}]" + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + } + }, + "description": "Returns all connection information and status. The v2.4.1 handler emits a text/plain Content-Type with a JSON array body and may include plaintext secret fields inside props." + }, + "post": { + "tags": [ + "Connections" + ], + "summary": "Create a named shared connection", + "operationId": "createConnection", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/rest.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/connection.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/docs/en_US/api/restapi/connection.md" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ConnectionRequest" + }, + "examples": { + "mqtt": { + "value": { + "id": "connection-1", + "typ": "mqtt", + "props": { + "server": "tcp://127.0.0.1:1883" + } + } + }, + "kafka": { + "value": { + "id": "kafka-1", + "typ": "kafka", + "props": { + "brokers": "127.0.0.1:9092", + "saslAuthType": "none" + } + } + } + } + } + } + }, + "responses": { + "201": { + "description": "Connection created", + "content": { + "text/plain": { + "schema": { + "type": "string" + }, + "example": "success" + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + } + } + } + }, + "/connections/{id}": { + "get": { + "tags": [ + "Connections" + ], + "summary": "Get a connection", + "operationId": "getConnection", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/rest.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/connection.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/docs/en_US/api/restapi/connection.md" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "parameters": [ + { + "$ref": "#/components/parameters/Id" + } + ], + "responses": { + "200": { + "description": "Connection details and status", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ConnectionResponse" + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "404": { + "$ref": "#/components/responses/NotFound" + } + } + }, + "put": { + "tags": [ + "Connections" + ], + "summary": "Update a connection", + "operationId": "updateConnection", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/rest.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/connection.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/docs/en_US/api/restapi/connection.md" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "description": "A connection referenced by a rule cannot be updated.", + "parameters": [ + { + "$ref": "#/components/parameters/Id" + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ConnectionRequest" + }, + "examples": { + "mqtt": { + "value": { + "id": "connection-1", + "typ": "mqtt", + "props": { + "server": "tcp://127.0.0.1:1883" + } + } + }, + "kafka": { + "value": { + "id": "kafka-1", + "typ": "kafka", + "props": { + "brokers": "127.0.0.1:9092", + "saslAuthType": "none" + } + } + } + } + } + } + }, + "responses": { + "200": { + "description": "Connection updated", + "content": { + "text/plain": { + "schema": { + "type": "string" + }, + "example": "success" + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "404": { + "$ref": "#/components/responses/NotFound" + } + } + }, + "delete": { + "tags": [ + "Connections" + ], + "summary": "Delete a connection", + "operationId": "deleteConnection", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/rest.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/connection.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/docs/en_US/api/restapi/connection.md" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "description": "A connection referenced by a rule cannot be deleted.", + "parameters": [ + { + "$ref": "#/components/parameters/Id" + } + ], + "responses": { + "200": { + "description": "Connection deleted", + "content": { + "text/plain": { + "schema": { + "type": "string" + }, + "example": "success" + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "404": { + "$ref": "#/components/responses/NotFound" + } + } + } + }, + "/schemas/{type}": { + "get": { + "tags": [ + "Schemas" + ], + "summary": "List schemas of a type", + "operationId": "listSchemas", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/schema_init.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/docs/en_US/api/restapi/schemas.md" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "parameters": [ + { + "$ref": "#/components/parameters/SchemaType" + } + ], + "responses": { + "200": { + "description": "Schema names", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + } + } + }, + "post": { + "tags": [ + "Schemas" + ], + "summary": "Create a schema", + "operationId": "createSchema", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/schema_init.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/docs/en_US/api/restapi/schemas.md" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "parameters": [ + { + "$ref": "#/components/parameters/SchemaType" + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SchemaCreateRequest" + }, + "examples": { + "content": { + "value": { + "name": "schema1", + "content": "message Book { required string title = 1; }" + } + }, + "file": { + "value": { + "name": "schema2", + "file": "file:///tmp/schema2.proto", + "version": "1756436910" + } + } + } + } + } + }, + "responses": { + "201": { + "description": "Schema created", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + } + } + } + }, + "/schemas/{type}/{name}": { + "get": { + "tags": [ + "Schemas" + ], + "summary": "Describe a schema", + "operationId": "getSchema", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/schema_init.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/docs/en_US/api/restapi/schemas.md" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "parameters": [ + { + "$ref": "#/components/parameters/SchemaType" + }, + { + "$ref": "#/components/parameters/Name" + } + ], + "responses": { + "200": { + "description": "Schema definition", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SchemaInfo" + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "404": { + "$ref": "#/components/responses/NotFound" + } + } + }, + "put": { + "tags": [ + "Schemas" + ], + "summary": "Create or update a schema", + "operationId": "updateSchema", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/schema_init.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/docs/en_US/api/restapi/schemas.md" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "description": "If version is supplied, it must be lexically greater than the stored version.", + "parameters": [ + { + "$ref": "#/components/parameters/SchemaType" + }, + { + "$ref": "#/components/parameters/Name" + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SchemaWriteRequest" + } + } + } + }, + "responses": { + "200": { + "description": "Schema updated", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "404": { + "$ref": "#/components/responses/NotFound" + } + } + }, + "delete": { + "tags": [ + "Schemas" + ], + "summary": "Delete a schema", + "operationId": "deleteSchema", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/schema_init.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/docs/en_US/api/restapi/schemas.md" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "parameters": [ + { + "$ref": "#/components/parameters/SchemaType" + }, + { + "$ref": "#/components/parameters/Name" + } + ], + "responses": { + "200": { + "description": "Schema deleted", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "404": { + "$ref": "#/components/responses/NotFound" + } + } + } + }, + "/schemas/{type}/{name}/upload": { + "put": { + "tags": [ + "Schemas" + ], + "summary": "Create or update a schema from a multipart file", + "operationId": "uploadSchema", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/schema_init.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/docs/en_US/api/restapi/schemas.md" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "description": "The file field must appear exactly once. version is optional, at most 4096 bytes, and may not repeat. The temporary upload is removed after processing.", + "parameters": [ + { + "$ref": "#/components/parameters/SchemaType" + }, + { + "$ref": "#/components/parameters/Name" + } + ], + "requestBody": { + "required": true, + "content": { + "multipart/form-data": { + "schema": { + "type": "object", + "required": [ + "file" + ], + "properties": { + "file": { + "type": "string", + "format": "binary" + }, + "version": { + "type": "string", + "maxLength": 4096 + } + } + } + } + } + }, + "responses": { + "200": { + "description": "Existing schema replaced", + "headers": { + "Location": { + "description": "Canonical schema resource path", + "schema": { + "type": "string" + } + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SchemaUploadResponse" + } + } + } + }, + "201": { + "description": "New schema created", + "headers": { + "Location": { + "description": "Canonical schema resource path", + "schema": { + "type": "string" + } + } + }, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/SchemaUploadResponse" + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "415": { + "description": "Content-Type is not multipart/form-data", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + }, + "500": { + "description": "Response encoding failed", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + } + } + } + } + } + }, + "/plugins/sources": { + "get": { + "tags": [ + "Plugins" + ], + "summary": "List native sources plugins", + "operationId": "listSourcesPlugins", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/plugin_init.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/docs/en_US/api/restapi/plugins.md" + ], + "x-ekuiper-build-tags": [ + "plugin", + "!core" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "responses": { + "200": { + "description": "Installed plugin names", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + } + } + }, + "post": { + "tags": [ + "Plugins" + ], + "summary": "Install a native sources plugin", + "operationId": "installSourcesPlugin", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/plugin_init.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/docs/en_US/api/restapi/plugins.md" + ], + "x-ekuiper-build-tags": [ + "plugin", + "!core" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PluginInstallRequest" + }, + "example": { + "name": "random", + "file": "file:///var/plugins/sources/random.zip" + } + } + } + }, + "responses": { + "201": { + "description": "Plugin installed", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + } + } + } + }, + "/plugins/sources/{name}": { + "get": { + "tags": [ + "Plugins" + ], + "summary": "Describe a native sources plugin", + "operationId": "getSourcesPlugin", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/plugin_init.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/docs/en_US/api/restapi/plugins.md" + ], + "x-ekuiper-build-tags": [ + "plugin", + "!core" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "parameters": [ + { + "$ref": "#/components/parameters/Name" + } + ], + "responses": { + "200": { + "description": "Plugin version and exported functions when applicable", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NativePluginInfo" + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "404": { + "$ref": "#/components/responses/NotFound" + } + } + }, + "put": { + "tags": [ + "Plugins" + ], + "summary": "Update a native sources plugin", + "operationId": "updateSourcesPlugin", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/plugin_init.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/docs/en_US/api/restapi/plugins.md" + ], + "x-ekuiper-build-tags": [ + "plugin", + "!core" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "description": "Native plugin updates require an eKuiper restart before the new binary takes effect.", + "parameters": [ + { + "$ref": "#/components/parameters/Name" + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PluginInstallRequest" + }, + "example": { + "name": "random", + "file": "file:///var/plugins/sources/random.zip" + } + } + } + }, + "responses": { + "200": { + "description": "Plugin updated; restart required", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "404": { + "$ref": "#/components/responses/NotFound" + } + } + }, + "delete": { + "tags": [ + "Plugins" + ], + "summary": "Delete a native sources plugin", + "operationId": "deleteSourcesPlugin", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/plugin_init.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/docs/en_US/api/restapi/plugins.md" + ], + "x-ekuiper-build-tags": [ + "plugin", + "!core" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "parameters": [ + { + "$ref": "#/components/parameters/Name" + }, + { + "name": "stop", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "enum": [ + 1 + ] + }, + "description": "When 1, stop eKuiper after deletion. Otherwise restart manually for the deletion to take effect." + } + ], + "responses": { + "200": { + "description": "Plugin deleted", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "404": { + "$ref": "#/components/responses/NotFound" + } + } + } + }, + "/plugins/sources/prebuild": { + "get": { + "tags": [ + "Plugins" + ], + "summary": "List installable native sources plugins", + "operationId": "listPrebuiltSourcesPlugins", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/plugin_init.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/docs/en_US/api/restapi/plugins.md" + ], + "x-ekuiper-build-tags": [ + "plugin", + "!core" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "description": "Available on Linux. URLs are constructed from pluginHosts, eKuiper version, distribution family, and architecture.", + "responses": { + "200": { + "description": "Plugin download URLs keyed by name", + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "format": "uri" + } + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + } + } + } + }, + "/plugins/sinks": { + "get": { + "tags": [ + "Plugins" + ], + "summary": "List native sinks plugins", + "operationId": "listSinksPlugins", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/plugin_init.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/docs/en_US/api/restapi/plugins.md" + ], + "x-ekuiper-build-tags": [ + "plugin", + "!core" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "responses": { + "200": { + "description": "Installed plugin names", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + } + } + }, + "post": { + "tags": [ + "Plugins" + ], + "summary": "Install a native sinks plugin", + "operationId": "installSinksPlugin", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/plugin_init.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/docs/en_US/api/restapi/plugins.md" + ], + "x-ekuiper-build-tags": [ + "plugin", + "!core" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PluginInstallRequest" + }, + "example": { + "name": "random", + "file": "file:///var/plugins/sinks/random.zip" + } + } + } + }, + "responses": { + "201": { + "description": "Plugin installed", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + } + } + } + }, + "/plugins/sinks/{name}": { + "get": { + "tags": [ + "Plugins" + ], + "summary": "Describe a native sinks plugin", + "operationId": "getSinksPlugin", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/plugin_init.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/docs/en_US/api/restapi/plugins.md" + ], + "x-ekuiper-build-tags": [ + "plugin", + "!core" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "parameters": [ + { + "$ref": "#/components/parameters/Name" + } + ], + "responses": { + "200": { + "description": "Plugin version and exported functions when applicable", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NativePluginInfo" + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "404": { + "$ref": "#/components/responses/NotFound" + } + } + }, + "put": { + "tags": [ + "Plugins" + ], + "summary": "Update a native sinks plugin", + "operationId": "updateSinksPlugin", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/plugin_init.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/docs/en_US/api/restapi/plugins.md" + ], + "x-ekuiper-build-tags": [ + "plugin", + "!core" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "description": "Native plugin updates require an eKuiper restart before the new binary takes effect.", + "parameters": [ + { + "$ref": "#/components/parameters/Name" + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PluginInstallRequest" + }, + "example": { + "name": "random", + "file": "file:///var/plugins/sinks/random.zip" + } + } + } + }, + "responses": { + "200": { + "description": "Plugin updated; restart required", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "404": { + "$ref": "#/components/responses/NotFound" + } + } + }, + "delete": { + "tags": [ + "Plugins" + ], + "summary": "Delete a native sinks plugin", + "operationId": "deleteSinksPlugin", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/plugin_init.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/docs/en_US/api/restapi/plugins.md" + ], + "x-ekuiper-build-tags": [ + "plugin", + "!core" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "parameters": [ + { + "$ref": "#/components/parameters/Name" + }, + { + "name": "stop", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "enum": [ + 1 + ] + }, + "description": "When 1, stop eKuiper after deletion. Otherwise restart manually for the deletion to take effect." + } + ], + "responses": { + "200": { + "description": "Plugin deleted", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "404": { + "$ref": "#/components/responses/NotFound" + } + } + } + }, + "/plugins/sinks/prebuild": { + "get": { + "tags": [ + "Plugins" + ], + "summary": "List installable native sinks plugins", + "operationId": "listPrebuiltSinksPlugins", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/plugin_init.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/docs/en_US/api/restapi/plugins.md" + ], + "x-ekuiper-build-tags": [ + "plugin", + "!core" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "description": "Available on Linux. URLs are constructed from pluginHosts, eKuiper version, distribution family, and architecture.", + "responses": { + "200": { + "description": "Plugin download URLs keyed by name", + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "format": "uri" + } + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + } + } + } + }, + "/plugins/functions": { + "get": { + "tags": [ + "Plugins" + ], + "summary": "List native functions plugins", + "operationId": "listFunctionsPlugins", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/plugin_init.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/docs/en_US/api/restapi/plugins.md" + ], + "x-ekuiper-build-tags": [ + "plugin", + "!core" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "responses": { + "200": { + "description": "Installed plugin names", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + } + } + }, + "post": { + "tags": [ + "Plugins" + ], + "summary": "Install a native functions plugin", + "operationId": "installFunctionsPlugin", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/plugin_init.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/docs/en_US/api/restapi/plugins.md" + ], + "x-ekuiper-build-tags": [ + "plugin", + "!core" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FunctionPluginInstallRequest" + }, + "example": { + "name": "random", + "file": "file:///var/plugins/functions/random.zip" + } + } + } + }, + "responses": { + "201": { + "description": "Plugin installed", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + } + } + } + }, + "/plugins/functions/{name}": { + "get": { + "tags": [ + "Plugins" + ], + "summary": "Describe a native functions plugin", + "operationId": "getFunctionsPlugin", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/plugin_init.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/docs/en_US/api/restapi/plugins.md" + ], + "x-ekuiper-build-tags": [ + "plugin", + "!core" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "parameters": [ + { + "$ref": "#/components/parameters/Name" + } + ], + "responses": { + "200": { + "description": "Plugin version and exported functions when applicable", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/NativePluginInfo" + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "404": { + "$ref": "#/components/responses/NotFound" + } + } + }, + "put": { + "tags": [ + "Plugins" + ], + "summary": "Update a native functions plugin", + "operationId": "updateFunctionsPlugin", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/plugin_init.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/docs/en_US/api/restapi/plugins.md" + ], + "x-ekuiper-build-tags": [ + "plugin", + "!core" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "description": "Native plugin updates require an eKuiper restart before the new binary takes effect.", + "parameters": [ + { + "$ref": "#/components/parameters/Name" + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FunctionPluginInstallRequest" + }, + "example": { + "name": "random", + "file": "file:///var/plugins/functions/random.zip" + } + } + } + }, + "responses": { + "200": { + "description": "Plugin updated; restart required", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "404": { + "$ref": "#/components/responses/NotFound" + } + } + }, + "delete": { + "tags": [ + "Plugins" + ], + "summary": "Delete a native functions plugin", + "operationId": "deleteFunctionsPlugin", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/plugin_init.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/docs/en_US/api/restapi/plugins.md" + ], + "x-ekuiper-build-tags": [ + "plugin", + "!core" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "parameters": [ + { + "$ref": "#/components/parameters/Name" + }, + { + "name": "stop", + "in": "query", + "required": false, + "schema": { + "type": "integer", + "enum": [ + 1 + ] + }, + "description": "When 1, stop eKuiper after deletion. Otherwise restart manually for the deletion to take effect." + } + ], + "responses": { + "200": { + "description": "Plugin deleted", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "404": { + "$ref": "#/components/responses/NotFound" + } + } + } + }, + "/plugins/functions/prebuild": { + "get": { + "tags": [ + "Plugins" + ], + "summary": "List installable native functions plugins", + "operationId": "listPrebuiltFunctionsPlugins", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/plugin_init.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/docs/en_US/api/restapi/plugins.md" + ], + "x-ekuiper-build-tags": [ + "plugin", + "!core" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "description": "Available on Linux. URLs are constructed from pluginHosts, eKuiper version, distribution family, and architecture.", + "responses": { + "200": { + "description": "Plugin download URLs keyed by name", + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": { + "type": "string", + "format": "uri" + } + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + } + } + } + }, + "/plugins/portables": { + "get": { + "tags": [ + "Plugins" + ], + "summary": "List portable plugins", + "operationId": "listPortablePlugins", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/portable_init.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/docs/en_US/api/restapi/plugins.md" + ], + "x-ekuiper-build-tags": [ + "portable", + "!core" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "responses": { + "200": { + "description": "Installed portable plugin names", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + } + } + }, + "post": { + "tags": [ + "Plugins" + ], + "summary": "Install a portable plugin", + "operationId": "installPortablePlugin", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/portable_init.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/docs/en_US/api/restapi/plugins.md" + ], + "x-ekuiper-build-tags": [ + "portable", + "!core" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PluginInstallRequest" + }, + "example": { + "name": "mirror", + "file": "file:///var/plugins/portables/mirror.zip" + } + } + } + }, + "responses": { + "201": { + "description": "Portable plugin installed", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + } + } + } + }, + "/plugins/portables/{name}": { + "get": { + "tags": [ + "Plugins" + ], + "summary": "Describe a portable plugin", + "operationId": "getPortablePlugin", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/portable_init.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/docs/en_US/api/restapi/plugins.md" + ], + "x-ekuiper-build-tags": [ + "portable", + "!core" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "parameters": [ + { + "$ref": "#/components/parameters/Name" + } + ], + "responses": { + "200": { + "description": "Portable package metadata and symbols", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PortablePluginInfo" + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "404": { + "$ref": "#/components/responses/NotFound" + } + } + }, + "put": { + "tags": [ + "Plugins" + ], + "summary": "Update a portable plugin", + "operationId": "updatePortablePlugin", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/portable_init.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/docs/en_US/api/restapi/plugins.md" + ], + "x-ekuiper-build-tags": [ + "portable", + "!core" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "description": "Portable updates take effect immediately, including for running rules.", + "parameters": [ + { + "$ref": "#/components/parameters/Name" + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/PluginInstallRequest" + }, + "example": { + "name": "mirror", + "file": "file:///var/plugins/portables/mirror.zip" + } + } + } + }, + "responses": { + "200": { + "description": "Portable plugin updated", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "404": { + "$ref": "#/components/responses/NotFound" + } + } + }, + "delete": { + "tags": [ + "Plugins" + ], + "summary": "Delete a portable plugin", + "operationId": "deletePortablePlugin", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/portable_init.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/docs/en_US/api/restapi/plugins.md" + ], + "x-ekuiper-build-tags": [ + "portable", + "!core" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "description": "Deletion takes effect immediately; rules using the plugin may report errors.", + "parameters": [ + { + "$ref": "#/components/parameters/Name" + } + ], + "responses": { + "200": { + "description": "Portable plugin deleted", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "404": { + "$ref": "#/components/responses/NotFound" + } + } + } + }, + "/plugins/portables/{name}/status": { + "get": { + "tags": [ + "Plugins" + ], + "summary": "Get portable plugin runtime status", + "operationId": "getPortablePluginStatus", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/portable_init.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/docs/en_US/api/restapi/plugins.md" + ], + "x-ekuiper-build-tags": [ + "portable", + "!core" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "description": "The tagged Markdown repeats the detail path, but the router registers this dedicated /status path.", + "parameters": [ + { + "$ref": "#/components/parameters/Name" + } + ], + "responses": { + "200": { + "description": "Runtime status and per-rule references", + "content": { + "text/plain": { + "schema": { + "type": "string", + "description": "JSON encoded as text/plain by the v2.4.1 handler." + }, + "x-decoded-schema": { + "$ref": "#/components/schemas/PortablePluginStatus" + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "404": { + "$ref": "#/components/responses/NotFound" + } + } + } + }, + "/plugins/udfs": { + "get": { + "tags": [ + "Plugins" + ], + "summary": "List UDF symbols exported by native function plugins", + "operationId": "listPluginUdfs", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/plugin_init.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/docs/en_US/api/restapi/plugins.md" + ], + "x-ekuiper-build-tags": [ + "plugin", + "!core" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "responses": { + "200": { + "description": "UDF symbol names", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + } + } + } + }, + "/plugins/udfs/{name}": { + "get": { + "tags": [ + "Plugins" + ], + "summary": "Find the native plugin that owns a UDF", + "operationId": "getPluginUdfOwner", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/plugin_init.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/docs/en_US/api/restapi/plugins.md" + ], + "x-ekuiper-build-tags": [ + "plugin", + "!core" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "parameters": [ + { + "$ref": "#/components/parameters/Name" + } + ], + "responses": { + "200": { + "description": "Symbol and owning plugin", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/UdfOwner" + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "404": { + "$ref": "#/components/responses/NotFound" + } + } + } + }, + "/plugins/functions/{name}/register": { + "post": { + "tags": [ + "Plugins" + ], + "summary": "Register symbols exported by a function plugin", + "operationId": "registerFunctionPluginSymbols", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/plugin_init.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/docs/en_US/api/restapi/plugins.md" + ], + "x-ekuiper-build-tags": [ + "plugin", + "!core" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "parameters": [ + { + "$ref": "#/components/parameters/Name" + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/FunctionRegistration" + }, + "example": { + "functions": [ + "func1", + "func2" + ] + } + } + } + }, + "responses": { + "200": { + "description": "Function list registered", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "404": { + "$ref": "#/components/responses/NotFound" + } + } + } + }, + "/udf/javascript": { + "get": { + "tags": [ + "UDF" + ], + "summary": "List JavaScript UDFs", + "operationId": "listJavascriptUdfs", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/script_init.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/docs/en_US/api/restapi/udf.md" + ], + "x-ekuiper-build-tags": [ + "script", + "full" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "responses": { + "200": { + "description": "Function ids", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + } + } + }, + "post": { + "tags": [ + "UDF" + ], + "summary": "Create a JavaScript UDF", + "operationId": "createJavascriptUdf", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/script_init.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/docs/en_US/api/restapi/udf.md" + ], + "x-ekuiper-build-tags": [ + "script", + "full" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/JavascriptUdf" + }, + "example": { + "id": "area", + "description": "calculate area", + "script": "function area(x, y) { return x * y; }", + "isAgg": false + } + } + } + }, + "responses": { + "201": { + "description": "JavaScript UDF created", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + } + } + } + }, + "/udf/javascript/{id}": { + "get": { + "tags": [ + "UDF" + ], + "summary": "Describe a JavaScript UDF", + "operationId": "getJavascriptUdf", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/script_init.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/docs/en_US/api/restapi/udf.md" + ], + "x-ekuiper-build-tags": [ + "script", + "full" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "parameters": [ + { + "$ref": "#/components/parameters/Id" + } + ], + "responses": { + "200": { + "description": "Function definition", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/JavascriptUdf" + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "404": { + "$ref": "#/components/responses/NotFound" + } + } + }, + "put": { + "tags": [ + "UDF" + ], + "summary": "Create or update a JavaScript UDF", + "operationId": "updateJavascriptUdf", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/script_init.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/docs/en_US/api/restapi/udf.md" + ], + "x-ekuiper-build-tags": [ + "script", + "full" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "description": "Running rules must be restarted to load the updated function.", + "parameters": [ + { + "$ref": "#/components/parameters/Id" + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/JavascriptUdf" + }, + "example": { + "id": "area", + "description": "calculate area", + "script": "function area(x, y) { return x * y; }", + "isAgg": false + } + } + } + }, + "responses": { + "200": { + "description": "JavaScript UDF updated", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "404": { + "$ref": "#/components/responses/NotFound" + } + } + }, + "delete": { + "tags": [ + "UDF" + ], + "summary": "Delete a JavaScript UDF", + "operationId": "deleteJavascriptUdf", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/script_init.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/docs/en_US/api/restapi/udf.md" + ], + "x-ekuiper-build-tags": [ + "script", + "full" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "parameters": [ + { + "$ref": "#/components/parameters/Id" + } + ], + "responses": { + "200": { + "description": "JavaScript UDF deleted", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "404": { + "$ref": "#/components/responses/NotFound" + } + } + } + }, + "/services": { + "get": { + "tags": [ + "Services" + ], + "summary": "List external services", + "operationId": "listServices", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/service_init.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/docs/en_US/api/restapi/services.md" + ], + "x-ekuiper-build-tags": [ + "service", + "!core" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "responses": { + "200": { + "description": "Service names", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + } + } + }, + "post": { + "tags": [ + "Services" + ], + "summary": "Register an external service", + "operationId": "createService", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/service_init.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/docs/en_US/api/restapi/services.md" + ], + "x-ekuiper-build-tags": [ + "service", + "!core" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ServiceRequest" + }, + "example": { + "name": "sample", + "file": "file:///var/services/sample.zip" + } + } + } + }, + "responses": { + "201": { + "description": "Service registered", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + } + } + } + }, + "/services/{name}": { + "get": { + "tags": [ + "Services" + ], + "summary": "Describe an external service", + "operationId": "getService", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/service_init.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/docs/en_US/api/restapi/services.md" + ], + "x-ekuiper-build-tags": [ + "service", + "!core" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "parameters": [ + { + "$ref": "#/components/parameters/Name" + } + ], + "responses": { + "200": { + "description": "Parsed service definition", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ServiceDetail" + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "404": { + "$ref": "#/components/responses/NotFound" + } + } + }, + "put": { + "tags": [ + "Services" + ], + "summary": "Update an external service", + "operationId": "updateService", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/service_init.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/docs/en_US/api/restapi/services.md" + ], + "x-ekuiper-build-tags": [ + "service", + "!core" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "parameters": [ + { + "$ref": "#/components/parameters/Name" + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ServiceUpdateRequest" + }, + "example": { + "name": "sample", + "file": "file:///var/services/sample.zip" + } + } + } + }, + "responses": { + "200": { + "description": "Service updated", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "404": { + "$ref": "#/components/responses/NotFound" + } + } + }, + "delete": { + "tags": [ + "Services" + ], + "summary": "Delete an external service", + "operationId": "deleteService", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/service_init.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/docs/en_US/api/restapi/services.md" + ], + "x-ekuiper-build-tags": [ + "service", + "!core" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "description": "Also deletes all functions defined by the service.", + "parameters": [ + { + "$ref": "#/components/parameters/Name" + } + ], + "responses": { + "200": { + "description": "Service deleted", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "404": { + "$ref": "#/components/responses/NotFound" + } + } + } + }, + "/services/functions": { + "get": { + "tags": [ + "Services" + ], + "summary": "List external functions", + "operationId": "listServiceFunctions", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/service_init.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/docs/en_US/api/restapi/services.md" + ], + "x-ekuiper-build-tags": [ + "service", + "!core" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "responses": { + "200": { + "description": "External function bindings", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/ExternalFunction" + } + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + } + } + } + }, + "/services/functions/{name}": { + "get": { + "tags": [ + "Services" + ], + "summary": "Describe an external function", + "operationId": "getServiceFunction", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/service_init.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/docs/en_US/api/restapi/services.md" + ], + "x-ekuiper-build-tags": [ + "service", + "!core" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "parameters": [ + { + "$ref": "#/components/parameters/Name" + } + ], + "responses": { + "200": { + "description": "External function binding", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ExternalFunction" + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "404": { + "$ref": "#/components/responses/NotFound" + } + } + } + }, + "/metadata/functions": { + "get": { + "tags": [ + "Metadata" + ], + "summary": "Get SQL function metadata", + "operationId": "getFunctionMetadata", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/meta_init.go" + ], + "x-ekuiper-build-tags": [ + "ui", + "!core" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "description": "Combines the JSON metadata documents installed under etc/functions and data/functions.", + "responses": { + "200": { + "description": "Function metadata documents", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/MetadataDocument" + } + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + } + } + } + }, + "/metadata/operators": { + "get": { + "tags": [ + "Metadata" + ], + "summary": "Get rule-graph operator metadata", + "operationId": "getOperatorMetadata", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/meta_init.go" + ], + "x-ekuiper-build-tags": [ + "ui", + "!core" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "description": "Combines the installed operator JSON documents.", + "responses": { + "200": { + "description": "Operator metadata documents", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/MetadataDocument" + } + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + } + } + } + }, + "/metadata/sinks": { + "get": { + "tags": [ + "Metadata" + ], + "summary": "List sink metadata summaries", + "operationId": "listSinkMetadata", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/meta_init.go" + ], + "x-ekuiper-build-tags": [ + "ui", + "!core" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "responses": { + "200": { + "description": "Installed sink metadata", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/MetadataPluginSummary" + } + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + } + } + } + }, + "/metadata/sinks/{name}": { + "get": { + "tags": [ + "Metadata" + ], + "summary": "Get sink metadata", + "operationId": "getSinkMetadata", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/meta_init.go" + ], + "x-ekuiper-build-tags": [ + "ui", + "!core" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "parameters": [ + { + "$ref": "#/components/parameters/Name" + }, + { + "$ref": "#/components/parameters/ContentLanguage" + } + ], + "responses": { + "200": { + "description": "UI metadata for the sink", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MetadataDocument" + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "404": { + "$ref": "#/components/responses/NotFound" + } + } + } + }, + "/metadata/sources": { + "get": { + "tags": [ + "Metadata" + ], + "summary": "List source metadata summaries", + "operationId": "listSourceMetadata", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/meta_init.go" + ], + "x-ekuiper-build-tags": [ + "ui", + "!core" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "parameters": [ + { + "name": "kind", + "in": "query", + "required": false, + "schema": { + "type": "string", + "enum": [ + "scan", + "lookup" + ], + "default": "scan" + }, + "description": "Source kind. Omitted and unrecognized values select scan sources." + } + ], + "responses": { + "200": { + "description": "Installed source metadata", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/MetadataPluginSummary" + } + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + } + } + } + }, + "/metadata/sources/{name}": { + "get": { + "tags": [ + "Metadata" + ], + "summary": "Get source metadata", + "operationId": "getSourceMetadata", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/meta_init.go" + ], + "x-ekuiper-build-tags": [ + "ui", + "!core" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "parameters": [ + { + "$ref": "#/components/parameters/Name" + }, + { + "$ref": "#/components/parameters/ContentLanguage" + } + ], + "responses": { + "200": { + "description": "UI metadata for the source", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MetadataDocument" + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "404": { + "$ref": "#/components/responses/NotFound" + } + } + } + }, + "/metadata/connections": { + "get": { + "tags": [ + "Metadata" + ], + "summary": "List connection metadata summaries", + "operationId": "listConnectionMetadata", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/meta_init.go" + ], + "x-ekuiper-build-tags": [ + "ui", + "!core" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "responses": { + "200": { + "description": "Installed shared-connection metadata", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "$ref": "#/components/schemas/MetadataPluginSummary" + } + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + } + } + } + }, + "/metadata/connections/{name}": { + "get": { + "tags": [ + "Metadata" + ], + "summary": "Get connection metadata", + "operationId": "getConnectionMetadata", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/meta_init.go" + ], + "x-ekuiper-build-tags": [ + "ui", + "!core" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "parameters": [ + { + "$ref": "#/components/parameters/Name" + }, + { + "$ref": "#/components/parameters/ContentLanguage" + } + ], + "responses": { + "200": { + "description": "UI metadata for the connection type", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/MetadataDocument" + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "404": { + "$ref": "#/components/responses/NotFound" + } + } + } + }, + "/metadata/sources/yaml/{name}": { + "get": { + "tags": [ + "Metadata" + ], + "summary": "List source configuration keys", + "operationId": "getSourceConfigKeys", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/meta_init.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/docs/en_US/api/restapi/configKey.md" + ], + "x-ekuiper-build-tags": [ + "ui", + "!core" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "description": "Configuration values keyed by configuration name. Despite the tagged Markdown claiming password/token redaction, the v2.4.1 handler does not call its secret-masking helper and live v2.4.1 responses can contain plaintext credentials. Protect this endpoint and never log or publish its response.", + "parameters": [ + { + "$ref": "#/components/parameters/Name" + }, + { + "$ref": "#/components/parameters/ContentLanguage" + } + ], + "responses": { + "200": { + "description": "Configuration-key map", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ConfigKeyMap" + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "404": { + "$ref": "#/components/responses/NotFound" + } + } + } + }, + "/metadata/sources/{name}/confKeys/{confKey}": { + "put": { + "tags": [ + "Metadata" + ], + "summary": "Create or replace a source configuration key", + "operationId": "putSourceConfigKey", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/meta_init.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/docs/en_US/api/restapi/configKey.md" + ], + "x-ekuiper-build-tags": [ + "ui", + "!core" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "parameters": [ + { + "$ref": "#/components/parameters/Name" + }, + { + "name": "confKey", + "in": "path", + "required": true, + "schema": { + "type": "string", + "minLength": 1 + } + }, + { + "$ref": "#/components/parameters/ContentLanguage" + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": true + }, + "example": { + "qos": 0, + "server": "tcp://127.0.0.1:1883" + } + } + } + }, + "responses": { + "200": { + "description": "Configuration stored; empty response body." + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + } + } + }, + "delete": { + "tags": [ + "Metadata" + ], + "summary": "Delete a source configuration key", + "operationId": "deleteSourceConfigKey", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/meta_init.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/docs/en_US/api/restapi/configKey.md" + ], + "x-ekuiper-build-tags": [ + "ui", + "!core" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "parameters": [ + { + "$ref": "#/components/parameters/Name" + }, + { + "name": "confKey", + "in": "path", + "required": true, + "schema": { + "type": "string", + "minLength": 1 + } + }, + { + "$ref": "#/components/parameters/ContentLanguage" + } + ], + "responses": { + "200": { + "description": "Configuration deleted; empty response body." + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "404": { + "$ref": "#/components/responses/NotFound" + } + } + } + }, + "/metadata/sinks/yaml/{name}": { + "get": { + "tags": [ + "Metadata" + ], + "summary": "List sink configuration keys", + "operationId": "getSinkConfigKeys", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/meta_init.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/docs/en_US/api/restapi/configKey.md" + ], + "x-ekuiper-build-tags": [ + "ui", + "!core" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "description": "Configuration values keyed by configuration name. Despite the tagged Markdown claiming password/token redaction, the v2.4.1 handler does not call its secret-masking helper and live v2.4.1 responses can contain plaintext credentials. Protect this endpoint and never log or publish its response.", + "parameters": [ + { + "$ref": "#/components/parameters/Name" + }, + { + "$ref": "#/components/parameters/ContentLanguage" + } + ], + "responses": { + "200": { + "description": "Configuration-key map", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ConfigKeyMap" + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "404": { + "$ref": "#/components/responses/NotFound" + } + } + } + }, + "/metadata/sinks/{name}/confKeys/{confKey}": { + "put": { + "tags": [ + "Metadata" + ], + "summary": "Create or replace a sink configuration key", + "operationId": "putSinkConfigKey", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/meta_init.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/docs/en_US/api/restapi/configKey.md" + ], + "x-ekuiper-build-tags": [ + "ui", + "!core" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "parameters": [ + { + "$ref": "#/components/parameters/Name" + }, + { + "name": "confKey", + "in": "path", + "required": true, + "schema": { + "type": "string", + "minLength": 1 + } + }, + { + "$ref": "#/components/parameters/ContentLanguage" + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": true + }, + "example": { + "qos": 0, + "server": "tcp://127.0.0.1:1883" + } + } + } + }, + "responses": { + "200": { + "description": "Configuration stored; empty response body." + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + } + } + }, + "delete": { + "tags": [ + "Metadata" + ], + "summary": "Delete a sink configuration key", + "operationId": "deleteSinkConfigKey", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/meta_init.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/docs/en_US/api/restapi/configKey.md" + ], + "x-ekuiper-build-tags": [ + "ui", + "!core" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "parameters": [ + { + "$ref": "#/components/parameters/Name" + }, + { + "name": "confKey", + "in": "path", + "required": true, + "schema": { + "type": "string", + "minLength": 1 + } + }, + { + "$ref": "#/components/parameters/ContentLanguage" + } + ], + "responses": { + "200": { + "description": "Configuration deleted; empty response body." + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "404": { + "$ref": "#/components/responses/NotFound" + } + } + } + }, + "/metadata/connections/yaml/{name}": { + "get": { + "tags": [ + "Metadata" + ], + "summary": "List connection configuration keys", + "operationId": "getConnectionConfigKeys", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/meta_init.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/docs/en_US/api/restapi/configKey.md" + ], + "x-ekuiper-build-tags": [ + "ui", + "!core" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "description": "Configuration values keyed by configuration name. Despite the tagged Markdown claiming password/token redaction, the v2.4.1 handler does not call its secret-masking helper and live v2.4.1 responses can contain plaintext credentials. Protect this endpoint and never log or publish its response.", + "parameters": [ + { + "$ref": "#/components/parameters/Name" + }, + { + "$ref": "#/components/parameters/ContentLanguage" + } + ], + "responses": { + "200": { + "description": "Configuration-key map", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ConfigKeyMap" + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "404": { + "$ref": "#/components/responses/NotFound" + } + } + } + }, + "/metadata/connections/{name}/confKeys/{confKey}": { + "put": { + "tags": [ + "Metadata" + ], + "summary": "Create or replace a connection configuration key", + "operationId": "putConnectionConfigKey", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/meta_init.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/docs/en_US/api/restapi/configKey.md" + ], + "x-ekuiper-build-tags": [ + "ui", + "!core" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "parameters": [ + { + "$ref": "#/components/parameters/Name" + }, + { + "name": "confKey", + "in": "path", + "required": true, + "schema": { + "type": "string", + "minLength": 1 + } + }, + { + "$ref": "#/components/parameters/ContentLanguage" + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": true + }, + "example": { + "qos": 0, + "server": "tcp://127.0.0.1:1883" + } + } + } + }, + "responses": { + "200": { + "description": "Configuration stored; empty response body." + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + } + } + }, + "delete": { + "tags": [ + "Metadata" + ], + "summary": "Delete a connection configuration key", + "operationId": "deleteConnectionConfigKey", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/meta_init.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/docs/en_US/api/restapi/configKey.md" + ], + "x-ekuiper-build-tags": [ + "ui", + "!core" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "parameters": [ + { + "$ref": "#/components/parameters/Name" + }, + { + "name": "confKey", + "in": "path", + "required": true, + "schema": { + "type": "string", + "minLength": 1 + } + }, + { + "$ref": "#/components/parameters/ContentLanguage" + } + ], + "responses": { + "200": { + "description": "Configuration deleted; empty response body." + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + }, + "404": { + "$ref": "#/components/responses/NotFound" + } + } + } + }, + "/metadata/resource": { + "get": { + "tags": [ + "Metadata" + ], + "summary": "Get source resource configurations", + "operationId": "getSourceResourceConfigurations", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/meta_init.go" + ], + "x-ekuiper-build-tags": [ + "ui", + "!core" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "parameters": [ + { + "name": "sourceType", + "in": "query", + "required": false, + "schema": { + "type": "string" + }, + "description": "When supplied, include configurations whose sourceType property equals this value; otherwise include all source configurations." + } + ], + "responses": { + "200": { + "description": "Configurations grouped by plugin and key", + "content": { + "text/plain": { + "schema": { + "type": "string", + "description": "JSON encoded as text/plain by the v2.4.1 handler." + }, + "x-decoded-schema": { + "$ref": "#/components/schemas/SourceResourceConfig" + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + } + }, + "description": "Returns stored source configurations grouped by plugin and key. Values may contain plaintext credentials; protect this endpoint and never log or publish responses." + } + }, + "/metadata/resources": { + "get": { + "tags": [ + "Metadata" + ], + "summary": "List updatable source and sink resources", + "operationId": "listUpdatableResources", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/meta_init.go" + ], + "x-ekuiper-build-tags": [ + "ui", + "!core" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "parameters": [ + { + "$ref": "#/components/parameters/ContentLanguage" + } + ], + "responses": { + "200": { + "description": "Updatable resource ids grouped by source/sink", + "content": { + "text/plain": { + "schema": { + "type": "string", + "description": "JSON encoded as text/plain by the v2.4.1 handler." + }, + "x-decoded-schema": { + "$ref": "#/components/schemas/UpdatableResources" + } + } + } + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + } + } + } + }, + "/metadata/sources/connection/{name}": { + "post": { + "tags": [ + "Metadata" + ], + "summary": "Test source connectivity", + "operationId": "testSourceConnection", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/meta_init.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/docs/en_US/api/restapi/connection.md" + ], + "x-ekuiper-build-tags": [ + "ui", + "!core" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "description": "The JSON properties are specific to the named connector type.", + "parameters": [ + { + "$ref": "#/components/parameters/Name" + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": true + }, + "example": { + "url": "mysql://root@127.0.0.1:4000/test" + } + } + } + }, + "responses": { + "200": { + "description": "Connectivity check succeeded; empty response body." + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + } + } + } + }, + "/metadata/sinks/connection/{name}": { + "post": { + "tags": [ + "Metadata" + ], + "summary": "Test sink connectivity", + "operationId": "testSinkConnection", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/meta_init.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/docs/en_US/api/restapi/connection.md" + ], + "x-ekuiper-build-tags": [ + "ui", + "!core" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "description": "The JSON properties are specific to the named connector type.", + "parameters": [ + { + "$ref": "#/components/parameters/Name" + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": true + }, + "example": { + "url": "mysql://root@127.0.0.1:4000/test" + } + } + } + }, + "responses": { + "200": { + "description": "Connectivity check succeeded; empty response body." + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + } + } + } + }, + "/metadata/lookups/connection/{name}": { + "post": { + "tags": [ + "Metadata" + ], + "summary": "Test lookup source connectivity", + "operationId": "testLookupSourceConnection", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/meta_init.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/docs/en_US/api/restapi/connection.md" + ], + "x-ekuiper-build-tags": [ + "ui", + "!core" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "description": "The JSON properties are specific to the named connector type.", + "parameters": [ + { + "$ref": "#/components/parameters/Name" + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "type": "object", + "additionalProperties": true + }, + "example": { + "url": "mysql://root@127.0.0.1:4000/test" + } + } + } + }, + "responses": { + "200": { + "description": "Connectivity check succeeded; empty response body." + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + } + } + } + }, + "/streams/{name}/data": { + "post": { + "summary": "Ingest JSON, CSV, or binary event payload into a stream", + "parameters": [ + { + "name": "name", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Data ingested successfully" + } + } + } + }, + "/tables/{name}/data": { + "post": { + "summary": "Insert or update lookup rows in a table", + "parameters": [ + { + "name": "name", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Table data ingested successfully" + } + } + } + }, + "/rules/{name}/errors": { + "get": { + "summary": "Get dead-letter queue (DLQ) statistics and recent poison-pill records for a rule", + "parameters": [ + { + "name": "name", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "DLQ statistics and recent error envelopes" + } + } + }, + "delete": { + "summary": "Clear buffered dead-letter queue (DLQ) error records for a rule", + "parameters": [ + { + "name": "name", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "DLQ errors cleared" + } + } + } + }, + "/rules/{name}/dlq": { + "get": { + "summary": "Alias of GET /rules/{name}/errors", + "parameters": [ + { + "name": "name", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "DLQ statistics and recent error envelopes" + } + } + }, + "delete": { + "summary": "Alias of DELETE /rules/{name}/errors", + "parameters": [ + { + "name": "name", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "DLQ errors cleared" + } + } + } + }, + "/declarative/reload": { + "post": { + "summary": "Trigger atomic reconciliation and hot-reload of declarative GitOps manifests", + "responses": { + "200": { + "description": "Reconciliation report" + }, + "400": { + "description": "Validation or mode error" + } + } + } + }, + "/v1/metrics": { + "post": { + "summary": "Ingest OpenTelemetry (OTLP/HTTP JSON) metrics batch", + "responses": { + "200": { + "description": "OTLP partialSuccess response" + } + } + } + }, + "/v1/logs": { + "post": { + "summary": "Ingest OpenTelemetry (OTLP/HTTP JSON) logs batch", + "responses": { + "200": { + "description": "OTLP partialSuccess response" + } + } + } + }, + "/v1/traces": { + "post": { + "summary": "Ingest OpenTelemetry (OTLP/HTTP JSON) traces batch", + "responses": { + "200": { + "description": "OTLP partialSuccess response" + } + } + } + }, + "/ui": { + "get": { + "summary": "Embedded self-contained web inspection console", + "responses": { + "200": { + "description": "HTML web console" + } + } + } + }, + "/plugins/wasm": { + "get": { + "summary": "List registered WebAssembly plugin modules", + "responses": { + "200": { + "description": "Array of WASM module names" + } + } + }, + "post": { + "summary": "Register a WebAssembly plugin module from file or base64 bytecode", + "responses": { + "201": { + "description": "Registered WASM module and exported UDFs" + } + } + } + }, + "/plugins/wasm/{name}": { + "delete": { + "summary": "Unregister a WebAssembly plugin module", + "parameters": [ + { + "name": "name", + "in": "path", + "required": true, + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Module unregistered" + } + } + } + }, + "/config": { + "get": { + "tags": [ + "System" + ], + "summary": "Get system configuration (alias for /configs)", + "operationId": "getConfigAlias", + "security": [ + {}, + { + "JwtToken": [] + } + ], + "responses": { + "200": { + "description": "System configuration object", + "content": { + "application/json": { + "schema": { + "type": "object" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + } + } + }, + "patch": { + "tags": [ + "System" + ], + "summary": "Dynamically reload supported configuration", + "operationId": "patchConfigs", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/rest.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/import_export.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/docs/en_US/api/restapi/configs.md" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DynamicConfig" + }, + "example": { + "debug": true, + "consoleLog": true, + "fileLog": true, + "timezone": "UTC" + } + } + } + }, + "responses": { + "204": { + "description": "Configuration updated; no response body." + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + } + } + } + } + }, + "components": { + "securitySchemes": { + "JwtToken": { + "type": "apiKey", + "in": "header", + "name": "Authorization", + "description": "Optional eKuiper RS256 JWT authentication. Supply the raw compact JWT without a Bearer prefix. The token audience must contain eKuiper." + } + }, + "parameters": { + "Name": { + "name": "name", + "in": "path", + "required": true, + "schema": { + "type": "string", + "minLength": 1 + } + }, + "Id": { + "name": "id", + "in": "path", + "required": true, + "schema": { + "type": "string", + "minLength": 1 + } + }, + "RuleID": { + "name": "ruleID", + "in": "path", + "required": true, + "schema": { + "type": "string", + "minLength": 1 + } + }, + "SchemaType": { + "name": "type", + "in": "path", + "required": true, + "schema": { + "type": "string", + "enum": [ + "protobuf", + "custom" + ] + } + }, + "ContentLanguage": { + "name": "Content-Language", + "in": "header", + "required": false, + "schema": { + "type": "string", + "default": "en_US" + }, + "description": "Metadata language, for example en-US or zh-CN." + } + }, + "responses": { + "BadRequest": { + "description": "Bad request", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + }, + "text/plain": { + "schema": { + "type": "string", + "description": "JSON error envelope serialized through http.Error." + } + } + } + }, + "NotFound": { + "description": "Resource not found", + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/ErrorResponse" + } + }, + "text/plain": { + "schema": { + "type": "string" + } + } + } + }, + "Unauthorized": { + "description": "Missing or invalid JWT when authentication is enabled", + "content": { + "text/plain": { + "schema": { + "type": "string" + } + } + } + } + }, + "schemas": { + "ErrorResponse": { + "type": "object", + "description": "Error envelope emitted by eKuiper. Most handlers serialize this JSON value through http.Error, so the HTTP Content-Type may be text/plain even though the payload is JSON.", + "required": [ + "error", + "message" + ], + "properties": { + "error": { + "type": "integer", + "description": "eKuiper internal error code." + }, + "message": { + "type": "string" + } + }, + "example": { + "error": 1001, + "message": "Invalid body: bad request" + } + }, + "SystemInfo": { + "type": "object", + "required": [ + "version", + "os", + "arch", + "upTimeSeconds", + "memoryTotal" + ], + "properties": { + "version": { + "type": "string", + "example": "2.4.1" + }, + "os": { + "type": "string", + "example": "linux" + }, + "arch": { + "type": "string", + "example": "amd64" + }, + "upTimeSeconds": { + "type": "integer", + "format": "int64" + }, + "cpuUsage": { + "type": "string" + }, + "memoryUsed": { + "type": "string" + }, + "memoryTotal": { + "type": "string" + } + } + }, + "BatchRequest": { + "type": "object", + "required": [ + "method", + "path" + ], + "properties": { + "method": { + "type": "string", + "example": "GET" + }, + "path": { + "type": "string", + "example": "/streams" + }, + "body": { + "type": "string", + "description": "Nested request body encoded as a string." + } + } + }, + "BatchResponse": { + "type": "object", + "required": [ + "code" + ], + "properties": { + "code": { + "type": "integer" + }, + "response": { + "type": "string" + }, + "error": { + "type": "string" + } + } + }, + "DynamicConfig": { + "type": "object", + "properties": { + "logLevel": { + "type": "string" + }, + "debug": { + "type": "boolean" + }, + "consoleLog": { + "type": "boolean" + }, + "fileLog": { + "type": "boolean" + }, + "timezone": { + "type": "string", + "example": "UTC" + }, + "metricsDumpConfig": { + "type": "object", + "properties": { + "enable": { + "type": "boolean" + } + } + } + }, + "additionalProperties": false + }, + "StatementRequest": { + "type": "object", + "required": [ + "sql" + ], + "properties": { + "sql": { + "type": "string", + "example": "CREATE STREAM demo () WITH (DATASOURCE=\"demo\", FORMAT=\"json\")" + } + }, + "additionalProperties": false + }, + "DatasourceDetail": { + "type": "object", + "required": [ + "name", + "type", + "format" + ], + "properties": { + "name": { + "type": "string" + }, + "type": { + "type": "string" + }, + "format": { + "type": "string" + } + } + }, + "DatasourceOptions": { + "type": "object", + "properties": { + "datasource": { + "type": "string" + }, + "key": { + "type": "string" + }, + "format": { + "type": "string" + }, + "confKey": { + "type": "string" + }, + "type": { + "type": "string" + }, + "strictValidation": { + "type": "boolean" + }, + "timestamp": { + "type": "string" + }, + "timestampFormat": { + "type": "string" + }, + "shared": { + "type": "boolean" + }, + "schemaid": { + "type": "string" + }, + "version": { + "type": "string" + }, + "extra": { + "type": "string" + }, + "temp": { + "type": "boolean" + }, + "retainSize": { + "type": "integer" + }, + "kind": { + "type": "string", + "enum": [ + "scan", + "lookup" + ] + }, + "delimiter": { + "type": "string" + } + }, + "additionalProperties": true + }, + "AstFieldType": { + "oneOf": [ + { + "type": "string", + "description": "Basic eKuiper type such as bigint, float, string, datetime, boolean or bytea." + }, + { + "type": "object", + "additionalProperties": true, + "description": "Complex array or struct type description." + } + ] + }, + "StreamField": { + "type": "object", + "required": [ + "Name", + "FieldType" + ], + "properties": { + "Name": { + "type": "string" + }, + "FieldType": { + "$ref": "#/components/schemas/AstFieldType" + } + } + }, + "DatasourceDescription": { + "type": "object", + "required": [ + "Name", + "StreamFields", + "Options", + "StreamType" + ], + "properties": { + "Name": { + "type": "string" + }, + "StreamFields": { + "type": "array", + "nullable": true, + "items": { + "$ref": "#/components/schemas/StreamField" + } + }, + "Options": { + "$ref": "#/components/schemas/DatasourceOptions" + }, + "StreamType": { + "type": "integer", + "description": "Internal stream/table kind code." + }, + "Statement": { + "type": "object", + "nullable": true, + "additionalProperties": true, + "description": "Parsed statement metadata; normally null in REST responses." + } + } + }, + "JsonSchemaField": { + "type": "object", + "properties": { + "type": { + "type": "string" + }, + "items": { + "$ref": "#/components/schemas/JsonSchemaField" + }, + "properties": { + "type": "object", + "additionalProperties": { + "$ref": "#/components/schemas/JsonSchemaField" + } + }, + "hasIndex": { + "type": "boolean" + }, + "index": { + "type": "integer" + }, + "selected": { + "type": "boolean" + } + } + }, + "RuleOptions": { + "type": "object", + "properties": { + "debug": { + "type": "boolean" + }, + "logFilename": { + "type": "string" + }, + "isEventTime": { + "type": "boolean" + }, + "lateTolerance": { + "oneOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ] + }, + "concurrency": { + "type": "integer" + }, + "bufferLength": { + "type": "integer" + }, + "sendMetaToSink": { + "type": "boolean" + }, + "sendNilField": { + "type": "boolean" + }, + "sendError": { + "type": "boolean" + }, + "qos": { + "type": "integer", + "enum": [ + 0, + 1, + 2 + ] + }, + "checkpointInterval": { + "oneOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ] + }, + "restartStrategy": { + "type": "object", + "properties": { + "attempts": { + "type": "integer" + } + } + }, + "cron": { + "type": "string" + }, + "duration": { + "type": "string" + }, + "cronDatetimeRange": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": true + } + }, + "planOptimizeStrategy": { + "type": "object", + "additionalProperties": true + }, + "notifySub": { + "type": "boolean" + }, + "disableBufferFullDiscard": { + "type": "boolean" + }, + "enableSaveStateBeforeStop": { + "type": "boolean" + }, + "forceExitTimeout": { + "oneOf": [ + { + "type": "integer" + }, + { + "type": "string" + } + ] + }, + "experiment": { + "type": "object", + "properties": { + "useSliceTuple": { + "type": "boolean" + } + } + } + }, + "additionalProperties": false + }, + "RuleGraph": { + "type": "object", + "required": [ + "nodes", + "topo" + ], + "properties": { + "nodes": { + "type": "object", + "additionalProperties": { + "type": "object", + "required": [ + "type", + "nodeType", + "props", + "ui" + ], + "properties": { + "type": { + "type": "string" + }, + "nodeType": { + "type": "string" + }, + "props": { + "type": "object", + "additionalProperties": true + }, + "ui": { + "type": "object", + "additionalProperties": true + } + } + } + }, + "topo": { + "$ref": "#/components/schemas/RuleTopology" + } + } + }, + "Rule": { + "type": "object", + "properties": { + "triggered": { + "type": "boolean", + "default": true + }, + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "version": { + "type": "string", + "description": "Lexically compared version used to control replacement." + }, + "temp": { + "type": "boolean" + }, + "sql": { + "type": "string" + }, + "graph": { + "$ref": "#/components/schemas/RuleGraph" + }, + "actions": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": true + } + }, + "options": { + "$ref": "#/components/schemas/RuleOptions" + }, + "tags": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "oneOf": [ + { + "required": [ + "sql", + "actions" + ] + }, + { + "required": [ + "graph" + ] + } + ], + "example": { + "id": "rule1", + "sql": "SELECT * FROM demo", + "actions": [ + { + "log": {} + } + ] + } + }, + "RuleListItem": { + "type": "object", + "required": [ + "id", + "name", + "status", + "version", + "trace", + "tags" + ], + "properties": { + "id": { + "type": "string" + }, + "name": { + "type": "string" + }, + "status": { + "type": "string" + }, + "version": { + "type": "string" + }, + "trace": { + "type": "boolean" + }, + "tags": { + "type": "array", + "nullable": true, + "items": { + "type": "string" + } + } + } + }, + "RuleStatus": { + "type": "object", + "required": [ + "status", + "message", + "lastStartTimestamp", + "lastStopTimestamp", + "nextStartTimestamp" + ], + "properties": { + "status": { + "type": "string" + }, + "message": { + "type": "string" + }, + "lastStartTimestamp": { + "type": "integer", + "format": "int64" + }, + "lastStopTimestamp": { + "type": "integer", + "format": "int64" + }, + "nextStartTimestamp": { + "type": "integer", + "format": "int64" + }, + "lastException": { + "type": "string", + "description": "Last recorded exception message (camelCase alias)" + }, + "last_exception": { + "type": "string", + "description": "Last recorded exception message (snake_case alias)" + }, + "exceptionsTotal": { + "type": "integer", + "format": "int64", + "description": "Total exception count (camelCase)" + }, + "exceptions_total": { + "type": "integer", + "format": "int64", + "description": "Total exception count (snake_case)" + }, + "sourceRecordsInTotal": { + "type": "integer", + "format": "int64", + "description": "Total input records read across all sources" + }, + "sourceRecordsFilteredTotal": { + "type": "integer", + "format": "int64", + "description": "Input records filtered out by WHERE clause" + }, + "sinkRecordsOutTotal": { + "type": "integer", + "format": "int64", + "description": "Total output records dispatched to sinks" + }, + "sinkRecordsEnqueuedTotal": { + "type": "integer", + "format": "int64", + "description": "Output records enqueued in sink buffer" + }, + "sinkRecordsFailedTotal": { + "type": "integer", + "format": "int64", + "description": "Sink operations that failed after dequeue" + }, + "droppedByPolicyTotal": { + "type": "integer", + "format": "int64", + "description": "Records dropped by buffer overflow/backpressure policy" + }, + "sinkQueueHighWater": { + "type": "integer", + "description": "Peak observed sink queue depth" + }, + "sinkBlockedMicrosTotal": { + "type": "integer", + "format": "int64", + "description": "Microseconds execution loop blocked on sink capacity" + }, + "dlqRecordsTotal": { + "type": "integer", + "format": "int64", + "description": "Total records routed to dead-letter queue" + } + }, + "additionalProperties": true + }, + "RuleExceptionStatus": { + "type": "object", + "required": [ + "status", + "last_exception", + "exceptions_total" + ], + "properties": { + "status": { + "type": "string" + }, + "last_exception": { + "type": "string" + }, + "exceptions_total": { + "type": "integer", + "format": "int64" + } + } + }, + "RuleTopology": { + "type": "object", + "required": [ + "sources", + "edges" + ], + "properties": { + "sources": { + "type": "array", + "items": { + "type": "string" + } + }, + "edges": { + "type": "object", + "additionalProperties": { + "type": "array", + "items": {} + } + } + } + }, + "RuleValidationResponse": { + "type": "object", + "required": [ + "valid", + "sources" + ], + "properties": { + "valid": { + "type": "boolean", + "enum": [ + true + ] + }, + "sources": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "RuleTagRequest": { + "type": "object", + "required": [ + "tags" + ], + "properties": { + "tags": { + "type": "array", + "items": { + "type": "string" + } + } + }, + "additionalProperties": false, + "example": { + "tags": [ + "t1", + "t2" + ] + } + }, + "RuleTagMatchResponse": { + "type": "object", + "properties": { + "rules": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "BulkOperationResponse": { + "type": "object", + "required": [ + "ruleId", + "success" + ], + "properties": { + "ruleId": { + "type": "string" + }, + "success": { + "type": "boolean" + }, + "error": { + "type": "string" + } + } + }, + "RuleStateUpdateRequest": { + "type": "object", + "required": [ + "type", + "params" + ], + "properties": { + "type": { + "type": "integer", + "enum": [ + 1 + ], + "description": "Only update-offset (1) is implemented in v2.4.1." + }, + "params": { + "type": "object", + "required": [ + "streamName", + "input" + ], + "properties": { + "streamName": { + "type": "string" + }, + "input": { + "type": "object", + "additionalProperties": true + } + } + } + } + }, + "TraceEnableRequest": { + "type": "object", + "required": [ + "strategy" + ], + "properties": { + "strategy": { + "type": "string", + "enum": [ + "always", + "head" + ] + } + }, + "additionalProperties": false + }, + "TracerRequest": { + "type": "object", + "required": [ + "action" + ], + "properties": { + "service_name": { + "type": "string" + }, + "action": { + "type": "string", + "enum": [ + "start", + "stop" + ] + }, + "collector_url": { + "type": "string", + "format": "uri" + } + }, + "additionalProperties": false + }, + "TraceLink": { + "type": "object", + "properties": { + "TraceID": { + "type": "string" + } + } + }, + "TraceSpan": { + "type": "object", + "required": [ + "name", + "traceID", + "spanID", + "startTime", + "endTime", + "ruleID", + "ChildSpan" + ], + "properties": { + "name": { + "type": "string" + }, + "traceID": { + "type": "string" + }, + "spanID": { + "type": "string" + }, + "parentSpanID": { + "type": "string" + }, + "attribute": { + "type": "object", + "additionalProperties": true + }, + "links": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TraceLink" + } + }, + "startTime": { + "type": "string", + "format": "date-time" + }, + "endTime": { + "type": "string", + "format": "date-time" + }, + "ruleID": { + "type": "string" + }, + "ChildSpan": { + "type": "array", + "items": { + "$ref": "#/components/schemas/TraceSpan" + } + } + } + }, + "ImportReference": { + "type": "object", + "properties": { + "content": { + "type": "string" + }, + "file": { + "type": "string", + "description": "http(s) or file URI readable by the eKuiper server." + } + }, + "oneOf": [ + { + "required": [ + "content" + ] + }, + { + "required": [ + "file" + ] + } + ], + "additionalProperties": false + }, + "Configuration": { + "type": "object", + "required": [ + "streams", + "tables", + "rules", + "nativePlugins", + "portablePlugins", + "sourceConfig", + "sinkConfig", + "connectionConfig", + "Service", + "Schema", + "uploads", + "scripts" + ], + "properties": { + "streams": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "tables": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "rules": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "nativePlugins": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "portablePlugins": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "sourceConfig": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "sinkConfig": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "connectionConfig": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "Service": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "Schema": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "uploads": { + "type": "object", + "additionalProperties": { + "type": "string" + } + }, + "scripts": { + "type": "object", + "additionalProperties": { + "type": "string" + } + } + } + }, + "ImportConfigurationStatus": { + "type": "object", + "required": [ + "ErrorMsg", + "ConfigResponse" + ], + "properties": { + "ErrorMsg": { + "type": "string" + }, + "ConfigResponse": { + "$ref": "#/components/schemas/Configuration" + } + } + }, + "AsyncTaskId": { + "type": "object", + "required": [ + "id" + ], + "properties": { + "id": { + "type": "string" + } + } + }, + "AsyncTaskStatus": { + "type": "object", + "required": [ + "id", + "status", + "message", + "createdTimestamp", + "updatedTimestamp" + ], + "properties": { + "id": { + "type": "string" + }, + "status": { + "type": "string", + "enum": [ + "register", + "running", + "finish", + "error", + "cancel" + ] + }, + "message": { + "type": "string" + }, + "createdTimestamp": { + "type": "integer", + "format": "int64" + }, + "updatedTimestamp": { + "type": "integer", + "format": "int64" + } + } + }, + "ConnectionRequest": { + "type": "object", + "required": [ + "id", + "typ", + "props" + ], + "properties": { + "id": { + "type": "string" + }, + "typ": { + "type": "string", + "enum": [ + "mqtt", + "nng", + "httppush", + "websocket", + "edgex", + "sql", + "kafka" + ] + }, + "props": { + "type": "object", + "additionalProperties": true + } + } + }, + "ConnectionResponse": { + "type": "object", + "required": [ + "id", + "typ", + "props", + "isNamed" + ], + "properties": { + "id": { + "type": "string" + }, + "typ": { + "type": "string" + }, + "props": { + "type": "object", + "additionalProperties": true, + "description": "Connector-specific properties. eKuiper returns stored values and may expose plaintext credentials; protect this endpoint and never log or publish responses." + }, + "isNamed": { + "type": "boolean" + }, + "status": { + "type": "string" + }, + "err": { + "type": "string" + }, + "refCount": { + "type": "integer" + } + } + }, + "MockSource": { + "type": "object", + "properties": { + "data": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": true + } + }, + "interval": { + "type": "integer" + }, + "loop": { + "type": "boolean" + } + } + }, + "RuleTestRequest": { + "type": "object", + "required": [ + "id", + "sql" + ], + "properties": { + "id": { + "type": "string" + }, + "sql": { + "type": "string" + }, + "mockSource": { + "type": "object", + "additionalProperties": { + "$ref": "#/components/schemas/MockSource" + } + }, + "sinkProps": { + "type": "object", + "additionalProperties": true + } + } + }, + "PluginInstallRequest": { + "type": "object", + "required": [ + "name", + "file" + ], + "properties": { + "name": { + "type": "string" + }, + "file": { + "type": "string", + "description": "http(s) or file URI of a plugin zip." + }, + "shellParas": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "FunctionPluginInstallRequest": { + "allOf": [ + { + "$ref": "#/components/schemas/PluginInstallRequest" + }, + { + "type": "object", + "properties": { + "functions": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + ] + }, + "NativePluginInfo": { + "type": "object", + "required": [ + "name", + "version" + ], + "properties": { + "name": { + "type": "string" + }, + "version": { + "type": "string" + }, + "functions": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "FunctionRegistration": { + "type": "object", + "properties": { + "functions": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "UdfOwner": { + "type": "object", + "required": [ + "name", + "plugin" + ], + "properties": { + "name": { + "type": "string" + }, + "plugin": { + "type": "string" + } + } + }, + "PortablePluginInfo": { + "type": "object", + "required": [ + "name", + "version", + "language", + "executable", + "sources", + "sinks", + "functions" + ], + "properties": { + "name": { + "type": "string" + }, + "version": { + "type": "string" + }, + "language": { + "type": "string", + "enum": [ + "go", + "python" + ] + }, + "executable": { + "type": "string" + }, + "virtualEnvType": { + "type": "string" + }, + "env": { + "type": "string" + }, + "sources": { + "type": "array", + "items": { + "type": "string" + } + }, + "sinks": { + "type": "array", + "items": { + "type": "string" + } + }, + "functions": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + "PortablePluginStatus": { + "type": "object", + "required": [ + "refCount", + "status", + "errMsg" + ], + "properties": { + "refCount": { + "type": "object", + "additionalProperties": { + "type": "integer" + } + }, + "status": { + "type": "string", + "enum": [ + "running", + "initializing", + "error", + "stop" + ] + }, + "errMsg": { + "type": "string" + } + } + }, + "SchemaInfo": { + "type": "object", + "required": [ + "type", + "name" + ], + "properties": { + "type": { + "type": "string", + "enum": [ + "protobuf", + "custom" + ] + }, + "name": { + "type": "string" + }, + "content": { + "type": "string" + }, + "file": { + "type": "string" + }, + "soFile": { + "type": "string" + }, + "version": { + "type": "string", + "description": "Updates are accepted only when lexically greater than the stored version." + } + } + }, + "SchemaUploadResponse": { + "type": "object", + "required": [ + "type", + "name" + ], + "properties": { + "type": { + "type": "string" + }, + "name": { + "type": "string" + } + } + }, + "JavascriptUdf": { + "type": "object", + "required": [ + "id", + "description", + "script", + "isAgg" + ], + "properties": { + "id": { + "type": "string" + }, + "description": { + "type": "string" + }, + "script": { + "type": "string" + }, + "isAgg": { + "type": "boolean" + } + } + }, + "ServiceRequest": { + "type": "object", + "required": [ + "name", + "file" + ], + "properties": { + "name": { + "type": "string" + }, + "file": { + "type": "string", + "description": "http(s) or file URI of the service zip." + } + } + }, + "ExternalFunction": { + "type": "object", + "required": [ + "ServiceName", + "InterfaceName", + "Addr", + "MethodName", + "FuncName" + ], + "properties": { + "ServiceName": { + "type": "string" + }, + "InterfaceName": { + "type": "string" + }, + "Addr": { + "type": "string" + }, + "MethodName": { + "type": "string" + }, + "FuncName": { + "type": "string" + } + } + }, + "ServiceDetail": { + "type": "object", + "properties": { + "About": { + "type": "object", + "additionalProperties": true + }, + "Interfaces": { + "type": "object", + "additionalProperties": { + "type": "object", + "additionalProperties": true + } + } + } + }, + "MetadataPluginSummary": { + "type": "object", + "required": [ + "name", + "about" + ], + "properties": { + "name": { + "type": "string" + }, + "about": { + "type": "object", + "additionalProperties": true + }, + "type": { + "type": "string" + } + } + }, + "MetadataDocument": { + "type": "object", + "additionalProperties": true + }, + "ConfigKeyMap": { + "type": "object", + "additionalProperties": { + "type": "object", + "additionalProperties": true + }, + "description": "Stored configuration values keyed by configuration name. In v2.4.1 these responses can contain plaintext credentials; do not expose, log, or publish them." + }, + "UploadJsonRequest": { + "type": "object", + "required": [ + "name" + ], + "properties": { + "name": { + "type": "string" + }, + "content": { + "type": "string" + }, + "file": { + "type": "string", + "description": "HTTP file URL." + } + }, + "anyOf": [ + { + "required": [ + "content" + ] + }, + { + "required": [ + "file" + ] + } + ], + "additionalProperties": false + }, + "SchemaWriteRequest": { + "type": "object", + "properties": { + "name": { + "type": "string" + }, + "content": { + "type": "string" + }, + "file": { + "type": "string", + "description": "http(s) or file URI; may reference a schema file or supported zip archive." + }, + "soFile": { + "type": "string", + "description": "Shared-object URI required for a custom schema." + }, + "version": { + "type": "string" + } + }, + "description": "For protobuf, exactly one of content or file is required. For custom, soFile is required. On PUT, omitted type/name retain the path values; supplied values must match the path.", + "additionalProperties": false, + "anyOf": [ + { + "required": [ + "content" + ] + }, + { + "required": [ + "file" + ] + }, + { + "required": [ + "soFile" + ] + } + ] + }, + "YamlImportRequest": { + "type": "object", + "properties": { + "content": { + "type": "string", + "description": "YAML configuration text." + }, + "file": { + "type": "string", + "description": "http(s) or file URI of YAML configuration." + }, + "partial": { + "type": "boolean", + "description": "Decoded but not implemented in v2.4.1." + }, + "reboot": { + "type": "boolean", + "description": "Decoded but not implemented in v2.4.1." + } + }, + "oneOf": [ + { + "required": [ + "content" + ] + }, + { + "required": [ + "file" + ] + } + ], + "additionalProperties": false + }, + "UpdatableResources": { + "type": "object", + "required": [ + "sources", + "sinks" + ], + "properties": { + "sources": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": { + "type": "string", + "description": "Plugin type that owns the resource id." + } + } + }, + "sinks": { + "type": "array", + "items": { + "type": "object", + "additionalProperties": { + "type": "string", + "description": "Plugin type that owns the resource id." + } + } + } + } + }, + "SourceResourceConfig": { + "type": "object", + "additionalProperties": { + "type": "object", + "additionalProperties": { + "type": "object", + "additionalProperties": true + } + } + }, + "RuleCreateRequest": { + "allOf": [ + { + "$ref": "#/components/schemas/Rule" + }, + { + "type": "object", + "required": [ + "id" + ] + } + ] + }, + "SchemaCreateRequest": { + "allOf": [ + { + "$ref": "#/components/schemas/SchemaWriteRequest" + }, + { + "type": "object", + "required": [ + "name" + ] + } + ] + }, + "ServiceUpdateRequest": { + "type": "object", + "required": [ + "file" + ], + "properties": { + "name": { + "type": "string", + "description": "Optional on update; the handler uses the path name." + }, + "file": { + "type": "string", + "description": "http(s) or file URI of the service zip." + } + }, + "additionalProperties": false + } + } + } +} \ No newline at end of file diff --git a/docs/en_US/public/screenshots/openapi_swagger_ui.png b/docs/en_US/public/screenshots/openapi_swagger_ui.png new file mode 100644 index 000000000..ee54633b5 Binary files /dev/null and b/docs/en_US/public/screenshots/openapi_swagger_ui.png differ diff --git a/docs/en_US/public/screenshots/web_console_dashboard.png b/docs/en_US/public/screenshots/web_console_dashboard.png new file mode 100644 index 000000000..59128e10d Binary files /dev/null and b/docs/en_US/public/screenshots/web_console_dashboard.png differ diff --git a/docs/en_US/public/swagger.html b/docs/en_US/public/swagger.html new file mode 100644 index 000000000..c483e39a6 --- /dev/null +++ b/docs/en_US/public/swagger.html @@ -0,0 +1,157 @@ + + + + + rekuiper REST API — OpenAPI 3.0 Interactive Explorer + + + + + + + +
+ + + + + + diff --git a/docs/en_US/resources/arch.png b/docs/en_US/resources/arch.png deleted file mode 100644 index 431403212..000000000 Binary files a/docs/en_US/resources/arch.png and /dev/null differ diff --git a/docs/en_US/resources/inc_p1.png b/docs/en_US/resources/inc_p1.png deleted file mode 100644 index 4fc947aa8..000000000 Binary files a/docs/en_US/resources/inc_p1.png and /dev/null differ diff --git a/docs/en_US/resources/inc_p2.png b/docs/en_US/resources/inc_p2.png deleted file mode 100644 index 09066ef55..000000000 Binary files a/docs/en_US/resources/inc_p2.png and /dev/null differ diff --git a/docs/en_US/resources/inc_p3.png b/docs/en_US/resources/inc_p3.png deleted file mode 100644 index e1ada904e..000000000 Binary files a/docs/en_US/resources/inc_p3.png and /dev/null differ diff --git a/docs/en_US/resources/inc_p4.png b/docs/en_US/resources/inc_p4.png deleted file mode 100644 index 6a9dc78ef..000000000 Binary files a/docs/en_US/resources/inc_p4.png and /dev/null differ diff --git a/docs/en_US/resources/traced.png b/docs/en_US/resources/traced.png deleted file mode 100644 index 82492c16a..000000000 Binary files a/docs/en_US/resources/traced.png and /dev/null differ diff --git a/docs/en_US/resources/un_traced.png b/docs/en_US/resources/un_traced.png deleted file mode 100644 index ee4f0ffea..000000000 Binary files a/docs/en_US/resources/un_traced.png and /dev/null differ diff --git a/docs/en_US/solutions/mcp-industrial-ai-agents.md b/docs/en_US/solutions/mcp-industrial-ai-agents.md new file mode 100644 index 000000000..2e9e73a8d --- /dev/null +++ b/docs/en_US/solutions/mcp-industrial-ai-agents.md @@ -0,0 +1,122 @@ +--- +title: Industrial AI Agents with Model Context Protocol +description: Connect Claude, Cursor, and autonomous AI agents to physical edge IoT gateways using rekuiper-mcp and the Model Context Protocol. +keywords: MCP server for IoT, Model Context Protocol industrial IoT, AI agent MQTT SQL, physical AI edge gateway +--- + +# Industrial AI Agents with Model Context Protocol (rekuiper-mcp) + +Physical AI and industrial edge operations require AI agents to inspect telemetry streams, validate SQL transformations, and manage gateway pipelines. **`rekuiper-mcp`** is a native Rust server implementing the [Model Context Protocol (MCP)](https://modelcontextprotocol.io/). It connects generative AI models (Claude, Cursor, custom agents) directly to live edge gateways over standard JSON-RPC 2.0. + +--- + +## Architecture: Bridging AI Models and OT Telemetry + +Large Language Models (LLMs) cannot safely interact directly with raw Modbus PLC registers or MQTT wildcards. `rekuiper-mcp` provides a structured, sandboxed boundary: + +![rekuiper-mcp Architecture](/diagrams/mcp_architecture.svg) + +### How It Works +1. **Model Context Protocol (JSON-RPC):** The AI assistant communicates with `rekuiper-mcp` via `stdio` transport. +2. **Schema & Stream Inspection:** The assistant queries available edge streams, schema types, and active rules. +3. **Offline SQL Validation (`ruletest`):** The assistant tests generated SQL against real or simulated message payloads before deploying. +4. **Controlled Gateway Deployment:** Once verified, the assistant deploys the rule through `rekuiper`'s REST API. + +--- + +## Client Setup and Configuration + +Add `rekuiper-mcp` to your MCP client configuration file: + +### 1. Antigravity IDE & Cursor (`.cursor/mcp.json` or `mcp_config.json`) + +```json +{ + "mcpServers": { + "rekuiper": { + "command": "rekuiper-mcp", + "args": [ + "--server-url", + "http://127.0.0.1:9081" + ], + "env": { + "RUST_LOG": "info" + } + } + } +} +``` + +### 2. Claude Desktop (`claude_desktop_config.json`) + +* **Path on macOS:** `~/Library/Application Support/Claude/claude_desktop_config.json` +* **Path on Windows:** `%APPDATA%\Claude\claude_desktop_config.json` + +```json +{ + "mcpServers": { + "rekuiper": { + "command": "rekuiper-mcp", + "args": [ + "--server-url", + "http://127.0.0.1:9081" + ] + } + } +} +``` + +--- + +## Built-in MCP Tools for Industrial Agents + +`rekuiper-mcp` exposes a complete toolset for autonomous agents: + +| Tool Name | Parameters | Purpose | +| :--- | :--- | :--- | +| `list_streams` | None | Discovers all active input telemetry streams on the gateway. | +| `describe_stream` | `name` | Returns schema fields, data types, and transport configuration (MQTT, Modbus, OPC-UA). | +| `validate_sql` | `sql` | Checks SQL syntax and type safety offline using the `rekuiper` query parser. | +| `dry_run_rule` | `sql`, `mock_data` | Simulates rule execution against synthetic or captured payloads using `ruletest`. | +| `list_rules` | None | Lists running, paused, and stopped stream processing rules. | +| `create_rule` | `id`, `sql`, `actions` | Deploys a verified streaming pipeline to the gateway. | +| `get_rule_metrics` | `id` | Inspects messages in, messages out, processing latency, and dead-letter queue counters. | + +--- + +## Real-World Conversational Example + +Here is a real conversation between an industrial automation engineer and an AI assistant connected via `rekuiper-mcp`: + +> **Engineer:** +> *"Inspect our live boiler telemetry stream. If temperature exceeds 120°C for three consecutive readings, write an alert rule that publishes to `alerts/boiler_overheat` and logs an emergency record."* + +> **AI Assistant (via `rekuiper-mcp`):** +> 1. *Invokes `describe_stream("boiler_telemetry")` to check sensor property names.* +> 2. *Writes SQL query:* +> ```sql +> SELECT deviceId, temperature, meta(topic) AS source_topic +> FROM boiler_telemetry +> WHERE temperature > 120.0 +> GROUP BY deviceId, SLIDINGWINDOW(ss, 10) +> HAVING count(*) >= 3 +> ``` +> 3. *Invokes `dry_run_rule` with 5 mock events to verify that normal readings are ignored and 3 spikes trigger exactly one alert.* +> 4. *Invokes `create_rule("boiler_overheat_monitor", sql, actions)`.* +> 5. *Reports: "Rule `boiler_overheat_monitor` is now active on the gateway. Current status: Running, 0 errors."* + +--- + +## Safety and Guardrails for Industrial Operations + +* **Zero Direct Process Control:** AI models never write directly to raw hardware registers. All actuation passes through strictly validated `rekuiper` sink definitions. +* **Deterministic Verification:** Every generated rule must pass `validate_sql` and `dry_run_rule` before registration. +* **Poison-Pill Protection:** Malformed payloads generated during testing route to Dead-Letter Queues without halting existing rules. + +--- + +## Next Steps + +* [Read the Full MCP Specification](../mcp/overview.md) +* [Explore Rule Testing and Debugging](../api/restapi/ruletest.md) +* [Review Dead-Letter Queues and Poison-Pill Isolation](../guide/rules/error_handling_dlq.md) diff --git a/docs/en_US/solutions/reduce-cloud-iot-costs.md b/docs/en_US/solutions/reduce-cloud-iot-costs.md new file mode 100644 index 000000000..989e4acec --- /dev/null +++ b/docs/en_US/solutions/reduce-cloud-iot-costs.md @@ -0,0 +1,171 @@ +--- +title: Reduce Cloud IoT Costs by 95% at the Edge +description: Cut AWS IoT Core and Azure IoT Hub bills by 95% using edge SQL downsampling, anomaly filters, and Snappy-compressed Apache Parquet archiving. +keywords: Reduce AWS IoT Core bill, Azure IoT Hub cost optimization, edge MQTT downsampling, MQTT to Parquet edge +--- + +# Reduce Cloud IoT Ingestion Costs by 95% at the Edge + +Industrial IoT systems generate massive telemetry streams. Connecting sensors directly to cloud brokers creates exponential data transfer bills. `rekuiper` sits on the edge gateway, downsampling and filtering streams locally so you send only meaningful data to the cloud. + +--- + +## The Cloud Ingestion Arithmetic: The Raw Telemetry Problem + +Consider a standard industrial manufacturing deployment: + +* **Fleet Size:** 100 industrial machines. +* **Tag Density:** 50 sensor tags per machine (temperatures, vibrations, motor currents). +* **Sampling Rate:** 10 Hz (10 samples per second per tag). + +``` +Calculations: +• Messages per second: 100 machines × 50 tags × 10 Hz = 50,000 messages/sec +• Messages per day: 50,000 msg/s × 86,400 seconds = 4.32 billion messages/day +• Messages per month: 4.32B × 30 days = 129.6 billion messages/month +``` + +### The Financial Impact on Cloud Brokers +Cloud providers meter ingestion and routing per message block (typically 5 KB blocks): +* **AWS IoT Core Pricing:** ~$1.00 to $1.50 per million messages. +* **Monthly Ingestion Cost:** 129.6 billion messages × $1.00/million = **$129,600 per month**. + +Over 90% of those messages contain static or repetitive values where motor temperatures and pressures remain unchanged. + +--- + +## The `rekuiper` 3-Step Edge Solution + +Deploying `rekuiper` on your local edge gateways reduces message volume by 95% to 98% while preserving sub-millisecond local safety alerts. + +``` +[ 50,000 msg/s Raw Telemetry ] + │ + ▼ + ┌───────────────────────┐ + │ rekuiper Edge Engine │ + │ • Tumbling Windows │ + │ • Change Detection │ + │ • Parquet Archiving │ + └───────────────────────┘ + │ │ + │ (98% drop)│ (< 1ms alert) + ▼ ▼ + [ Cloud MQTT ] [ Local PLC Actuation ] + (100 msg/s) (Immediate shutdown) +``` + +--- + +### Step 1: Tumbling Time Windows (Downsampling) + +Aggregate 60 seconds of high-frequency sensor readings into a single statistical summary row: + +```sql +SELECT + deviceId, + avg(temperature) AS avg_temp, + max(temperature) AS max_temp, + min(temperature) AS min_temp, + stddev(vibration) AS stddev_vib, + count(*) AS sample_count +FROM machine_stream +GROUP BY + deviceId, + TUMBLINGWINDOW(ss, 60) +``` + +**Result:** Replaces 600 raw messages per minute with 1 summary row per minute. +**Volume Reduction:** **99.83% drop in message count.** + +--- + +### Step 2: Local Safety Alerts with Zero Cloud Latency + +Do not route telemetry to the cloud to decide if a motor is overheating. Evaluate safety thresholds on the gateway: + +```sql +SELECT + deviceId, + temperature, + vibration, + meta(topic) AS source_topic +FROM machine_stream +WHERE temperature > 85.0 OR vibration > 4.5 +``` + +Configure this rule to publish directly to a local MQTT alert topic or call a PLC Modbus actuator sink: + +```json +{ + "id": "critical_overheat_alert", + "sql": "SELECT deviceId, temperature FROM machine_stream WHERE temperature > 85.0", + "actions": [ + { + "mqtt": { + "server": "tcp://127.0.0.1:1883", + "topic": "alerts/critical" + } + }, + { + "modbus": { + "address": "192.168.1.50:502", + "register": 40001, + "value": 1 + } + } + ] +} +``` + +**Result:** Emergency shutdowns trigger in sub-milliseconds without depending on cellular or WAN links. + +--- + +### Step 3: Columnar Apache Parquet Archiving + +High-resolution raw data is valuable for model training and historical audits, but does not require instant cloud transmission. + +Write raw telemetry directly to Snappy-compressed **Apache Parquet files** on local gateway storage: + +```json +{ + "id": "archive_raw_parquet", + "sql": "SELECT * FROM machine_stream", + "actions": [ + { + "file": { + "path": "/data/archives/telemetry.parquet", + "format": "parquet", + "rollingCount": 50000, + "rollingInterval": 3600 + } + } + ] +} +``` + +* **Arrow Schema Inference:** `rekuiper` infers the Arrow schema automatically from your JSON/Protobuf streams. +* **Snappy Compression:** Reduces disk footprint by 75–85% compared to raw JSON Lines. +* **Batched Egress:** Upload one consolidated Parquet file per hour via batch HTTPS object storage, eliminating per-message broker fees. + +--- + +## Financial Comparison: Before and After `rekuiper` + +| Parameter | Without `rekuiper` (Direct Cloud Stream) | With `rekuiper` (Edge SQL + Parquet) | +| :--- | :--- | :--- | +| **Ingested Messages to Cloud** | 129.6 billion / month | **1.29 billion / month** (Downsampled) | +| **Monthly Cloud Broker Fee** | ~$129,600 / month | **~$1,290 / month** | +| **Egress Bandwidth Usage** | ~1.8 TB / month (Raw JSON) | **~180 GB / month** (Snappy Parquet) | +| **Local Alert Latency** | 250–1,200 ms (Cloud round-trip) | **< 1 ms** (Evaluated in-memory) | +| **Offline Resilience** | Data lost during link drop | Buffered in disk sink cache | +| **Net Monthly Savings** | Baseline ($0) | **$128,310 / month (99% Cost Cut)** | + +--- + +## Next Steps + +* [Explore Windowing SQL Functions](../concepts/streaming/windowing.md) +* [Configure Apache Parquet Sinks](../guide/sinks/overview.md) +* [Review Offline Sink Caching & Resilience](../guide/rules/error_handling_dlq.md) diff --git a/docs/en_US/sqls/resources/hoppingWindow.png b/docs/en_US/sqls/resources/hoppingWindow.png deleted file mode 100644 index ee5c8d712..000000000 Binary files a/docs/en_US/sqls/resources/hoppingWindow.png and /dev/null differ diff --git a/docs/en_US/sqls/resources/sessionWindow.png b/docs/en_US/sqls/resources/sessionWindow.png deleted file mode 100644 index 65b2cd401..000000000 Binary files a/docs/en_US/sqls/resources/sessionWindow.png and /dev/null differ diff --git a/docs/en_US/sqls/resources/slidingCountWindow_1.png b/docs/en_US/sqls/resources/slidingCountWindow_1.png deleted file mode 100644 index e5eba0dab..000000000 Binary files a/docs/en_US/sqls/resources/slidingCountWindow_1.png and /dev/null differ diff --git a/docs/en_US/sqls/resources/slidingCountWindow_2.png b/docs/en_US/sqls/resources/slidingCountWindow_2.png deleted file mode 100644 index 89d5d2a7e..000000000 Binary files a/docs/en_US/sqls/resources/slidingCountWindow_2.png and /dev/null differ diff --git a/docs/en_US/sqls/resources/slidingWindow-delay.png b/docs/en_US/sqls/resources/slidingWindow-delay.png deleted file mode 100644 index 493234a0a..000000000 Binary files a/docs/en_US/sqls/resources/slidingWindow-delay.png and /dev/null differ diff --git a/docs/en_US/sqls/resources/slidingWindow.png b/docs/en_US/sqls/resources/slidingWindow.png deleted file mode 100644 index 2fd23655a..000000000 Binary files a/docs/en_US/sqls/resources/slidingWindow.png and /dev/null differ diff --git a/docs/en_US/sqls/resources/tumblingCountWindow.png b/docs/en_US/sqls/resources/tumblingCountWindow.png deleted file mode 100644 index f470a0319..000000000 Binary files a/docs/en_US/sqls/resources/tumblingCountWindow.png and /dev/null differ diff --git a/docs/en_US/sqls/resources/tumblingWindow.png b/docs/en_US/sqls/resources/tumblingWindow.png deleted file mode 100644 index d3051bd81..000000000 Binary files a/docs/en_US/sqls/resources/tumblingWindow.png and /dev/null differ diff --git a/docs/en_US/sqls/windows.md b/docs/en_US/sqls/windows.md index 3fb4c9132..a04a7d4fd 100644 --- a/docs/en_US/sqls/windows.md +++ b/docs/en_US/sqls/windows.md @@ -29,7 +29,7 @@ Temporal windows align to natural clock boundaries. For example, a 10-second win Tumbling windows divide streams into fixed, non-overlapping, contiguous time intervals. Each event belongs to exactly one window: -![Tumbling Window Diagram](./resources/tumblingWindow.png) +![Tumbling Window Diagram](/diagrams/windows/tumbling_window.svg) ```sql SELECT count(*) FROM demo GROUP BY ID, TUMBLINGWINDOW(ss, 10); @@ -39,7 +39,7 @@ SELECT count(*) FROM demo GROUP BY ID, TUMBLINGWINDOW(ss, 10); Hopping windows advance forward in time by a fixed hop interval. Windows can overlap, allowing events to belong to multiple windows: -![Hopping Window Diagram](./resources/hoppingWindow.png) +![Hopping Window Diagram](/diagrams/windows/hopping_window.svg) ```sql SELECT count(*) FROM demo GROUP BY ID, HOPPINGWINDOW(ss, 10, 5); @@ -49,7 +49,7 @@ SELECT count(*) FROM demo GROUP BY ID, HOPPINGWINDOW(ss, 10, 5); Sliding windows evaluate and emit results only when a new event arrives. Each window contains the events that occurred within the specified duration preceding the trigger event: -![Sliding Window Diagram](./resources/slidingWindow.png) +![Sliding Window Diagram](/diagrams/windows/sliding_window.svg) ```sql SELECT count(*) FROM demo GROUP BY ID, SLIDINGWINDOW(mi, 1); @@ -59,7 +59,7 @@ SELECT count(*) FROM demo GROUP BY ID, SLIDINGWINDOW(mi, 1); Sliding windows support delayed evaluation. When configured with a delay parameter, the window evaluates after the specified delay elapses, capturing events across both forward and backward intervals: -![Sliding Window with Delay Diagram](./resources/slidingWindow-delay.png) +![Sliding Window with Delay Diagram](/diagrams/windows/sliding_window_delay.svg) ```sql SELECT count(*) FROM demo GROUP BY ID, SLIDINGWINDOW(ss, 5, 5); @@ -69,7 +69,7 @@ SELECT count(*) FROM demo GROUP BY ID, SLIDINGWINDOW(ss, 5, 5); Session windows group events that arrive close together in time and close after a period of inactivity: -![Session Window Diagram](./resources/sessionWindow.png) +![Session Window Diagram](/diagrams/windows/session_window.svg) ```sql SELECT count(*) FROM demo GROUP BY ID, SESSIONWINDOW(mi, 2, 1); @@ -150,7 +150,7 @@ Count windows segment streams based on event counts rather than time intervals. Tumbling count windows group records into fixed-size batches of events: -![Tumbling Count Window Diagram](./resources/tumblingCountWindow.png) +![Tumbling Count Window Diagram](/diagrams/windows/tumbling_count_window.svg) ```sql SELECT * FROM demo WHERE temperature > 20 GROUP BY COUNTWINDOW(5); @@ -163,8 +163,8 @@ Sliding count windows take a window size and a trigger interval: `COUNTWINDOW(si - When `interval` is `1`, every incoming event triggers a window evaluation. - `interval` must be less than or equal to `size`. -![Sliding Count Window Diagram with Interval 1](./resources/slidingCountWindow_1.png) -![Sliding Count Window Diagram with Interval 2](./resources/slidingCountWindow_2.png) +![Sliding Count Window Diagram with Interval 1](/diagrams/windows/sliding_count_window_1.svg) +![Sliding Count Window Diagram with Interval 2](/diagrams/windows/sliding_count_window_2.svg) ```sql SELECT * FROM demo diff --git a/docs/en_US/usecases/esphome.md b/docs/en_US/usecases/esphome.md index 20418300f..dfe859334 100644 --- a/docs/en_US/usecases/esphome.md +++ b/docs/en_US/usecases/esphome.md @@ -6,7 +6,7 @@ When managing large device fleets, central brokers encounter heavy transmission ## Fleet Architecture -![ESPHome Fleet Telemetry Architecture](../public/diagrams/esphome_fleet.svg) +![ESPHome Fleet Telemetry Architecture](/diagrams/esphome_fleet.svg) ## High-Throughput Topic Extraction with meta(topic) diff --git a/docs/en_US/usecases/iiot.md b/docs/en_US/usecases/iiot.md index bd157d151..33183465b 100644 --- a/docs/en_US/usecases/iiot.md +++ b/docs/en_US/usecases/iiot.md @@ -8,7 +8,7 @@ rekuiper executes directly on industrial PCs, embedded gateways, and edge server In modern industrial architectures, rekuiper operates as the local compute engine between plant controllers and enterprise systems: -![Industrial IoT Edge Architecture](../public/diagrams/iiot_architecture.svg) +![Industrial IoT Edge Architecture](/diagrams/iiot_architecture.svg) ## Key Industrial Capabilities diff --git a/docs/en_US/usecases/iov.md b/docs/en_US/usecases/iov.md index 2b8370e80..b5e1f2fca 100644 --- a/docs/en_US/usecases/iov.md +++ b/docs/en_US/usecases/iov.md @@ -8,7 +8,7 @@ rekuiper deploys directly onto automotive telematics control units (T-Box), in-v In automotive and charging architectures, rekuiper operates as a local streaming coprocessor: -![Connected Vehicles and EV Charging Architecture](../public/diagrams/iov_architecture.svg) +![Connected Vehicles and EV Charging Architecture](/diagrams/iov_architecture.svg) ## Technical Advantages on Vehicle Hardware diff --git a/docs/en_US/usecases/public_data_analysis.md b/docs/en_US/usecases/public_data_analysis.md index d0ffc3514..bcff16928 100644 --- a/docs/en_US/usecases/public_data_analysis.md +++ b/docs/en_US/usecases/public_data_analysis.md @@ -113,7 +113,11 @@ Content-Type: application/json Apply the Haversine distance formula based on GPS coordinates: -![Haversine Formula](./resources/formula.png) +$$ +d = 2r \arcsin \left( \sqrt{\sin^2\left(\frac{\Delta \phi}{2}\right) + \cos(\phi_1)\cos(\phi_2)\sin^2\left(\frac{\Delta \lambda}{2}\right)} \right) +$$ + +Where $r = 6378.138\text{ km}$ is Earth's mean radius, $\phi_1, \phi_2$ are latitude coordinates in radians, and $\Delta \phi = \phi_2 - \phi_1$, $\Delta \lambda = \lambda_2 - \lambda_1$. Create a rule to calculate trip distance in meters and elapsed duration in seconds: @@ -203,4 +207,4 @@ client.close() The resulting chart visualizes user travel velocities: -Public Data Velocity Chart +![Public Data Velocity Chart](/diagrams/public_data_velocity_chart.svg) diff --git a/docs/en_US/usecases/resources/formula.png b/docs/en_US/usecases/resources/formula.png deleted file mode 100644 index f301e52a3..000000000 Binary files a/docs/en_US/usecases/resources/formula.png and /dev/null differ diff --git a/docs/en_US/usecases/resources/public-data-chart.png b/docs/en_US/usecases/resources/public-data-chart.png deleted file mode 100644 index 91800899e..000000000 Binary files a/docs/en_US/usecases/resources/public-data-chart.png and /dev/null differ diff --git a/docs/package-lock.json b/docs/package-lock.json index add7a9878..9f2c2c52e 100644 --- a/docs/package-lock.json +++ b/docs/package-lock.json @@ -11,6 +11,7 @@ "@vercel/analytics": "^2.0.1" }, "devDependencies": { + "debug": "^4.4.3", "mermaid": "^11.17.2", "vitepress": "^1.6.3", "vitepress-plugin-mermaid": "^2.0.17" @@ -2675,6 +2676,24 @@ "dev": true, "license": "MIT" }, + "node_modules/debug": { + "version": "4.4.3", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.4.3.tgz", + "integrity": "sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA==", + "dev": true, + "license": "MIT", + "dependencies": { + "ms": "^2.1.3" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, "node_modules/delaunator": { "version": "5.1.0", "resolved": "https://registry.npmjs.org/delaunator/-/delaunator-5.1.0.tgz", @@ -3168,6 +3187,13 @@ "dev": true, "license": "MIT" }, + "node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==", + "dev": true, + "license": "MIT" + }, "node_modules/nanoid": { "version": "3.3.19", "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.19.tgz", diff --git a/docs/package.json b/docs/package.json index 48fc7d2e8..6b3e88d5e 100644 --- a/docs/package.json +++ b/docs/package.json @@ -8,6 +8,7 @@ "preview": "vitepress preview" }, "devDependencies": { + "debug": "^4.4.3", "mermaid": "^11.17.2", "vitepress": "^1.6.3", "vitepress-plugin-mermaid": "^2.0.17" diff --git a/docs/resources/openvinoProject.zip b/docs/resources/openvinoProject.zip index 177371a29..3b595e3dc 100644 Binary files a/docs/resources/openvinoProject.zip and b/docs/resources/openvinoProject.zip differ diff --git a/etc/functions/internal.json b/etc/functions/internal.json index 08a441f4e..86268feb4 100644 --- a/etc/functions/internal.json +++ b/etc/functions/internal.json @@ -8,8 +8,8 @@ "website": "https://i-dacs.com" }, "helpUrl": { - "en_US": "https://github.com/ankur-paan/rekuiper/blob/main/docs/en_US/sqls/built-in_functions.html", - "zh_CN": "https://github.com/ankur-paan/rekuiper/blob/main/docs/zh_CN/sqls/built-in_functions.html" + "en_US": "https://github.com/Indus-Stack/rekuiper/blob/main/docs/en_US/sqls/built-in_functions.html", + "zh_CN": "https://github.com/Indus-Stack/rekuiper/blob/main/docs/zh_CN/sqls/built-in_functions.html" }, "description": { "en_US": "eKuiper has many built-in functions for performing calculations on data.", diff --git a/etc/mqtt_source.json b/etc/mqtt_source.json index 1fb762a53..91ae6c152 100644 --- a/etc/mqtt_source.json +++ b/etc/mqtt_source.json @@ -8,8 +8,8 @@ "website": "https://i-dacs.com" }, "helpUrl": { - "en_US": "https://github.com/ankur-paan/rekuiper/blob/main/docs/en_US/guide/sources/builtin/mqtt.html", - "zh_CN": "https://github.com/ankur-paan/rekuiper/blob/main/docs/zh_CN/guide/sources/builtin/mqtt.html" + "en_US": "https://github.com/Indus-Stack/rekuiper/blob/main/docs/en_US/guide/sources/builtin/mqtt.html", + "zh_CN": "https://github.com/Indus-Stack/rekuiper/blob/main/docs/zh_CN/guide/sources/builtin/mqtt.html" }, "description": { "en_US": "subscribe the message from MQTT broker and feed into the processing pipeline.", diff --git a/etc/sinks/edgex.json b/etc/sinks/edgex.json index 6cd2839d3..131006669 100644 --- a/etc/sinks/edgex.json +++ b/etc/sinks/edgex.json @@ -8,8 +8,8 @@ "website": "https://i-dacs.com" }, "helpUrl": { - "en_US": "https://github.com/ankur-paan/rekuiper/blob/main/docs/en_US/guide/sinks/builtin/edgex.html", - "zh_CN": "https://github.com/ankur-paan/rekuiper/blob/main/docs/zh_CN/guide/sinks/builtin/edgex.html" + "en_US": "https://github.com/Indus-Stack/rekuiper/blob/main/docs/en_US/guide/sinks/builtin/edgex.html", + "zh_CN": "https://github.com/Indus-Stack/rekuiper/blob/main/docs/zh_CN/guide/sinks/builtin/edgex.html" }, "description": { "en_US": "The action is used for publishing output message into EdgeX message bus.", diff --git a/etc/sinks/file.json b/etc/sinks/file.json index 59a72b5c6..54516c758 100644 --- a/etc/sinks/file.json +++ b/etc/sinks/file.json @@ -8,8 +8,8 @@ "website": "https://i-dacs.com" }, "helpUrl": { - "en_US": "https://github.com/ankur-paan/rekuiper/blob/main/docs/en_US/guide/sinks/builtin/file.html", - "zh_CN": "https://github.com/ankur-paan/rekuiper/blob/main/docs/zh_CN/guide/sinks/builtin/file.html" + "en_US": "https://github.com/Indus-Stack/rekuiper/blob/main/docs/en_US/guide/sinks/builtin/file.html", + "zh_CN": "https://github.com/Indus-Stack/rekuiper/blob/main/docs/zh_CN/guide/sinks/builtin/file.html" }, "description": { "en_US": "This a sink plugin for file, it can be used for saving the analysis data into file system.", diff --git a/etc/sinks/log.json b/etc/sinks/log.json index 6ee85c97e..32fa37ace 100644 --- a/etc/sinks/log.json +++ b/etc/sinks/log.json @@ -8,8 +8,8 @@ "website": "https://i-dacs.com" }, "helpUrl": { - "en_US": "https://github.com/ankur-paan/rekuiper/blob/main/docs/en_US/guide/sinks/builtin/log.html", - "zh_CN": "https://github.com/ankur-paan/rekuiper/blob/main/docs/zh_CN/guide/sinks/builtin/log.html" + "en_US": "https://github.com/Indus-Stack/rekuiper/blob/main/docs/en_US/guide/sinks/builtin/log.html", + "zh_CN": "https://github.com/Indus-Stack/rekuiper/blob/main/docs/zh_CN/guide/sinks/builtin/log.html" }, "description": { "en_US": "The action is used for print output message into log file", diff --git a/etc/sinks/memory.json b/etc/sinks/memory.json index 8d7bbbbae..f7a995c6d 100644 --- a/etc/sinks/memory.json +++ b/etc/sinks/memory.json @@ -8,8 +8,8 @@ "website": "https://i-dacs.com" }, "helpUrl": { - "en_US": "https://github.com/ankur-paan/rekuiper/blob/main/docs/en_US/guide/sinks/builtin/memory.html", - "zh_CN": "https://github.com/ankur-paan/rekuiper/blob/main/docs/zh_CN/guide/sinks/builtin/memory.html" + "en_US": "https://github.com/Indus-Stack/rekuiper/blob/main/docs/en_US/guide/sinks/builtin/memory.html", + "zh_CN": "https://github.com/Indus-Stack/rekuiper/blob/main/docs/zh_CN/guide/sinks/builtin/memory.html" }, "description": { "en_US": "The action is used to flush the result into an in-memory topic so that it can be consumed by the memory source.", diff --git a/etc/sinks/mqtt.json b/etc/sinks/mqtt.json index aaaffeaaf..5b44d9a3d 100644 --- a/etc/sinks/mqtt.json +++ b/etc/sinks/mqtt.json @@ -8,8 +8,8 @@ "website": "https://i-dacs.com" }, "helpUrl": { - "en_US": "https://github.com/ankur-paan/rekuiper/blob/main/docs/en_US/guide/sinks/builtin/mqtt.html", - "zh_CN": "https://github.com/ankur-paan/rekuiper/blob/main/docs/zh_CN/guide/sinks/builtin/mqtt.html" + "en_US": "https://github.com/Indus-Stack/rekuiper/blob/main/docs/en_US/guide/sinks/builtin/mqtt.html", + "zh_CN": "https://github.com/Indus-Stack/rekuiper/blob/main/docs/zh_CN/guide/sinks/builtin/mqtt.html" }, "description": { "en_US": "The action is used for publish output message into an MQTT server.", diff --git a/etc/sinks/neuron.json b/etc/sinks/neuron.json index b12fea351..2c7f4224e 100644 --- a/etc/sinks/neuron.json +++ b/etc/sinks/neuron.json @@ -8,7 +8,7 @@ "website": "https://i-dacs.com" }, "helpUrl": { - "en_US": "https://github.com/ankur-paan/rekuiper/blob/main/docs/en_US/guide/sinks/builtin/neuron.html", + "en_US": "https://github.com/Indus-Stack/rekuiper/blob/main/docs/en_US/guide/sinks/builtin/neuron.html", "zh_CN": "https://github.com/lf-edge/ekuiper/blob/master/docs/zh_CN/rules/sinks/builtin/" }, "description": { diff --git a/etc/sinks/nop.json b/etc/sinks/nop.json index b314ffa87..7fdfa22cb 100644 --- a/etc/sinks/nop.json +++ b/etc/sinks/nop.json @@ -8,8 +8,8 @@ "website": "https://i-dacs.com" }, "helpUrl": { - "en_US": "https://github.com/ankur-paan/rekuiper/blob/main/docs/en_US/guide/sinks/builtin/nop.html", - "zh_CN": "https://github.com/ankur-paan/rekuiper/blob/main/docs/zh_CN/guide/sinks/builtin/nop.html" + "en_US": "https://github.com/Indus-Stack/rekuiper/blob/main/docs/en_US/guide/sinks/builtin/nop.html", + "zh_CN": "https://github.com/Indus-Stack/rekuiper/blob/main/docs/zh_CN/guide/sinks/builtin/nop.html" }, "description": { "en_US": "The action is an Nop sink, the result sent to this sink will be ignored. ", diff --git a/etc/sinks/redis.json b/etc/sinks/redis.json index dd9364c4f..bc3179b13 100644 --- a/etc/sinks/redis.json +++ b/etc/sinks/redis.json @@ -8,8 +8,8 @@ "website": "https://github.com/feng-crazy" }, "helpUrl": { - "en_US": "https://github.com/ankur-paan/rekuiper/blob/main/docs/en_US/guide/sinks/plugin/reids.html", - "zh_CN": "https://github.com/ankur-paan/rekuiper/blob/main/docs/zh_CN/guide/sinks/plugin/reids.html" + "en_US": "https://github.com/Indus-Stack/rekuiper/blob/main/docs/en_US/guide/sinks/plugin/reids.html", + "zh_CN": "https://github.com/Indus-Stack/rekuiper/blob/main/docs/zh_CN/guide/sinks/plugin/reids.html" }, "description": { "en_US": "This a sink for Redis, it can be used for saving the analysis data into Redis.", diff --git a/etc/sinks/rest.json b/etc/sinks/rest.json index f04adf376..4d80edb35 100644 --- a/etc/sinks/rest.json +++ b/etc/sinks/rest.json @@ -8,8 +8,8 @@ "website": "https://i-dacs.com" }, "helpUrl": { - "en_US": "https://github.com/ankur-paan/rekuiper/blob/main/docs/en_US/guide/sinks/builtin/rest.html", - "zh_CN": "https://github.com/ankur-paan/rekuiper/blob/main/docs/zh_CN/guide/sinks/builtin/rest.html" + "en_US": "https://github.com/Indus-Stack/rekuiper/blob/main/docs/en_US/guide/sinks/builtin/rest.html", + "zh_CN": "https://github.com/Indus-Stack/rekuiper/blob/main/docs/zh_CN/guide/sinks/builtin/rest.html" }, "description": { "en_US": "The action is used for publish output message into a RESTful API.", diff --git a/etc/sources/edgex.json b/etc/sources/edgex.json index 6e6e507f9..19362f640 100644 --- a/etc/sources/edgex.json +++ b/etc/sources/edgex.json @@ -8,8 +8,8 @@ "website": "https://i-dacs.com" }, "helpUrl": { - "en_US": "https://github.com/ankur-paan/rekuiper/blob/main/docs/en_US/guide/sources/builtin/edgex.html", - "zh_CN": "https://github.com/ankur-paan/rekuiper/blob/main/docs/zh_CN/guide/sources/builtin/edgex.html" + "en_US": "https://github.com/Indus-Stack/rekuiper/blob/main/docs/en_US/guide/sources/builtin/edgex.html", + "zh_CN": "https://github.com/Indus-Stack/rekuiper/blob/main/docs/zh_CN/guide/sources/builtin/edgex.html" }, "description": { "en_US": "rekuiper provides built-in support for EdgeX source stream, which can subscribe the message from EdgeX message bus and feed into the rekuiper streaming process pipeline.", diff --git a/etc/sources/file.json b/etc/sources/file.json index f630383c6..bb70ed6ea 100644 --- a/etc/sources/file.json +++ b/etc/sources/file.json @@ -8,8 +8,8 @@ "website": "https://i-dacs.com" }, "helpUrl": { - "en_US": "https://github.com/ankur-paan/rekuiper/blob/main/docs/en_US/guide/sources/builtin/file.html", - "zh_CN": "https://github.com/ankur-paan/rekuiper/blob/main/docs/zh_CN/guide/sources/builtin/file.html" + "en_US": "https://github.com/Indus-Stack/rekuiper/blob/main/docs/en_US/guide/sources/builtin/file.html", + "zh_CN": "https://github.com/Indus-Stack/rekuiper/blob/main/docs/zh_CN/guide/sources/builtin/file.html" }, "description": { "en_US": "Monitor file system and load the content into the rekuiper processing pipeline.", diff --git a/etc/sources/httppull.json b/etc/sources/httppull.json index b62eca2c9..c6e13849f 100644 --- a/etc/sources/httppull.json +++ b/etc/sources/httppull.json @@ -9,8 +9,8 @@ "website": "https://i-dacs.com" }, "helpUrl": { - "en_US": "https://github.com/ankur-paan/rekuiper/blob/main/docs/en_US/guide/sources/builtin/http_pull.html", - "zh_CN": "https://github.com/ankur-paan/rekuiper/blob/main/docs/zh_CN/guide/sources/builtin/http_pull.html" + "en_US": "https://github.com/Indus-Stack/rekuiper/blob/main/docs/en_US/guide/sources/builtin/http_pull.html", + "zh_CN": "https://github.com/Indus-Stack/rekuiper/blob/main/docs/zh_CN/guide/sources/builtin/http_pull.html" }, "description": { "en_US": "rekuiper provides built-in support for pulling HTTP source stream, which can pull the message from HTTP server broker and feed into the rekuiper processing pipeline.", diff --git a/etc/sources/httppush.json b/etc/sources/httppush.json index 4b05ee154..78654d2c4 100644 --- a/etc/sources/httppush.json +++ b/etc/sources/httppush.json @@ -9,8 +9,8 @@ "website": "https://i-dacs.com" }, "helpUrl": { - "en_US": "https://github.com/ankur-paan/rekuiper/blob/main/docs/en_US/guide/sources/builtin/http_push.html", - "zh_CN": "https://github.com/ankur-paan/rekuiper/blob/main/docs/zh_CN/guide/sources/builtin/http_push.html" + "en_US": "https://github.com/Indus-Stack/rekuiper/blob/main/docs/en_US/guide/sources/builtin/http_push.html", + "zh_CN": "https://github.com/Indus-Stack/rekuiper/blob/main/docs/zh_CN/guide/sources/builtin/http_push.html" }, "description": { "en_US": "rekuiper provides built-in support for HTTP server to receive the stream data pushed by HTTP protocol.", diff --git a/etc/sources/memory.json b/etc/sources/memory.json index b0b615204..dcc387293 100644 --- a/etc/sources/memory.json +++ b/etc/sources/memory.json @@ -8,8 +8,8 @@ "website": "https://i-dacs.com" }, "helpUrl": { - "en_US": "https://github.com/ankur-paan/rekuiper/blob/main/docs/en_US/guide/sources/builtin/memory.html", - "zh_CN": "https://github.com/ankur-paan/rekuiper/blob/main/docs/zh_CN/guide/sources/builtin/memory.html" + "en_US": "https://github.com/Indus-Stack/rekuiper/blob/main/docs/en_US/guide/sources/builtin/memory.html", + "zh_CN": "https://github.com/Indus-Stack/rekuiper/blob/main/docs/zh_CN/guide/sources/builtin/memory.html" }, "description": { "en_US": "The source subscribes to topics to consume events from memory sink to form a rule pipeline.", diff --git a/etc/sources/neuron.json b/etc/sources/neuron.json index 24bdbbbf5..ec3739afd 100644 --- a/etc/sources/neuron.json +++ b/etc/sources/neuron.json @@ -8,8 +8,8 @@ "website": "https://i-dacs.com" }, "helpUrl": { - "en_US": "https://github.com/ankur-paan/rekuiper/blob/main/docs/en_US/guide/sources/builtin/neuron.html", - "zh_CN": "https://github.com/ankur-paan/rekuiper/blob/main/docs/zh_CN/guide/sources/builtin/neuron.html" + "en_US": "https://github.com/Indus-Stack/rekuiper/blob/main/docs/en_US/guide/sources/builtin/neuron.html", + "zh_CN": "https://github.com/Indus-Stack/rekuiper/blob/main/docs/zh_CN/guide/sources/builtin/neuron.html" }, "description": { "en_US": "Consume data from the data collection engine.", diff --git a/etc/sources/redis.json b/etc/sources/redis.json index c2a3cea76..ace940892 100644 --- a/etc/sources/redis.json +++ b/etc/sources/redis.json @@ -8,8 +8,8 @@ "website": "https://i-dacs.com" }, "helpUrl": { - "en_US": "https://github.com/ankur-paan/rekuiper/blob/main/docs/en_US/guide/sources/builtin/redis.html", - "zh_CN": "https://github.com/ankur-paan/rekuiper/blob/main/docs/zh_CN/guide/sources/builtin/redis.html" + "en_US": "https://github.com/Indus-Stack/rekuiper/blob/main/docs/en_US/guide/sources/builtin/redis.html", + "zh_CN": "https://github.com/Indus-Stack/rekuiper/blob/main/docs/zh_CN/guide/sources/builtin/redis.html" }, "description": { "en_US": "Read message from Redis", diff --git a/openapi.json b/openapi.json index 909895c28..b2bb5b620 100644 --- a/openapi.json +++ b/openapi.json @@ -18,7 +18,7 @@ }, "externalDocs": { "description": "Tagged rekuiper REST API documentation", - "url": "https://github.com/ankur-paan/rekuiper/tree/main/docs/en_US/api/restapi" + "url": "https://github.com/Indus-Stack/rekuiper/tree/main/docs/en_US/api/restapi" }, "servers": [ { @@ -285,6 +285,61 @@ "$ref": "#/components/responses/Unauthorized" } } + }, + "get": { + "tags": [ + "System" + ], + "summary": "Get system configuration", + "operationId": "getConfigs", + "security": [ + {}, + { + "JwtToken": [] + } + ], + "responses": { + "200": { + "description": "System configuration object", + "content": { + "application/json": { + "schema": { + "type": "object", + "properties": { + "basic": { + "type": "object", + "properties": { + "debug": { + "type": "boolean" + }, + "logLevel": { + "type": "string" + }, + "port": { + "type": "integer" + }, + "restPort": { + "type": "integer" + } + } + } + } + }, + "example": { + "basic": { + "debug": false, + "logLevel": "info", + "port": 20498, + "restPort": 9081 + } + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + } + } } }, "/metrics/dump/check": { @@ -2119,48 +2174,129 @@ "Rules" ], "summary": "Find rules containing all requested tags", - "operationId": "matchRulesByTags", - "x-ekuiper-source": [ - "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/rest.go", - "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/rule_tag.go", - "https://github.com/lf-edge/ekuiper/blob/v2.4.1/docs/en_US/api/restapi/rules.md" + "operationId": "matchRulesByTagsGet", + "security": [ + {}, + { + "JwtToken": [] + } ], + "description": "Matches rules containing all specified tags. Query parameters ?tags=, ?tag=, ?keys=, or ?key= (comma-separated) can be used, or a JSON body.", + "parameters": [ + { + "name": "tags", + "in": "query", + "required": false, + "description": "Comma-separated list of tags to match (e.g. env:prod,tier:vip)", + "schema": { + "type": "string" + } + }, + { + "name": "tag", + "in": "query", + "required": false, + "description": "Single tag or comma-separated tags to match", + "schema": { + "type": "string" + } + }, + { + "name": "keys", + "in": "query", + "required": false, + "description": "Legacy alias for tags parameter", + "schema": { + "type": "string" + } + } + ], + "responses": { + "200": { + "description": "Matching rule IDs", + "content": { + "application/json": { + "schema": { + "type": "array", + "items": { + "type": "string" + } + }, + "example": [ + "rule_comprehensive", + "rule_monitoring" + ] + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + } + } + }, + "post": { + "tags": [ + "Rules" + ], + "summary": "Find rules containing all requested tags via POST body", + "operationId": "matchRulesByTagsPost", "security": [ {}, { "JwtToken": [] } ], - "description": "The v2.4.1 handler requires a JSON request body even though this is GET. Some intermediaries and generators do not support GET bodies. The tagged Markdown incorrectly shows \"keys\"; code and tests use \"tags\".", "requestBody": { "required": true, "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/RuleTagRequest" + "oneOf": [ + { + "type": "object", + "properties": { + "tags": { + "type": "array", + "items": { + "type": "string" + } + } + } + }, + { + "type": "array", + "items": { + "type": "string" + } + } + ] + }, + "example": { + "tags": [ + "tier:vip", + "env:prod" + ] } } } }, "responses": { "200": { - "description": "Matching rule ids", + "description": "Matching rule IDs", "content": { "application/json": { "schema": { - "$ref": "#/components/schemas/RuleTagMatchResponse" + "type": "array", + "items": { + "type": "string" + } }, - "example": { - "rules": [ - "rule1" - ] - } + "example": [ + "rule_comprehensive" + ] } } }, - "400": { - "$ref": "#/components/responses/BadRequest" - }, "401": { "$ref": "#/components/responses/Unauthorized" } @@ -2967,18 +3103,33 @@ } ], "requestBody": { - "required": true, + "required": false, "content": { "application/json": { "schema": { - "type": "array", - "items": { - "type": "string" - } + "oneOf": [ + { + "type": "array", + "items": { + "type": "string" + }, + "description": "Array of rule IDs to export" + }, + { + "type": "object", + "properties": { + "rules": { + "type": "array", + "items": { + "type": "string" + } + } + } + } + ] }, "example": [ - "rule1", - "rule2" + "rule_comprehensive" ] } } @@ -7457,6 +7608,81 @@ } } } + }, + "/config": { + "get": { + "tags": [ + "System" + ], + "summary": "Get system configuration (alias for /configs)", + "operationId": "getConfigAlias", + "security": [ + {}, + { + "JwtToken": [] + } + ], + "responses": { + "200": { + "description": "System configuration object", + "content": { + "application/json": { + "schema": { + "type": "object" + } + } + } + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + } + } + }, + "patch": { + "tags": [ + "System" + ], + "summary": "Dynamically reload supported configuration", + "operationId": "patchConfigs", + "x-ekuiper-source": [ + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/rest.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/internal/server/import_export.go", + "https://github.com/lf-edge/ekuiper/blob/v2.4.1/docs/en_US/api/restapi/configs.md" + ], + "security": [ + {}, + { + "JwtToken": [] + } + ], + "requestBody": { + "required": true, + "content": { + "application/json": { + "schema": { + "$ref": "#/components/schemas/DynamicConfig" + }, + "example": { + "debug": true, + "consoleLog": true, + "fileLog": true, + "timezone": "UTC" + } + } + } + }, + "responses": { + "204": { + "description": "Configuration updated; no response body." + }, + "400": { + "$ref": "#/components/responses/BadRequest" + }, + "401": { + "$ref": "#/components/responses/Unauthorized" + } + } + } } }, "components": { @@ -8145,6 +8371,68 @@ "nextStartTimestamp": { "type": "integer", "format": "int64" + }, + "lastException": { + "type": "string", + "description": "Last recorded exception message (camelCase alias)" + }, + "last_exception": { + "type": "string", + "description": "Last recorded exception message (snake_case alias)" + }, + "exceptionsTotal": { + "type": "integer", + "format": "int64", + "description": "Total exception count (camelCase)" + }, + "exceptions_total": { + "type": "integer", + "format": "int64", + "description": "Total exception count (snake_case)" + }, + "sourceRecordsInTotal": { + "type": "integer", + "format": "int64", + "description": "Total input records read across all sources" + }, + "sourceRecordsFilteredTotal": { + "type": "integer", + "format": "int64", + "description": "Input records filtered out by WHERE clause" + }, + "sinkRecordsOutTotal": { + "type": "integer", + "format": "int64", + "description": "Total output records dispatched to sinks" + }, + "sinkRecordsEnqueuedTotal": { + "type": "integer", + "format": "int64", + "description": "Output records enqueued in sink buffer" + }, + "sinkRecordsFailedTotal": { + "type": "integer", + "format": "int64", + "description": "Sink operations that failed after dequeue" + }, + "droppedByPolicyTotal": { + "type": "integer", + "format": "int64", + "description": "Records dropped by buffer overflow/backpressure policy" + }, + "sinkQueueHighWater": { + "type": "integer", + "description": "Peak observed sink queue depth" + }, + "sinkBlockedMicrosTotal": { + "type": "integer", + "format": "int64", + "description": "Microseconds execution loop blocked on sink capacity" + }, + "dlqRecordsTotal": { + "type": "integer", + "format": "int64", + "description": "Total records routed to dead-letter queue" } }, "additionalProperties": true @@ -9197,4 +9485,4 @@ } } } -} +} \ No newline at end of file diff --git a/scripts/generate_pull_chart.py b/scripts/generate_pull_chart.py index 4fa077c68..3e38348c9 100644 --- a/scripts/generate_pull_chart.py +++ b/scripts/generate_pull_chart.py @@ -11,7 +11,7 @@ import urllib.request from datetime import datetime, timezone -DOCKER_HUB_REPO = "ankurkrp/rekuiper" +DOCKER_HUB_REPO = "indusstack/rekuiper" def fetch_current_pulls(): url = f"https://hub.docker.com/v2/repositories/{DOCKER_HUB_REPO}/" diff --git a/test/benchmark/multiple_rules/run_benchmark.py b/test/benchmark/multiple_rules/run_benchmark.py index 35936d636..4a07a9635 100644 --- a/test/benchmark/multiple_rules/run_benchmark.py +++ b/test/benchmark/multiple_rules/run_benchmark.py @@ -18,7 +18,7 @@ import urllib.error # Configuration -ENGINE_IMAGE = os.environ.get("REK_IMAGE", "ankurkrp/rekuiper:latest") +ENGINE_IMAGE = os.environ.get("REK_IMAGE", "indusstack/rekuiper:latest") ENGINE_NAME = "rekuiper-bench" MGMT_PORT = 9081 STREAM_NAME = "rawdata"