mirror of
https://github.com/absmach/magistrala.git
synced 2026-08-07 15:25:48 +00:00
Compare commits
106 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 7f372910dc | |||
| e8cf13c7f3 | |||
| 10791c1e28 | |||
| d63bbe1f93 | |||
| f8fab301de | |||
| 135490f680 | |||
| dcd6e85afd | |||
| 0ba7994db9 | |||
| 880634e009 | |||
| 168e8b90cb | |||
| 6429f16233 | |||
| d40757f36f | |||
| c09020a29c | |||
| 2320ec96c0 | |||
| 14d6db9684 | |||
| 513a84361b | |||
| 6ed7ca6a42 | |||
| 52645e2c39 | |||
| e078e00f73 | |||
| c3b9c20cc0 | |||
| 36fb079563 | |||
| 4d20126e75 | |||
| 09a56575c1 | |||
| 3b5f646719 | |||
| ededf5308c | |||
| bc7c9096f9 | |||
| c405028fc5 | |||
| cdc065a7b2 | |||
| 3cf6b2f0f4 | |||
| afd2665c9c | |||
| 45c426c8bf | |||
| 16ba29cf4a | |||
| 19ed0de788 | |||
| 7efeb875de | |||
| 935a0950f9 | |||
| d4f0d8fdef | |||
| aaa718bdf6 | |||
| 91e010128d | |||
| 5d7d3d412b | |||
| cb364d0426 | |||
| b68c9fe79e | |||
| 0d5048941e | |||
| 24edbe6ad8 | |||
| 610da72779 | |||
| 90672e5fc7 | |||
| 5821d2a513 | |||
| 49488738df | |||
| 493073ae49 | |||
| 5a528dd138 | |||
| 377b8dfc08 | |||
| 03b33fee9e | |||
| af75ac730c | |||
| 70d879275a | |||
| 353e050a39 | |||
| 683809dc6b | |||
| f380c8d360 | |||
| 78804278d4 | |||
| 426532099a | |||
| 7f03134d8e | |||
| f736bca7c1 | |||
| d840aeb1b9 | |||
| a0bc7c2108 | |||
| df242f6179 | |||
| 3f256ddcf6 | |||
| e294963450 | |||
| 12180707d2 | |||
| 68befa023c | |||
| dc72811048 | |||
| 92b2993366 | |||
| f3a7230cc0 | |||
| ac8dadefc6 | |||
| 3541ea8678 | |||
| 125e311eda | |||
| c9bf5beba2 | |||
| c5fc0b64d4 | |||
| 6c7e5d893d | |||
| 69d02ed58e | |||
| 3f329eb3c2 | |||
| b753294101 | |||
| 6dd470a41e | |||
| 61d0427898 | |||
| fc679e9982 | |||
| 791e084de6 | |||
| 6a3319828e | |||
| 5f230f9446 | |||
| 03893cf9e5 | |||
| 560e90aa96 | |||
| 2687a31ac2 | |||
| b70004500e | |||
| c336bf2bb6 | |||
| 74832cc081 | |||
| 468457c303 | |||
| b062fb22ee | |||
| fad25c9092 | |||
| 8e774b3398 | |||
| cc84466e7d | |||
| 351b25cd85 | |||
| ef5c253c51 | |||
| 08249c045b | |||
| e3be8d5f91 | |||
| cf7cd15a14 | |||
| 8f1ae9fd03 | |||
| 0f7ad10534 | |||
| fade98b84e | |||
| 492965d379 | |||
| 6969fd2ce8 |
+1
-1
@@ -1 +1 @@
|
||||
* @absmach/supermq
|
||||
* @absmach/magistrala
|
||||
|
||||
@@ -5,7 +5,7 @@ blank_issues_enabled: false
|
||||
contact_links:
|
||||
- name: Google group
|
||||
url: https://groups.google.com/forum/#!forum/mainflux
|
||||
about: Join the SuperMQ community on Google group.
|
||||
about: Join the Magistrala community on Google group.
|
||||
- name: Gitter
|
||||
url: https://gitter.im/mainflux/mainflux
|
||||
about: Join the SuperMQ community on Gitter.
|
||||
about: Join the Magistrala community on Gitter.
|
||||
|
||||
@@ -3,8 +3,8 @@ SPDX-License-Identifier: Apache-2.0 -->
|
||||
|
||||
<!--
|
||||
|
||||
Pull request title should be `SMQ-XXX - description` or `NOISSUE - description` where XXX is ID of the issue that this PR relate to.
|
||||
Please review the [CONTRIBUTING.md](https://github.com/absmach/supermq/blob/main/CONTRIBUTING.md) file for detailed contributing guidelines.
|
||||
Pull request title should be `MG-XXX - description` or `NOISSUE - description` where XXX is ID of the issue that this PR relate to.
|
||||
Please review the [CONTRIBUTING.md](https://github.com/absmach/magistrala/blob/main/CONTRIBUTING.md) file for detailed contributing guidelines.
|
||||
|
||||
For Work In Progress Pull Requests, please use the Draft PR feature, see https://github.blog/2019-02-14-introducing-draft-pull-requests/ for further details.
|
||||
|
||||
|
||||
@@ -5,9 +5,11 @@ version: 2
|
||||
updates:
|
||||
- package-ecosystem: "github-actions"
|
||||
directory: "./.github/workflows"
|
||||
target-branch: "main"
|
||||
schedule:
|
||||
interval: "monthly"
|
||||
interval: "weekly"
|
||||
day: "monday"
|
||||
time: "06:00"
|
||||
timezone: "Europe/Paris"
|
||||
groups:
|
||||
gh-dependency:
|
||||
@@ -16,16 +18,24 @@ updates:
|
||||
|
||||
- package-ecosystem: "gomod"
|
||||
directory: "/"
|
||||
target-branch: "main"
|
||||
schedule:
|
||||
interval: "weekly"
|
||||
day: "monday"
|
||||
time: "06:15"
|
||||
timezone: "Europe/Paris"
|
||||
groups:
|
||||
go-dependency:
|
||||
patterns:
|
||||
- "*"
|
||||
|
||||
- package-ecosystem: "docker"
|
||||
directory: "./docker"
|
||||
directory: "/docker"
|
||||
target-branch: "main"
|
||||
schedule:
|
||||
interval: "monthly"
|
||||
interval: "weekly"
|
||||
day: "monday"
|
||||
time: "06:30"
|
||||
timezone: "Europe/Paris"
|
||||
groups:
|
||||
docker-dependency:
|
||||
@@ -7,7 +7,7 @@ SPDX-License-Identifier: Apache-2.0
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>SuperMQ API Documentation</title>
|
||||
<title>Magistrala API Documentation</title>
|
||||
<link rel="stylesheet" type="text/css" href="https://cdn.jsdelivr.net/npm/swagger-ui-dist@5.30.3/swagger-ui.css">
|
||||
<style>
|
||||
body {
|
||||
@@ -101,7 +101,7 @@ SPDX-License-Identifier: Apache-2.0
|
||||
</head>
|
||||
<body>
|
||||
<div class="service-selector">
|
||||
<h1>SuperMQ API Documentation</h1>
|
||||
<h1>Magistrala API Documentation</h1>
|
||||
<div class="service-dropdown-container">
|
||||
<label for="serviceDropdown">Select Service:</label>
|
||||
<select id="serviceDropdown" class="service-dropdown"></select>
|
||||
|
||||
@@ -10,14 +10,15 @@ on:
|
||||
paths:
|
||||
- ".github/workflows/api-tests.yaml"
|
||||
- "api/**"
|
||||
- "auth/api/http/**"
|
||||
- "internal/atom/**"
|
||||
- "channels/api/http/**"
|
||||
- "clients/api/http/**"
|
||||
- "domains/api/http/**"
|
||||
- "groups/api/http/**"
|
||||
- "http/api/**"
|
||||
- "journal/api/**"
|
||||
- "users/api/**"
|
||||
- "bootstrap/api/**"
|
||||
- "certs/api/http/**"
|
||||
- "readers/api/http/**"
|
||||
- "apidocs/openapi/**"
|
||||
pull_request:
|
||||
branches:
|
||||
@@ -25,14 +26,15 @@ on:
|
||||
paths:
|
||||
- ".github/workflows/api-tests.yaml"
|
||||
- "api/**"
|
||||
- "auth/api/http/**"
|
||||
- "internal/atom/**"
|
||||
- "channels/api/http/**"
|
||||
- "clients/api/http/**"
|
||||
- "domains/api/http/**"
|
||||
- "groups/api/http/**"
|
||||
- "http/api/**"
|
||||
- "journal/api/**"
|
||||
- "users/api/**"
|
||||
- "bootstrap/api/**"
|
||||
- "certs/api/http/**"
|
||||
- "readers/api/http/**"
|
||||
- "apidocs/openapi/**"
|
||||
|
||||
concurrency:
|
||||
@@ -40,84 +42,87 @@ concurrency:
|
||||
cancel-in-progress: true
|
||||
|
||||
env:
|
||||
TOKENS_URL: http://localhost:9002/users/tokens/issue
|
||||
CREATE_DOMAINS_URL: http://localhost:9003/domains
|
||||
USER_IDENTITY: admin@example.com
|
||||
ATOM_LOGIN_URL: http://localhost/auth/login
|
||||
USER_IDENTITY: admin
|
||||
USER_SECRET: 12345678
|
||||
DOMAIN_NAME: demo-test
|
||||
USERS_URL: http://localhost:9002
|
||||
DOMAIN_URL: http://localhost:9003
|
||||
CLIENTS_URL: http://localhost:9006
|
||||
CHANNELS_URL: http://localhost:9005
|
||||
GROUPS_URL: http://localhost:9004
|
||||
HTTP_ADAPTER_URL: http://localhost:8008
|
||||
AUTH_URL: http://localhost:9001
|
||||
JOURNAL_URL: http://localhost:9021
|
||||
USERS_URL: http://localhost
|
||||
DOMAIN_URL: http://localhost
|
||||
CLIENTS_URL: http://localhost
|
||||
CHANNELS_URL: http://localhost
|
||||
GROUPS_URL: http://localhost
|
||||
BOOTSTRAP_URL: http://localhost:9013
|
||||
CERTS_URL: http://localhost:9019
|
||||
READERS_URL: http://localhost:9011
|
||||
|
||||
jobs:
|
||||
api-test:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout Code
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Get Go version from go.mod
|
||||
id: go-version
|
||||
run: echo "version=$(grep '^go ' go.mod | awk '{print $2}')" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v6
|
||||
uses: actions/setup-go@v7
|
||||
with:
|
||||
go-version: ${{ steps.go-version.outputs.version }}
|
||||
go-version-file: go.mod
|
||||
cache-dependency-path: "go.sum"
|
||||
|
||||
- name: Check for changes in specific paths
|
||||
uses: dorny/paths-filter@v3
|
||||
uses: dorny/paths-filter@v4
|
||||
id: changes
|
||||
with:
|
||||
filters: |
|
||||
workflow:
|
||||
- ".github/workflows/api-tests.yaml"
|
||||
|
||||
journal:
|
||||
- "apidocs/openapi/journal.yaml"
|
||||
- "journal/api/**"
|
||||
|
||||
auth:
|
||||
- "apidocs/openapi/auth.yaml"
|
||||
- "auth/api/http/**"
|
||||
|
||||
domains:
|
||||
- "apidocs/openapi/domains.yaml"
|
||||
- "internal/atom/**"
|
||||
- "domains/api/http/**"
|
||||
|
||||
http:
|
||||
- "apidocs/openapi/http.yaml"
|
||||
- "http/api/**"
|
||||
|
||||
clients:
|
||||
- "apidocs/openapi/clients.yaml"
|
||||
- "internal/atom/**"
|
||||
- "clients/api/http/**"
|
||||
|
||||
channels:
|
||||
- "apidocs/openapi/channels.yaml"
|
||||
- "internal/atom/**"
|
||||
- "channels/api/http/**"
|
||||
|
||||
groups:
|
||||
- "apidocs/openapi/groups.yaml"
|
||||
- "internal/atom/**"
|
||||
- "groups/api/http/**"
|
||||
|
||||
users:
|
||||
- "apidocs/openapi/users.yaml"
|
||||
- "internal/atom/**"
|
||||
- "users/api/**"
|
||||
|
||||
bootstrap:
|
||||
- "apidocs/openapi/bootstrap.yaml"
|
||||
- "bootstrap/api/**"
|
||||
|
||||
certs:
|
||||
- "apidocs/openapi/certs.yaml"
|
||||
- "certs/api/http/**"
|
||||
|
||||
readers:
|
||||
- "apidocs/openapi/readers.yaml"
|
||||
- "readers/api/http/**"
|
||||
|
||||
- name: Build images
|
||||
run: make all -j $(nproc) && make dockers_dev -j $(nproc)
|
||||
|
||||
- name: Provision Atom service tokens
|
||||
run: make provision_atom_tokens
|
||||
|
||||
- name: Start containers
|
||||
run: make run_latest up args="-d" && make run_addons up args="-d"
|
||||
run: make run_latest_ci up args="-d" && make run_addons up args="-d"
|
||||
|
||||
- name: Wait for services to be ready
|
||||
run: |
|
||||
@@ -126,94 +131,114 @@ jobs:
|
||||
|
||||
# Check if services are responding
|
||||
for i in {1..30}; do
|
||||
if curl -f -s http://localhost:9002/health > /dev/null 2>&1; then
|
||||
if curl -f -s http://localhost/health > /dev/null 2>&1; then
|
||||
echo "Services are ready!"
|
||||
break
|
||||
exit 0
|
||||
fi
|
||||
echo "Waiting for services... ($i/30)"
|
||||
sleep 2
|
||||
done
|
||||
|
||||
echo "Services failed to become ready" >&2
|
||||
docker compose -f docker/docker-compose.yaml -f docker/docker-compose-ci.yaml --env-file docker/.env --env-file docker/.env.tokens -p "${USER_REPO:-absmach_magistrala}" ps || true
|
||||
docker logs --tail 100 magistrala-nginx || true
|
||||
docker logs --tail 100 magistrala-atom || true
|
||||
docker logs --tail 100 magistrala-atom-bootstrap || true
|
||||
exit 1
|
||||
|
||||
- name: Set access token
|
||||
run: |
|
||||
export USER_TOKEN=$(curl -sSX POST $TOKENS_URL -H "Content-Type: application/json" -d "{\"identity\": \"$USER_IDENTITY\",\"secret\": \"$USER_SECRET\"}" | jq -r .access_token)
|
||||
export DOMAIN_ID=$(curl -sSX POST $CREATE_DOMAINS_URL -H "Content-Type: application/json" -H "Authorization: Bearer $USER_TOKEN" -d "{\"name\":\"$DOMAIN_NAME\",\"route\":\"$DOMAIN_NAME\"}" | jq -r .id)
|
||||
export USER_TOKEN=$(curl -fsS -X POST "$ATOM_LOGIN_URL" -H "Content-Type: application/json" -d "{\"identifier\":\"$USER_IDENTITY\",\"secret\":\"$USER_SECRET\",\"kind\":\"password\"}" | jq -er .token)
|
||||
echo "USER_TOKEN=$USER_TOKEN" >> $GITHUB_ENV
|
||||
export CLIENT_SECRET=$(supermq-cli provision test | /usr/bin/grep -Eo '"secret": "[^"]+"' | awk 'NR % 2 == 0' | sed 's/"secret": "\(.*\)"/\1/')
|
||||
echo "CLIENT_SECRET=$CLIENT_SECRET" >> $GITHUB_ENV
|
||||
|
||||
- name: Run Users API tests
|
||||
if: steps.changes.outputs.users == 'true' || steps.changes.outputs.workflow == 'true'
|
||||
uses: schemathesis/action@v2.1.0
|
||||
if: (steps.changes.outputs.users == 'true' || steps.changes.outputs.workflow == 'true') && hashFiles('users/api/**') != ''
|
||||
uses: schemathesis/action@v3.0.0
|
||||
with:
|
||||
schema: apidocs/openapi/users.yaml
|
||||
base-url: ${{ env.USERS_URL }}
|
||||
checks: all
|
||||
args: '--header "Authorization: Bearer ${{ env.USER_TOKEN }}" --suppress-health-check=filter_too_much --exclude-checks=positive_data_acceptance --exclude-operation-id=requestPasswordReset --phases=examples'
|
||||
coverage-artifact-name: schema-coverage-users
|
||||
coverage-pr-comment: false
|
||||
|
||||
- name: Run Groups API tests
|
||||
if: steps.changes.outputs.groups == 'true' || steps.changes.outputs.workflow == 'true'
|
||||
uses: schemathesis/action@v2.1.0
|
||||
if: (steps.changes.outputs.groups == 'true' || steps.changes.outputs.workflow == 'true') && hashFiles('groups/api/http/**') != ''
|
||||
uses: schemathesis/action@v3.0.0
|
||||
with:
|
||||
schema: apidocs/openapi/groups.yaml
|
||||
base-url: ${{ env.GROUPS_URL }}
|
||||
checks: all
|
||||
args: '--header "Authorization: Bearer ${{ env.USER_TOKEN }}" --suppress-health-check=filter_too_much --exclude-checks=positive_data_acceptance --phases=examples'
|
||||
coverage-artifact-name: schema-coverage-groups
|
||||
coverage-pr-comment: false
|
||||
|
||||
- name: Run Clients API tests
|
||||
if: steps.changes.outputs.clients == 'true' || steps.changes.outputs.workflow == 'true'
|
||||
uses: schemathesis/action@v2.1.0
|
||||
if: (steps.changes.outputs.clients == 'true' || steps.changes.outputs.workflow == 'true') && hashFiles('clients/api/http/**') != ''
|
||||
uses: schemathesis/action@v3.0.0
|
||||
with:
|
||||
schema: apidocs/openapi/clients.yaml
|
||||
base-url: ${{ env.CLIENTS_URL }}
|
||||
checks: all
|
||||
args: '--header "Authorization: Bearer ${{ env.USER_TOKEN }}" --suppress-health-check=filter_too_much --exclude-checks=positive_data_acceptance --phases=examples'
|
||||
coverage-artifact-name: schema-coverage-clients
|
||||
coverage-pr-comment: false
|
||||
|
||||
- name: Run Channels API tests
|
||||
if: steps.changes.outputs.channels == 'true' || steps.changes.outputs.workflow == 'true'
|
||||
uses: schemathesis/action@v2.1.0
|
||||
if: (steps.changes.outputs.channels == 'true' || steps.changes.outputs.workflow == 'true') && hashFiles('channels/api/http/**') != ''
|
||||
uses: schemathesis/action@v3.0.0
|
||||
with:
|
||||
schema: apidocs/openapi/channels.yaml
|
||||
base-url: ${{ env.CHANNELS_URL }}
|
||||
checks: all
|
||||
args: '--header "Authorization: Bearer ${{ env.USER_TOKEN }}" --suppress-health-check=filter_too_much --exclude-checks=positive_data_acceptance --phases=examples'
|
||||
|
||||
- name: Run HTTP Adapter API tests
|
||||
if: steps.changes.outputs.http == 'true' || steps.changes.outputs.workflow == 'true'
|
||||
uses: schemathesis/action@v2.1.0
|
||||
with:
|
||||
schema: apidocs/openapi/http.yaml
|
||||
base-url: ${{ env.HTTP_ADAPTER_URL }}
|
||||
checks: all
|
||||
args: '--header "Authorization: Client ${{ env.CLIENT_SECRET }}" --suppress-health-check=filter_too_much --exclude-checks=positive_data_acceptance --phases=examples'
|
||||
|
||||
- name: Run Auth API tests
|
||||
if: steps.changes.outputs.auth == 'true' || steps.changes.outputs.workflow == 'true'
|
||||
uses: schemathesis/action@v2.1.0
|
||||
with:
|
||||
schema: apidocs/openapi/auth.yaml
|
||||
base-url: ${{ env.AUTH_URL }}
|
||||
checks: all
|
||||
args: '--header "Authorization: Bearer ${{ env.USER_TOKEN }}" --suppress-health-check=filter_too_much --exclude-checks=positive_data_acceptance --phases=examples'
|
||||
coverage-artifact-name: schema-coverage-channels
|
||||
coverage-pr-comment: false
|
||||
|
||||
- name: Run Domains API tests
|
||||
if: steps.changes.outputs.domains == 'true' || steps.changes.outputs.workflow == 'true'
|
||||
uses: schemathesis/action@v2.1.0
|
||||
if: (steps.changes.outputs.domains == 'true' || steps.changes.outputs.workflow == 'true') && hashFiles('domains/api/http/**') != ''
|
||||
uses: schemathesis/action@v3.0.0
|
||||
with:
|
||||
schema: apidocs/openapi/domains.yaml
|
||||
base-url: ${{ env.DOMAIN_URL }}
|
||||
checks: all
|
||||
args: '--header "Authorization: Bearer ${{ env.USER_TOKEN }}" --suppress-health-check=filter_too_much --exclude-checks=positive_data_acceptance --phases=examples'
|
||||
coverage-artifact-name: schema-coverage-domains
|
||||
coverage-pr-comment: false
|
||||
|
||||
- name: Run Journal API tests
|
||||
if: steps.changes.outputs.journal == 'true' || steps.changes.outputs.workflow == 'true'
|
||||
uses: schemathesis/action@v2.1.0
|
||||
- name: Run Bootstrap API tests
|
||||
if: (steps.changes.outputs.bootstrap == 'true' || steps.changes.outputs.workflow == 'true') && hashFiles('bootstrap/api/**') != ''
|
||||
uses: schemathesis/action@v3.0.0
|
||||
with:
|
||||
schema: apidocs/openapi/journal.yaml
|
||||
base-url: ${{ env.JOURNAL_URL }}
|
||||
schema: apidocs/openapi/bootstrap.yaml
|
||||
base-url: ${{ env.BOOTSTRAP_URL }}
|
||||
checks: all
|
||||
args: '--header "Authorization: Bearer ${{ env.USER_TOKEN }}" --suppress-health-check=filter_too_much --exclude-checks=positive_data_acceptance --phases=examples'
|
||||
coverage-artifact-name: schema-coverage-bootstrap
|
||||
coverage-pr-comment: false
|
||||
|
||||
- name: Run Certs API tests
|
||||
if: (steps.changes.outputs.certs == 'true' || steps.changes.outputs.workflow == 'true') && hashFiles('docker/addons/certs/docker-compose.yaml') != ''
|
||||
uses: schemathesis/action@v3.0.0
|
||||
with:
|
||||
schema: apidocs/openapi/certs.yaml
|
||||
base-url: ${{ env.CERTS_URL }}
|
||||
checks: all
|
||||
args: '--header "Authorization: Bearer ${{ env.USER_TOKEN }}" --suppress-health-check=filter_too_much --exclude-checks=positive_data_acceptance --phases=examples'
|
||||
coverage-artifact-name: schema-coverage-certs
|
||||
coverage-pr-comment: false
|
||||
|
||||
- name: Run Readers API tests
|
||||
if: steps.changes.outputs.readers == 'true' || steps.changes.outputs.workflow == 'true'
|
||||
uses: schemathesis/action@v3.0.0
|
||||
with:
|
||||
schema: apidocs/openapi/readers.yaml
|
||||
base-url: ${{ env.READERS_URL }}
|
||||
checks: all
|
||||
args: '--header "Authorization: Bearer ${{ env.USER_TOKEN }}" --suppress-health-check=filter_too_much --exclude-checks=positive_data_acceptance --phases=examples'
|
||||
coverage-artifact-name: schema-coverage-readers
|
||||
coverage-pr-comment: false
|
||||
|
||||
- name: Stop containers
|
||||
if: always()
|
||||
run: make run_latest down args="-v" && make run_addons down args="-v"
|
||||
run: make run_latest_ci down args="-v" && make run_addons down args="-v"
|
||||
|
||||
@@ -8,12 +8,12 @@ on:
|
||||
branches:
|
||||
- main
|
||||
paths-ignore:
|
||||
- '**.md'
|
||||
- 'docs/**'
|
||||
- '.github/workflows/**'
|
||||
- 'LICENSE'
|
||||
- 'MAINTAINERS'
|
||||
- 'CODEOWNERS'
|
||||
- "**/*.md"
|
||||
- "docs/**"
|
||||
- ".github/workflows/**"
|
||||
- "LICENSE"
|
||||
- "MAINTAINERS"
|
||||
- "CODEOWNERS"
|
||||
|
||||
concurrency:
|
||||
group: ${{ github.workflow }}-${{ github.ref }}
|
||||
@@ -29,35 +29,31 @@ jobs:
|
||||
needs: [lint-and-build]
|
||||
permissions:
|
||||
contents: read
|
||||
packages: write
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
fetch-depth: 0
|
||||
fetch-tags: true
|
||||
|
||||
- name: Get Go version from go.mod
|
||||
id: go-version
|
||||
run: echo "version=$(grep '^go ' go.mod | awk '{print $2}')" >> $GITHUB_OUTPUT
|
||||
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@v6
|
||||
uses: actions/setup-go@v7
|
||||
with:
|
||||
go-version: ${{ steps.go-version.outputs.version }}
|
||||
go-version-file: go.mod
|
||||
cache-dependency-path: "go.sum"
|
||||
|
||||
- name: Set up Docker Build
|
||||
uses: docker/setup-buildx-action@v4
|
||||
|
||||
- name: Login to DockerHub
|
||||
- name: Login to GHCR
|
||||
uses: docker/login-action@v4
|
||||
with:
|
||||
registry: docker.io
|
||||
username: ${{ secrets.DOCKER_USERNAME }}
|
||||
password: ${{ secrets.DOCKER_TOKEN }}
|
||||
registry: ghcr.io
|
||||
username: ${{ github.actor }}
|
||||
password: ${{ secrets.GITHUB_TOKEN }}
|
||||
|
||||
- name: Build and push Docker images
|
||||
run: |
|
||||
make latest -j $(nproc)
|
||||
|
||||
|
||||
@@ -12,21 +12,17 @@ jobs:
|
||||
check-generated-files:
|
||||
runs-on: ubuntu-latest
|
||||
env:
|
||||
PROTOC_VERSION: "33.0"
|
||||
PROTOC_VERSION: "35.1"
|
||||
PROTOC_GEN_GO_VERSION: "v1.36.11"
|
||||
PROTOC_GEN_GO_GRPC_VERSION: "v1.6.0"
|
||||
PROTOC_GEN_GO_GRPC_VERSION: "v1.6.2"
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Get Go version from go.mod
|
||||
id: go-version
|
||||
run: echo "version=$(grep '^go ' go.mod | awk '{print $2}')" >> $GITHUB_OUTPUT
|
||||
uses: actions/checkout@v7
|
||||
|
||||
- name: Install Go
|
||||
uses: actions/setup-go@v6
|
||||
uses: actions/setup-go@v7
|
||||
with:
|
||||
go-version: ${{ steps.go-version.outputs.version }}
|
||||
go-version-file: go.mod
|
||||
cache-dependency-path: "go.sum"
|
||||
|
||||
- name: Set GOBIN
|
||||
@@ -41,7 +37,7 @@ jobs:
|
||||
git diff --exit-code
|
||||
|
||||
- name: Check for changes in specific paths
|
||||
uses: dorny/paths-filter@v3
|
||||
uses: dorny/paths-filter@v4
|
||||
id: changes
|
||||
with:
|
||||
base: main
|
||||
@@ -54,6 +50,7 @@ jobs:
|
||||
- "pkg/messaging/*.pb.go"
|
||||
|
||||
mocks:
|
||||
- "tools/config/.mockery.yaml"
|
||||
- ".github/workflows/check-generated-files.yaml"
|
||||
- "pkg/sdk/sdk.go"
|
||||
- "users/postgres/clients.go"
|
||||
@@ -71,7 +68,6 @@ jobs:
|
||||
- "pkg/groups/groups.go"
|
||||
- "users/emailer.go"
|
||||
- "users/hasher.go"
|
||||
- "journal/journal.go"
|
||||
- "consumers/notifier.go"
|
||||
|
||||
- name: Install Protoc
|
||||
|
||||
@@ -13,7 +13,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@v7
|
||||
|
||||
- name: Check License Header
|
||||
run: |
|
||||
|
||||
@@ -12,20 +12,16 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Get Go version from go.mod
|
||||
id: go-version
|
||||
run: echo "version=$(grep '^go ' go.mod | awk '{print $2}')" >> $GITHUB_OUTPUT
|
||||
uses: actions/checkout@v7
|
||||
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@v6
|
||||
uses: actions/setup-go@v7
|
||||
with:
|
||||
go-version: ${{ steps.go-version.outputs.version }}
|
||||
go-version-file: go.mod
|
||||
cache-dependency-path: "go.sum"
|
||||
|
||||
- name: Run linters
|
||||
uses: golangci/golangci-lint-action@v9.2.0
|
||||
uses: golangci/golangci-lint-action@v9.3.0
|
||||
with:
|
||||
version: v2.10.1
|
||||
args: --config ./tools/config/.golangci.yaml
|
||||
@@ -36,16 +32,12 @@ jobs:
|
||||
needs: lint
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Get Go version from go.mod
|
||||
id: go-version
|
||||
run: echo "version=$(grep '^go ' go.mod | awk '{print $2}')" >> $GITHUB_OUTPUT
|
||||
uses: actions/checkout@v7
|
||||
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@v6
|
||||
uses: actions/setup-go@v7
|
||||
with:
|
||||
go-version: ${{ steps.go-version.outputs.version }}
|
||||
go-version-file: go.mod
|
||||
cache-dependency-path: "go.sum"
|
||||
|
||||
- name: Build all binaries
|
||||
@@ -53,34 +45,19 @@ jobs:
|
||||
make all -j $(nproc)
|
||||
|
||||
compile-check:
|
||||
name: Compile Check ${{ matrix.variant.name }}
|
||||
name: Compile Check Redis Event Store
|
||||
runs-on: ubuntu-latest
|
||||
needs: lint
|
||||
strategy:
|
||||
fail-fast: true
|
||||
matrix:
|
||||
variant:
|
||||
- name: rabbitmq
|
||||
env: SMQ_MESSAGE_BROKER_TYPE=msg_rabbitmq
|
||||
target: mqtt
|
||||
- name: redis
|
||||
env: SMQ_ES_TYPE=es_redis
|
||||
target: mqtt
|
||||
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Get Go version from go.mod
|
||||
id: go-version
|
||||
run: echo "version=$(grep '^go ' go.mod | awk '{print $2}')" >> $GITHUB_OUTPUT
|
||||
uses: actions/checkout@v7
|
||||
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@v6
|
||||
uses: actions/setup-go@v7
|
||||
with:
|
||||
go-version: ${{ steps.go-version.outputs.version }}
|
||||
go-version-file: go.mod
|
||||
cache-dependency-path: "go.sum"
|
||||
|
||||
- name: Compile check for ${{ matrix.variant.name }}
|
||||
- name: Compile check
|
||||
run: |
|
||||
${{ matrix.variant.env }} make ${{ matrix.variant.target }}
|
||||
MG_ES_TYPE=es_redis make all -j $(nproc)
|
||||
|
||||
@@ -16,7 +16,7 @@ jobs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout code
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@v7
|
||||
|
||||
- name: Build Swagger UI
|
||||
run: |
|
||||
@@ -42,4 +42,4 @@ jobs:
|
||||
with:
|
||||
github_token: ${{ secrets.GITHUB_TOKEN }}
|
||||
publish_dir: ./swagger-ui
|
||||
cname: docs.api.supermq.absmach.eu
|
||||
cname: docs.api.magistrala.absmach.eu
|
||||
|
||||
+50
-123
@@ -8,7 +8,7 @@ on:
|
||||
branches:
|
||||
- main
|
||||
paths-ignore:
|
||||
- '**.md'
|
||||
- '**/*.md'
|
||||
- 'docs/**'
|
||||
- 'LICENSE'
|
||||
- 'MAINTAINERS'
|
||||
@@ -22,39 +22,17 @@ concurrency:
|
||||
cancel-in-progress: true
|
||||
|
||||
jobs:
|
||||
check-certs:
|
||||
name: Check Certs
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout Code
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Fetch Certs
|
||||
run: |
|
||||
make fetch_certs
|
||||
if [[ -n $(git status --porcelain docker/addons/certs) ]]; then
|
||||
echo "Certs docker file is not up to date. Please update it"
|
||||
git diff docker/addons/certs
|
||||
exit 1
|
||||
else
|
||||
exit 0
|
||||
fi
|
||||
|
||||
lint-proto:
|
||||
name: Lint Proto
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- name: Checkout Code
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Get Go version from go.mod
|
||||
id: go-version
|
||||
run: echo "version=$(grep '^go ' go.mod | awk '{print $2}')" >> $GITHUB_OUTPUT
|
||||
uses: actions/checkout@v7
|
||||
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@v6
|
||||
uses: actions/setup-go@v7
|
||||
with:
|
||||
go-version: ${{ steps.go-version.outputs.version }}
|
||||
go-version-file: go.mod
|
||||
cache-dependency-path: "go.sum"
|
||||
|
||||
- name: Install protolint
|
||||
@@ -66,46 +44,30 @@ jobs:
|
||||
protolint .
|
||||
|
||||
lint-and-build:
|
||||
needs: [check-certs, lint-proto]
|
||||
needs: [lint-proto]
|
||||
uses: ./.github/workflows/lint-and-build.yaml
|
||||
|
||||
|
||||
|
||||
detect-changes:
|
||||
name: Detect Changes
|
||||
runs-on: ubuntu-latest
|
||||
outputs:
|
||||
modules: ${{ steps.set-matrix.outputs.modules }}
|
||||
workflow_changed: ${{ steps.changes.outputs.workflow }}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@v7
|
||||
with:
|
||||
fetch-depth: 0
|
||||
|
||||
- name: Check for changes in specific paths
|
||||
uses: dorny/paths-filter@v3
|
||||
uses: dorny/paths-filter@v4
|
||||
id: changes
|
||||
with:
|
||||
filters: |
|
||||
workflow:
|
||||
- ".github/workflows/tests.yaml"
|
||||
|
||||
auth:
|
||||
- "auth/**"
|
||||
- "cmd/auth/**"
|
||||
- "auth.proto"
|
||||
- "auth.pb.go"
|
||||
- "auth_grpc.pb.go"
|
||||
- "pkg/ulid/**"
|
||||
- "pkg/uuid/**"
|
||||
|
||||
channels:
|
||||
- "channels/**"
|
||||
- "cmd/channels/**"
|
||||
- "auth.pb.go"
|
||||
- "auth_grpc.pb.go"
|
||||
- "auth/**"
|
||||
- "pkg/sdk/**"
|
||||
- "clients/api/grpc/**"
|
||||
- "groups/api/grpc/**"
|
||||
@@ -119,10 +81,6 @@ jobs:
|
||||
|
||||
clients:
|
||||
- "clients/**"
|
||||
- "cmd/clients/**"
|
||||
- "auth.pb.go"
|
||||
- "auth_grpc.pb.go"
|
||||
- "auth/**"
|
||||
- "pkg/ulid/**"
|
||||
- "pkg/uuid/**"
|
||||
- "pkg/events/**"
|
||||
@@ -131,28 +89,12 @@ jobs:
|
||||
- "domains/api/grpc/**"
|
||||
- "internal/grpc/**"
|
||||
|
||||
coap:
|
||||
- "coap/**"
|
||||
- "cmd/coap/**"
|
||||
- "auth.pb.go"
|
||||
- "auth_grpc.pb.go"
|
||||
- "clients/**"
|
||||
- "pkg/messaging/**"
|
||||
|
||||
domains:
|
||||
- "domains/**"
|
||||
- "cmd/domains/**"
|
||||
- "auth.pb.go"
|
||||
- "auth_grpc.pb.go"
|
||||
- "auth/**"
|
||||
- "internal/grpc/**"
|
||||
|
||||
groups:
|
||||
- "groups/**"
|
||||
- "cmd/groups/**"
|
||||
- "auth.pb.go"
|
||||
- "auth_grpc.pb.go"
|
||||
- "auth/**"
|
||||
- "pkg/ulid/**"
|
||||
- "pkg/uuid/**"
|
||||
- "clients/api/grpc/**"
|
||||
@@ -160,38 +102,24 @@ jobs:
|
||||
- "domains/api/grpc/**"
|
||||
- "internal/grpc/**"
|
||||
|
||||
http:
|
||||
- "http/**"
|
||||
- "cmd/http/**"
|
||||
- "auth.pb.go"
|
||||
- "auth_grpc.pb.go"
|
||||
- "clients/**"
|
||||
- "pkg/messaging/**"
|
||||
- "logger/**"
|
||||
|
||||
internal:
|
||||
- "internal/**"
|
||||
|
||||
journal:
|
||||
- "journal/**"
|
||||
- "cmd/journal/**"
|
||||
- "auth.pb.go"
|
||||
- "auth_grpc.pb.go"
|
||||
- "auth/**"
|
||||
- "pkg/events/**"
|
||||
|
||||
logger:
|
||||
- "logger/**"
|
||||
|
||||
mqtt:
|
||||
- "mqtt/**"
|
||||
- "cmd/mqtt/**"
|
||||
- "auth.pb.go"
|
||||
- "auth_grpc.pb.go"
|
||||
- "clients/**"
|
||||
- "pkg/messaging/**"
|
||||
- "logger/**"
|
||||
- "pkg/events/**"
|
||||
pkg-atom:
|
||||
- "pkg/atom/**"
|
||||
|
||||
pkg-email:
|
||||
- "pkg/email/**"
|
||||
- "pkg/emailer/**"
|
||||
|
||||
pkg-readersclient:
|
||||
- "pkg/readersclient/**"
|
||||
|
||||
pkg-testsutil:
|
||||
- "pkg/testsutil/**"
|
||||
|
||||
pkg-errors:
|
||||
- "pkg/errors/**"
|
||||
@@ -210,15 +138,12 @@ jobs:
|
||||
- "pkg/sdk/**"
|
||||
- "pkg/errors/**"
|
||||
- "pkg/groups/**"
|
||||
- "auth/**"
|
||||
- "http/**"
|
||||
- "internal/*"
|
||||
- "clients/**"
|
||||
- "users/**"
|
||||
- "channels/**"
|
||||
- "domains/**"
|
||||
- "groups/**"
|
||||
- "journal/**"
|
||||
- "api/http/**"
|
||||
|
||||
pkg-transformers:
|
||||
@@ -232,63 +157,55 @@ jobs:
|
||||
|
||||
users:
|
||||
- "users/**"
|
||||
- "cmd/users/**"
|
||||
- "auth.pb.go"
|
||||
- "auth_grpc.pb.go"
|
||||
- "auth/**"
|
||||
- "pkg/ulid/**"
|
||||
- "pkg/uuid/**"
|
||||
- "pkg/events/**"
|
||||
|
||||
notifications:
|
||||
- "notifications/**"
|
||||
- "cmd/notifications/**"
|
||||
- "auth.pb.go"
|
||||
- "auth_grpc.pb.go"
|
||||
- "consumers/notifier.go"
|
||||
- "pkg/events/**"
|
||||
|
||||
api:
|
||||
- "api/**"
|
||||
|
||||
consumers:
|
||||
- "consumers/**"
|
||||
- "cmd/postgres-writer/**"
|
||||
- "cmd/timescale-writer/**"
|
||||
- "cmd/smpp-notifier/**"
|
||||
- "cmd/smtp-notifier/**"
|
||||
|
||||
readers:
|
||||
- "readers/**"
|
||||
- "cmd/postgres-reader/**"
|
||||
- "cmd/timescale-reader/**"
|
||||
|
||||
- name: Set matrix for changed modules
|
||||
id: set-matrix
|
||||
run: |
|
||||
modules=()
|
||||
|
||||
if [[ "${{ steps.changes.outputs.workflow }}" == "true" || "${{ steps.changes.outputs.pkg-errors }}" == "true" ]]; then
|
||||
# If workflow or pkg/errors changed, test everything
|
||||
modules=("auth" "channels" "cli" "clients" "coap" "domains" "groups" "http" "internal" "journal" "logger" "mqtt" "pkg-errors" "pkg-events" "pkg-grpcclient" "pkg-messaging" "pkg-sdk" "pkg-transformers" "pkg-ulid" "pkg-uuid" "users" "notifications" "api" "consumers" "readers")
|
||||
if [[ "${{ steps.changes.outputs.workflow }}" == "true" || "${{ steps.changes.outputs.pkg-errors }}" == "true" || "${{ steps.changes.outputs.pkg-testsutil }}" == "true" ]]; then
|
||||
# If workflow, shared errors, or test utilities changed, test everything
|
||||
modules=("auth" "channels" "cli" "clients" "domains" "groups" "internal" "logger" "pkg-atom" "pkg-email" "pkg-errors" "pkg-events" "pkg-grpcclient" "pkg-messaging" "pkg-readersclient" "pkg-sdk" "pkg-testsutil" "pkg-transformers" "pkg-ulid" "pkg-uuid" "users" "api" "consumers" "readers")
|
||||
else
|
||||
# Add only changed modules
|
||||
[[ "${{ steps.changes.outputs.auth }}" == "true" ]] && modules+=("auth")
|
||||
[[ "${{ steps.changes.outputs.channels }}" == "true" ]] && modules+=("channels")
|
||||
[[ "${{ steps.changes.outputs.cli }}" == "true" ]] && modules+=("cli")
|
||||
[[ "${{ steps.changes.outputs.clients }}" == "true" ]] && modules+=("clients")
|
||||
[[ "${{ steps.changes.outputs.coap }}" == "true" ]] && modules+=("coap")
|
||||
[[ "${{ steps.changes.outputs.domains }}" == "true" ]] && modules+=("domains")
|
||||
[[ "${{ steps.changes.outputs.groups }}" == "true" ]] && modules+=("groups")
|
||||
[[ "${{ steps.changes.outputs.http }}" == "true" ]] && modules+=("http")
|
||||
[[ "${{ steps.changes.outputs.internal }}" == "true" ]] && modules+=("internal")
|
||||
[[ "${{ steps.changes.outputs.journal }}" == "true" ]] && modules+=("journal")
|
||||
[[ "${{ steps.changes.outputs.logger }}" == "true" ]] && modules+=("logger")
|
||||
[[ "${{ steps.changes.outputs.mqtt }}" == "true" ]] && modules+=("mqtt")
|
||||
[[ "${{ steps.changes.outputs.pkg-atom }}" == "true" ]] && modules+=("pkg-atom")
|
||||
[[ "${{ steps.changes.outputs.pkg-email }}" == "true" ]] && modules+=("pkg-email")
|
||||
[[ "${{ steps.changes.outputs.pkg-errors }}" == "true" ]] && modules+=("pkg-errors")
|
||||
[[ "${{ steps.changes.outputs.pkg-events }}" == "true" ]] && modules+=("pkg-events")
|
||||
[[ "${{ steps.changes.outputs.pkg-grpcclient }}" == "true" ]] && modules+=("pkg-grpcclient")
|
||||
[[ "${{ steps.changes.outputs.pkg-messaging }}" == "true" ]] && modules+=("pkg-messaging")
|
||||
[[ "${{ steps.changes.outputs.pkg-readersclient }}" == "true" ]] && modules+=("pkg-readersclient")
|
||||
[[ "${{ steps.changes.outputs.pkg-sdk }}" == "true" ]] && modules+=("pkg-sdk")
|
||||
[[ "${{ steps.changes.outputs.pkg-transformers }}" == "true" ]] && modules+=("pkg-transformers")
|
||||
[[ "${{ steps.changes.outputs.pkg-ulid }}" == "true" ]] && modules+=("pkg-ulid")
|
||||
[[ "${{ steps.changes.outputs.pkg-uuid }}" == "true" ]] && modules+=("pkg-uuid")
|
||||
[[ "${{ steps.changes.outputs.users }}" == "true" ]] && modules+=("users")
|
||||
[[ "${{ steps.changes.outputs.notifications }}" == "true" ]] && modules+=("notifications")
|
||||
[[ "${{ steps.changes.outputs.api }}" == "true" ]] && modules+=("api")
|
||||
[[ "${{ steps.changes.outputs.consumers }}" == "true" ]] && modules+=("consumers")
|
||||
[[ "${{ steps.changes.outputs.readers }}" == "true" ]] && modules+=("readers")
|
||||
@@ -312,16 +229,12 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
|
||||
- name: Get Go version from go.mod
|
||||
id: go-version
|
||||
run: echo "version=$(grep '^go ' go.mod | awk '{print $2}')" >> $GITHUB_OUTPUT
|
||||
uses: actions/checkout@v7
|
||||
|
||||
- name: Setup Go
|
||||
uses: actions/setup-go@v6
|
||||
uses: actions/setup-go@v7
|
||||
with:
|
||||
go-version: ${{ steps.go-version.outputs.version }}
|
||||
go-version-file: go.mod
|
||||
cache-dependency-path: "go.sum"
|
||||
|
||||
- name: Verify dependencies
|
||||
@@ -333,17 +246,31 @@ jobs:
|
||||
run: |
|
||||
# Map module names to directories
|
||||
case "${{ matrix.module }}" in
|
||||
pkg-atom) dir="pkg/atom" ;;
|
||||
pkg-email) dir="pkg/email" ;;
|
||||
pkg-errors) dir="pkg/errors" ;;
|
||||
pkg-events) dir="pkg/events" ;;
|
||||
pkg-grpcclient) dir="pkg/grpcclient" ;;
|
||||
pkg-messaging) dir="pkg/messaging" ;;
|
||||
pkg-readersclient) dir="pkg/readersclient" ;;
|
||||
pkg-sdk) dir="pkg/sdk" ;;
|
||||
pkg-testsutil) dir="pkg/testsutil" ;;
|
||||
pkg-transformers) dir="pkg/transformers" ;;
|
||||
pkg-ulid) dir="pkg/ulid" ;;
|
||||
pkg-uuid) dir="pkg/uuid" ;;
|
||||
channels) dir="pkg/channels" ;;
|
||||
clients) dir="pkg/clients" ;;
|
||||
domains) dir="pkg/domains" ;;
|
||||
groups) dir="pkg/groups" ;;
|
||||
*) dir="${{ matrix.module }}" ;;
|
||||
esac
|
||||
|
||||
if [[ ! -d "$dir" ]]; then
|
||||
echo "Skipping ${{ matrix.module }}; ./$dir is not present in this branch"
|
||||
echo "mode: atomic" > coverage-${{ matrix.module }}.out
|
||||
exit 0
|
||||
fi
|
||||
|
||||
go test -mod=readonly --race -v -count=1 -failfast -coverprofile=coverage-${{ matrix.module }}.out ./$dir/...
|
||||
|
||||
- name: Upload coverage
|
||||
@@ -360,7 +287,7 @@ jobs:
|
||||
if: always() && needs.run-tests.result != 'cancelled'
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
uses: actions/checkout@v7
|
||||
|
||||
- name: Download all coverage artifacts
|
||||
uses: actions/download-artifact@v8
|
||||
@@ -370,7 +297,7 @@ jobs:
|
||||
merge-multiple: true
|
||||
|
||||
- name: Upload coverage to Codecov
|
||||
uses: codecov/codecov-action@v5
|
||||
uses: codecov/codecov-action@v7
|
||||
with:
|
||||
token: ${{ secrets.CODECOV }}
|
||||
directory: ./coverage
|
||||
|
||||
@@ -18,3 +18,12 @@ coverage
|
||||
|
||||
# Ignore Openbao data directory as it contains runtime-generated data
|
||||
docker/addons/certs/openbao/
|
||||
|
||||
# Ignore generated local Atom service tokens.
|
||||
docker/.env.tokens
|
||||
|
||||
# Ignore SeaweedFS data directory as it contains runtime-generated data
|
||||
docker/data/*
|
||||
|
||||
demo-ui
|
||||
node_modules
|
||||
|
||||
+6
-6
@@ -1,12 +1,12 @@
|
||||
# Adopters
|
||||
|
||||
As SuperMQ Community grows, we'd like to keep track of SuperMQ adopters to grow the community, contact other users, share experiences and best practices.
|
||||
As Magistrala Community grows, we'd like to keep track of Magistrala adopters to grow the community, contact other users, share experiences and best practices.
|
||||
|
||||
To accomplish this, we created a public ledger. The list of organizations and users who consider themselves as SuperMQ adopters and that **publicly/officially** shared information and/or details of their adoption journey(optional).
|
||||
To accomplish this, we created a public ledger. The list of organizations and users who consider themselves as Magistrala adopters and that **publicly/officially** shared information and/or details of their adoption journey(optional).
|
||||
Where users themselves directly maintain the list.
|
||||
|
||||
## Adding yourself as an adopter
|
||||
If you are using SuperMQ, please consider adding yourself as an adopter with a brief description of your use case by opening a pull request to this file and adding a section describing your adoption of SuperMQ technology.
|
||||
If you are using Magistrala, please consider adding yourself as an adopter with a brief description of your use case by opening a pull request to this file and adding a section describing your adoption of Magistrala technology.
|
||||
|
||||
**Please send PRs to add or remove organizations/users**
|
||||
|
||||
@@ -25,12 +25,12 @@ Pull request commit must be [signed](https://docs.github.com/en/github/authentic
|
||||
* There is no minimum requirement or adaptation size, but we request to list permanent deployments only, i.e., no demo or trial deployments. Commercial or production use is not required. A well-done home lab setup can be equally impressive as a large-scale commercial deployment.
|
||||
|
||||
|
||||
**The list of organizations/users that have publicly shared the usage of SuperMQ:**
|
||||
**The list of organizations/users that have publicly shared the usage of Magistrala:**
|
||||
|
||||
**Note**: Several other organizations/users couldn't publicly share their usage details but are active project contributors and SuperMQ Community members.
|
||||
**Note**: Several other organizations/users couldn't publicly share their usage details but are active project contributors and Magistrala Community members.
|
||||
|
||||
|
||||
## Adopters list (alphabetical)
|
||||
|
||||
|
||||
**Note:** The list is maintained by the users themselves. If you find yourself on this list, and you think it's inappropriate. Please contact [project maintainers](https://github.com/absmach/supermq/blob/main/MAINTAINERS) and you will be permanently removed from the list.
|
||||
**Note:** The list is maintained by the users themselves. If you find yourself on this list, and you think it's inappropriate. Please contact [project maintainers](https://github.com/absmach/magistrala/blob/main/MAINTAINERS) and you will be permanently removed from the list.
|
||||
|
||||
+9
-9
@@ -1,6 +1,6 @@
|
||||
# Contributing to SuperMQ
|
||||
# Contributing to Magistrala
|
||||
|
||||
The following is a set of guidelines to contribute to SuperMQ and its libraries, which are
|
||||
The following is a set of guidelines to contribute to Magistrala and its libraries, which are
|
||||
hosted on the [Abstract Machines Organization](https://github.com/absmach) on GitHub.
|
||||
|
||||
This project adheres to the [Contributor Covenant 1.2](http://contributor-covenant.org/version/1/2/0).
|
||||
@@ -13,7 +13,7 @@ Reporting issues are a great way to contribute to the project. We are perpetuall
|
||||
thorough bug report.
|
||||
|
||||
Before raising a new issue, check [our issue
|
||||
list](https://github.com/absmach/supermq/issues) to determine if it already contains the
|
||||
list](https://github.com/absmach/magistrala/issues) to determine if it already contains the
|
||||
problem that you are facing.
|
||||
|
||||
A good bug report shouldn't leave others needing to chase you for more information. Please be as detailed as possible. The following questions might serve as a template for writing a detailed
|
||||
@@ -41,9 +41,9 @@ To contribute to the project, [fork](https://help.github.com/articles/fork-a-rep
|
||||
clone your fork repository, and configure the remotes:
|
||||
|
||||
```
|
||||
git clone https://github.com/<your-username>/supermq.git
|
||||
cd supermq
|
||||
git remote add upstream https://github.com/absmach/supermq.git
|
||||
git clone https://github.com/<your-username>/magistrala.git
|
||||
cd magistrala
|
||||
git remote add upstream https://github.com/absmach/magistrala.git
|
||||
```
|
||||
|
||||
If your cloned repository is behind the upstream commits, then get the latest changes from upstream:
|
||||
@@ -53,11 +53,11 @@ git checkout main
|
||||
git pull --rebase upstream main
|
||||
```
|
||||
|
||||
Create a new topic branch from `main` using the naming convention `SMQ-[issue-number]`
|
||||
Create a new topic branch from `main` using the naming convention `MG-[issue-number]`
|
||||
to help us keep track of your contribution scope:
|
||||
|
||||
```
|
||||
git checkout -b SMQ-[issue-number]
|
||||
git checkout -b MG-[issue-number]
|
||||
```
|
||||
|
||||
Commit your changes in logical chunks. When you are ready to commit, make sure
|
||||
@@ -80,7 +80,7 @@ git pull --rebase upstream main
|
||||
Push your topic branch up to your fork:
|
||||
|
||||
```
|
||||
git push origin SMQ-[issue-number]
|
||||
git push origin MG-[issue-number]
|
||||
```
|
||||
|
||||
[Open a Pull Request](https://help.github.com/articles/using-pull-requests/) with a clear title
|
||||
|
||||
@@ -176,7 +176,7 @@
|
||||
|
||||
END OF TERMS AND CONDITIONS
|
||||
|
||||
Copyright 2015-2026 SuperMQ
|
||||
Copyright 2015-2026 Magistrala
|
||||
|
||||
Licensed under the Apache License, Version 2.0 (the "License");
|
||||
you may not use this file except in compliance with the License.
|
||||
|
||||
+2
-2
@@ -1,6 +1,6 @@
|
||||
# SuperMQ Maintainers
|
||||
# Magistrala Maintainers
|
||||
|
||||
SuperMQ follows a BDFL model for dead-lock situations; day-to-day decisions happen through discussion and pull requests.
|
||||
Magistrala follows a BDFL model for dead-lock situations; day-to-day decisions happen through discussion and pull requests.
|
||||
|
||||
## BDFL
|
||||
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
# Copyright (c) Abstract Machines
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
SMQ_DOCKER_IMAGE_NAME_PREFIX ?= supermq
|
||||
override MG_DOCKER_IMAGE_NAME_PREFIX := ghcr.io/absmach/magistrala
|
||||
MG_DOCKER_VOLUME_NAME_PREFIX ?= magistrala
|
||||
BUILD_DIR ?= build
|
||||
SERVICES = auth users clients groups channels domains http coap cli mqtt journal notifications
|
||||
TEST_API_SERVICES = journal auth certs http clients users channels groups domains
|
||||
SERVICES = atom-bootstrap certs postgres-writer postgres-reader timescale-writer timescale-reader fluxmq
|
||||
TEST_API_SERVICES = certs clients users channels groups domains
|
||||
TEST_API = $(addprefix test_api_,$(TEST_API_SERVICES))
|
||||
DOCKERS = $(addprefix docker_,$(SERVICES))
|
||||
DOCKERS_DEV = $(addprefix docker_dev_,$(SERVICES))
|
||||
@@ -22,6 +23,15 @@ space:= $(empty) $(empty)
|
||||
DOCKER_PROJECT ?= $(shell echo $(subst $(space),,$(USER_REPO)) | sed -E 's/[^a-zA-Z0-9]/_/g' | tr '[:upper:]' '[:lower:]')
|
||||
DOCKER_COMPOSE_COMMANDS_SUPPORTED := up down config restart
|
||||
DEFAULT_DOCKER_COMPOSE_COMMAND := up
|
||||
ATOM_TOKENS_ENV ?= docker/.env.tokens
|
||||
REQUIRED_ATOM_TOKEN_ENVS := MG_ATOM_TOKEN_FLUXMQ_AUTH MG_ATOM_TOKEN_FLUXMQ_NODE1 MG_ATOM_TOKEN_FLUXMQ_NODE2 MG_ATOM_TOKEN_FLUXMQ_NODE3 MG_ATOM_TOKEN_TIMESCALE_READER MG_ATOM_TOKEN_RE MG_ATOM_TOKEN_ALARMS MG_ATOM_TOKEN_REPORTS MG_ATOM_TOKEN_POSTGRES_READER
|
||||
PROVISION_ATOM_TOKENS ?= false
|
||||
PROVISION_ATOM_TOKEN_GOALS := provision-atom-tokens
|
||||
DOCKER_BASE_ENV_FILES := --env-file docker/.env
|
||||
DOCKER_ENV_FILES = $(if $(filter down,$(DOCKER_COMPOSE_COMMAND)),$(DOCKER_BASE_ENV_FILES),$(DOCKER_BASE_ENV_FILES) --env-file $(ATOM_TOKENS_ENV))
|
||||
DOCKER_PROVISION_ENV_FILES = $(DOCKER_BASE_ENV_FILES) $(if $(wildcard $(ATOM_TOKENS_ENV)),--env-file $(ATOM_TOKENS_ENV))
|
||||
HOST_UID := $(shell id -u)
|
||||
HOST_GID := $(shell id -g)
|
||||
GRPC_MTLS_CERT_FILES_EXISTS = 0
|
||||
MOCKERY = $(GOBIN)/mockery
|
||||
MOCKERY_VERSION=3.6.4
|
||||
@@ -29,24 +39,26 @@ PKG_PROTO_GEN_OUT_DIR=api/grpc
|
||||
INTERNAL_PROTO_DIR=internal/proto
|
||||
INTERNAL_PROTO_FILES := $(shell find $(INTERNAL_PROTO_DIR) -name "*.proto" | sed 's|$(INTERNAL_PROTO_DIR)/||')
|
||||
|
||||
ifneq ($(SMQ_MESSAGE_BROKER_TYPE),)
|
||||
SMQ_MESSAGE_BROKER_TYPE := $(SMQ_MESSAGE_BROKER_TYPE)
|
||||
ifneq ($(MG_MESSAGE_BROKER_TYPE),)
|
||||
MG_MESSAGE_BROKER_TYPE := $(MG_MESSAGE_BROKER_TYPE)
|
||||
else
|
||||
SMQ_MESSAGE_BROKER_TYPE=msg_nats
|
||||
MG_MESSAGE_BROKER_TYPE=msg_fluxmq
|
||||
endif
|
||||
|
||||
ifneq ($(SMQ_ES_TYPE),)
|
||||
SMQ_ES_TYPE := $(SMQ_ES_TYPE)
|
||||
ifneq ($(MG_ES_TYPE),)
|
||||
MG_ES_TYPE := $(MG_ES_TYPE)
|
||||
else
|
||||
SMQ_ES_TYPE=es_nats
|
||||
MG_ES_TYPE=es_fluxmq
|
||||
endif
|
||||
|
||||
BUILD_TAGS := $(strip $(MG_MESSAGE_BROKER_TYPE) $(MG_ES_TYPE))
|
||||
|
||||
define compile_service
|
||||
CGO_ENABLED=$(CGO_ENABLED) GOOS=$(GOOS) GOARCH=$(GOARCH) GOARM=$(GOARM) \
|
||||
go build -tags $(SMQ_MESSAGE_BROKER_TYPE) -tags $(SMQ_ES_TYPE) -ldflags "-s -w \
|
||||
-X 'github.com/absmach/supermq.BuildTime=$(TIME)' \
|
||||
-X 'github.com/absmach/supermq.Version=$(VERSION)' \
|
||||
-X 'github.com/absmach/supermq.Commit=$(COMMIT)'" \
|
||||
go build -tags "$(BUILD_TAGS)" -ldflags "-s -w \
|
||||
-X 'github.com/absmach/magistrala.BuildTime=$(TIME)' \
|
||||
-X 'github.com/absmach/magistrala.Version=$(VERSION)' \
|
||||
-X 'github.com/absmach/magistrala.Commit=$(COMMIT)'" \
|
||||
-o ${BUILD_DIR}/$(1) cmd/$(1)/main.go
|
||||
endef
|
||||
|
||||
@@ -61,7 +73,8 @@ define make_docker
|
||||
--build-arg VERSION=$(VERSION) \
|
||||
--build-arg COMMIT=$(COMMIT) \
|
||||
--build-arg TIME=$(TIME) \
|
||||
--tag=$(SMQ_DOCKER_IMAGE_NAME_PREFIX)/$(svc) \
|
||||
--build-arg BUILD_TAGS="$(BUILD_TAGS)" \
|
||||
--tag=$(MG_DOCKER_IMAGE_NAME_PREFIX)/$(svc) \
|
||||
-f docker/Dockerfile .
|
||||
endef
|
||||
|
||||
@@ -71,31 +84,71 @@ define make_docker_dev
|
||||
docker build \
|
||||
--no-cache \
|
||||
--build-arg SVC=$(svc) \
|
||||
--tag=$(SMQ_DOCKER_IMAGE_NAME_PREFIX)/$(svc) \
|
||||
--tag=$(MG_DOCKER_IMAGE_NAME_PREFIX)/$(svc) \
|
||||
-f docker/Dockerfile.dev ./build
|
||||
endef
|
||||
|
||||
define require_atom_tokens_env
|
||||
@if [ -z "$(filter down,$(DOCKER_COMPOSE_COMMAND))" ]; then \
|
||||
if [ ! -f "$(ATOM_TOKENS_ENV)" ]; then \
|
||||
echo "Missing $(ATOM_TOKENS_ENV). Run 'make provision_atom_tokens' before starting the Docker Compose stack."; \
|
||||
exit 2; \
|
||||
fi; \
|
||||
missing=""; \
|
||||
for env_name in $(REQUIRED_ATOM_TOKEN_ENVS); do \
|
||||
if ! grep -q "^$${env_name}=" "$(ATOM_TOKENS_ENV)"; then \
|
||||
missing="$${missing} $${env_name}"; \
|
||||
fi; \
|
||||
done; \
|
||||
if [ -n "$${missing}" ]; then \
|
||||
echo "Missing Atom service token(s) in $(ATOM_TOKENS_ENV):$${missing}. Run 'make provision_atom_tokens' before starting the Docker Compose stack."; \
|
||||
exit 2; \
|
||||
fi; \
|
||||
fi
|
||||
endef
|
||||
|
||||
define ensure_atom_tokens_env
|
||||
@if [ "$(PROVISION_ATOM_TOKENS)" = "true" ] && [ -z "$(filter down,$(DOCKER_COMPOSE_COMMAND))" ]; then \
|
||||
$(MAKE) provision_atom_tokens; \
|
||||
elif [ -z "$(filter down,$(DOCKER_COMPOSE_COMMAND))" ]; then \
|
||||
if [ ! -f "$(ATOM_TOKENS_ENV)" ]; then \
|
||||
echo "Missing $(ATOM_TOKENS_ENV). Run 'make provision_atom_tokens' before starting the Docker Compose stack."; \
|
||||
exit 2; \
|
||||
fi; \
|
||||
missing=""; \
|
||||
for env_name in $(REQUIRED_ATOM_TOKEN_ENVS); do \
|
||||
if ! grep -q "^$${env_name}=" "$(ATOM_TOKENS_ENV)"; then \
|
||||
missing="$${missing} $${env_name}"; \
|
||||
fi; \
|
||||
done; \
|
||||
if [ -n "$${missing}" ]; then \
|
||||
echo "Missing Atom service token(s) in $(ATOM_TOKENS_ENV):$${missing}. Run 'make provision_atom_tokens' before starting the Docker Compose stack."; \
|
||||
exit 2; \
|
||||
fi; \
|
||||
fi
|
||||
endef
|
||||
|
||||
define run_with_arch_detection
|
||||
$(call require_atom_tokens_env)
|
||||
@echo "Detecting architecture..."
|
||||
@if [ "$(DETECTED_ARCH)" = "arm64" ] || [ "$(DETECTED_ARCH)" = "aarch64" ]; then \
|
||||
echo "ARM64 architecture detected."; \
|
||||
git checkout $(1); \
|
||||
GOARCH=arm64 $(MAKE) dockers; \
|
||||
for svc in $(SERVICES); do \
|
||||
docker tag supermq/$$svc supermq/$$svc:latest; \
|
||||
docker tag supermq/$$svc docker.io/supermq/$$svc:latest; \
|
||||
docker tag $(MG_DOCKER_IMAGE_NAME_PREFIX)/$$svc $(MG_DOCKER_IMAGE_NAME_PREFIX)/$$svc:latest; \
|
||||
done; \
|
||||
sed -i.bak 's/^SMQ_RELEASE_TAG=.*/SMQ_RELEASE_TAG=latest/' docker/.env && rm -f docker/.env.bak; \
|
||||
docker compose -f docker/docker-compose.yaml --env-file docker/.env -p $(DOCKER_PROJECT) $(DOCKER_COMPOSE_COMMAND) $(args); \
|
||||
sed -i.bak 's/^MG_RELEASE_TAG=.*/MG_RELEASE_TAG=latest/' docker/.env && rm -f docker/.env.bak; \
|
||||
docker compose -f docker/docker-compose.yaml $(DOCKER_ENV_FILES) -p $(DOCKER_PROJECT) $(DOCKER_COMPOSE_COMMAND) $(args); \
|
||||
else \
|
||||
echo "x86_64 architecture detected."; \
|
||||
git checkout $(1); \
|
||||
sed -i.bak 's/^SMQ_RELEASE_TAG=.*/SMQ_RELEASE_TAG=$(2)/' docker/.env && rm -f docker/.env.bak; \
|
||||
docker compose -f docker/docker-compose.yaml --env-file docker/.env -p $(DOCKER_PROJECT) $(DOCKER_COMPOSE_COMMAND) $(args); \
|
||||
sed -i.bak 's/^MG_RELEASE_TAG=.*/MG_RELEASE_TAG=$(2)/' docker/.env && rm -f docker/.env.bak; \
|
||||
docker compose -f docker/docker-compose.yaml $(DOCKER_ENV_FILES) -p $(DOCKER_PROJECT) $(DOCKER_COMPOSE_COMMAND) $(args); \
|
||||
fi
|
||||
endef
|
||||
|
||||
ADDON_SERVICES = journal certs
|
||||
ADDON_SERVICES = bootstrap provision postgres-writer postgres-reader
|
||||
|
||||
EXTERNAL_SERVICES = prometheus
|
||||
|
||||
@@ -122,6 +175,9 @@ DOCKER_PLATFORM ?=
|
||||
ifneq ($(filter run%,$(firstword $(MAKECMDGOALS))),)
|
||||
temp_args := $(wordlist 2,$(words $(MAKECMDGOALS)),$(MAKECMDGOALS))
|
||||
DOCKER_COMPOSE_COMMAND := $(if $(filter $(DOCKER_COMPOSE_COMMANDS_SUPPORTED),$(temp_args)), $(filter $(DOCKER_COMPOSE_COMMANDS_SUPPORTED),$(temp_args)), $(DEFAULT_DOCKER_COMPOSE_COMMAND))
|
||||
ifneq ($(filter $(PROVISION_ATOM_TOKEN_GOALS),$(temp_args)),)
|
||||
override PROVISION_ATOM_TOKENS := true
|
||||
endif
|
||||
$(eval $(DOCKER_COMPOSE_COMMAND):;@)
|
||||
endif
|
||||
|
||||
@@ -141,7 +197,14 @@ FILTERED_SERVICES = $(filter-out $(RUN_ADDON_ARGS), $(SERVICES))
|
||||
|
||||
all: $(SERVICES)
|
||||
|
||||
.PHONY: all $(SERVICES) dockers dockers_dev latest release run_latest run_stable run_addons grpc_mtls_certs check_mtls check_certs test_api mocks
|
||||
.PHONY: all help $(SERVICES) dockers dockers_dev latest release provision_atom_tokens provision-atom-tokens migrate_atom run_latest run_latest_ci run_tls run_stable run_addons grpc_mtls_certs check_mtls check_certs check_fluxmq_service_certs check_re_trace_key test_api mocks
|
||||
|
||||
help:
|
||||
@printf 'Usage:\n make <target> [VARIABLE=value ...]\n\nAvailable targets:\n'
|
||||
@$(MAKE) -qpRr : 2>/dev/null | \
|
||||
awk -F: '/^[[:alnum:]_][^$$#\/\t=]*:([^=]|$$)/ { split($$1, targets, /[[:space:]]+/); for (i in targets) if (targets[i] != "") print targets[i] }' | \
|
||||
LC_ALL=C sort -u | \
|
||||
awk '$$0 != "Makefile" { printf " make %s\n", $$0 }'
|
||||
|
||||
clean:
|
||||
rm -rf ${BUILD_DIR}
|
||||
@@ -152,12 +215,12 @@ cleandocker:
|
||||
|
||||
ifdef pv
|
||||
# Remove unused volumes
|
||||
docker volume ls -f name=$(SMQ_DOCKER_IMAGE_NAME_PREFIX) -f dangling=true -q | xargs -r docker volume rm
|
||||
docker volume ls -f name=$(MG_DOCKER_VOLUME_NAME_PREFIX) -f dangling=true -q | xargs -r docker volume rm
|
||||
endif
|
||||
|
||||
install:
|
||||
for file in $(BUILD_DIR)/*; do \
|
||||
cp $$file $(GOBIN)/supermq-`basename $$file`; \
|
||||
cp $$file $(GOBIN)/magistrala-`basename $$file`; \
|
||||
done
|
||||
|
||||
mocks: $(MOCKERY)
|
||||
@@ -182,45 +245,26 @@ define test_api_service
|
||||
|
||||
@if [ -z "$(USER_TOKEN)" ]; then \
|
||||
echo "USER_TOKEN is not set"; \
|
||||
echo "Please set it to a valid token"; \
|
||||
exit 1; \
|
||||
echo "Please set it to a valid token"; \
|
||||
exit 1; \
|
||||
fi
|
||||
|
||||
@if [ "$(svc)" = "http" ] && [ -z "$(CLIENT_SECRET)" ]; then \
|
||||
echo "CLIENT_SECRET is not set"; \
|
||||
echo "Please set it to a valid secret"; \
|
||||
exit 1; \
|
||||
fi
|
||||
|
||||
@if [ "$(svc)" = "http" ]; then \
|
||||
uvx schemathesis run apidocs/openapi/$(svc).yaml \
|
||||
--checks all \
|
||||
--url $(2) \
|
||||
--header "Authorization: Client $(CLIENT_SECRET)" \
|
||||
--suppress-health-check=filter_too_much \
|
||||
--exclude-checks=positive_data_acceptance \
|
||||
--phases=examples,stateful; \
|
||||
else \
|
||||
uvx schemathesis run apidocs/openapi/$(svc).yaml \
|
||||
--checks all \
|
||||
--url $(2) \
|
||||
--header "Authorization: Bearer $(USER_TOKEN)" \
|
||||
--suppress-health-check=filter_too_much \
|
||||
--exclude-checks=positive_data_acceptance \
|
||||
--exclude-operation-id=requestPasswordReset \
|
||||
--phases=examples,stateful; \
|
||||
fi
|
||||
@uvx schemathesis run apidocs/openapi/$(svc).yaml \
|
||||
--checks all \
|
||||
--url $(2) \
|
||||
--header "Authorization: Bearer $(USER_TOKEN)" \
|
||||
--suppress-health-check=filter_too_much \
|
||||
--exclude-checks=positive_data_acceptance \
|
||||
--exclude-operation-id=requestPasswordReset \
|
||||
--phases=examples,stateful
|
||||
endef
|
||||
|
||||
test_api_users: TEST_API_URL := http://localhost:9002
|
||||
test_api_clients: TEST_API_URL := http://localhost:9006
|
||||
test_api_domains: TEST_API_URL := http://localhost:9003
|
||||
test_api_channels: TEST_API_URL := http://localhost:9005
|
||||
test_api_groups: TEST_API_URL := http://localhost:9004
|
||||
test_api_http: TEST_API_URL := http://localhost:8008
|
||||
test_api_auth: TEST_API_URL := http://localhost:9001
|
||||
test_api_users: TEST_API_URL := http://localhost:9000
|
||||
test_api_clients: TEST_API_URL := http://localhost:9000
|
||||
test_api_domains: TEST_API_URL := http://localhost:9000
|
||||
test_api_channels: TEST_API_URL := http://localhost:9000
|
||||
test_api_groups: TEST_API_URL := http://localhost:9000
|
||||
test_api_certs: TEST_API_URL := http://localhost:9019
|
||||
test_api_journal: TEST_API_URL := http://localhost:9021
|
||||
|
||||
$(TEST_API):
|
||||
$(call test_api_service,$(@),$(TEST_API_URL))
|
||||
@@ -244,7 +288,7 @@ dockers_dev: $(DOCKERS_DEV)
|
||||
|
||||
define docker_push
|
||||
for svc in $(SERVICES); do \
|
||||
docker push $(SMQ_DOCKER_IMAGE_NAME_PREFIX)/$$svc:$(1); \
|
||||
docker push $(MG_DOCKER_IMAGE_NAME_PREFIX)/$$svc:$(1); \
|
||||
done
|
||||
endef
|
||||
|
||||
@@ -257,10 +301,10 @@ latest: dockers
|
||||
publish_arch:
|
||||
$(MAKE) dockers GOOS=$(GOOS) GOARCH=$(GOARCH) GOARM=$(GOARM)
|
||||
for svc in $(SERVICES); do \
|
||||
docker tag $(SMQ_DOCKER_IMAGE_NAME_PREFIX)/$$svc $(SMQ_DOCKER_IMAGE_NAME_PREFIX)/$$svc:$(VERSION)-$(GOARCH); \
|
||||
docker tag $(SMQ_DOCKER_IMAGE_NAME_PREFIX)/$$svc $(SMQ_DOCKER_IMAGE_NAME_PREFIX)/$$svc:latest-$(GOARCH); \
|
||||
docker push $(SMQ_DOCKER_IMAGE_NAME_PREFIX)/$$svc:$(VERSION)-$(GOARCH); \
|
||||
docker push $(SMQ_DOCKER_IMAGE_NAME_PREFIX)/$$svc:latest-$(GOARCH); \
|
||||
docker tag $(MG_DOCKER_IMAGE_NAME_PREFIX)/$$svc $(MG_DOCKER_IMAGE_NAME_PREFIX)/$$svc:$(VERSION)-$(GOARCH); \
|
||||
docker tag $(MG_DOCKER_IMAGE_NAME_PREFIX)/$$svc $(MG_DOCKER_IMAGE_NAME_PREFIX)/$$svc:latest-$(GOARCH); \
|
||||
docker push $(MG_DOCKER_IMAGE_NAME_PREFIX)/$$svc:$(VERSION)-$(GOARCH); \
|
||||
docker push $(MG_DOCKER_IMAGE_NAME_PREFIX)/$$svc:latest-$(GOARCH); \
|
||||
done
|
||||
|
||||
release:
|
||||
@@ -268,7 +312,7 @@ release:
|
||||
git checkout $(version)
|
||||
$(MAKE) dockers
|
||||
for svc in $(SERVICES); do \
|
||||
docker tag $(SMQ_DOCKER_IMAGE_NAME_PREFIX)/$$svc $(SMQ_DOCKER_IMAGE_NAME_PREFIX)/$$svc:$(version); \
|
||||
docker tag $(MG_DOCKER_IMAGE_NAME_PREFIX)/$$svc $(MG_DOCKER_IMAGE_NAME_PREFIX)/$$svc:$(version); \
|
||||
done
|
||||
$(call docker_push,$(version))
|
||||
|
||||
@@ -276,7 +320,25 @@ rundev:
|
||||
cd scripts && ./run.sh
|
||||
|
||||
grpc_mtls_certs:
|
||||
$(MAKE) -C docker/ssl auth_grpc_certs clients_grpc_certs
|
||||
$(MAKE) -C docker/ssl clients_grpc_certs
|
||||
|
||||
provision_atom_tokens:
|
||||
$(DOCKER_PLATFORM) docker compose -f docker/docker-compose.yaml $(DOCKER_PROVISION_ENV_FILES) -p $(DOCKER_PROJECT) up -d --wait --wait-timeout 120 atom
|
||||
$(MAKE) docker_atom-bootstrap
|
||||
$(DOCKER_PLATFORM) docker compose -f docker/docker-compose.yaml $(DOCKER_PROVISION_ENV_FILES) -p $(DOCKER_PROJECT) run --rm --no-deps --user "$(HOST_UID):$(HOST_GID)" -v "$(PWD)/docker:/host/docker" atom-bootstrap provision-tokens --output /host/docker/.env.tokens
|
||||
|
||||
provision-atom-tokens:
|
||||
@:
|
||||
|
||||
# Migrate an old Magistrala (v0.30.0 / pre-Atom) deployment into Atom. Runs an
|
||||
# isolated, collision-free stack, seeds the Atom schema into the run_latest Atom
|
||||
# volume and loads the data. Default is a dry-run; pass args="--apply" to load,
|
||||
# args="--verify" to reconcile afterwards.
|
||||
# make migrate_atom # dry-run
|
||||
# make migrate_atom args="--apply" # perform the migration
|
||||
# make migrate_atom args="--apply --fresh-atom" # rebuild Atom schema first
|
||||
migrate_atom:
|
||||
DOCKER_PROJECT="$(DOCKER_PROJECT)" tools/atom-migration/migrate.sh $(args)
|
||||
|
||||
check_tls:
|
||||
ifeq ($(GRPC_TLS),true)
|
||||
@@ -294,39 +356,85 @@ else
|
||||
$(eval GRPC_MTLS :=)
|
||||
endif
|
||||
|
||||
check_certs: check_mtls check_tls
|
||||
# Internal services reach FluxMQ on the mTLS local listener, and Compose mounts
|
||||
# both sides of those connections. Certificates and principal secrets are
|
||||
# generated rather than committed, so make them before anything binds them.
|
||||
check_fluxmq_service_certs:
|
||||
ifeq ("$(wildcard docker/ssl/certs/re-fluxmq-client.crt)","")
|
||||
$(MAKE) -C docker/ssl fluxmq_service_certs
|
||||
endif
|
||||
ifeq ("$(wildcard docker/ssl/certs/timescale-writer-fluxmq-client.crt)","")
|
||||
$(MAKE) -C docker/ssl timescale_writer_fluxmq_client_cert
|
||||
endif
|
||||
ifeq ("$(wildcard docker/ssl/certs/postgres-writer-fluxmq-client.crt)","")
|
||||
$(MAKE) -C docker/ssl postgres_writer_fluxmq_client_cert
|
||||
endif
|
||||
ifeq ("$(wildcard docker/ssl/certs/fluxmq-auth-fluxmq-client.crt)","")
|
||||
$(MAKE) -C docker/ssl fluxmq_auth_fluxmq_client_cert
|
||||
endif
|
||||
ifeq ("$(wildcard docker/fluxmq/secrets/re-current)","")
|
||||
$(MAKE) -C docker/ssl fluxmq_service_secret
|
||||
endif
|
||||
ifeq ("$(wildcard docker/fluxmq/secrets/timescale-writer-current)","")
|
||||
$(MAKE) -C docker/ssl timescale_writer_fluxmq_service_secret
|
||||
endif
|
||||
ifeq ("$(wildcard docker/fluxmq/secrets/postgres-writer-current)","")
|
||||
$(MAKE) -C docker/ssl postgres_writer_fluxmq_service_secret
|
||||
endif
|
||||
ifeq ("$(wildcard docker/fluxmq/secrets/fluxmq-auth-current)","")
|
||||
$(MAKE) -C docker/ssl fluxmq_auth_fluxmq_service_secret
|
||||
endif
|
||||
|
||||
check_re_trace_key:
|
||||
ifeq ("$(wildcard docker/re/secrets/trace.key)","")
|
||||
$(MAKE) -C docker/ssl re_trace_key
|
||||
endif
|
||||
|
||||
check_certs: check_mtls check_tls check_fluxmq_service_certs check_re_trace_key
|
||||
ifeq ($(GRPC_MTLS_CERT_FILES_EXISTS),0)
|
||||
ifeq ($(filter true,$(GRPC_MTLS) $(GRPC_TLS)),true)
|
||||
ifeq ($(filter $(DEFAULT_DOCKER_COMPOSE_COMMAND),$(DOCKER_COMPOSE_COMMAND)),$(DEFAULT_DOCKER_COMPOSE_COMMAND))
|
||||
$(MAKE) -C docker/ssl auth_grpc_certs clients_grpc_certs
|
||||
$(MAKE) -C docker/ssl clients_grpc_certs
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
fetch_certs:
|
||||
@./scripts/certs.sh
|
||||
|
||||
run_latest: check_certs
|
||||
git checkout main
|
||||
$(SED_INPLACE) 's/^SMQ_RELEASE_TAG=.*/SMQ_RELEASE_TAG=latest/' docker/.env
|
||||
$(DOCKER_PLATFORM) docker compose -f docker/docker-compose.yaml --env-file docker/.env -p $(DOCKER_PROJECT) $(DOCKER_COMPOSE_COMMAND) $(args)
|
||||
$(SED_INPLACE) 's/^MG_RELEASE_TAG=.*/MG_RELEASE_TAG=latest/' docker/.env
|
||||
$(call ensure_atom_tokens_env)
|
||||
$(DOCKER_PLATFORM) docker compose -f docker/docker-compose.yaml $(DOCKER_ENV_FILES) -p $(DOCKER_PROJECT) $(DOCKER_COMPOSE_COMMAND) $(args)
|
||||
|
||||
run_latest_ci: check_certs
|
||||
$(call require_atom_tokens_env)
|
||||
$(SED_INPLACE) 's/^MG_RELEASE_TAG=.*/MG_RELEASE_TAG=latest/' docker/.env
|
||||
$(DOCKER_PLATFORM) docker compose -f docker/docker-compose.yaml -f docker/docker-compose-ci.yaml $(DOCKER_ENV_FILES) -p $(DOCKER_PROJECT) $(DOCKER_COMPOSE_COMMAND) $(args)
|
||||
|
||||
run_tls: check_certs
|
||||
@test -n "$(host)" || (echo "Usage: make run_tls host=example.com [email=admin@example.com] [letsencrypt=false] [staging=true] [force=true]" && exit 2)
|
||||
@if [ "$(or $(letsencrypt),true)" != "false" ] && [ -z "$(email)" ]; then echo "Usage: make run_tls host=example.com email=admin@example.com [letsencrypt=false] [staging=true] [force=true]"; exit 2; fi
|
||||
MG_PUBLIC_HOST="$(host)" \
|
||||
MG_LETSENCRYPT_ENABLED="$(or $(letsencrypt),true)" \
|
||||
MG_LETSENCRYPT_EMAIL="$(email)" \
|
||||
MG_LETSENCRYPT_STAGING="$(or $(staging),false)" \
|
||||
MG_LETSENCRYPT_FORCE_RENEWAL="$(or $(force),false)" \
|
||||
DOCKER_PROJECT="$(DOCKER_PROJECT)" \
|
||||
./docker/setup-tls.sh
|
||||
|
||||
run_stable: check_certs
|
||||
$(call require_atom_tokens_env)
|
||||
$(eval version = $(shell git describe --abbrev=0 --tags))
|
||||
git checkout $(version)
|
||||
$(SED_INPLACE) 's/^SMQ_RELEASE_TAG=.*/SMQ_RELEASE_TAG=$(version)/' docker/.env
|
||||
$(DOCKER_PLATFORM) docker compose -f docker/docker-compose.yaml --env-file docker/.env -p $(DOCKER_PROJECT) $(DOCKER_COMPOSE_COMMAND) $(args)
|
||||
$(SED_INPLACE) 's/^MG_RELEASE_TAG=.*/MG_RELEASE_TAG=$(version)/' docker/.env
|
||||
$(DOCKER_PLATFORM) docker compose -f docker/docker-compose.yaml $(DOCKER_ENV_FILES) -p $(DOCKER_PROJECT) $(DOCKER_COMPOSE_COMMAND) $(args)
|
||||
|
||||
run_addons: check_certs
|
||||
$(call require_atom_tokens_env)
|
||||
$(foreach SVC,$(RUN_ADDON_ARGS),$(if $(filter $(SVC),$(ADDON_SERVICES) $(EXTERNAL_SERVICES)),,$(error Invalid Service $(SVC))))
|
||||
@$(DOCKER_PLATFORM) docker compose -f docker/docker-compose.yaml --env-file ./docker/.env -p $(DOCKER_PROJECT) up -d auth domains jaeger
|
||||
@$(DOCKER_PLATFORM) docker compose -f docker/docker-compose.yaml $(DOCKER_ENV_FILES) -p $(DOCKER_PROJECT) up -d atom jaeger
|
||||
@for SVC in $(RUN_ADDON_ARGS); do \
|
||||
if [ "$$SVC" = "certs" ]; then \
|
||||
$(DOCKER_PLATFORM) docker compose -f docker/addons/$$SVC/docker-compose.yaml -f docker/certs-docker-compose-override.yaml --env-file ./docker/.env --env-file ./docker/addons/$$SVC/.env -p $(DOCKER_PROJECT) $(DOCKER_COMPOSE_COMMAND) $(args) & \
|
||||
else \
|
||||
SMQ_ADDONS_CERTS_PATH_PREFIX="../." $(DOCKER_PLATFORM) docker compose -f docker/addons/$$SVC/docker-compose.yaml -p $(DOCKER_PROJECT) --env-file ./docker/.env $(DOCKER_COMPOSE_COMMAND) $(args) & \
|
||||
fi; \
|
||||
MG_ADDONS_CERTS_PATH_PREFIX="../" $(DOCKER_PLATFORM) docker compose -f docker/addons/$$SVC/docker-compose.yaml -p $(DOCKER_PROJECT) $(DOCKER_ENV_FILES) $(DOCKER_COMPOSE_COMMAND) $(args) & \
|
||||
done
|
||||
|
||||
run_live: check_certs
|
||||
GOPATH=$(go env GOPATH) $(DOCKER_PLATFORM) docker compose -f docker/docker-compose.yaml -f docker/docker-compose-live.yaml --env-file docker/.env -p $(DOCKER_PROJECT) $(DOCKER_COMPOSE_COMMAND) $(args)
|
||||
$(call require_atom_tokens_env)
|
||||
GOPATH=$(go env GOPATH) $(DOCKER_PLATFORM) docker compose -f docker/docker-compose.yaml -f docker/docker-compose-live.yaml $(DOCKER_ENV_FILES) -p $(DOCKER_PROJECT) $(DOCKER_COMPOSE_COMMAND) $(args)
|
||||
|
||||
@@ -1,153 +1,412 @@
|
||||
<div align="center">
|
||||
|
||||
# SuperMQ
|
||||
|
||||
### Planetary event-driven infrastructure
|
||||
|
||||
**Made with ❤️ by [Abstract Machines](https://absmach.eu/)**
|
||||
# Magistrala
|
||||
|
||||
[](https://github.com/absmach/supermq/actions/workflows/build.yaml)
|
||||
[](https://goreportcard.com/report/github.com/absmach/supermq)
|
||||
[](https://deepwiki.com/absmach/supermq)
|
||||
[](https://github.com/absmach/supermq/actions/workflows/check-license.yaml)
|
||||
[](https://github.com/absmach/supermq/actions/workflows/check-generated-files.yaml)
|
||||
[](https://codecov.io/gh/absmach/supermq)
|
||||
### A Modern IoT Platform Framework for Scalable IoT
|
||||
|
||||
**Made with ❤ by [Abstract Machines](https://absmach.eu/)**
|
||||
|
||||
[](https://github.com/absmach/magistrala/actions/workflows/build.yaml)
|
||||
[](https://goreportcard.com/report/github.com/absmach/magistrala)
|
||||
[](https://deepwiki.com/absmach/magistrala)
|
||||
[](https://github.com/absmach/magistrala/actions/workflows/check-license.yaml)
|
||||
[](https://github.com/absmach/magistrala/actions/workflows/check-generated-files.yaml)
|
||||
[](https://codecov.io/gh/absmach/magistrala)
|
||||
[](LICENSE)
|
||||
[](https://matrix.to/#/#supermq:matrix.org)
|
||||
|
||||
### [Guide](https://docs.supermq.absmach.eu) | [Contributing](CONTRIBUTING.md) | [Website](https://absmach.eu/) | [Chat](https://matrix.to/#/#supermq:matrix.org)
|
||||
|
||||
[Guide](https://magistrala.absmach.eu/docs/) | [Contributing](CONTRIBUTING.md) | [Website](https://absmach.eu/) | [Chat](https://matrix.to/#/#supermq:matrix.org)
|
||||
</div>
|
||||
|
||||
## Introduction 📖
|
||||
## Introduction 🌍
|
||||
|
||||
SuperMQ is a distributed, highly scalable, and secure open-source cloud platform for messaging and event-driven architecture (EDA). It is a planetarily distributed, highly scalable, and secure platform that serves as a robust foundation for building advanced real-time and reactive systems.
|
||||
Magistrala is an open-source IoT platform built for engineers who need full control over their messaging, device management, and data pipelines.
|
||||
|
||||
## Why SuperMQ Stands Out 🚀
|
||||
It is built on top of [FluxMQ](https://github.com/absmach/fluxmq), a modern message broker designed for both messaging and event streams. Magistrala provides everything around it: identity, access control, device provisioning, data processing, and observability.
|
||||
|
||||
SuperMQ bridges the gap between various network protocols (HTTP, MQTT, WebSocket, CoAP, and more) to provide a seamless messaging experience. Whether you're working on IoT solutions, real-time data pipelines, or event-driven systems, SuperMQ has you covered. 🌐✨
|
||||
IoT systems usually involve brokers, databases, rule engines, and custom services. Magistrala does not pretend those pieces disappear. It provides a coherent framework for integrating them into a single system with a consistent model for identity, access control, messaging, and observability.
|
||||
|
||||
## Key Features 🌟
|
||||
**What it is:**
|
||||
- An event-driven IoT middleware platform
|
||||
- A unified control plane for devices, users, and data
|
||||
- A foundation for building scalable IoT systems
|
||||
|
||||
- **Multi-Protocol Connectivity**: HTTP, MQTT, WebSocket, CoAP, and more! 🌉
|
||||
- **Secure by Design**: Mutual TLS (mTLS) with X.509 Certificates, JWT support, and multi-protocol authorization. 🔒
|
||||
- **Fine-Grained Access Control**: Support for ABAC and RBAC policies. 📜
|
||||
- **Multi-Tenant**: Manage multiple domains seamlessly. 🏢
|
||||
- **Multi-User**: Unlimited organizational hierarchies for user management. 👥
|
||||
- **Application Management**: Group and share messaging clients for streamlined operations. 📱
|
||||
- **Ease of Use**: Simple and powerful communication channel management, grouping, and sharing. ✨
|
||||
- **Personal Access Tokens (PATs)**: Scoped and revocable tokens for enhanced security. 🔑
|
||||
- **Observability**: Integrated logging and instrumentation with Prometheus and OpenTelemetry. 📈
|
||||
- **Event Sourcing**: Build robust and scalable architectures. ⚡
|
||||
- **Edge and IoT Ready**: Supports MQTT and CoAP protocols for seamless IoT gateway and sensor communication and management. 🌍
|
||||
- **Developer-Friendly**: SDKs, CLI tools, and comprehensive documentation to get you started. 👩💻👨💻
|
||||
- **Production-Ready**: Container-based deployment using Docker and Kubernetes. 🐳☸️
|
||||
**What it is not:**
|
||||
- Not just an MQTT broker
|
||||
- Not a black-box SaaS
|
||||
- Not tied to a single cloud or vendor
|
||||
|
||||
## Installation 🛠️
|
||||
---
|
||||
|
||||
There are multiple ways to run SuperMQ.
|
||||
First, clone the repository and position to it:
|
||||
## 🧩 IoT Platform Framework
|
||||
|
||||
```bash
|
||||
git clone https://github.com/absmach/supermq.git
|
||||
cd supermq
|
||||
We call Magistrala a **framework**, not just a platform.
|
||||
|
||||
It is extremely flexible and lets you build systems the way you want — from simple prototypes to complex, large-scale deployments — without forcing you into rigid patterns.
|
||||
|
||||
At the same time, it avoids the typical complexity of many IoT platforms, where you need to learn an entirely new set of concepts before you can even get started.
|
||||
|
||||
Magistrala is built around a small number of main concepts:
|
||||
- users
|
||||
- clients (devices)
|
||||
- channels
|
||||
- messages
|
||||
- policies
|
||||
|
||||
Most engineers are already familiar with these ideas, so you can start building immediately.
|
||||
|
||||
You can keep things simple:
|
||||
- connect devices
|
||||
- send messages
|
||||
- store data
|
||||
|
||||
Or you can go deeper:
|
||||
- define complex access control policies
|
||||
- build event-driven pipelines
|
||||
- integrate custom processing and automation
|
||||
|
||||
Magistrala scales with your needs — simple when you want it, powerful when you need it.
|
||||
|
||||
---
|
||||
|
||||
## 🚀 Key Benefits
|
||||
|
||||
- **A Coherent System, Not a Mess of Integrations**
|
||||
Build IoT systems from multiple components without ending up with fragmented security, messaging, and operations.
|
||||
|
||||
- **Event-Driven at the Core**
|
||||
Everything is built around events — enabling real-time processing, streaming, and scalable data flows.
|
||||
|
||||
- **Protocol-Native, Not Forced Abstractions**
|
||||
MQTT, HTTP, WebSocket, and CoAP are treated as first-class citizens, each with their own semantics.
|
||||
|
||||
- **Security Built Into the Model**
|
||||
Identity, authentication, and authorization are part of the system design — not bolted on later.
|
||||
|
||||
- **Flexible by Design**
|
||||
Start simple or build complex systems — without changing platforms or rewriting your architecture.
|
||||
|
||||
- **Runs Where You Need It**
|
||||
Cloud, edge, or hybrid — no vendor lock-in, no hidden dependencies.
|
||||
---
|
||||
## ✨ Features
|
||||
|
||||
Magistrala provides a complete set of building blocks for IoT systems — from device connectivity to data processing and observability — without forcing a rigid architecture.
|
||||
|
||||
### 🔐 Identity & Access
|
||||
|
||||
- Multi-tenant domains for isolating environments
|
||||
- Users, roles, and organizational hierarchies
|
||||
- Fine-grained access control (ABAC + RBAC)
|
||||
- Mutual TLS (X.509) and JWT-based authentication
|
||||
- Personal Access Tokens (PATs) with scoping and revocation
|
||||
|
||||
### 🔌 Connectivity
|
||||
|
||||
- Native support for MQTT, HTTP, WebSocket, and CoAP
|
||||
- Consistent authentication and authorization across protocols
|
||||
- Designed for both cloud services and constrained devices
|
||||
|
||||
### 📦 Device & Application Model
|
||||
|
||||
- Device (client) provisioning and lifecycle management
|
||||
- Channels for grouping and controlling message flow
|
||||
- Application-level grouping and sharing of clients
|
||||
- Simple but flexible communication model
|
||||
|
||||
### ⚙️ Processing & Automation
|
||||
|
||||
- Rules engine for message processing and routing (Enterprise Edition)
|
||||
- Alarms and triggers for reacting to events (Enterprise Edition)
|
||||
- Scheduled actions for time-based workflows
|
||||
- Event-driven architecture as the foundation
|
||||
|
||||
### 📊 Observability
|
||||
|
||||
- Audit logs for tracking system activity (Enterprise Edition)
|
||||
- Metrics and tracing via Prometheus and OpenTelemetry
|
||||
- Built-in visibility into system behavior and data flows
|
||||
|
||||
### 🚀 Deployment & Operations
|
||||
|
||||
- Container-native (Docker, Kubernetes)
|
||||
- Designed for cloud, edge, and hybrid deployments
|
||||
- Works with external storage and processing systems
|
||||
- Scales from small setups to production environments
|
||||
|
||||
### 🧑💻 Developer Experience
|
||||
|
||||
- CLI and SDKs for fast integration
|
||||
- Straightforward APIs and concepts
|
||||
- Documentation focused on getting you running quickly
|
||||
---
|
||||
|
||||
## Atom Integration Model
|
||||
|
||||
Magistrala uses **Atom** as the backend for identity, authorization, and the catalog.
|
||||
|
||||
Atom is the source of truth for:
|
||||
- domains
|
||||
- users
|
||||
- clients
|
||||
- channels
|
||||
- groups
|
||||
- roles
|
||||
- access policies
|
||||
|
||||
Magistrala services such as rules, alarms, and reports remain Magistrala services, but they use Atom for identity and authorization.
|
||||
|
||||
Current Docker deployments use the Atom image configured by `ATOM_IMAGE` in `docker/.env`. For compatibility with the current Magistrala integration, the generated `MG_ATOM_TOKEN_*` service credentials are unscoped Atom access tokens. Scoped Atom access tokens should not be used for these service env vars until Magistrala stops using owner-wide Atom listing APIs such as `authorizedObjectIds` in service policy paths.
|
||||
|
||||
### Core Entity Mapping
|
||||
|
||||
| Magistrala concept | Atom concept | Meaning |
|
||||
| ------------------ | ---------------------------- | ------------------------------------------------------------------ |
|
||||
| Domain | Tenant | Isolation boundary for one organization, project, or environment |
|
||||
| User | Entity with kind `human` | A person who logs in and uses the UI/API |
|
||||
| Client | Entity with kind `device` | A device or application that sends/receives data |
|
||||
| Channel | Resource with kind `channel` | A messaging/data path that clients can publish or subscribe to |
|
||||
| Group | Group | A collection of users, clients, channels, or other grouped objects |
|
||||
|
||||
In simple terms:
|
||||
|
||||
```text
|
||||
MG Domain = Atom Tenant
|
||||
MG User = Atom Human Entity
|
||||
MG Client = Atom Device Entity
|
||||
MG Channel = Atom Channel Resource
|
||||
MG Group = Atom Group
|
||||
```
|
||||
|
||||
To run the latest stable (tagged) version, use:
|
||||
### Actions, Permission Blocks, Roles, and Assignments
|
||||
|
||||
```bash
|
||||
# Run with latest stable tagged version
|
||||
make run_stable
|
||||
Atom access control has these basic parts:
|
||||
|
||||
| Atom word | Simple meaning | Example |
|
||||
| ---------------- | ----------------------------- | --------------------------------------------------------- |
|
||||
| Action | One permission verb | `read`, `write`, `delete`, `role.manage`, `policy.manage` |
|
||||
| Permission Block | Where actions apply | all channels in domain `d1` can `read`, `publish` |
|
||||
| Role | A bundle of permission blocks | `tenant-admin` bundles domain, role, and member access |
|
||||
| Role Assignment | Who gets a role | give `user1` the `tenant-admin` role |
|
||||
|
||||
Read an assignment like this:
|
||||
|
||||
```text
|
||||
Give <who> this <role>.
|
||||
The role contains permission blocks that say where and what.
|
||||
```
|
||||
|
||||
To run the latest version, use:
|
||||
Example:
|
||||
|
||||
```text
|
||||
Give user1 the tenant-admin role on domain d1.
|
||||
```
|
||||
|
||||
That means:
|
||||
|
||||
```text
|
||||
user1 can use the tenant-admin permissions inside domain d1.
|
||||
```
|
||||
|
||||
### How MG Roles Work With Atom
|
||||
|
||||
MG UI shows actions such as:
|
||||
- read
|
||||
- update
|
||||
- delete
|
||||
- manage roles
|
||||
- add/remove members
|
||||
- publish
|
||||
- subscribe
|
||||
|
||||
These are mapped to Atom actions:
|
||||
|
||||
| MG action | Atom action |
|
||||
| ---------------------------- | --------------- |
|
||||
| view/read | `read` |
|
||||
| create/update/edit/connect | `write` |
|
||||
| delete/remove | `delete` |
|
||||
| manage roles | `role.manage` |
|
||||
| add/remove members or access | `policy.manage` |
|
||||
| channel publish | `publish` |
|
||||
| channel subscribe | `subscribe` |
|
||||
|
||||
So when MG UI checks:
|
||||
|
||||
```text
|
||||
Can user1 manage roles for client1?
|
||||
```
|
||||
|
||||
Atom checks:
|
||||
|
||||
```text
|
||||
Does user1 have role.manage on client1, or on the domain that contains client1?
|
||||
```
|
||||
|
||||
When MG UI checks:
|
||||
|
||||
```text
|
||||
Can user1 add a member to channel1?
|
||||
```
|
||||
|
||||
Atom checks:
|
||||
|
||||
```text
|
||||
Does user1 have policy.manage on channel1, or on the domain that contains channel1?
|
||||
```
|
||||
|
||||
### Practical Rule
|
||||
|
||||
If a user is domain admin, they usually receive a tenant-scoped role in Atom.
|
||||
|
||||
That tenant-scoped role can allow them to manage objects inside the domain:
|
||||
- clients
|
||||
- channels
|
||||
- groups
|
||||
- rules
|
||||
- alarms
|
||||
- reports
|
||||
|
||||
For narrower access, create object-scoped roles. For example:
|
||||
|
||||
```text
|
||||
Give user2 a reader role only on channel1.
|
||||
```
|
||||
|
||||
Then user2 can read only that channel, not the whole domain.
|
||||
|
||||
## Installation
|
||||
|
||||
```bash
|
||||
# Run with latest development version (from main branch)
|
||||
git clone https://github.com/absmach/magistrala.git
|
||||
cd magistrala
|
||||
make provision_atom_tokens
|
||||
make run_latest
|
||||
```
|
||||
|
||||
The `make run_stable` command will:
|
||||
- Checkout the repository to the latest git tag
|
||||
- Update the version in the environment configuration
|
||||
- Start the services with the stable release
|
||||
A fresh clone carries no generated secrets. Two sets have to exist before the
|
||||
stack can start — certificates and keys the internal services authenticate
|
||||
with, and the Atom service tokens each service presents to Atom. `make
|
||||
run_latest` produces the first set itself but expects the second to be there
|
||||
already, which is why the token step comes first above.
|
||||
|
||||
**Note:** After running `make run_stable`, you'll be on a detached HEAD state. To return to your working branch:
|
||||
### Certificates, broker secret and trace key
|
||||
|
||||
Generated by `make run_latest`, or on demand:
|
||||
|
||||
```bash
|
||||
git checkout main
|
||||
make check_certs
|
||||
```
|
||||
|
||||
### Running on Apple Silicon (M1/M2/M3) Macs
|
||||
This creates whatever is missing and leaves anything already present alone:
|
||||
|
||||
When running SuperMQ on Apple Silicon Macs, the Makefile will automatically detect your ARM64 architecture and build Docker images locally.
|
||||
| Path | What it is |
|
||||
| ----------------------------------------------------------- | ------------------------------------------------------------------------- |
|
||||
| `docker/ssl/certs/fluxmq-service-server.{crt,key}` | Server certificate for FluxMQ's mTLS service listener |
|
||||
| `docker/ssl/certs/re-fluxmq-client.{crt,key}` | Client certificate whose URI SAN identifies the Rules Engine |
|
||||
| `docker/ssl/certs/timescale-writer-fluxmq-client.{crt,key}` | Client certificate whose URI SAN identifies the Timescale writer |
|
||||
| `docker/ssl/certs/postgres-writer-fluxmq-client.{crt,key}` | Client certificate whose URI SAN identifies the Postgres writer |
|
||||
| `docker/ssl/certs/fluxmq-auth-fluxmq-client.{crt,key}` | Client certificate whose URI SAN identifies the publish proxy |
|
||||
| `docker/fluxmq/secrets/re-current` | Rules Engine principal secret, from `MG_RE_BROKER_SECRET` |
|
||||
| `docker/fluxmq/secrets/timescale-writer-current` | Timescale writer secret, from `MG_TIMESCALE_WRITER_BROKER_SECRET` |
|
||||
| `docker/fluxmq/secrets/postgres-writer-current` | Postgres writer secret, from `MG_POSTGRES_WRITER_BROKER_SECRET` |
|
||||
| `docker/fluxmq/secrets/fluxmq-auth-current` | Publish proxy secret, from `MG_FLUXMQ_BROKER_SECRET` |
|
||||
| `docker/re/secrets/trace.key` | HMAC key the Rules Engine signs its loop-detection traces with |
|
||||
|
||||
**If using Docker Desktop:**
|
||||
Internal services reach the broker as *local principals* rather than as ordinary
|
||||
clients: each presents a client certificate whose URI SAN names it, plus a SASL
|
||||
secret, and the broker grants it only what it needs — the Rules Engine consumes
|
||||
`m`, republishes under it, and feeds the `writers` and `alarms` streams; the
|
||||
writers only subscribe to `writers`; the publish proxy that serves the UI's
|
||||
HTTP publish endpoint only publishes under `m.`. The principals are declared in
|
||||
`docker/fluxmq/node{1,2,3}.yaml`, and adding a service means adding an entry
|
||||
there alongside its certificate and secret.
|
||||
|
||||
1. **Enable Apple Virtualization Framework**: In Docker Desktop, go to:
|
||||
- Settings → General → Enable "Use the new Virtualization framework"
|
||||
|
||||
2. **Enable Rosetta for x86_64 Emulation**: In Docker Desktop, go to:
|
||||
- Settings → General → Enable "Use Rosetta for x86_64/amd64 emulation on Apple Silicon"
|
||||
Being a local principal is also what preserves a message's origin. The broker
|
||||
stamps its own transport protocol and identity on anything published over a
|
||||
connection it does not trust, so a message relayed to the writers over the plain
|
||||
AMQP listener would be stored as `protocol: amqp` with the relaying service as
|
||||
its publisher. A `service`-role principal on the mTLS listener may state the
|
||||
origin instead, and the protocol the device actually published with survives to
|
||||
the database.
|
||||
|
||||
After enabling these options, restart Docker Desktop, then run `make run_stable` or `make run_latest` as usual.
|
||||
The certificates are issued by the development CA committed at
|
||||
`docker/ssl/certs/ca.crt`, so no extra setup is needed for a local run. The
|
||||
generated material is gitignored.
|
||||
|
||||
To manually run SuperMQ, clone the repository and start all core services:
|
||||
The server certificate is issued for `fluxmq` and `fluxmq-node{1,2,3}`, which
|
||||
covers both this Compose stack and a single-node deployment. Point any
|
||||
`MG_*_BROKER_URL` at a host outside that set and the service fails its TLS
|
||||
verification with `certificate is valid for ...`; add the name to
|
||||
`FLUXMQ_SERVICE_SERVER_CERT_CONFIG` in `docker/ssl/Makefile` and reissue:
|
||||
|
||||
```bash
|
||||
docker compose -f docker/docker-compose.yaml --env-file docker/.env up
|
||||
rm -f docker/ssl/certs/fluxmq-service-server.* \
|
||||
docker/ssl/certs/re-fluxmq-client.* \
|
||||
docker/ssl/certs/timescale-writer-fluxmq-client.* \
|
||||
docker/ssl/certs/postgres-writer-fluxmq-client.*
|
||||
make -C docker/ssl fluxmq_service_certs
|
||||
```
|
||||
|
||||
### Usage 📤📥
|
||||
`make check_certs` skips certificates that already exist, so stale certificates
|
||||
have to be removed rather than merely re-running the target.
|
||||
|
||||
**Using the CLI :**
|
||||
Each local-principal secret must stay equal to the corresponding value in
|
||||
`docker/.env`; a mismatch fails that service's broker authentication. After
|
||||
changing one, re-run its target:
|
||||
|
||||
| Variable | Target |
|
||||
| ----------------------------------- | ----------------------------------------- |
|
||||
| `MG_RE_BROKER_SECRET` | `fluxmq_service_secret` |
|
||||
| `MG_TIMESCALE_WRITER_BROKER_SECRET` | `timescale_writer_fluxmq_service_secret` |
|
||||
| `MG_POSTGRES_WRITER_BROKER_SECRET` | `postgres_writer_fluxmq_service_secret` |
|
||||
| `MG_FLUXMQ_BROKER_SECRET` | `fluxmq_auth_fluxmq_service_secret` |
|
||||
|
||||
`trace.key` is created once and preserved on later runs — replacing it while
|
||||
messages are in flight would invalidate the rule traces they already carry, so
|
||||
delete it only deliberately. Every Rules Engine replica must read the same key.
|
||||
|
||||
Start the stack through `make run_latest` rather than calling `docker compose
|
||||
up` directly. Compose creates a missing bind-mount source as an empty
|
||||
*directory*, so bringing up `re` or `fluxmq` before these files exist leaves the
|
||||
containers failing against a directory where they expect a key.
|
||||
|
||||
### Atom service tokens
|
||||
|
||||
Not generated automatically, because provisioning them starts Atom and runs a
|
||||
bootstrap job against it:
|
||||
|
||||
```bash
|
||||
make provision_atom_tokens
|
||||
```
|
||||
|
||||
This brings up Atom, runs `atom-bootstrap`, and writes the gitignored
|
||||
`docker/.env.tokens` with one service token per consumer —
|
||||
`MG_ATOM_TOKEN_FLUXMQ_AUTH`, `MG_ATOM_TOKEN_FLUXMQ_NODE{1,2,3}`,
|
||||
`MG_ATOM_TOKEN_RE`, `MG_ATOM_TOKEN_ALARMS`, `MG_ATOM_TOKEN_REPORTS`,
|
||||
`MG_ATOM_TOKEN_TIMESCALE_READER`, and `MG_ATOM_TOKEN_POSTGRES_READER`.
|
||||
|
||||
`make run_latest` refuses to start when that file is absent or short of any of
|
||||
those variables, and names what is missing. To fold the step into the run:
|
||||
|
||||
```bash
|
||||
make run_latest PROVISION_ATOM_TOKENS=true
|
||||
```
|
||||
|
||||
Re-run `provision_atom_tokens` after anything that resets Atom's database; the
|
||||
old tokens do not survive it.
|
||||
|
||||
---
|
||||
|
||||
## Usage
|
||||
|
||||
```bash
|
||||
make cli
|
||||
./build/supermq-cli status
|
||||
./build/cli health <service>
|
||||
```
|
||||
|
||||
This command retrieves the status of the SuperMQ server and outputs it to the console.
|
||||
---
|
||||
|
||||
**Using HTTP with Curl :**
|
||||
## License
|
||||
|
||||
```bash
|
||||
curl -X GET http://localhost:8080/status
|
||||
```
|
||||
|
||||
This request fetches the server status over HTTP and provides a JSON response.
|
||||
|
||||
See our [CLI documentation](https://docs.supermq.absmach.eu/cli) for more details.
|
||||
|
||||
## Documentation 📚
|
||||
|
||||
The official documentation is hosted at [SuperMQ docs page](https://docs.supermq.absmach.eu/).
|
||||
|
||||
Documentation is auto-generated, check out the instructions in the [docs repository](https://github.com/absmach/supermq-docs).
|
||||
If you spot an error or a need for corrections, please let us know - or even better: send us a PR! 💌
|
||||
|
||||
## Community and Contributing 🤝
|
||||
|
||||
Thank you for your interest in SuperMQ and the desire to contribute!
|
||||
|
||||
1. Take a look at our [open issues](https://github.com/absmach/supermq/issues). The [good-first-issue](https://github.com/absmach/supermq/labels/good-first-issue) label is specifically for issues that are great for getting started.
|
||||
2. Checkout the [contribution guide](CONTRIBUTING.md) to learn more about our style and conventions.
|
||||
3. Make your changes compatible to our workflow.
|
||||
|
||||
Join our community:
|
||||
|
||||
- [Matrix Room](https://matrix.to/#/#supermq\:matrix.org)
|
||||
|
||||
## Professional Support 💼
|
||||
|
||||
Need help deploying SuperMQ or integrating it into your system? Reach out to **[Abstract Machines](https://absmach.eu/)** for professional support and guidance.
|
||||
|
||||
## License 📜
|
||||
|
||||
SuperMQ is open-source software licensed under the [Apache License 2.0](LICENSE). Contributions are welcome!
|
||||
|
||||
## Acknowledgments 🙌
|
||||
|
||||
Special thanks to the amazing contributors who make SuperMQ possible. Check out the [MAINTAINERS](MAINTAINERS) file to see the team behind the magic.
|
||||
|
||||
Ready to build the future of messaging and event-driven systems? Let's get started! 🚀
|
||||
Apache-2.0
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
// Copyright (c) Abstract Machines
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package supermq
|
||||
package magistrala
|
||||
|
||||
// Response contains HTTP response specific methods.
|
||||
type Response interface {
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.36.11
|
||||
// protoc v6.33.0
|
||||
// protoc v7.35.1
|
||||
// source: auth/v1/auth.proto
|
||||
|
||||
package v1
|
||||
@@ -74,6 +74,7 @@ type AuthNRes struct {
|
||||
UserId string `protobuf:"bytes,2,opt,name=user_id,json=userId,proto3" json:"user_id,omitempty"`
|
||||
UserRole uint32 `protobuf:"varint,3,opt,name=user_role,json=userRole,proto3" json:"user_role,omitempty"`
|
||||
Verified bool `protobuf:"varint,4,opt,name=verified,proto3" json:"verified,omitempty"`
|
||||
TokenType uint32 `protobuf:"varint,5,opt,name=token_type,json=tokenType,proto3" json:"token_type,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
@@ -136,6 +137,13 @@ func (x *AuthNRes) GetVerified() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (x *AuthNRes) GetTokenType() uint32 {
|
||||
if x != nil {
|
||||
return x.TokenType
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
type PolicyReq struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Domain string `protobuf:"bytes,1,opt,name=domain,proto3" json:"domain,omitempty"`
|
||||
@@ -438,12 +446,14 @@ const file_auth_v1_auth_proto_rawDesc = "" +
|
||||
"\n" +
|
||||
"\x12auth/v1/auth.proto\x12\aauth.v1\" \n" +
|
||||
"\bAuthNReq\x12\x14\n" +
|
||||
"\x05token\x18\x01 \x01(\tR\x05token\"l\n" +
|
||||
"\x05token\x18\x01 \x01(\tR\x05token\"\x8b\x01\n" +
|
||||
"\bAuthNRes\x12\x0e\n" +
|
||||
"\x02id\x18\x01 \x01(\tR\x02id\x12\x17\n" +
|
||||
"\auser_id\x18\x02 \x01(\tR\x06userId\x12\x1b\n" +
|
||||
"\tuser_role\x18\x03 \x01(\rR\buserRole\x12\x1a\n" +
|
||||
"\bverified\x18\x04 \x01(\bR\bverified\"\xa3\x02\n" +
|
||||
"\bverified\x18\x04 \x01(\bR\bverified\x12\x1d\n" +
|
||||
"\n" +
|
||||
"token_type\x18\x05 \x01(\rR\ttokenType\"\xa3\x02\n" +
|
||||
"\tPolicyReq\x12\x16\n" +
|
||||
"\x06domain\x18\x01 \x01(\tR\x06domain\x12!\n" +
|
||||
"\fsubject_type\x18\x02 \x01(\tR\vsubjectType\x12!\n" +
|
||||
@@ -478,7 +488,7 @@ const file_auth_v1_auth_proto_rawDesc = "" +
|
||||
"\x02id\x18\x02 \x01(\tR\x02id2z\n" +
|
||||
"\vAuthService\x123\n" +
|
||||
"\tAuthorize\x12\x11.auth.v1.AuthZReq\x1a\x11.auth.v1.AuthZRes\"\x00\x126\n" +
|
||||
"\fAuthenticate\x12\x11.auth.v1.AuthNReq\x1a\x11.auth.v1.AuthNRes\"\x00B-Z+github.com/absmach/supermq/api/grpc/auth/v1b\x06proto3"
|
||||
"\fAuthenticate\x12\x11.auth.v1.AuthNReq\x1a\x11.auth.v1.AuthNRes\"\x00B0Z.github.com/absmach/magistrala/api/grpc/auth/v1b\x06proto3"
|
||||
|
||||
var (
|
||||
file_auth_v1_auth_proto_rawDescOnce sync.Once
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
|
||||
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
||||
// versions:
|
||||
// - protoc-gen-go-grpc v1.6.0
|
||||
// - protoc v6.33.0
|
||||
// - protoc-gen-go-grpc v1.6.2
|
||||
// - protoc v7.35.1
|
||||
// source: auth/v1/auth.proto
|
||||
|
||||
package v1
|
||||
@@ -31,7 +31,7 @@ const (
|
||||
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
|
||||
//
|
||||
// AuthService is a service that provides authentication
|
||||
// and authorization functionalities for SuperMQ services.
|
||||
// and authorization functionalities for Magistrala services.
|
||||
type AuthServiceClient interface {
|
||||
Authorize(ctx context.Context, in *AuthZReq, opts ...grpc.CallOption) (*AuthZRes, error)
|
||||
Authenticate(ctx context.Context, in *AuthNReq, opts ...grpc.CallOption) (*AuthNRes, error)
|
||||
@@ -70,7 +70,7 @@ func (c *authServiceClient) Authenticate(ctx context.Context, in *AuthNReq, opts
|
||||
// for forward compatibility.
|
||||
//
|
||||
// AuthService is a service that provides authentication
|
||||
// and authorization functionalities for SuperMQ services.
|
||||
// and authorization functionalities for Magistrala services.
|
||||
type AuthServiceServer interface {
|
||||
Authorize(context.Context, *AuthZReq) (*AuthZRes, error)
|
||||
Authenticate(context.Context, *AuthNReq) (*AuthNRes, error)
|
||||
|
||||
@@ -0,0 +1,228 @@
|
||||
// Copyright (c) Abstract Machines
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.36.11
|
||||
// protoc v7.35.1
|
||||
// source: certs/v1/certs.proto
|
||||
|
||||
package v1
|
||||
|
||||
import (
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
emptypb "google.golang.org/protobuf/types/known/emptypb"
|
||||
reflect "reflect"
|
||||
sync "sync"
|
||||
unsafe "unsafe"
|
||||
)
|
||||
|
||||
const (
|
||||
// Verify that this generated code is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
type EntityReq struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
SerialNumber string `protobuf:"bytes,1,opt,name=serial_number,json=serialNumber,proto3" json:"serial_number,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *EntityReq) Reset() {
|
||||
*x = EntityReq{}
|
||||
mi := &file_certs_v1_certs_proto_msgTypes[0]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *EntityReq) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*EntityReq) ProtoMessage() {}
|
||||
|
||||
func (x *EntityReq) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_certs_v1_certs_proto_msgTypes[0]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use EntityReq.ProtoReflect.Descriptor instead.
|
||||
func (*EntityReq) Descriptor() ([]byte, []int) {
|
||||
return file_certs_v1_certs_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
func (x *EntityReq) GetSerialNumber() string {
|
||||
if x != nil {
|
||||
return x.SerialNumber
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type EntityRes struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
EntityId string `protobuf:"bytes,1,opt,name=entity_id,json=entityId,proto3" json:"entity_id,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *EntityRes) Reset() {
|
||||
*x = EntityRes{}
|
||||
mi := &file_certs_v1_certs_proto_msgTypes[1]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *EntityRes) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*EntityRes) ProtoMessage() {}
|
||||
|
||||
func (x *EntityRes) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_certs_v1_certs_proto_msgTypes[1]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use EntityRes.ProtoReflect.Descriptor instead.
|
||||
func (*EntityRes) Descriptor() ([]byte, []int) {
|
||||
return file_certs_v1_certs_proto_rawDescGZIP(), []int{1}
|
||||
}
|
||||
|
||||
func (x *EntityRes) GetEntityId() string {
|
||||
if x != nil {
|
||||
return x.EntityId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type RevokeReq struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
EntityId string `protobuf:"bytes,1,opt,name=entity_id,json=entityId,proto3" json:"entity_id,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *RevokeReq) Reset() {
|
||||
*x = RevokeReq{}
|
||||
mi := &file_certs_v1_certs_proto_msgTypes[2]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *RevokeReq) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*RevokeReq) ProtoMessage() {}
|
||||
|
||||
func (x *RevokeReq) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_certs_v1_certs_proto_msgTypes[2]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use RevokeReq.ProtoReflect.Descriptor instead.
|
||||
func (*RevokeReq) Descriptor() ([]byte, []int) {
|
||||
return file_certs_v1_certs_proto_rawDescGZIP(), []int{2}
|
||||
}
|
||||
|
||||
func (x *RevokeReq) GetEntityId() string {
|
||||
if x != nil {
|
||||
return x.EntityId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
var File_certs_v1_certs_proto protoreflect.FileDescriptor
|
||||
|
||||
const file_certs_v1_certs_proto_rawDesc = "" +
|
||||
"\n" +
|
||||
"\x14certs/v1/certs.proto\x12\rabsmach.certs\x1a\x1bgoogle/protobuf/empty.proto\"0\n" +
|
||||
"\tEntityReq\x12#\n" +
|
||||
"\rserial_number\x18\x01 \x01(\tR\fserialNumber\"(\n" +
|
||||
"\tEntityRes\x12\x1b\n" +
|
||||
"\tentity_id\x18\x01 \x01(\tR\bentityId\"(\n" +
|
||||
"\tRevokeReq\x12\x1b\n" +
|
||||
"\tentity_id\x18\x01 \x01(\tR\bentityId2\x96\x01\n" +
|
||||
"\fCertsService\x12C\n" +
|
||||
"\vGetEntityID\x12\x18.absmach.certs.EntityReq\x1a\x18.absmach.certs.EntityRes\"\x00\x12A\n" +
|
||||
"\vRevokeCerts\x12\x18.absmach.certs.RevokeReq\x1a\x16.google.protobuf.Empty\"\x00B1Z/github.com/absmach/magistrala/api/grpc/certs/v1b\x06proto3"
|
||||
|
||||
var (
|
||||
file_certs_v1_certs_proto_rawDescOnce sync.Once
|
||||
file_certs_v1_certs_proto_rawDescData []byte
|
||||
)
|
||||
|
||||
func file_certs_v1_certs_proto_rawDescGZIP() []byte {
|
||||
file_certs_v1_certs_proto_rawDescOnce.Do(func() {
|
||||
file_certs_v1_certs_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_certs_v1_certs_proto_rawDesc), len(file_certs_v1_certs_proto_rawDesc)))
|
||||
})
|
||||
return file_certs_v1_certs_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_certs_v1_certs_proto_msgTypes = make([]protoimpl.MessageInfo, 3)
|
||||
var file_certs_v1_certs_proto_goTypes = []any{
|
||||
(*EntityReq)(nil), // 0: absmach.certs.EntityReq
|
||||
(*EntityRes)(nil), // 1: absmach.certs.EntityRes
|
||||
(*RevokeReq)(nil), // 2: absmach.certs.RevokeReq
|
||||
(*emptypb.Empty)(nil), // 3: google.protobuf.Empty
|
||||
}
|
||||
var file_certs_v1_certs_proto_depIdxs = []int32{
|
||||
0, // 0: absmach.certs.CertsService.GetEntityID:input_type -> absmach.certs.EntityReq
|
||||
2, // 1: absmach.certs.CertsService.RevokeCerts:input_type -> absmach.certs.RevokeReq
|
||||
1, // 2: absmach.certs.CertsService.GetEntityID:output_type -> absmach.certs.EntityRes
|
||||
3, // 3: absmach.certs.CertsService.RevokeCerts:output_type -> google.protobuf.Empty
|
||||
2, // [2:4] is the sub-list for method output_type
|
||||
0, // [0:2] is the sub-list for method input_type
|
||||
0, // [0:0] is the sub-list for extension type_name
|
||||
0, // [0:0] is the sub-list for extension extendee
|
||||
0, // [0:0] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_certs_v1_certs_proto_init() }
|
||||
func file_certs_v1_certs_proto_init() {
|
||||
if File_certs_v1_certs_proto != nil {
|
||||
return
|
||||
}
|
||||
type x struct{}
|
||||
out := protoimpl.TypeBuilder{
|
||||
File: protoimpl.DescBuilder{
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: unsafe.Slice(unsafe.StringData(file_certs_v1_certs_proto_rawDesc), len(file_certs_v1_certs_proto_rawDesc)),
|
||||
NumEnums: 0,
|
||||
NumMessages: 3,
|
||||
NumExtensions: 0,
|
||||
NumServices: 1,
|
||||
},
|
||||
GoTypes: file_certs_v1_certs_proto_goTypes,
|
||||
DependencyIndexes: file_certs_v1_certs_proto_depIdxs,
|
||||
MessageInfos: file_certs_v1_certs_proto_msgTypes,
|
||||
}.Build()
|
||||
File_certs_v1_certs_proto = out.File
|
||||
file_certs_v1_certs_proto_goTypes = nil
|
||||
file_certs_v1_certs_proto_depIdxs = nil
|
||||
}
|
||||
@@ -0,0 +1,163 @@
|
||||
// Copyright (c) Abstract Machines
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
||||
// versions:
|
||||
// - protoc-gen-go-grpc v1.6.2
|
||||
// - protoc v7.35.1
|
||||
// source: certs/v1/certs.proto
|
||||
|
||||
package v1
|
||||
|
||||
import (
|
||||
context "context"
|
||||
grpc "google.golang.org/grpc"
|
||||
codes "google.golang.org/grpc/codes"
|
||||
status "google.golang.org/grpc/status"
|
||||
emptypb "google.golang.org/protobuf/types/known/emptypb"
|
||||
)
|
||||
|
||||
// This is a compile-time assertion to ensure that this generated file
|
||||
// is compatible with the grpc package it is being compiled against.
|
||||
// Requires gRPC-Go v1.64.0 or later.
|
||||
const _ = grpc.SupportPackageIsVersion9
|
||||
|
||||
const (
|
||||
CertsService_GetEntityID_FullMethodName = "/absmach.certs.CertsService/GetEntityID"
|
||||
CertsService_RevokeCerts_FullMethodName = "/absmach.certs.CertsService/RevokeCerts"
|
||||
)
|
||||
|
||||
// CertsServiceClient is the client API for CertsService service.
|
||||
//
|
||||
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
|
||||
type CertsServiceClient interface {
|
||||
GetEntityID(ctx context.Context, in *EntityReq, opts ...grpc.CallOption) (*EntityRes, error)
|
||||
RevokeCerts(ctx context.Context, in *RevokeReq, opts ...grpc.CallOption) (*emptypb.Empty, error)
|
||||
}
|
||||
|
||||
type certsServiceClient struct {
|
||||
cc grpc.ClientConnInterface
|
||||
}
|
||||
|
||||
func NewCertsServiceClient(cc grpc.ClientConnInterface) CertsServiceClient {
|
||||
return &certsServiceClient{cc}
|
||||
}
|
||||
|
||||
func (c *certsServiceClient) GetEntityID(ctx context.Context, in *EntityReq, opts ...grpc.CallOption) (*EntityRes, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(EntityRes)
|
||||
err := c.cc.Invoke(ctx, CertsService_GetEntityID_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
func (c *certsServiceClient) RevokeCerts(ctx context.Context, in *RevokeReq, opts ...grpc.CallOption) (*emptypb.Empty, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(emptypb.Empty)
|
||||
err := c.cc.Invoke(ctx, CertsService_RevokeCerts_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// CertsServiceServer is the server API for CertsService service.
|
||||
// All implementations must embed UnimplementedCertsServiceServer
|
||||
// for forward compatibility.
|
||||
type CertsServiceServer interface {
|
||||
GetEntityID(context.Context, *EntityReq) (*EntityRes, error)
|
||||
RevokeCerts(context.Context, *RevokeReq) (*emptypb.Empty, error)
|
||||
mustEmbedUnimplementedCertsServiceServer()
|
||||
}
|
||||
|
||||
// UnimplementedCertsServiceServer must be embedded to have
|
||||
// forward compatible implementations.
|
||||
//
|
||||
// NOTE: this should be embedded by value instead of pointer to avoid a nil
|
||||
// pointer dereference when methods are called.
|
||||
type UnimplementedCertsServiceServer struct{}
|
||||
|
||||
func (UnimplementedCertsServiceServer) GetEntityID(context.Context, *EntityReq) (*EntityRes, error) {
|
||||
return nil, status.Error(codes.Unimplemented, "method GetEntityID not implemented")
|
||||
}
|
||||
func (UnimplementedCertsServiceServer) RevokeCerts(context.Context, *RevokeReq) (*emptypb.Empty, error) {
|
||||
return nil, status.Error(codes.Unimplemented, "method RevokeCerts not implemented")
|
||||
}
|
||||
func (UnimplementedCertsServiceServer) mustEmbedUnimplementedCertsServiceServer() {}
|
||||
func (UnimplementedCertsServiceServer) testEmbeddedByValue() {}
|
||||
|
||||
// UnsafeCertsServiceServer may be embedded to opt out of forward compatibility for this service.
|
||||
// Use of this interface is not recommended, as added methods to CertsServiceServer will
|
||||
// result in compilation errors.
|
||||
type UnsafeCertsServiceServer interface {
|
||||
mustEmbedUnimplementedCertsServiceServer()
|
||||
}
|
||||
|
||||
func RegisterCertsServiceServer(s grpc.ServiceRegistrar, srv CertsServiceServer) {
|
||||
// If the following call panics, it indicates UnimplementedCertsServiceServer was
|
||||
// embedded by pointer and is nil. This will cause panics if an
|
||||
// unimplemented method is ever invoked, so we test this at initialization
|
||||
// time to prevent it from happening at runtime later due to I/O.
|
||||
if t, ok := srv.(interface{ testEmbeddedByValue() }); ok {
|
||||
t.testEmbeddedByValue()
|
||||
}
|
||||
s.RegisterService(&CertsService_ServiceDesc, srv)
|
||||
}
|
||||
|
||||
func _CertsService_GetEntityID_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(EntityReq)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(CertsServiceServer).GetEntityID(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: CertsService_GetEntityID_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(CertsServiceServer).GetEntityID(ctx, req.(*EntityReq))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
func _CertsService_RevokeCerts_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(RevokeReq)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(CertsServiceServer).RevokeCerts(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: CertsService_RevokeCerts_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(CertsServiceServer).RevokeCerts(ctx, req.(*RevokeReq))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
// CertsService_ServiceDesc is the grpc.ServiceDesc for CertsService service.
|
||||
// It's only intended for direct use with grpc.RegisterService,
|
||||
// and not to be introspected or modified (even as a copy)
|
||||
var CertsService_ServiceDesc = grpc.ServiceDesc{
|
||||
ServiceName: "absmach.certs.CertsService",
|
||||
HandlerType: (*CertsServiceServer)(nil),
|
||||
Methods: []grpc.MethodDesc{
|
||||
{
|
||||
MethodName: "GetEntityID",
|
||||
Handler: _CertsService_GetEntityID_Handler,
|
||||
},
|
||||
{
|
||||
MethodName: "RevokeCerts",
|
||||
Handler: _CertsService_RevokeCerts_Handler,
|
||||
},
|
||||
},
|
||||
Streams: []grpc.StreamDesc{},
|
||||
Metadata: "certs/v1/certs.proto",
|
||||
}
|
||||
@@ -4,13 +4,13 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.36.11
|
||||
// protoc v6.33.0
|
||||
// protoc v7.35.1
|
||||
// source: channels/v1/channels.proto
|
||||
|
||||
package v1
|
||||
|
||||
import (
|
||||
v1 "github.com/absmach/supermq/api/grpc/common/v1"
|
||||
v1 "github.com/absmach/magistrala/api/grpc/common/v1"
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
reflect "reflect"
|
||||
@@ -333,7 +333,7 @@ const file_channels_v1_channels_proto_rawDesc = "" +
|
||||
"\x17RemoveClientConnections\x12'.channels.v1.RemoveClientConnectionsReq\x1a'.channels.v1.RemoveClientConnectionsRes\"\x00\x12|\n" +
|
||||
"\x1cUnsetParentGroupFromChannels\x12,.channels.v1.UnsetParentGroupFromChannelsReq\x1a,.channels.v1.UnsetParentGroupFromChannelsRes\"\x00\x12N\n" +
|
||||
"\x0eRetrieveEntity\x12\x1c.common.v1.RetrieveEntityReq\x1a\x1c.common.v1.RetrieveEntityRes\"\x00\x12T\n" +
|
||||
"\x11RetrieveIDByRoute\x12\x1f.common.v1.RetrieveIDByRouteReq\x1a\x1c.common.v1.RetrieveEntityRes\"\x00B1Z/github.com/absmach/supermq/api/grpc/channels/v1b\x06proto3"
|
||||
"\x11RetrieveIDByRoute\x12\x1f.common.v1.RetrieveIDByRouteReq\x1a\x1c.common.v1.RetrieveEntityRes\"\x00B4Z2github.com/absmach/magistrala/api/grpc/channels/v1b\x06proto3"
|
||||
|
||||
var (
|
||||
file_channels_v1_channels_proto_rawDescOnce sync.Once
|
||||
|
||||
@@ -3,15 +3,15 @@
|
||||
|
||||
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
||||
// versions:
|
||||
// - protoc-gen-go-grpc v1.6.0
|
||||
// - protoc v6.33.0
|
||||
// - protoc-gen-go-grpc v1.6.2
|
||||
// - protoc v7.35.1
|
||||
// source: channels/v1/channels.proto
|
||||
|
||||
package v1
|
||||
|
||||
import (
|
||||
context "context"
|
||||
v1 "github.com/absmach/supermq/api/grpc/common/v1"
|
||||
v1 "github.com/absmach/magistrala/api/grpc/common/v1"
|
||||
grpc "google.golang.org/grpc"
|
||||
codes "google.golang.org/grpc/codes"
|
||||
status "google.golang.org/grpc/status"
|
||||
|
||||
@@ -4,13 +4,13 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.36.11
|
||||
// protoc v6.33.0
|
||||
// protoc v7.35.1
|
||||
// source: clients/v1/clients.proto
|
||||
|
||||
package v1
|
||||
|
||||
import (
|
||||
v1 "github.com/absmach/supermq/api/grpc/common/v1"
|
||||
v1 "github.com/absmach/magistrala/api/grpc/common/v1"
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
reflect "reflect"
|
||||
@@ -306,7 +306,7 @@ const file_clients_v1_clients_proto_rawDesc = "" +
|
||||
"\x0eAddConnections\x12\x1c.common.v1.AddConnectionsReq\x1a\x1c.common.v1.AddConnectionsRes\"\x00\x12W\n" +
|
||||
"\x11RemoveConnections\x12\x1f.common.v1.RemoveConnectionsReq\x1a\x1f.common.v1.RemoveConnectionsRes\"\x00\x12n\n" +
|
||||
"\x18RemoveChannelConnections\x12'.clients.v1.RemoveChannelConnectionsReq\x1a'.clients.v1.RemoveChannelConnectionsRes\"\x00\x12t\n" +
|
||||
"\x1aUnsetParentGroupFromClient\x12).clients.v1.UnsetParentGroupFromClientReq\x1a).clients.v1.UnsetParentGroupFromClientRes\"\x00B0Z.github.com/absmach/supermq/api/grpc/clients/v1b\x06proto3"
|
||||
"\x1aUnsetParentGroupFromClient\x12).clients.v1.UnsetParentGroupFromClientReq\x1a).clients.v1.UnsetParentGroupFromClientRes\"\x00B3Z1github.com/absmach/magistrala/api/grpc/clients/v1b\x06proto3"
|
||||
|
||||
var (
|
||||
file_clients_v1_clients_proto_rawDescOnce sync.Once
|
||||
|
||||
@@ -3,15 +3,15 @@
|
||||
|
||||
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
||||
// versions:
|
||||
// - protoc-gen-go-grpc v1.6.0
|
||||
// - protoc v6.33.0
|
||||
// - protoc-gen-go-grpc v1.6.2
|
||||
// - protoc v7.35.1
|
||||
// source: clients/v1/clients.proto
|
||||
|
||||
package v1
|
||||
|
||||
import (
|
||||
context "context"
|
||||
v1 "github.com/absmach/supermq/api/grpc/common/v1"
|
||||
v1 "github.com/absmach/magistrala/api/grpc/common/v1"
|
||||
grpc "google.golang.org/grpc"
|
||||
codes "google.golang.org/grpc/codes"
|
||||
status "google.golang.org/grpc/status"
|
||||
@@ -37,7 +37,7 @@ const (
|
||||
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
|
||||
//
|
||||
// ClientsService is a service that provides clients
|
||||
// authorization functionalities for SuperMQ services.
|
||||
// authorization functionalities for Magistrala services.
|
||||
type ClientsServiceClient interface {
|
||||
// Authorize checks if the client is authorized to perform
|
||||
Authenticate(ctx context.Context, in *AuthnReq, opts ...grpc.CallOption) (*AuthnRes, error)
|
||||
@@ -132,7 +132,7 @@ func (c *clientsServiceClient) UnsetParentGroupFromClient(ctx context.Context, i
|
||||
// for forward compatibility.
|
||||
//
|
||||
// ClientsService is a service that provides clients
|
||||
// authorization functionalities for SuperMQ services.
|
||||
// authorization functionalities for Magistrala services.
|
||||
type ClientsServiceServer interface {
|
||||
// Authorize checks if the client is authorized to perform
|
||||
Authenticate(context.Context, *AuthnReq) (*AuthnRes, error)
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.36.11
|
||||
// protoc v6.33.0
|
||||
// protoc v7.35.1
|
||||
// source: common/v1/common.proto
|
||||
|
||||
package v1
|
||||
@@ -626,7 +626,7 @@ const file_common_v1_common_proto_rawDesc = "" +
|
||||
"\x04type\x18\x04 \x01(\rR\x04type\"I\n" +
|
||||
"\x14RetrieveIDByRouteReq\x12\x14\n" +
|
||||
"\x05route\x18\x01 \x01(\tR\x05route\x12\x1b\n" +
|
||||
"\tdomain_id\x18\x02 \x01(\tR\bdomainIdB/Z-github.com/absmach/supermq/api/grpc/common/v1b\x06proto3"
|
||||
"\tdomain_id\x18\x02 \x01(\tR\bdomainIdB2Z0github.com/absmach/magistrala/api/grpc/common/v1b\x06proto3"
|
||||
|
||||
var (
|
||||
file_common_v1_common_proto_rawDescOnce sync.Once
|
||||
|
||||
@@ -4,13 +4,13 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.36.11
|
||||
// protoc v6.33.0
|
||||
// protoc v7.35.1
|
||||
// source: domains/v1/domains.proto
|
||||
|
||||
package v1
|
||||
|
||||
import (
|
||||
v1 "github.com/absmach/supermq/api/grpc/common/v1"
|
||||
v1 "github.com/absmach/magistrala/api/grpc/common/v1"
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
reflect "reflect"
|
||||
@@ -126,7 +126,7 @@ const file_domains_v1_domains_proto_rawDesc = "" +
|
||||
"\x0eDomainsService\x12O\n" +
|
||||
"\x15DeleteUserFromDomains\x12\x19.domains.v1.DeleteUserReq\x1a\x19.domains.v1.DeleteUserRes\"\x00\x12N\n" +
|
||||
"\x0eRetrieveStatus\x12\x1c.common.v1.RetrieveEntityReq\x1a\x1c.common.v1.RetrieveEntityRes\"\x00\x12T\n" +
|
||||
"\x11RetrieveIDByRoute\x12\x1f.common.v1.RetrieveIDByRouteReq\x1a\x1c.common.v1.RetrieveEntityRes\"\x00B5Z3github.com/absmach/supermq/internal/grpc/domains/v1b\x06proto3"
|
||||
"\x11RetrieveIDByRoute\x12\x1f.common.v1.RetrieveIDByRouteReq\x1a\x1c.common.v1.RetrieveEntityRes\"\x00B8Z6github.com/absmach/magistrala/internal/grpc/domains/v1b\x06proto3"
|
||||
|
||||
var (
|
||||
file_domains_v1_domains_proto_rawDescOnce sync.Once
|
||||
|
||||
@@ -3,15 +3,15 @@
|
||||
|
||||
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
||||
// versions:
|
||||
// - protoc-gen-go-grpc v1.6.0
|
||||
// - protoc v6.33.0
|
||||
// - protoc-gen-go-grpc v1.6.2
|
||||
// - protoc v7.35.1
|
||||
// source: domains/v1/domains.proto
|
||||
|
||||
package v1
|
||||
|
||||
import (
|
||||
context "context"
|
||||
v1 "github.com/absmach/supermq/api/grpc/common/v1"
|
||||
v1 "github.com/absmach/magistrala/api/grpc/common/v1"
|
||||
grpc "google.golang.org/grpc"
|
||||
codes "google.golang.org/grpc/codes"
|
||||
status "google.golang.org/grpc/status"
|
||||
@@ -33,7 +33,7 @@ const (
|
||||
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
|
||||
//
|
||||
// DomainsService is a service that provides access to
|
||||
// domains functionalities for SuperMQ services.
|
||||
// domains functionalities for Magistrala services.
|
||||
type DomainsServiceClient interface {
|
||||
DeleteUserFromDomains(ctx context.Context, in *DeleteUserReq, opts ...grpc.CallOption) (*DeleteUserRes, error)
|
||||
RetrieveStatus(ctx context.Context, in *v1.RetrieveEntityReq, opts ...grpc.CallOption) (*v1.RetrieveEntityRes, error)
|
||||
@@ -83,7 +83,7 @@ func (c *domainsServiceClient) RetrieveIDByRoute(ctx context.Context, in *v1.Ret
|
||||
// for forward compatibility.
|
||||
//
|
||||
// DomainsService is a service that provides access to
|
||||
// domains functionalities for SuperMQ services.
|
||||
// domains functionalities for Magistrala services.
|
||||
type DomainsServiceServer interface {
|
||||
DeleteUserFromDomains(context.Context, *DeleteUserReq) (*DeleteUserRes, error)
|
||||
RetrieveStatus(context.Context, *v1.RetrieveEntityReq) (*v1.RetrieveEntityRes, error)
|
||||
|
||||
@@ -4,13 +4,13 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.36.11
|
||||
// protoc v6.33.0
|
||||
// protoc v7.35.1
|
||||
// source: groups/v1/groups.proto
|
||||
|
||||
package v1
|
||||
|
||||
import (
|
||||
v1 "github.com/absmach/supermq/api/grpc/common/v1"
|
||||
v1 "github.com/absmach/magistrala/api/grpc/common/v1"
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
reflect "reflect"
|
||||
@@ -30,7 +30,7 @@ const file_groups_v1_groups_proto_rawDesc = "" +
|
||||
"\n" +
|
||||
"\x16groups/v1/groups.proto\x12\tgroups.v1\x1a\x16common/v1/common.proto2_\n" +
|
||||
"\rGroupsService\x12N\n" +
|
||||
"\x0eRetrieveEntity\x12\x1c.common.v1.RetrieveEntityReq\x1a\x1c.common.v1.RetrieveEntityRes\"\x00B/Z-github.com/absmach/supermq/api/grpc/groups/v1b\x06proto3"
|
||||
"\x0eRetrieveEntity\x12\x1c.common.v1.RetrieveEntityReq\x1a\x1c.common.v1.RetrieveEntityRes\"\x00B2Z0github.com/absmach/magistrala/api/grpc/groups/v1b\x06proto3"
|
||||
|
||||
var file_groups_v1_groups_proto_goTypes = []any{
|
||||
(*v1.RetrieveEntityReq)(nil), // 0: common.v1.RetrieveEntityReq
|
||||
|
||||
@@ -3,15 +3,15 @@
|
||||
|
||||
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
||||
// versions:
|
||||
// - protoc-gen-go-grpc v1.6.0
|
||||
// - protoc v6.33.0
|
||||
// - protoc-gen-go-grpc v1.6.2
|
||||
// - protoc v7.35.1
|
||||
// source: groups/v1/groups.proto
|
||||
|
||||
package v1
|
||||
|
||||
import (
|
||||
context "context"
|
||||
v1 "github.com/absmach/supermq/api/grpc/common/v1"
|
||||
v1 "github.com/absmach/magistrala/api/grpc/common/v1"
|
||||
grpc "google.golang.org/grpc"
|
||||
codes "google.golang.org/grpc/codes"
|
||||
status "google.golang.org/grpc/status"
|
||||
@@ -31,7 +31,7 @@ const (
|
||||
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
|
||||
//
|
||||
// GroupssService is a service that provides groups
|
||||
// functionalities for SuperMQ services.
|
||||
// functionalities for Magistrala services.
|
||||
type GroupsServiceClient interface {
|
||||
RetrieveEntity(ctx context.Context, in *v1.RetrieveEntityReq, opts ...grpc.CallOption) (*v1.RetrieveEntityRes, error)
|
||||
}
|
||||
@@ -59,7 +59,7 @@ func (c *groupsServiceClient) RetrieveEntity(ctx context.Context, in *v1.Retriev
|
||||
// for forward compatibility.
|
||||
//
|
||||
// GroupssService is a service that provides groups
|
||||
// functionalities for SuperMQ services.
|
||||
// functionalities for Magistrala services.
|
||||
type GroupsServiceServer interface {
|
||||
RetrieveEntity(context.Context, *v1.RetrieveEntityReq) (*v1.RetrieveEntityRes, error)
|
||||
mustEmbedUnimplementedGroupsServiceServer()
|
||||
|
||||
@@ -0,0 +1,884 @@
|
||||
// Copyright (c) Abstract Machines
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.36.11
|
||||
// protoc v7.35.1
|
||||
// source: readers/v1/readers.proto
|
||||
|
||||
package v1
|
||||
|
||||
import (
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
reflect "reflect"
|
||||
sync "sync"
|
||||
unsafe "unsafe"
|
||||
)
|
||||
|
||||
const (
|
||||
// Verify that this generated code is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(20 - protoimpl.MinVersion)
|
||||
// Verify that runtime/protoimpl is sufficiently up-to-date.
|
||||
_ = protoimpl.EnforceVersion(protoimpl.MaxVersion - 20)
|
||||
)
|
||||
|
||||
// Aggregation defines supported data aggregations.
|
||||
type Aggregation int32
|
||||
|
||||
const (
|
||||
Aggregation_AGGREGATION_UNSPECIFIED Aggregation = 0
|
||||
Aggregation_AGGREGATION_MAX Aggregation = 1
|
||||
Aggregation_AGGREGATION_MIN Aggregation = 2
|
||||
Aggregation_AGGREGATION_SUM Aggregation = 3
|
||||
Aggregation_AGGREGATION_COUNT Aggregation = 4
|
||||
Aggregation_AGGREGATION_AVG Aggregation = 5
|
||||
)
|
||||
|
||||
// Enum value maps for Aggregation.
|
||||
var (
|
||||
Aggregation_name = map[int32]string{
|
||||
0: "AGGREGATION_UNSPECIFIED",
|
||||
1: "AGGREGATION_MAX",
|
||||
2: "AGGREGATION_MIN",
|
||||
3: "AGGREGATION_SUM",
|
||||
4: "AGGREGATION_COUNT",
|
||||
5: "AGGREGATION_AVG",
|
||||
}
|
||||
Aggregation_value = map[string]int32{
|
||||
"AGGREGATION_UNSPECIFIED": 0,
|
||||
"AGGREGATION_MAX": 1,
|
||||
"AGGREGATION_MIN": 2,
|
||||
"AGGREGATION_SUM": 3,
|
||||
"AGGREGATION_COUNT": 4,
|
||||
"AGGREGATION_AVG": 5,
|
||||
}
|
||||
)
|
||||
|
||||
func (x Aggregation) Enum() *Aggregation {
|
||||
p := new(Aggregation)
|
||||
*p = x
|
||||
return p
|
||||
}
|
||||
|
||||
func (x Aggregation) String() string {
|
||||
return protoimpl.X.EnumStringOf(x.Descriptor(), protoreflect.EnumNumber(x))
|
||||
}
|
||||
|
||||
func (Aggregation) Descriptor() protoreflect.EnumDescriptor {
|
||||
return file_readers_v1_readers_proto_enumTypes[0].Descriptor()
|
||||
}
|
||||
|
||||
func (Aggregation) Type() protoreflect.EnumType {
|
||||
return &file_readers_v1_readers_proto_enumTypes[0]
|
||||
}
|
||||
|
||||
func (x Aggregation) Number() protoreflect.EnumNumber {
|
||||
return protoreflect.EnumNumber(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use Aggregation.Descriptor instead.
|
||||
func (Aggregation) EnumDescriptor() ([]byte, []int) {
|
||||
return file_readers_v1_readers_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
type PageMetadata struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Limit uint64 `protobuf:"varint,1,opt,name=limit,proto3" json:"limit,omitempty"`
|
||||
Offset uint64 `protobuf:"varint,2,opt,name=offset,proto3" json:"offset,omitempty"`
|
||||
Protocol string `protobuf:"bytes,3,opt,name=protocol,proto3" json:"protocol,omitempty"`
|
||||
Name string `protobuf:"bytes,4,opt,name=name,proto3" json:"name,omitempty"`
|
||||
Value float64 `protobuf:"fixed64,5,opt,name=value,proto3" json:"value,omitempty"`
|
||||
Publisher string `protobuf:"bytes,6,opt,name=publisher,proto3" json:"publisher,omitempty"`
|
||||
BoolValue bool `protobuf:"varint,7,opt,name=bool_value,json=boolValue,proto3" json:"bool_value,omitempty"`
|
||||
StringValue string `protobuf:"bytes,8,opt,name=string_value,json=stringValue,proto3" json:"string_value,omitempty"`
|
||||
DataValue string `protobuf:"bytes,9,opt,name=data_value,json=dataValue,proto3" json:"data_value,omitempty"`
|
||||
From float64 `protobuf:"fixed64,10,opt,name=from,proto3" json:"from,omitempty"`
|
||||
To float64 `protobuf:"fixed64,11,opt,name=to,proto3" json:"to,omitempty"`
|
||||
Subtopic string `protobuf:"bytes,12,opt,name=subtopic,proto3" json:"subtopic,omitempty"`
|
||||
Interval string `protobuf:"bytes,13,opt,name=interval,proto3" json:"interval,omitempty"`
|
||||
Read bool `protobuf:"varint,14,opt,name=read,proto3" json:"read,omitempty"`
|
||||
Aggregation Aggregation `protobuf:"varint,15,opt,name=aggregation,proto3,enum=readers.v1.Aggregation" json:"aggregation,omitempty"`
|
||||
Comparator string `protobuf:"bytes,16,opt,name=comparator,proto3" json:"comparator,omitempty"`
|
||||
Format string `protobuf:"bytes,17,opt,name=format,proto3" json:"format,omitempty"`
|
||||
Order string `protobuf:"bytes,18,opt,name=order,proto3" json:"order,omitempty"`
|
||||
Dir string `protobuf:"bytes,19,opt,name=dir,proto3" json:"dir,omitempty"`
|
||||
Publishers []string `protobuf:"bytes,20,rep,name=publishers,proto3" json:"publishers,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *PageMetadata) Reset() {
|
||||
*x = PageMetadata{}
|
||||
mi := &file_readers_v1_readers_proto_msgTypes[0]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *PageMetadata) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*PageMetadata) ProtoMessage() {}
|
||||
|
||||
func (x *PageMetadata) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_readers_v1_readers_proto_msgTypes[0]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use PageMetadata.ProtoReflect.Descriptor instead.
|
||||
func (*PageMetadata) Descriptor() ([]byte, []int) {
|
||||
return file_readers_v1_readers_proto_rawDescGZIP(), []int{0}
|
||||
}
|
||||
|
||||
func (x *PageMetadata) GetLimit() uint64 {
|
||||
if x != nil {
|
||||
return x.Limit
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *PageMetadata) GetOffset() uint64 {
|
||||
if x != nil {
|
||||
return x.Offset
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *PageMetadata) GetProtocol() string {
|
||||
if x != nil {
|
||||
return x.Protocol
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *PageMetadata) GetName() string {
|
||||
if x != nil {
|
||||
return x.Name
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *PageMetadata) GetValue() float64 {
|
||||
if x != nil {
|
||||
return x.Value
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *PageMetadata) GetPublisher() string {
|
||||
if x != nil {
|
||||
return x.Publisher
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *PageMetadata) GetBoolValue() bool {
|
||||
if x != nil {
|
||||
return x.BoolValue
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (x *PageMetadata) GetStringValue() string {
|
||||
if x != nil {
|
||||
return x.StringValue
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *PageMetadata) GetDataValue() string {
|
||||
if x != nil {
|
||||
return x.DataValue
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *PageMetadata) GetFrom() float64 {
|
||||
if x != nil {
|
||||
return x.From
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *PageMetadata) GetTo() float64 {
|
||||
if x != nil {
|
||||
return x.To
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *PageMetadata) GetSubtopic() string {
|
||||
if x != nil {
|
||||
return x.Subtopic
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *PageMetadata) GetInterval() string {
|
||||
if x != nil {
|
||||
return x.Interval
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *PageMetadata) GetRead() bool {
|
||||
if x != nil {
|
||||
return x.Read
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (x *PageMetadata) GetAggregation() Aggregation {
|
||||
if x != nil {
|
||||
return x.Aggregation
|
||||
}
|
||||
return Aggregation_AGGREGATION_UNSPECIFIED
|
||||
}
|
||||
|
||||
func (x *PageMetadata) GetComparator() string {
|
||||
if x != nil {
|
||||
return x.Comparator
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *PageMetadata) GetFormat() string {
|
||||
if x != nil {
|
||||
return x.Format
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *PageMetadata) GetOrder() string {
|
||||
if x != nil {
|
||||
return x.Order
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *PageMetadata) GetDir() string {
|
||||
if x != nil {
|
||||
return x.Dir
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *PageMetadata) GetPublishers() []string {
|
||||
if x != nil {
|
||||
return x.Publishers
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type ReadMessagesRes struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Total uint64 `protobuf:"varint,1,opt,name=total,proto3" json:"total,omitempty"`
|
||||
PageMetadata *PageMetadata `protobuf:"bytes,2,opt,name=page_metadata,json=pageMetadata,proto3" json:"page_metadata,omitempty"`
|
||||
Messages []*Message `protobuf:"bytes,3,rep,name=messages,proto3" json:"messages,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *ReadMessagesRes) Reset() {
|
||||
*x = ReadMessagesRes{}
|
||||
mi := &file_readers_v1_readers_proto_msgTypes[1]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *ReadMessagesRes) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*ReadMessagesRes) ProtoMessage() {}
|
||||
|
||||
func (x *ReadMessagesRes) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_readers_v1_readers_proto_msgTypes[1]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use ReadMessagesRes.ProtoReflect.Descriptor instead.
|
||||
func (*ReadMessagesRes) Descriptor() ([]byte, []int) {
|
||||
return file_readers_v1_readers_proto_rawDescGZIP(), []int{1}
|
||||
}
|
||||
|
||||
func (x *ReadMessagesRes) GetTotal() uint64 {
|
||||
if x != nil {
|
||||
return x.Total
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *ReadMessagesRes) GetPageMetadata() *PageMetadata {
|
||||
if x != nil {
|
||||
return x.PageMetadata
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *ReadMessagesRes) GetMessages() []*Message {
|
||||
if x != nil {
|
||||
return x.Messages
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type Message struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
// Types that are valid to be assigned to Payload:
|
||||
//
|
||||
// *Message_Senml
|
||||
// *Message_Json
|
||||
Payload isMessage_Payload `protobuf_oneof:"payload"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *Message) Reset() {
|
||||
*x = Message{}
|
||||
mi := &file_readers_v1_readers_proto_msgTypes[2]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *Message) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*Message) ProtoMessage() {}
|
||||
|
||||
func (x *Message) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_readers_v1_readers_proto_msgTypes[2]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use Message.ProtoReflect.Descriptor instead.
|
||||
func (*Message) Descriptor() ([]byte, []int) {
|
||||
return file_readers_v1_readers_proto_rawDescGZIP(), []int{2}
|
||||
}
|
||||
|
||||
func (x *Message) GetPayload() isMessage_Payload {
|
||||
if x != nil {
|
||||
return x.Payload
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *Message) GetSenml() *SenMLMessage {
|
||||
if x != nil {
|
||||
if x, ok := x.Payload.(*Message_Senml); ok {
|
||||
return x.Senml
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *Message) GetJson() *JsonMessage {
|
||||
if x != nil {
|
||||
if x, ok := x.Payload.(*Message_Json); ok {
|
||||
return x.Json
|
||||
}
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type isMessage_Payload interface {
|
||||
isMessage_Payload()
|
||||
}
|
||||
|
||||
type Message_Senml struct {
|
||||
Senml *SenMLMessage `protobuf:"bytes,1,opt,name=senml,proto3,oneof"`
|
||||
}
|
||||
|
||||
type Message_Json struct {
|
||||
Json *JsonMessage `protobuf:"bytes,2,opt,name=json,proto3,oneof"`
|
||||
}
|
||||
|
||||
func (*Message_Senml) isMessage_Payload() {}
|
||||
|
||||
func (*Message_Json) isMessage_Payload() {}
|
||||
|
||||
type BaseMessage struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Channel string `protobuf:"bytes,1,opt,name=channel,proto3" json:"channel,omitempty"`
|
||||
Subtopic string `protobuf:"bytes,2,opt,name=subtopic,proto3" json:"subtopic,omitempty"`
|
||||
Publisher string `protobuf:"bytes,3,opt,name=publisher,proto3" json:"publisher,omitempty"`
|
||||
Protocol string `protobuf:"bytes,4,opt,name=protocol,proto3" json:"protocol,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *BaseMessage) Reset() {
|
||||
*x = BaseMessage{}
|
||||
mi := &file_readers_v1_readers_proto_msgTypes[3]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *BaseMessage) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*BaseMessage) ProtoMessage() {}
|
||||
|
||||
func (x *BaseMessage) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_readers_v1_readers_proto_msgTypes[3]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use BaseMessage.ProtoReflect.Descriptor instead.
|
||||
func (*BaseMessage) Descriptor() ([]byte, []int) {
|
||||
return file_readers_v1_readers_proto_rawDescGZIP(), []int{3}
|
||||
}
|
||||
|
||||
func (x *BaseMessage) GetChannel() string {
|
||||
if x != nil {
|
||||
return x.Channel
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *BaseMessage) GetSubtopic() string {
|
||||
if x != nil {
|
||||
return x.Subtopic
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *BaseMessage) GetPublisher() string {
|
||||
if x != nil {
|
||||
return x.Publisher
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *BaseMessage) GetProtocol() string {
|
||||
if x != nil {
|
||||
return x.Protocol
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
type SenMLMessage struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Base *BaseMessage `protobuf:"bytes,1,opt,name=base,proto3" json:"base,omitempty"`
|
||||
Name string `protobuf:"bytes,2,opt,name=name,proto3" json:"name,omitempty"`
|
||||
Unit string `protobuf:"bytes,3,opt,name=unit,proto3" json:"unit,omitempty"`
|
||||
Time float64 `protobuf:"fixed64,4,opt,name=time,proto3" json:"time,omitempty"`
|
||||
UpdateTime float64 `protobuf:"fixed64,5,opt,name=update_time,json=updateTime,proto3" json:"update_time,omitempty"`
|
||||
Value *float64 `protobuf:"fixed64,6,opt,name=value,proto3,oneof" json:"value,omitempty"`
|
||||
StringValue *string `protobuf:"bytes,7,opt,name=string_value,json=stringValue,proto3,oneof" json:"string_value,omitempty"`
|
||||
DataValue *string `protobuf:"bytes,8,opt,name=data_value,json=dataValue,proto3,oneof" json:"data_value,omitempty"`
|
||||
BoolValue *bool `protobuf:"varint,9,opt,name=bool_value,json=boolValue,proto3,oneof" json:"bool_value,omitempty"`
|
||||
Sum *float64 `protobuf:"fixed64,10,opt,name=sum,proto3,oneof" json:"sum,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *SenMLMessage) Reset() {
|
||||
*x = SenMLMessage{}
|
||||
mi := &file_readers_v1_readers_proto_msgTypes[4]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *SenMLMessage) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*SenMLMessage) ProtoMessage() {}
|
||||
|
||||
func (x *SenMLMessage) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_readers_v1_readers_proto_msgTypes[4]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use SenMLMessage.ProtoReflect.Descriptor instead.
|
||||
func (*SenMLMessage) Descriptor() ([]byte, []int) {
|
||||
return file_readers_v1_readers_proto_rawDescGZIP(), []int{4}
|
||||
}
|
||||
|
||||
func (x *SenMLMessage) GetBase() *BaseMessage {
|
||||
if x != nil {
|
||||
return x.Base
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *SenMLMessage) GetName() string {
|
||||
if x != nil {
|
||||
return x.Name
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *SenMLMessage) GetUnit() string {
|
||||
if x != nil {
|
||||
return x.Unit
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *SenMLMessage) GetTime() float64 {
|
||||
if x != nil {
|
||||
return x.Time
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *SenMLMessage) GetUpdateTime() float64 {
|
||||
if x != nil {
|
||||
return x.UpdateTime
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *SenMLMessage) GetValue() float64 {
|
||||
if x != nil && x.Value != nil {
|
||||
return *x.Value
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *SenMLMessage) GetStringValue() string {
|
||||
if x != nil && x.StringValue != nil {
|
||||
return *x.StringValue
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *SenMLMessage) GetDataValue() string {
|
||||
if x != nil && x.DataValue != nil {
|
||||
return *x.DataValue
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *SenMLMessage) GetBoolValue() bool {
|
||||
if x != nil && x.BoolValue != nil {
|
||||
return *x.BoolValue
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
func (x *SenMLMessage) GetSum() float64 {
|
||||
if x != nil && x.Sum != nil {
|
||||
return *x.Sum
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
type JsonMessage struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
Base *BaseMessage `protobuf:"bytes,1,opt,name=base,proto3" json:"base,omitempty"`
|
||||
Created int64 `protobuf:"varint,2,opt,name=created,proto3" json:"created,omitempty"`
|
||||
Payload []byte `protobuf:"bytes,3,opt,name=payload,proto3" json:"payload,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *JsonMessage) Reset() {
|
||||
*x = JsonMessage{}
|
||||
mi := &file_readers_v1_readers_proto_msgTypes[5]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *JsonMessage) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*JsonMessage) ProtoMessage() {}
|
||||
|
||||
func (x *JsonMessage) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_readers_v1_readers_proto_msgTypes[5]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use JsonMessage.ProtoReflect.Descriptor instead.
|
||||
func (*JsonMessage) Descriptor() ([]byte, []int) {
|
||||
return file_readers_v1_readers_proto_rawDescGZIP(), []int{5}
|
||||
}
|
||||
|
||||
func (x *JsonMessage) GetBase() *BaseMessage {
|
||||
if x != nil {
|
||||
return x.Base
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (x *JsonMessage) GetCreated() int64 {
|
||||
if x != nil {
|
||||
return x.Created
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
func (x *JsonMessage) GetPayload() []byte {
|
||||
if x != nil {
|
||||
return x.Payload
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type ReadMessagesReq struct {
|
||||
state protoimpl.MessageState `protogen:"open.v1"`
|
||||
ChannelId string `protobuf:"bytes,1,opt,name=channel_id,json=channelId,proto3" json:"channel_id,omitempty"`
|
||||
DomainId string `protobuf:"bytes,2,opt,name=domain_id,json=domainId,proto3" json:"domain_id,omitempty"`
|
||||
PageMetadata *PageMetadata `protobuf:"bytes,3,opt,name=page_metadata,json=pageMetadata,proto3" json:"page_metadata,omitempty"`
|
||||
unknownFields protoimpl.UnknownFields
|
||||
sizeCache protoimpl.SizeCache
|
||||
}
|
||||
|
||||
func (x *ReadMessagesReq) Reset() {
|
||||
*x = ReadMessagesReq{}
|
||||
mi := &file_readers_v1_readers_proto_msgTypes[6]
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
|
||||
func (x *ReadMessagesReq) String() string {
|
||||
return protoimpl.X.MessageStringOf(x)
|
||||
}
|
||||
|
||||
func (*ReadMessagesReq) ProtoMessage() {}
|
||||
|
||||
func (x *ReadMessagesReq) ProtoReflect() protoreflect.Message {
|
||||
mi := &file_readers_v1_readers_proto_msgTypes[6]
|
||||
if x != nil {
|
||||
ms := protoimpl.X.MessageStateOf(protoimpl.Pointer(x))
|
||||
if ms.LoadMessageInfo() == nil {
|
||||
ms.StoreMessageInfo(mi)
|
||||
}
|
||||
return ms
|
||||
}
|
||||
return mi.MessageOf(x)
|
||||
}
|
||||
|
||||
// Deprecated: Use ReadMessagesReq.ProtoReflect.Descriptor instead.
|
||||
func (*ReadMessagesReq) Descriptor() ([]byte, []int) {
|
||||
return file_readers_v1_readers_proto_rawDescGZIP(), []int{6}
|
||||
}
|
||||
|
||||
func (x *ReadMessagesReq) GetChannelId() string {
|
||||
if x != nil {
|
||||
return x.ChannelId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *ReadMessagesReq) GetDomainId() string {
|
||||
if x != nil {
|
||||
return x.DomainId
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
func (x *ReadMessagesReq) GetPageMetadata() *PageMetadata {
|
||||
if x != nil {
|
||||
return x.PageMetadata
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
var File_readers_v1_readers_proto protoreflect.FileDescriptor
|
||||
|
||||
const file_readers_v1_readers_proto_rawDesc = "" +
|
||||
"\n" +
|
||||
"\x18readers/v1/readers.proto\x12\n" +
|
||||
"readers.v1\"\xac\x04\n" +
|
||||
"\fPageMetadata\x12\x14\n" +
|
||||
"\x05limit\x18\x01 \x01(\x04R\x05limit\x12\x16\n" +
|
||||
"\x06offset\x18\x02 \x01(\x04R\x06offset\x12\x1a\n" +
|
||||
"\bprotocol\x18\x03 \x01(\tR\bprotocol\x12\x12\n" +
|
||||
"\x04name\x18\x04 \x01(\tR\x04name\x12\x14\n" +
|
||||
"\x05value\x18\x05 \x01(\x01R\x05value\x12\x1c\n" +
|
||||
"\tpublisher\x18\x06 \x01(\tR\tpublisher\x12\x1d\n" +
|
||||
"\n" +
|
||||
"bool_value\x18\a \x01(\bR\tboolValue\x12!\n" +
|
||||
"\fstring_value\x18\b \x01(\tR\vstringValue\x12\x1d\n" +
|
||||
"\n" +
|
||||
"data_value\x18\t \x01(\tR\tdataValue\x12\x12\n" +
|
||||
"\x04from\x18\n" +
|
||||
" \x01(\x01R\x04from\x12\x0e\n" +
|
||||
"\x02to\x18\v \x01(\x01R\x02to\x12\x1a\n" +
|
||||
"\bsubtopic\x18\f \x01(\tR\bsubtopic\x12\x1a\n" +
|
||||
"\binterval\x18\r \x01(\tR\binterval\x12\x12\n" +
|
||||
"\x04read\x18\x0e \x01(\bR\x04read\x129\n" +
|
||||
"\vaggregation\x18\x0f \x01(\x0e2\x17.readers.v1.AggregationR\vaggregation\x12\x1e\n" +
|
||||
"\n" +
|
||||
"comparator\x18\x10 \x01(\tR\n" +
|
||||
"comparator\x12\x16\n" +
|
||||
"\x06format\x18\x11 \x01(\tR\x06format\x12\x14\n" +
|
||||
"\x05order\x18\x12 \x01(\tR\x05order\x12\x10\n" +
|
||||
"\x03dir\x18\x13 \x01(\tR\x03dir\x12\x1e\n" +
|
||||
"\n" +
|
||||
"publishers\x18\x14 \x03(\tR\n" +
|
||||
"publishers\"\x97\x01\n" +
|
||||
"\x0fReadMessagesRes\x12\x14\n" +
|
||||
"\x05total\x18\x01 \x01(\x04R\x05total\x12=\n" +
|
||||
"\rpage_metadata\x18\x02 \x01(\v2\x18.readers.v1.PageMetadataR\fpageMetadata\x12/\n" +
|
||||
"\bmessages\x18\x03 \x03(\v2\x13.readers.v1.MessageR\bmessages\"u\n" +
|
||||
"\aMessage\x120\n" +
|
||||
"\x05senml\x18\x01 \x01(\v2\x18.readers.v1.SenMLMessageH\x00R\x05senml\x12-\n" +
|
||||
"\x04json\x18\x02 \x01(\v2\x17.readers.v1.JsonMessageH\x00R\x04jsonB\t\n" +
|
||||
"\apayload\"}\n" +
|
||||
"\vBaseMessage\x12\x18\n" +
|
||||
"\achannel\x18\x01 \x01(\tR\achannel\x12\x1a\n" +
|
||||
"\bsubtopic\x18\x02 \x01(\tR\bsubtopic\x12\x1c\n" +
|
||||
"\tpublisher\x18\x03 \x01(\tR\tpublisher\x12\x1a\n" +
|
||||
"\bprotocol\x18\x04 \x01(\tR\bprotocol\"\xfb\x02\n" +
|
||||
"\fSenMLMessage\x12+\n" +
|
||||
"\x04base\x18\x01 \x01(\v2\x17.readers.v1.BaseMessageR\x04base\x12\x12\n" +
|
||||
"\x04name\x18\x02 \x01(\tR\x04name\x12\x12\n" +
|
||||
"\x04unit\x18\x03 \x01(\tR\x04unit\x12\x12\n" +
|
||||
"\x04time\x18\x04 \x01(\x01R\x04time\x12\x1f\n" +
|
||||
"\vupdate_time\x18\x05 \x01(\x01R\n" +
|
||||
"updateTime\x12\x19\n" +
|
||||
"\x05value\x18\x06 \x01(\x01H\x00R\x05value\x88\x01\x01\x12&\n" +
|
||||
"\fstring_value\x18\a \x01(\tH\x01R\vstringValue\x88\x01\x01\x12\"\n" +
|
||||
"\n" +
|
||||
"data_value\x18\b \x01(\tH\x02R\tdataValue\x88\x01\x01\x12\"\n" +
|
||||
"\n" +
|
||||
"bool_value\x18\t \x01(\bH\x03R\tboolValue\x88\x01\x01\x12\x15\n" +
|
||||
"\x03sum\x18\n" +
|
||||
" \x01(\x01H\x04R\x03sum\x88\x01\x01B\b\n" +
|
||||
"\x06_valueB\x0f\n" +
|
||||
"\r_string_valueB\r\n" +
|
||||
"\v_data_valueB\r\n" +
|
||||
"\v_bool_valueB\x06\n" +
|
||||
"\x04_sum\"n\n" +
|
||||
"\vJsonMessage\x12+\n" +
|
||||
"\x04base\x18\x01 \x01(\v2\x17.readers.v1.BaseMessageR\x04base\x12\x18\n" +
|
||||
"\acreated\x18\x02 \x01(\x03R\acreated\x12\x18\n" +
|
||||
"\apayload\x18\x03 \x01(\fR\apayload\"\x8c\x01\n" +
|
||||
"\x0fReadMessagesReq\x12\x1d\n" +
|
||||
"\n" +
|
||||
"channel_id\x18\x01 \x01(\tR\tchannelId\x12\x1b\n" +
|
||||
"\tdomain_id\x18\x02 \x01(\tR\bdomainId\x12=\n" +
|
||||
"\rpage_metadata\x18\x03 \x01(\v2\x18.readers.v1.PageMetadataR\fpageMetadata*\x95\x01\n" +
|
||||
"\vAggregation\x12\x1b\n" +
|
||||
"\x17AGGREGATION_UNSPECIFIED\x10\x00\x12\x13\n" +
|
||||
"\x0fAGGREGATION_MAX\x10\x01\x12\x13\n" +
|
||||
"\x0fAGGREGATION_MIN\x10\x02\x12\x13\n" +
|
||||
"\x0fAGGREGATION_SUM\x10\x03\x12\x15\n" +
|
||||
"\x11AGGREGATION_COUNT\x10\x04\x12\x13\n" +
|
||||
"\x0fAGGREGATION_AVG\x10\x052\\\n" +
|
||||
"\x0eReadersService\x12J\n" +
|
||||
"\fReadMessages\x12\x1b.readers.v1.ReadMessagesReq\x1a\x1b.readers.v1.ReadMessagesRes\"\x00B3Z1github.com/absmach/magistrala/api/grpc/readers/v1b\x06proto3"
|
||||
|
||||
var (
|
||||
file_readers_v1_readers_proto_rawDescOnce sync.Once
|
||||
file_readers_v1_readers_proto_rawDescData []byte
|
||||
)
|
||||
|
||||
func file_readers_v1_readers_proto_rawDescGZIP() []byte {
|
||||
file_readers_v1_readers_proto_rawDescOnce.Do(func() {
|
||||
file_readers_v1_readers_proto_rawDescData = protoimpl.X.CompressGZIP(unsafe.Slice(unsafe.StringData(file_readers_v1_readers_proto_rawDesc), len(file_readers_v1_readers_proto_rawDesc)))
|
||||
})
|
||||
return file_readers_v1_readers_proto_rawDescData
|
||||
}
|
||||
|
||||
var file_readers_v1_readers_proto_enumTypes = make([]protoimpl.EnumInfo, 1)
|
||||
var file_readers_v1_readers_proto_msgTypes = make([]protoimpl.MessageInfo, 7)
|
||||
var file_readers_v1_readers_proto_goTypes = []any{
|
||||
(Aggregation)(0), // 0: readers.v1.Aggregation
|
||||
(*PageMetadata)(nil), // 1: readers.v1.PageMetadata
|
||||
(*ReadMessagesRes)(nil), // 2: readers.v1.ReadMessagesRes
|
||||
(*Message)(nil), // 3: readers.v1.Message
|
||||
(*BaseMessage)(nil), // 4: readers.v1.BaseMessage
|
||||
(*SenMLMessage)(nil), // 5: readers.v1.SenMLMessage
|
||||
(*JsonMessage)(nil), // 6: readers.v1.JsonMessage
|
||||
(*ReadMessagesReq)(nil), // 7: readers.v1.ReadMessagesReq
|
||||
}
|
||||
var file_readers_v1_readers_proto_depIdxs = []int32{
|
||||
0, // 0: readers.v1.PageMetadata.aggregation:type_name -> readers.v1.Aggregation
|
||||
1, // 1: readers.v1.ReadMessagesRes.page_metadata:type_name -> readers.v1.PageMetadata
|
||||
3, // 2: readers.v1.ReadMessagesRes.messages:type_name -> readers.v1.Message
|
||||
5, // 3: readers.v1.Message.senml:type_name -> readers.v1.SenMLMessage
|
||||
6, // 4: readers.v1.Message.json:type_name -> readers.v1.JsonMessage
|
||||
4, // 5: readers.v1.SenMLMessage.base:type_name -> readers.v1.BaseMessage
|
||||
4, // 6: readers.v1.JsonMessage.base:type_name -> readers.v1.BaseMessage
|
||||
1, // 7: readers.v1.ReadMessagesReq.page_metadata:type_name -> readers.v1.PageMetadata
|
||||
7, // 8: readers.v1.ReadersService.ReadMessages:input_type -> readers.v1.ReadMessagesReq
|
||||
2, // 9: readers.v1.ReadersService.ReadMessages:output_type -> readers.v1.ReadMessagesRes
|
||||
9, // [9:10] is the sub-list for method output_type
|
||||
8, // [8:9] is the sub-list for method input_type
|
||||
8, // [8:8] is the sub-list for extension type_name
|
||||
8, // [8:8] is the sub-list for extension extendee
|
||||
0, // [0:8] is the sub-list for field type_name
|
||||
}
|
||||
|
||||
func init() { file_readers_v1_readers_proto_init() }
|
||||
func file_readers_v1_readers_proto_init() {
|
||||
if File_readers_v1_readers_proto != nil {
|
||||
return
|
||||
}
|
||||
file_readers_v1_readers_proto_msgTypes[2].OneofWrappers = []any{
|
||||
(*Message_Senml)(nil),
|
||||
(*Message_Json)(nil),
|
||||
}
|
||||
file_readers_v1_readers_proto_msgTypes[4].OneofWrappers = []any{}
|
||||
type x struct{}
|
||||
out := protoimpl.TypeBuilder{
|
||||
File: protoimpl.DescBuilder{
|
||||
GoPackagePath: reflect.TypeOf(x{}).PkgPath(),
|
||||
RawDescriptor: unsafe.Slice(unsafe.StringData(file_readers_v1_readers_proto_rawDesc), len(file_readers_v1_readers_proto_rawDesc)),
|
||||
NumEnums: 1,
|
||||
NumMessages: 7,
|
||||
NumExtensions: 0,
|
||||
NumServices: 1,
|
||||
},
|
||||
GoTypes: file_readers_v1_readers_proto_goTypes,
|
||||
DependencyIndexes: file_readers_v1_readers_proto_depIdxs,
|
||||
EnumInfos: file_readers_v1_readers_proto_enumTypes,
|
||||
MessageInfos: file_readers_v1_readers_proto_msgTypes,
|
||||
}.Build()
|
||||
File_readers_v1_readers_proto = out.File
|
||||
file_readers_v1_readers_proto_goTypes = nil
|
||||
file_readers_v1_readers_proto_depIdxs = nil
|
||||
}
|
||||
@@ -0,0 +1,130 @@
|
||||
// Copyright (c) Abstract Machines
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
||||
// versions:
|
||||
// - protoc-gen-go-grpc v1.6.2
|
||||
// - protoc v7.35.1
|
||||
// source: readers/v1/readers.proto
|
||||
|
||||
package v1
|
||||
|
||||
import (
|
||||
context "context"
|
||||
grpc "google.golang.org/grpc"
|
||||
codes "google.golang.org/grpc/codes"
|
||||
status "google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
// This is a compile-time assertion to ensure that this generated file
|
||||
// is compatible with the grpc package it is being compiled against.
|
||||
// Requires gRPC-Go v1.64.0 or later.
|
||||
const _ = grpc.SupportPackageIsVersion9
|
||||
|
||||
const (
|
||||
ReadersService_ReadMessages_FullMethodName = "/readers.v1.ReadersService/ReadMessages"
|
||||
)
|
||||
|
||||
// ReadersServiceClient is the client API for ReadersService service.
|
||||
//
|
||||
// For semantics around ctx use and closing/ending streaming RPCs, please refer to https://pkg.go.dev/google.golang.org/grpc/?tab=doc#ClientConn.NewStream.
|
||||
//
|
||||
// ReadersService is a service that provides access to
|
||||
// readers functionalities for Magistrala services.
|
||||
type ReadersServiceClient interface {
|
||||
ReadMessages(ctx context.Context, in *ReadMessagesReq, opts ...grpc.CallOption) (*ReadMessagesRes, error)
|
||||
}
|
||||
|
||||
type readersServiceClient struct {
|
||||
cc grpc.ClientConnInterface
|
||||
}
|
||||
|
||||
func NewReadersServiceClient(cc grpc.ClientConnInterface) ReadersServiceClient {
|
||||
return &readersServiceClient{cc}
|
||||
}
|
||||
|
||||
func (c *readersServiceClient) ReadMessages(ctx context.Context, in *ReadMessagesReq, opts ...grpc.CallOption) (*ReadMessagesRes, error) {
|
||||
cOpts := append([]grpc.CallOption{grpc.StaticMethod()}, opts...)
|
||||
out := new(ReadMessagesRes)
|
||||
err := c.cc.Invoke(ctx, ReadersService_ReadMessages_FullMethodName, in, out, cOpts...)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return out, nil
|
||||
}
|
||||
|
||||
// ReadersServiceServer is the server API for ReadersService service.
|
||||
// All implementations must embed UnimplementedReadersServiceServer
|
||||
// for forward compatibility.
|
||||
//
|
||||
// ReadersService is a service that provides access to
|
||||
// readers functionalities for Magistrala services.
|
||||
type ReadersServiceServer interface {
|
||||
ReadMessages(context.Context, *ReadMessagesReq) (*ReadMessagesRes, error)
|
||||
mustEmbedUnimplementedReadersServiceServer()
|
||||
}
|
||||
|
||||
// UnimplementedReadersServiceServer must be embedded to have
|
||||
// forward compatible implementations.
|
||||
//
|
||||
// NOTE: this should be embedded by value instead of pointer to avoid a nil
|
||||
// pointer dereference when methods are called.
|
||||
type UnimplementedReadersServiceServer struct{}
|
||||
|
||||
func (UnimplementedReadersServiceServer) ReadMessages(context.Context, *ReadMessagesReq) (*ReadMessagesRes, error) {
|
||||
return nil, status.Error(codes.Unimplemented, "method ReadMessages not implemented")
|
||||
}
|
||||
func (UnimplementedReadersServiceServer) mustEmbedUnimplementedReadersServiceServer() {}
|
||||
func (UnimplementedReadersServiceServer) testEmbeddedByValue() {}
|
||||
|
||||
// UnsafeReadersServiceServer may be embedded to opt out of forward compatibility for this service.
|
||||
// Use of this interface is not recommended, as added methods to ReadersServiceServer will
|
||||
// result in compilation errors.
|
||||
type UnsafeReadersServiceServer interface {
|
||||
mustEmbedUnimplementedReadersServiceServer()
|
||||
}
|
||||
|
||||
func RegisterReadersServiceServer(s grpc.ServiceRegistrar, srv ReadersServiceServer) {
|
||||
// If the following call panics, it indicates UnimplementedReadersServiceServer was
|
||||
// embedded by pointer and is nil. This will cause panics if an
|
||||
// unimplemented method is ever invoked, so we test this at initialization
|
||||
// time to prevent it from happening at runtime later due to I/O.
|
||||
if t, ok := srv.(interface{ testEmbeddedByValue() }); ok {
|
||||
t.testEmbeddedByValue()
|
||||
}
|
||||
s.RegisterService(&ReadersService_ServiceDesc, srv)
|
||||
}
|
||||
|
||||
func _ReadersService_ReadMessages_Handler(srv interface{}, ctx context.Context, dec func(interface{}) error, interceptor grpc.UnaryServerInterceptor) (interface{}, error) {
|
||||
in := new(ReadMessagesReq)
|
||||
if err := dec(in); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
if interceptor == nil {
|
||||
return srv.(ReadersServiceServer).ReadMessages(ctx, in)
|
||||
}
|
||||
info := &grpc.UnaryServerInfo{
|
||||
Server: srv,
|
||||
FullMethod: ReadersService_ReadMessages_FullMethodName,
|
||||
}
|
||||
handler := func(ctx context.Context, req interface{}) (interface{}, error) {
|
||||
return srv.(ReadersServiceServer).ReadMessages(ctx, req.(*ReadMessagesReq))
|
||||
}
|
||||
return interceptor(ctx, in, info, handler)
|
||||
}
|
||||
|
||||
// ReadersService_ServiceDesc is the grpc.ServiceDesc for ReadersService service.
|
||||
// It's only intended for direct use with grpc.RegisterService,
|
||||
// and not to be introspected or modified (even as a copy)
|
||||
var ReadersService_ServiceDesc = grpc.ServiceDesc{
|
||||
ServiceName: "readers.v1.ReadersService",
|
||||
HandlerType: (*ReadersServiceServer)(nil),
|
||||
Methods: []grpc.MethodDesc{
|
||||
{
|
||||
MethodName: "ReadMessages",
|
||||
Handler: _ReadersService_ReadMessages_Handler,
|
||||
},
|
||||
},
|
||||
Streams: []grpc.StreamDesc{},
|
||||
Metadata: "readers/v1/readers.proto",
|
||||
}
|
||||
@@ -4,7 +4,7 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.36.11
|
||||
// protoc v6.33.0
|
||||
// protoc v7.35.1
|
||||
// source: token/v1/token.proto
|
||||
|
||||
package v1
|
||||
@@ -479,7 +479,7 @@ const file_token_v1_token_proto_rawDesc = "" +
|
||||
"\x05Issue\x12\x12.token.v1.IssueReq\x1a\x0f.token.v1.Token\"\x00\x122\n" +
|
||||
"\aRefresh\x12\x14.token.v1.RefreshReq\x1a\x0f.token.v1.Token\"\x00\x124\n" +
|
||||
"\x06Revoke\x12\x13.token.v1.RevokeReq\x1a\x13.token.v1.RevokeRes\"\x00\x12a\n" +
|
||||
"\x15ListUserRefreshTokens\x12\".token.v1.ListUserRefreshTokensReq\x1a\".token.v1.ListUserRefreshTokensRes\"\x00B.Z,github.com/absmach/supermq/api/grpc/token/v1b\x06proto3"
|
||||
"\x15ListUserRefreshTokens\x12\".token.v1.ListUserRefreshTokensReq\x1a\".token.v1.ListUserRefreshTokensRes\"\x00B1Z/github.com/absmach/magistrala/api/grpc/token/v1b\x06proto3"
|
||||
|
||||
var (
|
||||
file_token_v1_token_proto_rawDescOnce sync.Once
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
|
||||
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
||||
// versions:
|
||||
// - protoc-gen-go-grpc v1.6.0
|
||||
// - protoc v6.33.0
|
||||
// - protoc-gen-go-grpc v1.6.2
|
||||
// - protoc v7.35.1
|
||||
// source: token/v1/token.proto
|
||||
|
||||
package v1
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
// Code generated by protoc-gen-go. DO NOT EDIT.
|
||||
// versions:
|
||||
// protoc-gen-go v1.36.11
|
||||
// protoc v6.33.0
|
||||
// protoc v7.35.1
|
||||
// source: users/v1/users.proto
|
||||
|
||||
package v1
|
||||
@@ -365,7 +365,7 @@ const file_users_v1_users_proto_rawDesc = "" +
|
||||
"\rauth_provider\x18\x10 \x01(\tR\fauthProvider\x12 \n" +
|
||||
"\vpermissions\x18\x11 \x03(\tR\vpermissions2Y\n" +
|
||||
"\fUsersService\x12I\n" +
|
||||
"\rRetrieveUsers\x12\x1a.users.v1.RetrieveUsersReq\x1a\x1a.users.v1.RetrieveUsersRes\"\x00B.Z,github.com/absmach/supermq/api/grpc/users/v1b\x06proto3"
|
||||
"\rRetrieveUsers\x12\x1a.users.v1.RetrieveUsersReq\x1a\x1a.users.v1.RetrieveUsersRes\"\x00B1Z/github.com/absmach/magistrala/api/grpc/users/v1b\x06proto3"
|
||||
|
||||
var (
|
||||
file_users_v1_users_proto_rawDescOnce sync.Once
|
||||
|
||||
@@ -3,8 +3,8 @@
|
||||
|
||||
// Code generated by protoc-gen-go-grpc. DO NOT EDIT.
|
||||
// versions:
|
||||
// - protoc-gen-go-grpc v1.6.0
|
||||
// - protoc v6.33.0
|
||||
// - protoc-gen-go-grpc v1.6.2
|
||||
// - protoc v7.35.1
|
||||
// source: users/v1/users.proto
|
||||
|
||||
package v1
|
||||
|
||||
+22
-10
@@ -11,12 +11,9 @@ import (
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/absmach/supermq"
|
||||
apiutil "github.com/absmach/supermq/api/http/util"
|
||||
"github.com/absmach/supermq/clients"
|
||||
"github.com/absmach/supermq/groups"
|
||||
"github.com/absmach/supermq/pkg/errors"
|
||||
"github.com/absmach/supermq/users"
|
||||
"github.com/absmach/magistrala"
|
||||
apiutil "github.com/absmach/magistrala/api/http/util"
|
||||
"github.com/absmach/magistrala/pkg/errors"
|
||||
"github.com/gofrs/uuid/v5"
|
||||
)
|
||||
|
||||
@@ -80,9 +77,9 @@ const (
|
||||
DefStartLevel = 1
|
||||
DefEndLevel = 0
|
||||
DefStatus = "enabled"
|
||||
DefClientStatus = clients.Enabled
|
||||
DefUserStatus = users.Enabled
|
||||
DefGroupStatus = groups.Enabled
|
||||
DefClientStatus = "enabled"
|
||||
DefUserStatus = "enabled"
|
||||
DefGroupStatus = "enabled"
|
||||
|
||||
// ContentType represents JSON content type.
|
||||
ContentType = "application/json"
|
||||
@@ -158,7 +155,7 @@ func ValidateUserName(name string) error {
|
||||
|
||||
// EncodeResponse encodes successful response.
|
||||
func EncodeResponse(_ context.Context, w http.ResponseWriter, response any) error {
|
||||
if ar, ok := response.(supermq.Response); ok {
|
||||
if ar, ok := response.(magistrala.Response); ok {
|
||||
for k, v := range ar.Headers() {
|
||||
w.Header().Set(k, v)
|
||||
}
|
||||
@@ -184,6 +181,21 @@ func EncodeError(_ context.Context, err error, w http.ResponseWriter) {
|
||||
return
|
||||
}
|
||||
|
||||
if errors.Contains(err, errors.ErrAuthentication) {
|
||||
w.WriteHeader(http.StatusUnauthorized)
|
||||
if err := json.NewEncoder(w).Encode(err); err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
}
|
||||
return
|
||||
}
|
||||
if errors.Contains(err, errors.ErrAuthorization) {
|
||||
w.WriteHeader(http.StatusForbidden)
|
||||
if err := json.NewEncoder(w).Encode(err); err != nil {
|
||||
w.WriteHeader(http.StatusInternalServerError)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
switch retErr := err.(type) {
|
||||
case *errors.RequestError:
|
||||
w.WriteHeader(http.StatusBadRequest)
|
||||
|
||||
+19
-7
@@ -10,16 +10,16 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/absmach/supermq"
|
||||
api "github.com/absmach/supermq/api/http"
|
||||
apiutil "github.com/absmach/supermq/api/http/util"
|
||||
"github.com/absmach/supermq/internal/testsutil"
|
||||
"github.com/absmach/supermq/pkg/errors"
|
||||
svcerr "github.com/absmach/supermq/pkg/errors/service"
|
||||
"github.com/absmach/magistrala"
|
||||
api "github.com/absmach/magistrala/api/http"
|
||||
apiutil "github.com/absmach/magistrala/api/http/util"
|
||||
"github.com/absmach/magistrala/pkg/errors"
|
||||
svcerr "github.com/absmach/magistrala/pkg/errors/service"
|
||||
"github.com/absmach/magistrala/pkg/testsutil"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
var _ supermq.Response = (*response)(nil)
|
||||
var _ magistrala.Response = (*response)(nil)
|
||||
|
||||
var validUUID = testsutil.GenerateUUID(&testing.T{})
|
||||
|
||||
@@ -260,12 +260,24 @@ func TestEncodeError(t *testing.T) {
|
||||
code: http.StatusUnauthorized,
|
||||
hasBody: true,
|
||||
},
|
||||
{
|
||||
desc: "Generic Authentication Failed",
|
||||
err: errors.ErrAuthentication,
|
||||
code: http.StatusUnauthorized,
|
||||
hasBody: true,
|
||||
},
|
||||
{
|
||||
desc: "AuthZError - Authorization Failed",
|
||||
err: svcerr.ErrAuthorization,
|
||||
code: http.StatusForbidden,
|
||||
hasBody: true,
|
||||
},
|
||||
{
|
||||
desc: "Generic Authorization Failed",
|
||||
err: errors.Wrap(errors.New("not authorized"), errors.ErrAuthorization),
|
||||
code: http.StatusForbidden,
|
||||
hasBody: true,
|
||||
},
|
||||
{
|
||||
desc: "AuthZError - Domain Authorization Failed",
|
||||
err: svcerr.ErrDomainAuthorization,
|
||||
|
||||
@@ -7,11 +7,11 @@ import (
|
||||
"context"
|
||||
"net/http"
|
||||
|
||||
"github.com/absmach/supermq"
|
||||
"github.com/absmach/magistrala"
|
||||
"github.com/go-chi/chi/v5/middleware"
|
||||
)
|
||||
|
||||
func RequestIDMiddleware(idp supermq.IDProvider) func(http.Handler) http.Handler {
|
||||
func RequestIDMiddleware(idp magistrala.IDProvider) func(http.Handler) http.Handler {
|
||||
return func(next http.Handler) http.Handler {
|
||||
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
requestID, err := idp.ID()
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
package util
|
||||
|
||||
import "github.com/absmach/supermq/pkg/errors"
|
||||
import "github.com/absmach/magistrala/pkg/errors"
|
||||
|
||||
// Errors defined in this file are used by the LoggingErrorEncoder decorator
|
||||
// to distinguish and log API request validation errors and avoid that service
|
||||
|
||||
@@ -7,7 +7,7 @@ import (
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
apiutil "github.com/absmach/supermq/api/http/util"
|
||||
apiutil "github.com/absmach/magistrala/api/http/util"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
|
||||
@@ -10,7 +10,7 @@ import (
|
||||
"net/http"
|
||||
"strconv"
|
||||
|
||||
"github.com/absmach/supermq/pkg/errors"
|
||||
"github.com/absmach/magistrala/pkg/errors"
|
||||
kithttp "github.com/go-kit/kit/transport/http"
|
||||
)
|
||||
|
||||
|
||||
@@ -11,10 +11,10 @@ import (
|
||||
"net/url"
|
||||
"testing"
|
||||
|
||||
apiutil "github.com/absmach/supermq/api/http/util"
|
||||
smqlog "github.com/absmach/supermq/logger"
|
||||
"github.com/absmach/supermq/pkg/errors"
|
||||
svcerr "github.com/absmach/supermq/pkg/errors/service"
|
||||
apiutil "github.com/absmach/magistrala/api/http/util"
|
||||
mglog "github.com/absmach/magistrala/logger"
|
||||
"github.com/absmach/magistrala/pkg/errors"
|
||||
svcerr "github.com/absmach/magistrala/pkg/errors/service"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
@@ -355,7 +355,7 @@ func TestLoggingErrorEncoder(t *testing.T) {
|
||||
encCalled = true
|
||||
}
|
||||
|
||||
errorEncoder := apiutil.LoggingErrorEncoder(smqlog.NewMock(), encFunc)
|
||||
errorEncoder := apiutil.LoggingErrorEncoder(mglog.NewMock(), encFunc)
|
||||
errorEncoder(context.Background(), c.err, httptest.NewRecorder())
|
||||
|
||||
assert.True(t, encCalled)
|
||||
|
||||
@@ -2,13 +2,13 @@
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
asyncapi: '2.6.0'
|
||||
id: 'https://github.com/absmach/supermq/blob/main/api/asyncapi/mqtt.yaml'
|
||||
id: 'https://github.com/absmach/magistrala/blob/main/api/asyncapi/mqtt.yaml'
|
||||
info:
|
||||
title: SuperMQ MQTT Adapter
|
||||
title: Magistrala MQTT Adapter
|
||||
version: '0.18.0'
|
||||
contact:
|
||||
name: SuperMQ Team
|
||||
url: 'https://github.com/absmach/supermq'
|
||||
name: Magistrala Team
|
||||
url: 'https://github.com/absmach/magistrala'
|
||||
email: info@absmach.eu
|
||||
description: |
|
||||
MQTT adapter provides an MQTT API for sending messages through the platform. MQTT adapter uses [mProxy](https://github.com/absmach/mproxy) for proxying traffic between client and MQTT broker.
|
||||
@@ -16,7 +16,7 @@ info:
|
||||
|
||||
license:
|
||||
name: Apache 2.0
|
||||
url: 'https://github.com/absmach/supermq/blob/main/LICENSE'
|
||||
url: 'https://github.com/absmach/magistrala/blob/main/LICENSE'
|
||||
|
||||
|
||||
defaultContentType: application/json
|
||||
|
||||
@@ -2,18 +2,18 @@
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
asyncapi: 2.6.0
|
||||
id: 'https://github.com/absmach/supermq/blob/main/api/asyncapi/websocket.yaml'
|
||||
id: 'https://github.com/absmach/magistrala/blob/main/api/asyncapi/websocket.yaml'
|
||||
info:
|
||||
title: SuperMQ WebSocket adapter
|
||||
title: Magistrala WebSocket adapter
|
||||
description: WebSocket adapter provides a WebSocket API for sending messages through communication channels. WebSocket adapter uses [mProxy](https://github.com/absmach/mproxy) for proxying traffic between client and MQTT broker.
|
||||
version: '0.18.0'
|
||||
contact:
|
||||
name: SuperMQ Team
|
||||
url: 'https://github.com/absmach/supermq'
|
||||
name: Magistrala Team
|
||||
url: 'https://github.com/absmach/magistrala'
|
||||
email: info@absmach.eu
|
||||
license:
|
||||
name: Apache 2.0
|
||||
url: 'https://github.com/absmach/supermq/blob/main/LICENSE'
|
||||
url: 'https://github.com/absmach/magistrala/blob/main/LICENSE'
|
||||
tags:
|
||||
- name: WebSocket
|
||||
defaultContentType: application/json
|
||||
@@ -28,7 +28,7 @@ servers:
|
||||
description: Hostname of the WebSocket adapter
|
||||
default: localhost
|
||||
port:
|
||||
description: SuperMQ WebSocket Adapter port
|
||||
description: Magistrala WebSocket Adapter port
|
||||
default: '8008'
|
||||
|
||||
channels:
|
||||
@@ -74,7 +74,7 @@ channels:
|
||||
- bearerAuth: []
|
||||
/version:
|
||||
subscribe:
|
||||
summary: Get the version of the SuperMQ adapter
|
||||
summary: Get the version of the Magistrala adapter
|
||||
operationId: getVersion
|
||||
bindings:
|
||||
http:
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
# SuperMQ OpenAPI Specification
|
||||
# Magistrala OpenAPI Specification
|
||||
|
||||
This folder contains an OpenAPI specifications for SuperMQ API.
|
||||
This folder contains an OpenAPI specifications for Magistrala API.
|
||||
|
||||
View specification in Swagger UI at [docs.api.supermq.absmach.eu](https://docs.api.supermq.absmach.eu)
|
||||
View specification in Swagger UI at [docs.api.magistrala.absmach.eu](https://docs.api.magistrala.absmach.eu)
|
||||
|
||||
@@ -0,0 +1,508 @@
|
||||
# Copyright (c) Abstract Machines
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
openapi: 3.0.1
|
||||
info:
|
||||
title: Magistrala Alarms API
|
||||
description: |
|
||||
HTTP API for managing alarms service.
|
||||
Some useful links:
|
||||
- [The Magistrala repository](https://github.com/absmach/magistrala)
|
||||
contact:
|
||||
email: info@absmach.eu
|
||||
license:
|
||||
name: Apache 2.0
|
||||
url: https://github.com/absmach/magistrala/blob/main/LICENSE
|
||||
version: 0.18.5
|
||||
|
||||
servers:
|
||||
- url: http://localhost:8050
|
||||
- url: https://localhost:8050
|
||||
|
||||
tags:
|
||||
- name: alarms
|
||||
description: Everything about your Alarms
|
||||
externalDocs:
|
||||
description: Find out more about alarms
|
||||
url: https://magistrala.absmach.eu/docs/
|
||||
|
||||
paths:
|
||||
/{domainID}/alarms:
|
||||
get:
|
||||
operationId: listAlarms
|
||||
summary: List Alarms
|
||||
description: |
|
||||
Retrieves a list of alarms with optional filtering
|
||||
tags:
|
||||
- alarms
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/DomainID'
|
||||
- $ref: '#/components/parameters/Offset'
|
||||
- $ref: '#/components/parameters/Limit'
|
||||
- $ref: '#/components/parameters/Order'
|
||||
- $ref: '#/components/parameters/Dir'
|
||||
- $ref: '#/components/parameters/ChannelID'
|
||||
- $ref: '#/components/parameters/ClientID'
|
||||
- $ref: '#/components/parameters/Subtopic'
|
||||
- $ref: '#/components/parameters/RuleID'
|
||||
- $ref: '#/components/parameters/Status'
|
||||
- $ref: '#/components/parameters/AssigneeID'
|
||||
- $ref: '#/components/parameters/Severity'
|
||||
- $ref: '#/components/parameters/UpdatedBy'
|
||||
- $ref: '#/components/parameters/AssignedBy'
|
||||
- $ref: '#/components/parameters/AcknowledgedBy'
|
||||
- $ref: '#/components/parameters/ResolvedBy'
|
||||
- $ref: '#/components/parameters/CreatedFrom'
|
||||
- $ref: '#/components/parameters/CreatedTo'
|
||||
security:
|
||||
- bearerAuth: []
|
||||
responses:
|
||||
'200':
|
||||
$ref: '#/components/responses/AlarmsPageRes'
|
||||
'400':
|
||||
description: Failed due to malformed query parameters
|
||||
'401':
|
||||
description: Missing or invalid access token
|
||||
'422':
|
||||
description: Database can't process request
|
||||
'500':
|
||||
$ref: '#/components/responses/ServiceError'
|
||||
|
||||
/{domainID}/alarms/{alarmID}:
|
||||
get:
|
||||
operationId: viewAlarm
|
||||
summary: View Alarm
|
||||
description: Retrieves an alarm by ID
|
||||
tags:
|
||||
- alarms
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/DomainID'
|
||||
- $ref: '#/components/parameters/AlarmID'
|
||||
security:
|
||||
- bearerAuth: []
|
||||
responses:
|
||||
'200':
|
||||
$ref: '#/components/responses/AlarmRes'
|
||||
'400':
|
||||
description: Missing or invalid alarm ID
|
||||
'401':
|
||||
description: Missing or invalid access token
|
||||
'403':
|
||||
description: Failed to perform authorization over the entity
|
||||
'404':
|
||||
description: Alarm does not exist
|
||||
'422':
|
||||
description: Database can't process request
|
||||
'500':
|
||||
$ref: '#/components/responses/ServiceError'
|
||||
put:
|
||||
operationId: updateAlarm
|
||||
summary: Update Alarm
|
||||
description: Updates an existing alarm
|
||||
tags:
|
||||
- alarms
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/DomainID'
|
||||
- $ref: '#/components/parameters/AlarmID'
|
||||
security:
|
||||
- bearerAuth: []
|
||||
requestBody:
|
||||
$ref: '#/components/requestBodies/AlarmUpdateReq'
|
||||
responses:
|
||||
'200':
|
||||
$ref: '#/components/responses/AlarmRes'
|
||||
'400':
|
||||
description: Failed due to malformed JSON
|
||||
'401':
|
||||
description: Missing or invalid access token
|
||||
'403':
|
||||
description: Failed to perform authorization over the entity
|
||||
'404':
|
||||
description: Alarm does not exist
|
||||
'415':
|
||||
description: Missing or invalid content type
|
||||
'422':
|
||||
description: Database can't process request
|
||||
'500':
|
||||
$ref: '#/components/responses/ServiceError'
|
||||
delete:
|
||||
operationId: deleteAlarm
|
||||
summary: Delete Alarm
|
||||
description: Deletes an alarm
|
||||
tags:
|
||||
- alarms
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/DomainID'
|
||||
- $ref: '#/components/parameters/AlarmID'
|
||||
security:
|
||||
- bearerAuth: []
|
||||
responses:
|
||||
'204':
|
||||
description: Alarm deleted successfully
|
||||
'400':
|
||||
description: Failed due to malformed alarm ID
|
||||
'401':
|
||||
description: Missing or invalid access token
|
||||
'403':
|
||||
description: Failed to perform authorization over the entity
|
||||
'404':
|
||||
description: Alarm does not exist
|
||||
'422':
|
||||
description: Database can't process request
|
||||
'500':
|
||||
$ref: '#/components/responses/ServiceError'
|
||||
|
||||
/health:
|
||||
get:
|
||||
summary: Retrieves service health check info
|
||||
tags:
|
||||
- health
|
||||
security: []
|
||||
responses:
|
||||
'200':
|
||||
$ref: '#/components/responses/HealthRes'
|
||||
'500':
|
||||
$ref: '#/components/responses/ServiceError'
|
||||
|
||||
components:
|
||||
schemas:
|
||||
Alarm:
|
||||
type: object
|
||||
properties:
|
||||
id:
|
||||
type: string
|
||||
description: Unique alarm identifier
|
||||
readOnly: true
|
||||
rule_id:
|
||||
type: string
|
||||
description: Rule ID that triggered this alarm
|
||||
domain_id:
|
||||
type: string
|
||||
description: Domain ID this alarm belongs to
|
||||
channel_id:
|
||||
type: string
|
||||
description: Channel ID where the alarm was triggered
|
||||
client_id:
|
||||
type: string
|
||||
description: Client ID that triggered the alarm
|
||||
subtopic:
|
||||
type: string
|
||||
description: Subtopic associated with the alarm
|
||||
status:
|
||||
type: string
|
||||
description: Alarm status
|
||||
enum: [active, cleared]
|
||||
measurement:
|
||||
type: string
|
||||
description: Measurement that triggered the alarm
|
||||
value:
|
||||
type: string
|
||||
description: Value that triggered the alarm
|
||||
unit:
|
||||
type: string
|
||||
description: Unit of measurement
|
||||
threshold:
|
||||
type: string
|
||||
description: Threshold value that was exceeded
|
||||
cause:
|
||||
type: string
|
||||
description: Cause or description of the alarm
|
||||
severity:
|
||||
type: integer
|
||||
description: Severity level (0-100)
|
||||
minimum: 0
|
||||
maximum: 100
|
||||
assignee_id:
|
||||
type: string
|
||||
description: ID of the user assigned to this alarm
|
||||
created_at:
|
||||
type: string
|
||||
format: date-time
|
||||
description: Creation timestamp
|
||||
readOnly: true
|
||||
updated_at:
|
||||
type: string
|
||||
format: date-time
|
||||
description: Last update timestamp
|
||||
readOnly: true
|
||||
updated_by:
|
||||
type: string
|
||||
description: User who last updated the alarm
|
||||
readOnly: true
|
||||
assigned_at:
|
||||
type: string
|
||||
format: date-time
|
||||
description: When the alarm was assigned
|
||||
readOnly: true
|
||||
assigned_by:
|
||||
type: string
|
||||
description: User who assigned the alarm
|
||||
readOnly: true
|
||||
acknowledged_at:
|
||||
type: string
|
||||
format: date-time
|
||||
description: When the alarm was acknowledged
|
||||
readOnly: true
|
||||
acknowledged_by:
|
||||
type: string
|
||||
description: User who acknowledged the alarm
|
||||
readOnly: true
|
||||
resolved_at:
|
||||
type: string
|
||||
format: date-time
|
||||
description: When the alarm was resolved
|
||||
readOnly: true
|
||||
resolved_by:
|
||||
type: string
|
||||
description: User who resolved the alarm
|
||||
readOnly: true
|
||||
metadata:
|
||||
type: object
|
||||
description: Custom metadata
|
||||
additionalProperties: true
|
||||
|
||||
AlarmsPage:
|
||||
type: object
|
||||
properties:
|
||||
offset:
|
||||
type: integer
|
||||
description: Number of items to skip during retrieval
|
||||
minimum: 0
|
||||
default: 0
|
||||
limit:
|
||||
type: integer
|
||||
description: Size of the subset to retrieve
|
||||
minimum: 1
|
||||
maximum: 1000
|
||||
default: 10
|
||||
total:
|
||||
type: integer
|
||||
description: Total number of results
|
||||
minimum: 0
|
||||
alarms:
|
||||
type: array
|
||||
minItems: 0
|
||||
items:
|
||||
$ref: '#/components/schemas/Alarm'
|
||||
required:
|
||||
- alarms
|
||||
- total
|
||||
- offset
|
||||
- limit
|
||||
|
||||
parameters:
|
||||
DomainID:
|
||||
name: domainID
|
||||
description: Domain ID
|
||||
in: path
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
AlarmID:
|
||||
name: alarmID
|
||||
description: Alarm ID
|
||||
in: path
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
Offset:
|
||||
name: offset
|
||||
description: Number of items to skip
|
||||
in: query
|
||||
required: false
|
||||
schema:
|
||||
type: integer
|
||||
default: 0
|
||||
minimum: 0
|
||||
Limit:
|
||||
name: limit
|
||||
description: Size of the subset to retrieve
|
||||
in: query
|
||||
required: false
|
||||
schema:
|
||||
type: integer
|
||||
default: 10
|
||||
minimum: 1
|
||||
maximum: 1000
|
||||
Order:
|
||||
name: order
|
||||
description: Order by field
|
||||
in: query
|
||||
required: false
|
||||
schema:
|
||||
type: string
|
||||
enum: [created_at, updated_at]
|
||||
default: created_at
|
||||
Dir:
|
||||
name: dir
|
||||
description: Sort direction
|
||||
in: query
|
||||
required: false
|
||||
schema:
|
||||
type: string
|
||||
enum: [asc, desc]
|
||||
default: desc
|
||||
ChannelID:
|
||||
name: channel_id
|
||||
description: Filter by channel ID
|
||||
in: query
|
||||
required: false
|
||||
schema:
|
||||
type: string
|
||||
ClientID:
|
||||
name: client_id
|
||||
description: Filter by client ID
|
||||
in: query
|
||||
required: false
|
||||
schema:
|
||||
type: string
|
||||
Subtopic:
|
||||
name: subtopic
|
||||
description: Filter by subtopic
|
||||
in: query
|
||||
required: false
|
||||
schema:
|
||||
type: string
|
||||
RuleID:
|
||||
name: rule_id
|
||||
description: Filter by rule ID
|
||||
in: query
|
||||
required: false
|
||||
schema:
|
||||
type: string
|
||||
Status:
|
||||
name: status
|
||||
description: Filter by alarm status
|
||||
in: query
|
||||
required: false
|
||||
schema:
|
||||
type: string
|
||||
enum: [active, cleared, all]
|
||||
default: all
|
||||
AssigneeID:
|
||||
name: assignee_id
|
||||
description: Filter by assignee ID
|
||||
in: query
|
||||
required: false
|
||||
schema:
|
||||
type: string
|
||||
Severity:
|
||||
name: severity
|
||||
description: Filter by severity level
|
||||
in: query
|
||||
required: false
|
||||
schema:
|
||||
type: integer
|
||||
minimum: 0
|
||||
maximum: 100
|
||||
UpdatedBy:
|
||||
name: updated_by
|
||||
description: Filter by user who updated
|
||||
in: query
|
||||
required: false
|
||||
schema:
|
||||
type: string
|
||||
AssignedBy:
|
||||
name: assigned_by
|
||||
description: Filter by user who assigned
|
||||
in: query
|
||||
required: false
|
||||
schema:
|
||||
type: string
|
||||
AcknowledgedBy:
|
||||
name: acknowledged_by
|
||||
description: Filter by user who acknowledged
|
||||
in: query
|
||||
required: false
|
||||
schema:
|
||||
type: string
|
||||
ResolvedBy:
|
||||
name: resolved_by
|
||||
description: Filter by user who resolved
|
||||
in: query
|
||||
required: false
|
||||
schema:
|
||||
type: string
|
||||
CreatedFrom:
|
||||
name: created_from
|
||||
description: Filter alarms created after this time (RFC3339 format)
|
||||
in: query
|
||||
required: false
|
||||
schema:
|
||||
type: string
|
||||
format: date-time
|
||||
CreatedTo:
|
||||
name: created_to
|
||||
description: Filter alarms created before this time (RFC3339 format)
|
||||
in: query
|
||||
required: false
|
||||
schema:
|
||||
type: string
|
||||
format: date-time
|
||||
|
||||
requestBodies:
|
||||
AlarmUpdateReq:
|
||||
description: JSON-formatted document describing the alarm update
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
status:
|
||||
type: string
|
||||
description: Alarm status
|
||||
enum: [active, cleared]
|
||||
assignee_id:
|
||||
type: string
|
||||
description: ID of the user assigned to this alarm
|
||||
severity:
|
||||
type: integer
|
||||
description: Severity level (0-100)
|
||||
minimum: 0
|
||||
maximum: 100
|
||||
metadata:
|
||||
type: object
|
||||
description: Custom metadata
|
||||
additionalProperties: true
|
||||
|
||||
responses:
|
||||
AlarmRes:
|
||||
description: Alarm data retrieved
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Alarm'
|
||||
links:
|
||||
update:
|
||||
operationId: updateAlarm
|
||||
parameters:
|
||||
alarmID: $response.body#/id
|
||||
domainID: $response.body#/domain_id
|
||||
delete:
|
||||
operationId: deleteAlarm
|
||||
parameters:
|
||||
alarmID: $response.body#/id
|
||||
domainID: $response.body#/domain_id
|
||||
AlarmsPageRes:
|
||||
description: Alarms page retrieved
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/AlarmsPage'
|
||||
ServiceError:
|
||||
description: Unexpected server-side error occurred
|
||||
HealthRes:
|
||||
description: Service Health Check
|
||||
content:
|
||||
application/health+json:
|
||||
schema:
|
||||
$ref: "./schemas/health_info.yaml"
|
||||
|
||||
securitySchemes:
|
||||
bearerAuth:
|
||||
type: http
|
||||
scheme: bearer
|
||||
bearerFormat: JWT
|
||||
description: |
|
||||
* Users access: "Authorization: Bearer <user_token>"
|
||||
@@ -3,16 +3,16 @@
|
||||
|
||||
openapi: 3.0.3
|
||||
info:
|
||||
title: SuperMQ Auth Service
|
||||
title: Magistrala Auth Service
|
||||
description: |
|
||||
This is the Auth Server based on the OpenAPI 3.0 specification. It is the HTTP API for managing platform users. You can now help us improve the API whether it's by making changes to the definition itself or to the code.
|
||||
Some useful links:
|
||||
- [The SuperMQ repository](https://github.com/absmach/supermq)
|
||||
- [The Magistrala repository](https://github.com/absmach/magistrala)
|
||||
contact:
|
||||
email: info@absmach.eu
|
||||
license:
|
||||
name: Apache 2.0
|
||||
url: https://github.com/absmach/supermq/blob/main/LICENSE
|
||||
url: https://github.com/absmach/magistrala/blob/main/LICENSE
|
||||
version: 0.18.0
|
||||
|
||||
servers:
|
||||
@@ -24,17 +24,17 @@ tags:
|
||||
description: Everything about your Keys.
|
||||
externalDocs:
|
||||
description: Find out more about keys
|
||||
url: https://docs.supermq.absmach.eu/
|
||||
url: https://magistrala.absmach.eu/docs/
|
||||
- name: PATs
|
||||
description: Everything about your Personal Access Tokens.
|
||||
externalDocs:
|
||||
description: Find out more about Personal Access Tokens
|
||||
url: https://docs.supermq.absmach.eu/
|
||||
url: https://magistrala.absmach.eu/docs/
|
||||
- name: Health
|
||||
description: Service health check endpoint.
|
||||
externalDocs:
|
||||
description: Find out more about health check
|
||||
url: https://docs.supermq.absmach.eu/
|
||||
url: https://magistrala.absmach.eu/docs/
|
||||
|
||||
paths:
|
||||
/keys:
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,722 @@
|
||||
# Copyright (c) Abstract Machines
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
openapi: 3.0.3
|
||||
info:
|
||||
title: Certs Service API
|
||||
description: |
|
||||
Certificate management service for issuing, renewing, revoking, and managing X.509 certificates.
|
||||
This service provides PKI functionality including certificate lifecycle management, OCSP responder,
|
||||
and CRL generation.
|
||||
version: 1.0.0
|
||||
contact:
|
||||
name: Abstract Machines
|
||||
license:
|
||||
name: Apache-2.0
|
||||
url: https://www.apache.org/licenses/LICENSE-2.0.html
|
||||
|
||||
servers:
|
||||
- url: http://localhost:9019
|
||||
description: Development server
|
||||
|
||||
tags:
|
||||
- name: certificates
|
||||
description: Certificate lifecycle management operations
|
||||
- name: pki
|
||||
description: PKI infrastructure operations (OCSP, CRL, CA)
|
||||
- name: health
|
||||
description: Service health and monitoring
|
||||
|
||||
security:
|
||||
- BearerAuth: []
|
||||
|
||||
paths:
|
||||
/{domainID}/certs/issue/{entityID}:
|
||||
post:
|
||||
tags:
|
||||
- certificates
|
||||
summary: Issue a new certificate
|
||||
description: Issues a new X.509 certificate for the specified entity with custom subject options
|
||||
operationId: issueCert
|
||||
security:
|
||||
- BearerAuth: []
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/DomainID'
|
||||
- $ref: '#/components/parameters/EntityID'
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/IssueCertRequest'
|
||||
responses:
|
||||
'201':
|
||||
description: Certificate successfully issued
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/CertificateResponse'
|
||||
'400':
|
||||
$ref: '#/components/responses/BadRequest'
|
||||
'401':
|
||||
$ref: '#/components/responses/Unauthorized'
|
||||
'500':
|
||||
$ref: '#/components/responses/InternalServerError'
|
||||
|
||||
/{domainID}/certs/{id}/renew:
|
||||
patch:
|
||||
tags:
|
||||
- certificates
|
||||
summary: Renew a certificate
|
||||
description: Renews an existing certificate with extended TTL and new serial number
|
||||
operationId: renewCert
|
||||
security:
|
||||
- BearerAuth: []
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/DomainID'
|
||||
- $ref: '#/components/parameters/CertID'
|
||||
responses:
|
||||
'200':
|
||||
description: Certificate successfully renewed
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/RenewCertResponse'
|
||||
'400':
|
||||
$ref: '#/components/responses/BadRequest'
|
||||
'401':
|
||||
$ref: '#/components/responses/Unauthorized'
|
||||
'404':
|
||||
$ref: '#/components/responses/NotFound'
|
||||
'500':
|
||||
$ref: '#/components/responses/InternalServerError'
|
||||
|
||||
/{domainID}/certs/{id}/revoke:
|
||||
patch:
|
||||
tags:
|
||||
- certificates
|
||||
summary: Revoke a certificate
|
||||
description: Revokes a certificate by its serial number
|
||||
operationId: revokeCert
|
||||
security:
|
||||
- BearerAuth: []
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/DomainID'
|
||||
- $ref: '#/components/parameters/CertID'
|
||||
responses:
|
||||
'204':
|
||||
description: Certificate successfully revoked
|
||||
'401':
|
||||
$ref: '#/components/responses/Unauthorized'
|
||||
'404':
|
||||
$ref: '#/components/responses/NotFound'
|
||||
'422':
|
||||
$ref: '#/components/responses/UnprocessableEntity'
|
||||
'500':
|
||||
$ref: '#/components/responses/InternalServerError'
|
||||
|
||||
/{domainID}/certs/{entityID}/delete:
|
||||
delete:
|
||||
tags:
|
||||
- certificates
|
||||
summary: Delete certificates for an entity
|
||||
description: Deletes all certificates associated with the specified entity
|
||||
operationId: deleteCert
|
||||
security:
|
||||
- BearerAuth: []
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/DomainID'
|
||||
- $ref: '#/components/parameters/EntityID'
|
||||
responses:
|
||||
'204':
|
||||
description: Certificates successfully deleted
|
||||
'401':
|
||||
$ref: '#/components/responses/Unauthorized'
|
||||
'422':
|
||||
$ref: '#/components/responses/UnprocessableEntity'
|
||||
'500':
|
||||
$ref: '#/components/responses/InternalServerError'
|
||||
|
||||
/{domainID}/certs:
|
||||
get:
|
||||
tags:
|
||||
- certificates
|
||||
summary: List certificates
|
||||
description: Retrieves a paginated list of certificates with optional filtering by entity ID
|
||||
operationId: listCerts
|
||||
security:
|
||||
- BearerAuth: []
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/DomainID'
|
||||
- $ref: '#/components/parameters/Offset'
|
||||
- $ref: '#/components/parameters/Limit'
|
||||
- $ref: '#/components/parameters/EntityIDFilter'
|
||||
responses:
|
||||
'200':
|
||||
description: Certificates successfully retrieved
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/CertificateListResponse'
|
||||
'400':
|
||||
$ref: '#/components/responses/BadRequest'
|
||||
'401':
|
||||
$ref: '#/components/responses/Unauthorized'
|
||||
'500':
|
||||
$ref: '#/components/responses/InternalServerError'
|
||||
|
||||
/{domainID}/certs/{id}:
|
||||
get:
|
||||
tags:
|
||||
- certificates
|
||||
summary: View certificate details
|
||||
description: Retrieves detailed information about a specific certificate by serial number
|
||||
operationId: viewCert
|
||||
security:
|
||||
- BearerAuth: []
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/DomainID'
|
||||
- $ref: '#/components/parameters/CertID'
|
||||
responses:
|
||||
'200':
|
||||
description: Certificate details successfully retrieved
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ViewCertResponse'
|
||||
'401':
|
||||
$ref: '#/components/responses/Unauthorized'
|
||||
'404':
|
||||
$ref: '#/components/responses/NotFound'
|
||||
'500':
|
||||
$ref: '#/components/responses/InternalServerError'
|
||||
|
||||
/{domainID}/certs/csrs/{entityID}:
|
||||
post:
|
||||
tags:
|
||||
- certificates
|
||||
summary: Issue certificate from CSR
|
||||
description: Issues a certificate from a Certificate Signing Request (CSR)
|
||||
operationId: issueFromCSR
|
||||
security:
|
||||
- BearerAuth: []
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/DomainID'
|
||||
- $ref: '#/components/parameters/EntityID'
|
||||
- $ref: '#/components/parameters/TTL'
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/IssueFromCSRRequest'
|
||||
responses:
|
||||
'200':
|
||||
description: Certificate successfully issued from CSR
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/IssueFromCSRResponse'
|
||||
'400':
|
||||
$ref: '#/components/responses/BadRequest'
|
||||
'401':
|
||||
$ref: '#/components/responses/Unauthorized'
|
||||
'500':
|
||||
$ref: '#/components/responses/InternalServerError'
|
||||
|
||||
/certs/csrs/{entityID}:
|
||||
post:
|
||||
tags:
|
||||
- certificates
|
||||
summary: Issue certificate from CSR (Internal)
|
||||
description: Issues a certificate from a CSR using internal agent authentication
|
||||
operationId: issueFromCSRInternal
|
||||
security:
|
||||
- AgentAuth: []
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/EntityID'
|
||||
- $ref: '#/components/parameters/TTL'
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/IssueFromCSRRequest'
|
||||
responses:
|
||||
'200':
|
||||
description: Certificate successfully issued from CSR
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/IssueFromCSRResponse'
|
||||
'400':
|
||||
$ref: '#/components/responses/BadRequest'
|
||||
'401':
|
||||
$ref: '#/components/responses/Unauthorized'
|
||||
'500':
|
||||
$ref: '#/components/responses/InternalServerError'
|
||||
|
||||
/certs/ocsp:
|
||||
post:
|
||||
tags:
|
||||
- pki
|
||||
summary: OCSP responder
|
||||
description: |
|
||||
Online Certificate Status Protocol (OCSP) responder endpoint.
|
||||
Accepts both binary OCSP requests and JSON format requests.
|
||||
operationId: ocsp
|
||||
security: []
|
||||
parameters:
|
||||
- name: force_status
|
||||
in: query
|
||||
description: Force a specific OCSP status for testing
|
||||
required: false
|
||||
schema:
|
||||
type: string
|
||||
requestBody:
|
||||
required: true
|
||||
content:
|
||||
application/ocsp-request:
|
||||
schema:
|
||||
type: string
|
||||
format: binary
|
||||
description: DER-encoded OCSP request
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/OCSPRequest'
|
||||
responses:
|
||||
'200':
|
||||
description: OCSP response
|
||||
content:
|
||||
application/ocsp-response:
|
||||
schema:
|
||||
type: string
|
||||
format: binary
|
||||
description: DER-encoded OCSP response
|
||||
'400':
|
||||
$ref: '#/components/responses/BadRequest'
|
||||
'500':
|
||||
$ref: '#/components/responses/InternalServerError'
|
||||
|
||||
/certs/crl:
|
||||
get:
|
||||
tags:
|
||||
- pki
|
||||
summary: Generate Certificate Revocation List
|
||||
description: Generates and returns the current Certificate Revocation List (CRL)
|
||||
operationId: generateCRL
|
||||
security: []
|
||||
responses:
|
||||
'200':
|
||||
description: CRL successfully generated
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/CRLResponse'
|
||||
'500':
|
||||
$ref: '#/components/responses/InternalServerError'
|
||||
|
||||
/certs/view-ca:
|
||||
get:
|
||||
tags:
|
||||
- pki
|
||||
summary: View CA certificate
|
||||
description: Retrieves the CA certificate chain (root and intermediate certificates)
|
||||
operationId: viewCA
|
||||
security: []
|
||||
responses:
|
||||
'200':
|
||||
description: CA certificate successfully retrieved
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ViewCertResponse'
|
||||
'500':
|
||||
$ref: '#/components/responses/InternalServerError'
|
||||
|
||||
/certs/download-ca:
|
||||
get:
|
||||
tags:
|
||||
- pki
|
||||
summary: Download CA certificate
|
||||
description: Downloads the CA certificate as a ZIP file
|
||||
operationId: downloadCA
|
||||
security: []
|
||||
responses:
|
||||
'200':
|
||||
description: CA certificate ZIP file
|
||||
content:
|
||||
application/zip:
|
||||
schema:
|
||||
type: string
|
||||
format: binary
|
||||
'500':
|
||||
$ref: '#/components/responses/InternalServerError'
|
||||
|
||||
/health:
|
||||
get:
|
||||
summary: Retrieves service health check info.
|
||||
tags:
|
||||
- health
|
||||
security: []
|
||||
responses:
|
||||
'200':
|
||||
$ref: '#/components/responses/HealthRes'
|
||||
'500':
|
||||
$ref: '#/components/responses/InternalServerError'
|
||||
|
||||
/metrics:
|
||||
get:
|
||||
tags:
|
||||
- health
|
||||
summary: Prometheus metrics
|
||||
description: Returns Prometheus metrics for monitoring
|
||||
operationId: metrics
|
||||
security: []
|
||||
responses:
|
||||
'200':
|
||||
description: Metrics successfully retrieved
|
||||
content:
|
||||
text/plain:
|
||||
schema:
|
||||
type: string
|
||||
|
||||
components:
|
||||
securitySchemes:
|
||||
BearerAuth:
|
||||
type: http
|
||||
scheme: bearer
|
||||
bearerFormat: JWT
|
||||
description: User authentication token
|
||||
AgentAuth:
|
||||
type: http
|
||||
scheme: bearer
|
||||
description: Agent authentication token for internal operations
|
||||
|
||||
parameters:
|
||||
DomainID:
|
||||
name: domainID
|
||||
in: path
|
||||
required: true
|
||||
description: Domain identifier
|
||||
schema:
|
||||
type: string
|
||||
EntityID:
|
||||
name: entityID
|
||||
in: path
|
||||
required: true
|
||||
description: Entity identifier for the certificate
|
||||
schema:
|
||||
type: string
|
||||
CertID:
|
||||
name: id
|
||||
in: path
|
||||
required: true
|
||||
description: Certificate serial number
|
||||
schema:
|
||||
type: string
|
||||
Offset:
|
||||
name: offset
|
||||
in: query
|
||||
description: Number of items to skip
|
||||
schema:
|
||||
type: integer
|
||||
minimum: 0
|
||||
default: 0
|
||||
Limit:
|
||||
name: limit
|
||||
in: query
|
||||
description: Maximum number of items to return
|
||||
schema:
|
||||
type: integer
|
||||
minimum: 1
|
||||
maximum: 100
|
||||
default: 10
|
||||
EntityIDFilter:
|
||||
name: entity_id
|
||||
in: query
|
||||
description: Filter certificates by entity ID
|
||||
schema:
|
||||
type: string
|
||||
TTL:
|
||||
name: ttl
|
||||
in: query
|
||||
description: Time to live for the certificate (e.g., "8760h", "365d")
|
||||
schema:
|
||||
type: string
|
||||
|
||||
schemas:
|
||||
IssueCertRequest:
|
||||
type: object
|
||||
required:
|
||||
- options
|
||||
properties:
|
||||
ttl:
|
||||
type: string
|
||||
description: Time to live for the certificate (e.g., "8760h" for 1 year)
|
||||
example: "8760h"
|
||||
ip_addresses:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
description: IP addresses to include in the certificate
|
||||
example: ["192.168.1.1", "10.0.0.1"]
|
||||
options:
|
||||
$ref: '#/components/schemas/SubjectOptions'
|
||||
|
||||
SubjectOptions:
|
||||
type: object
|
||||
required:
|
||||
- common_name
|
||||
properties:
|
||||
common_name:
|
||||
type: string
|
||||
description: Common Name (CN) for the certificate subject
|
||||
example: "example.com"
|
||||
organization:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
description: Organization (O)
|
||||
example: ["Abstract Machines"]
|
||||
organizational_unit:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
description: Organizational Unit (OU)
|
||||
example: ["Engineering"]
|
||||
country:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
description: Country (C)
|
||||
example: ["US"]
|
||||
province:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
description: Province or State (ST)
|
||||
example: ["California"]
|
||||
locality:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
description: Locality or City (L)
|
||||
example: ["San Francisco"]
|
||||
street_address:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
description: Street Address
|
||||
example: ["123 Main St"]
|
||||
postal_code:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
description: Postal Code
|
||||
example: ["94105"]
|
||||
dns_names:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
description: DNS names for Subject Alternative Names
|
||||
example: ["example.com", "www.example.com"]
|
||||
ip_addresses:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
description: IP addresses for Subject Alternative Names
|
||||
example: ["192.168.1.1"]
|
||||
|
||||
CertificateResponse:
|
||||
type: object
|
||||
properties:
|
||||
serial_number:
|
||||
type: string
|
||||
description: Unique serial number of the certificate
|
||||
example: "4a:3f:5e:2c:1b:8d:9e:7f"
|
||||
certificate:
|
||||
type: string
|
||||
description: PEM-encoded certificate
|
||||
example: "-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----"
|
||||
key:
|
||||
type: string
|
||||
description: PEM-encoded private key
|
||||
example: "-----BEGIN RSA PRIVATE KEY-----\n...\n-----END RSA PRIVATE KEY-----"
|
||||
revoked:
|
||||
type: boolean
|
||||
description: Whether the certificate is revoked
|
||||
example: false
|
||||
expiry_time:
|
||||
type: string
|
||||
format: date-time
|
||||
description: Certificate expiration time
|
||||
example: "2026-11-05T12:00:00Z"
|
||||
entity_id:
|
||||
type: string
|
||||
description: Entity identifier associated with the certificate
|
||||
example: "entity-123"
|
||||
|
||||
RenewCertResponse:
|
||||
type: object
|
||||
properties:
|
||||
certificate:
|
||||
$ref: '#/components/schemas/ViewCertResponse'
|
||||
|
||||
ViewCertResponse:
|
||||
type: object
|
||||
properties:
|
||||
serial_number:
|
||||
type: string
|
||||
description: Certificate serial number
|
||||
example: "4a:3f:5e:2c:1b:8d:9e:7f"
|
||||
certificate:
|
||||
type: string
|
||||
description: PEM-encoded certificate
|
||||
example: "-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----"
|
||||
key:
|
||||
type: string
|
||||
description: PEM-encoded private key
|
||||
example: "-----BEGIN RSA PRIVATE KEY-----\n...\n-----END RSA PRIVATE KEY-----"
|
||||
revoked:
|
||||
type: boolean
|
||||
description: Revocation status
|
||||
example: false
|
||||
expiry_time:
|
||||
type: string
|
||||
format: date-time
|
||||
description: Expiration timestamp
|
||||
example: "2026-11-05T12:00:00Z"
|
||||
entity_id:
|
||||
type: string
|
||||
description: Associated entity identifier
|
||||
example: "entity-123"
|
||||
|
||||
CertificateListResponse:
|
||||
type: object
|
||||
properties:
|
||||
total:
|
||||
type: integer
|
||||
format: uint64
|
||||
description: Total number of certificates
|
||||
example: 100
|
||||
offset:
|
||||
type: integer
|
||||
format: uint64
|
||||
description: Current offset
|
||||
example: 0
|
||||
limit:
|
||||
type: integer
|
||||
format: uint64
|
||||
description: Current limit
|
||||
example: 10
|
||||
certificates:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/ViewCertResponse'
|
||||
|
||||
IssueFromCSRRequest:
|
||||
type: object
|
||||
required:
|
||||
- csr
|
||||
properties:
|
||||
csr:
|
||||
type: string
|
||||
format: byte
|
||||
description: PEM-encoded Certificate Signing Request
|
||||
example: "LS0tLS1CRUdJTiBDRVJUSUZJQ0FURSBSRVFVRVNULS0tLS0K..."
|
||||
|
||||
IssueFromCSRResponse:
|
||||
type: object
|
||||
properties:
|
||||
serial_number:
|
||||
type: string
|
||||
description: Serial number of the issued certificate
|
||||
example: "4a:3f:5e:2c:1b:8d:9e:7f"
|
||||
certificate:
|
||||
type: string
|
||||
description: PEM-encoded certificate
|
||||
example: "-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----"
|
||||
revoked:
|
||||
type: boolean
|
||||
description: Revocation status
|
||||
example: false
|
||||
expiry_time:
|
||||
type: string
|
||||
format: date-time
|
||||
description: Expiration timestamp
|
||||
example: "2026-11-05T12:00:00Z"
|
||||
entity_id:
|
||||
type: string
|
||||
description: Associated entity identifier
|
||||
example: "entity-123"
|
||||
|
||||
OCSPRequest:
|
||||
type: object
|
||||
properties:
|
||||
serial_number:
|
||||
type: string
|
||||
description: Certificate serial number to check
|
||||
example: "4a:3f:5e:2c:1b:8d:9e:7f"
|
||||
certificate:
|
||||
type: string
|
||||
description: PEM-encoded certificate to check
|
||||
example: "-----BEGIN CERTIFICATE-----\n...\n-----END CERTIFICATE-----"
|
||||
status:
|
||||
type: string
|
||||
description: Force a specific status (for testing)
|
||||
enum: [good, revoked, unknown]
|
||||
|
||||
CRLResponse:
|
||||
type: object
|
||||
properties:
|
||||
crl:
|
||||
type: string
|
||||
format: byte
|
||||
description: DER-encoded Certificate Revocation List
|
||||
|
||||
Error:
|
||||
type: object
|
||||
properties:
|
||||
error:
|
||||
type: string
|
||||
description: Error message
|
||||
example: "invalid request"
|
||||
|
||||
responses:
|
||||
BadRequest:
|
||||
description: Bad request - invalid parameters or malformed request
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Error'
|
||||
Unauthorized:
|
||||
description: Unauthorized - invalid or missing authentication token
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Error'
|
||||
NotFound:
|
||||
description: Resource not found
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Error'
|
||||
UnprocessableEntity:
|
||||
description: Unprocessable entity - request cannot be processed
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Error'
|
||||
InternalServerError:
|
||||
description: Internal server error
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Error'
|
||||
HealthRes:
|
||||
description: Service Health Check.
|
||||
content:
|
||||
application/health+json:
|
||||
schema:
|
||||
$ref: './schemas/health_info.yaml'
|
||||
@@ -3,16 +3,16 @@
|
||||
|
||||
openapi: 3.0.3
|
||||
info:
|
||||
title: SuperMQ Channels Service
|
||||
title: Magistrala Channels Service
|
||||
description: |
|
||||
This is the Channels Server based on the OpenAPI 3.0 specification. It is the HTTP API for managing platform channels. You can now help us improve the API whether it's by making changes to the definition itself or to the code.
|
||||
Some useful links:
|
||||
- [The SuperMQ repository](https://github.com/absmach/supermq)
|
||||
- [The Magistrala repository](https://github.com/absmach/magistrala)
|
||||
contact:
|
||||
email: info@absmach.eu
|
||||
license:
|
||||
name: Apache 2.0
|
||||
url: https://github.com/absmach/supermq/blob/main/LICENSE
|
||||
url: https://github.com/absmach/magistrala/blob/main/LICENSE
|
||||
version: 0.18.0
|
||||
|
||||
servers:
|
||||
@@ -24,17 +24,17 @@ tags:
|
||||
description: CRUD operations for your channels
|
||||
externalDocs:
|
||||
description: Find out more about channels
|
||||
url: https://docs.supermq.absmach.eu/
|
||||
url: https://magistrala.absmach.eu/docs/
|
||||
- name: Connections
|
||||
description: All operations involving channel and client connections
|
||||
externalDocs:
|
||||
description: Find out more about channel and client connections
|
||||
url: https://docs.supermq.absmach.eu/
|
||||
url: https://magistrala.absmach.eu/docs/
|
||||
- name: Health
|
||||
description: Health check operations
|
||||
externalDocs:
|
||||
description: Find out more about health checks
|
||||
url: https://docs.supermq.absmach.eu/
|
||||
url: https://magistrala.absmach.eu/docs/
|
||||
|
||||
paths:
|
||||
/{domainID}/channels:
|
||||
|
||||
@@ -3,16 +3,16 @@
|
||||
|
||||
openapi: 3.0.3
|
||||
info:
|
||||
title: SuperMQ Clients Service
|
||||
title: Magistrala Clients Service
|
||||
description: |
|
||||
This is the Clients Server based on the OpenAPI 3.0 specification. It is the HTTP API for managing platform clients. You can now help us improve the API whether it's by making changes to the definition itself or to the code.
|
||||
Some useful links:
|
||||
- [The SuperMQ repository](https://github.com/absmach/supermq)
|
||||
- [The Magistrala repository](https://github.com/absmach/magistrala)
|
||||
contact:
|
||||
email: info@absmach.eu
|
||||
license:
|
||||
name: Apache 2.0
|
||||
url: https://github.com/absmach/supermq/blob/main/LICENSE
|
||||
url: https://github.com/absmach/magistrala/blob/main/LICENSE
|
||||
version: 0.18.0
|
||||
|
||||
servers:
|
||||
@@ -24,17 +24,17 @@ tags:
|
||||
description: CRUD operations for your clients
|
||||
externalDocs:
|
||||
description: Find out more about clients
|
||||
url: https://docs.supermq.absmach.eu/
|
||||
url: https://magistrala.absmach.eu/docs/
|
||||
- name: Roles
|
||||
description: All operations involving roles for clients
|
||||
externalDocs:
|
||||
description: Find out more about roles
|
||||
url: https://docs.supermq.absmach.eu/
|
||||
url: https://magistrala.absmach.eu/docs/
|
||||
- name: Health
|
||||
description: Health check operations
|
||||
externalDocs:
|
||||
description: Find out more about health checks
|
||||
url: https://docs.supermq.absmach.eu/
|
||||
url: https://magistrala.absmach.eu/docs/
|
||||
|
||||
paths:
|
||||
/{domainID}/clients:
|
||||
|
||||
@@ -3,16 +3,16 @@
|
||||
|
||||
openapi: 3.0.3
|
||||
info:
|
||||
title: SuperMQ Domains Service
|
||||
title: Magistrala Domains Service
|
||||
description: |
|
||||
This is the Domains Server based on the OpenAPI 3.0 specification. It is the HTTP API for managing platform domains. You can now help us improve the API whether it's by making changes to the definition itself or to the code.
|
||||
Some useful links:
|
||||
- [The SuperMQ repository](https://github.com/absmach/supermq)
|
||||
- [The Magistrala repository](https://github.com/absmach/magistrala)
|
||||
contact:
|
||||
email: info@absmach.eu
|
||||
license:
|
||||
name: Apache 2.0
|
||||
url: https://github.com/absmach/supermq/blob/main/LICENSE
|
||||
url: https://github.com/absmach/magistrala/blob/main/LICENSE
|
||||
version: 0.18.0
|
||||
|
||||
servers:
|
||||
@@ -24,22 +24,22 @@ tags:
|
||||
description: CRUD operations for your domains
|
||||
externalDocs:
|
||||
description: Find out more about domains
|
||||
url: https://docs.supermq.absmach.eu/
|
||||
url: https://magistrala.absmach.eu/docs/
|
||||
- name: Roles
|
||||
description: All operations involving roles for domains
|
||||
externalDocs:
|
||||
description: Find out more about roles
|
||||
url: https://docs.supermq.absmach.eu/
|
||||
url: https://magistrala.absmach.eu/docs/
|
||||
- name: Invitations
|
||||
description: All operations involving invitations for domains
|
||||
externalDocs:
|
||||
description: Find out more about Invitations
|
||||
url: https://docs.supermq.absmach.eu/
|
||||
url: https://magistrala.absmach.eu/docs/
|
||||
- name: Health
|
||||
description: Service health check endpoint.
|
||||
externalDocs:
|
||||
description: Find out more about health check
|
||||
url: https://docs.supermq.absmach.eu/
|
||||
url: https://magistrala.absmach.eu/docs/
|
||||
|
||||
paths:
|
||||
/domains:
|
||||
|
||||
@@ -3,16 +3,16 @@
|
||||
|
||||
openapi: 3.0.3
|
||||
info:
|
||||
title: SuperMQ Groups Service
|
||||
title: Magistrala Groups Service
|
||||
description: |
|
||||
This is the Groups Server based on the OpenAPI 3.0 specification. It is the HTTP API for managing platform groups. You can now help us improve the API whether it's by making changes to the definition itself or to the code.
|
||||
Some useful links:
|
||||
- [The SuperMQ repository](https://github.com/absmach/supermq)
|
||||
- [The Magistrala repository](https://github.com/absmach/magistrala)
|
||||
contact:
|
||||
email: info@absmach.eu
|
||||
license:
|
||||
name: Apache 2.0
|
||||
url: https://github.com/absmach/supermq/blob/main/LICENSE
|
||||
url: https://github.com/absmach/magistrala/blob/main/LICENSE
|
||||
version: 0.18.0
|
||||
|
||||
servers:
|
||||
@@ -24,17 +24,17 @@ tags:
|
||||
description: CRUD operations for your groups
|
||||
externalDocs:
|
||||
description: Find out more about users groups
|
||||
url: https://docs.supermq.absmach.eu/
|
||||
url: https://magistrala.absmach.eu/docs/
|
||||
- name: Roles
|
||||
description: All operations involving roles for groups
|
||||
externalDocs:
|
||||
description: Find out more about roles
|
||||
url: https://docs.supermq.absmach.eu/
|
||||
url: https://magistrala.absmach.eu/docs/
|
||||
- name: Health
|
||||
description: Health check operations
|
||||
externalDocs:
|
||||
description: Find out more about health checks
|
||||
url: https://docs.supermq.absmach.eu/
|
||||
url: https://magistrala.absmach.eu/docs/
|
||||
|
||||
paths:
|
||||
/{domainID}/groups:
|
||||
@@ -1155,7 +1155,7 @@ components:
|
||||
description: User's last name.
|
||||
email:
|
||||
type: string
|
||||
example: user@supermq.com
|
||||
example: user@magistrala.com
|
||||
description: User's email address.
|
||||
tags:
|
||||
type: array
|
||||
|
||||
@@ -3,16 +3,16 @@
|
||||
|
||||
openapi: 3.0.1
|
||||
info:
|
||||
title: SuperMQ http adapter
|
||||
title: Magistrala http adapter
|
||||
description: |
|
||||
HTTP API for sending messages through communication channels.
|
||||
Some useful links:
|
||||
- [The SuperMQ repository](https://github.com/absmach/supermq)
|
||||
- [The Magistrala repository](https://github.com/absmach/magistrala)
|
||||
contact:
|
||||
email: info@absmach.eu
|
||||
license:
|
||||
name: Apache 2.0
|
||||
url: https://github.com/absmach/supermq/blob/main/LICENSE
|
||||
url: https://github.com/absmach/magistrala/blob/main/LICENSE
|
||||
version: 0.18.0
|
||||
|
||||
servers:
|
||||
@@ -24,7 +24,7 @@ tags:
|
||||
description: Everything about your Messages
|
||||
externalDocs:
|
||||
description: Find out more about messages
|
||||
url: https://docs.supermq.absmach.eu/
|
||||
url: https://magistrala.absmach.eu/docs/
|
||||
|
||||
paths:
|
||||
/m/{domainPrefix}/c/{channelPrefix}:
|
||||
|
||||
@@ -1,426 +0,0 @@
|
||||
# Copyright (c) Abstract Machines
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
openapi: 3.0.3
|
||||
info:
|
||||
title: SuperMQ Journal Log Service
|
||||
description: |
|
||||
This is the Journal Log Server based on the OpenAPI 3.0 specification. It is the HTTP API for viewing journal log history. You can now help us improve the API whether it's by making changes to the definition itself or to the code.
|
||||
Some useful links:
|
||||
- [The SuperMQ repository](https://github.com/absmach/supermq)
|
||||
contact:
|
||||
email: info@mainflux.com
|
||||
license:
|
||||
name: Apache 2.0
|
||||
url: https://github.com/absmach/supermq/blob/main/LICENSE
|
||||
version: 0.18.0
|
||||
|
||||
servers:
|
||||
- url: http://localhost:9021
|
||||
- url: https://localhost:9021
|
||||
|
||||
tags:
|
||||
- name: journal-log
|
||||
description: Everything about your Journal Log
|
||||
externalDocs:
|
||||
description: Find out more about Journal Log
|
||||
url: http://docs.mainflux.io/
|
||||
|
||||
paths:
|
||||
/journal/user/{userID}:
|
||||
get:
|
||||
tags:
|
||||
- journal-log
|
||||
summary: List user journal log
|
||||
description: |
|
||||
Retrieves a list of journal. Due to performance concerns, data
|
||||
is retrieved in subsets. The API must ensure that the entire
|
||||
dataset is consumed either by making subsequent requests, or by
|
||||
increasing the subset size of the initial request.
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/user_id"
|
||||
- $ref: "#/components/parameters/offset"
|
||||
- $ref: "#/components/parameters/limit"
|
||||
- $ref: "#/components/parameters/operation"
|
||||
- $ref: "#/components/parameters/with_attributes"
|
||||
- $ref: "#/components/parameters/with_metadata"
|
||||
- $ref: "#/components/parameters/from"
|
||||
- $ref: "#/components/parameters/to"
|
||||
- $ref: "#/components/parameters/dir"
|
||||
security:
|
||||
- bearerAuth: []
|
||||
responses:
|
||||
"200":
|
||||
$ref: "#/components/responses/JournalsPageRes"
|
||||
"400":
|
||||
description: Failed due to malformed query parameters.
|
||||
"401":
|
||||
description: Missing or invalid access token provided.
|
||||
"403":
|
||||
description: Failed to perform authorization over the entity.
|
||||
"404":
|
||||
description: A non-existent entity request.
|
||||
"422":
|
||||
description: Database can't process request.
|
||||
"500":
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
|
||||
/{domainID}/journal/client/{clientID}/telemetry:
|
||||
get:
|
||||
tags:
|
||||
- journal-log
|
||||
summary: View client telemetry
|
||||
description: |
|
||||
Retrieves telemetry data for a specific client within a domain.
|
||||
This includes connection status, messages sent/received, and other metrics.
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/domain_id"
|
||||
- $ref: "#/components/parameters/client_id"
|
||||
security:
|
||||
- bearerAuth: []
|
||||
responses:
|
||||
"200":
|
||||
description: Client telemetry data retrieved successfully
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/Telemetry"
|
||||
"400":
|
||||
description: Failed due to malformed request parameters.
|
||||
"401":
|
||||
description: Missing or invalid access token provided.
|
||||
"403":
|
||||
description: Failed to perform authorization over the entity.
|
||||
"404":
|
||||
description: Client not found.
|
||||
"422":
|
||||
description: Database can't process request.
|
||||
"500":
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
|
||||
/{domainID}/journal/{entityType}/{id}:
|
||||
get:
|
||||
tags:
|
||||
- journal-log
|
||||
summary: List entity journal log
|
||||
description: |
|
||||
Retrieves a list of journal. Due to performance concerns, data
|
||||
is retrieved in subsets. The API must ensure that the entire
|
||||
dataset is consumed either by making subsequent requests, or by
|
||||
increasing the subset size of the initial request.
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/domain_id"
|
||||
- $ref: "#/components/parameters/entity_type"
|
||||
- $ref: "#/components/parameters/id"
|
||||
- $ref: "#/components/parameters/offset"
|
||||
- $ref: "#/components/parameters/limit"
|
||||
- $ref: "#/components/parameters/operation"
|
||||
- $ref: "#/components/parameters/with_attributes"
|
||||
- $ref: "#/components/parameters/with_metadata"
|
||||
- $ref: "#/components/parameters/from"
|
||||
- $ref: "#/components/parameters/to"
|
||||
- $ref: "#/components/parameters/dir"
|
||||
security:
|
||||
- bearerAuth: []
|
||||
responses:
|
||||
"200":
|
||||
$ref: "#/components/responses/JournalsPageRes"
|
||||
"400":
|
||||
description: Failed due to malformed query parameters.
|
||||
"401":
|
||||
description: Missing or invalid access token provided.
|
||||
"403":
|
||||
description: Failed to perform authorization over the entity.
|
||||
"404":
|
||||
description: A non-existent entity request.
|
||||
"422":
|
||||
description: Database can't process request.
|
||||
"500":
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
|
||||
/health:
|
||||
get:
|
||||
summary: Retrieves service health check info.
|
||||
tags:
|
||||
- health
|
||||
security: []
|
||||
responses:
|
||||
"200":
|
||||
$ref: "#/components/responses/HealthRes"
|
||||
"500":
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
|
||||
components:
|
||||
schemas:
|
||||
Telemetry:
|
||||
type: object
|
||||
properties:
|
||||
client_id:
|
||||
type: string
|
||||
format: uuid
|
||||
description: Unique identifier of the client
|
||||
example: "bb7edb32-2eac-4aad-aebe-ed96fe073879"
|
||||
domain_id:
|
||||
type: string
|
||||
format: uuid
|
||||
description: Unique identifier of the domain
|
||||
example: "29d425c8-542b-4614-8a4d-a5951945d720"
|
||||
subscriptions:
|
||||
type: integer
|
||||
format: int64
|
||||
description: Number of active subscriptions for the client
|
||||
example: 5
|
||||
inbound_messages:
|
||||
type: integer
|
||||
format: int64
|
||||
description: Number of messages received by the client
|
||||
example: 1234567
|
||||
outbound_messages:
|
||||
type: integer
|
||||
format: int64
|
||||
description: Number of messages sent by the client
|
||||
example: 987654
|
||||
first_seen:
|
||||
type: string
|
||||
format: date-time
|
||||
description: Timestamp when the client was first seen
|
||||
example: "2024-01-11T10:00:00.000Z"
|
||||
last_seen:
|
||||
type: string
|
||||
format: date-time
|
||||
description: Timestamp when the client was last seen
|
||||
example: "2024-01-11T12:05:07.449053Z"
|
||||
|
||||
Journal:
|
||||
type: object
|
||||
properties:
|
||||
operation:
|
||||
type: string
|
||||
example: user.create
|
||||
description: Journal operation.
|
||||
occurred_at:
|
||||
type: string
|
||||
format: date-time
|
||||
example: "2024-01-11T12:05:07.449053Z"
|
||||
description: Time when the journal occurred.
|
||||
attributes:
|
||||
type: object
|
||||
description: Journal attributes.
|
||||
example:
|
||||
{
|
||||
"created_at": "2024-06-12T11:34:32.991591Z",
|
||||
"id": "29d425c8-542b-4614-8a4d-a5951945d720",
|
||||
"identity": "Gawne-Havlicek@email.com",
|
||||
"name": "Newgard-Frisina",
|
||||
"status": "enabled",
|
||||
"updated_at": "2024-06-12T11:34:33.116795Z",
|
||||
"updated_by": "ad228f20-4741-47c5-bef7-d871b541c019",
|
||||
}
|
||||
metadata:
|
||||
type: object
|
||||
description: Journal payload.
|
||||
example: { "Update": "Calvo-Felkins" }
|
||||
xml:
|
||||
name: journal
|
||||
|
||||
JournalPage:
|
||||
type: object
|
||||
properties:
|
||||
journals:
|
||||
type: array
|
||||
minItems: 0
|
||||
uniqueItems: true
|
||||
items:
|
||||
$ref: "#/components/schemas/Journal"
|
||||
total:
|
||||
type: integer
|
||||
example: 1
|
||||
description: Total number of items.
|
||||
offset:
|
||||
type: integer
|
||||
description: Number of items to skip during retrieval.
|
||||
limit:
|
||||
type: integer
|
||||
example: 10
|
||||
description: Maximum number of items to return in one page.
|
||||
required:
|
||||
- journals
|
||||
- total
|
||||
- offset
|
||||
|
||||
Error:
|
||||
type: object
|
||||
properties:
|
||||
error:
|
||||
type: string
|
||||
description: Error message
|
||||
example: { "error": "malformed entity specification" }
|
||||
|
||||
parameters:
|
||||
domain_id:
|
||||
name: domainID
|
||||
description: Unique identifier for a domain.
|
||||
in: path
|
||||
schema:
|
||||
type: string
|
||||
format: uuid
|
||||
required: true
|
||||
example: bb7edb32-2eac-4aad-aebe-ed96fe073879
|
||||
|
||||
client_id:
|
||||
name: clientID
|
||||
description: Unique identifier for a client
|
||||
in: path
|
||||
schema:
|
||||
type: string
|
||||
format: uuid
|
||||
required: true
|
||||
example: bb7edb32-2eac-4aad-aebe-ed96fe073879
|
||||
|
||||
entity_type:
|
||||
name: entityType
|
||||
description: Type of entity, e.g. group, client, channel.
|
||||
in: path
|
||||
schema:
|
||||
type: string
|
||||
enum:
|
||||
- group
|
||||
- client
|
||||
- channel
|
||||
required: true
|
||||
example: group
|
||||
|
||||
user_id:
|
||||
name: userID
|
||||
description: Unique identifier for a user.
|
||||
in: path
|
||||
schema:
|
||||
type: string
|
||||
format: uuid
|
||||
required: true
|
||||
example: bb7edb32-2eac-4aad-aebe-ed96fe073879
|
||||
|
||||
id:
|
||||
name: id
|
||||
description: Unique identifier for an entity, e.g. group, channel or client. Used together with entity_type.
|
||||
in: path
|
||||
schema:
|
||||
type: string
|
||||
format: uuid
|
||||
required: true
|
||||
example: bb7edb32-2eac-4aad-aebe-ed96fe073879
|
||||
|
||||
offset:
|
||||
name: offset
|
||||
description: Number of items to skip during retrieval.
|
||||
in: query
|
||||
schema:
|
||||
type: integer
|
||||
default: 0
|
||||
minimum: 0
|
||||
required: false
|
||||
example: 0
|
||||
|
||||
limit:
|
||||
name: limit
|
||||
description: Size of the subset to retrieve.
|
||||
in: query
|
||||
schema:
|
||||
type: integer
|
||||
default: 10
|
||||
maximum: 100
|
||||
minimum: 1
|
||||
required: false
|
||||
example: 10
|
||||
|
||||
operation:
|
||||
name: operation
|
||||
description: Journal operation.
|
||||
in: query
|
||||
schema:
|
||||
type: string
|
||||
required: false
|
||||
example: user.create
|
||||
|
||||
with_attributes:
|
||||
name: with_attributes
|
||||
description: Include journal attributes.
|
||||
in: query
|
||||
schema:
|
||||
type: boolean
|
||||
required: false
|
||||
example: true
|
||||
|
||||
with_metadata:
|
||||
name: with_metadata
|
||||
description: Include journal metadata.
|
||||
in: query
|
||||
schema:
|
||||
type: boolean
|
||||
required: false
|
||||
example: true
|
||||
|
||||
from:
|
||||
name: from
|
||||
description: Start date in unix time.
|
||||
in: query
|
||||
schema:
|
||||
type: integer
|
||||
format: int64
|
||||
required: false
|
||||
example: 1966777289
|
||||
|
||||
to:
|
||||
name: to
|
||||
description: End date in unix time.
|
||||
in: query
|
||||
schema:
|
||||
type: integer
|
||||
format: int64
|
||||
required: false
|
||||
example: 1966777289
|
||||
|
||||
dir:
|
||||
name: dir
|
||||
description: Sort direction.
|
||||
in: query
|
||||
schema:
|
||||
type: string
|
||||
enum:
|
||||
- asc
|
||||
- desc
|
||||
required: false
|
||||
example: desc
|
||||
|
||||
responses:
|
||||
JournalsPageRes:
|
||||
description: Data retrieved.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/JournalPage"
|
||||
|
||||
HealthRes:
|
||||
description: Service Health Check.
|
||||
content:
|
||||
application/health+json:
|
||||
schema:
|
||||
$ref: "./schemas/health_info.yaml"
|
||||
|
||||
ServiceError:
|
||||
description: Unexpected server-side error occurred.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/Error"
|
||||
|
||||
securitySchemes:
|
||||
bearerAuth:
|
||||
type: http
|
||||
scheme: bearer
|
||||
bearerFormat: JWT
|
||||
description: |
|
||||
* User access: "Authorization: Bearer <user_access_token>"
|
||||
|
||||
security:
|
||||
- bearerAuth: []
|
||||
@@ -0,0 +1,292 @@
|
||||
# Copyright (c) Abstract Machines
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
openapi: 3.0.1
|
||||
info:
|
||||
title: Magistrala Notifiers service
|
||||
description: |
|
||||
HTTP API for Notifiers service.
|
||||
Some useful links:
|
||||
- [The Magistrala repository](https://github.com/absmach/magistrala)
|
||||
contact:
|
||||
email: info@absmach.eu
|
||||
license:
|
||||
name: Apache 2.0
|
||||
url: https://github.com/absmach/magistrala/blob/main/LICENSE
|
||||
version: 0.18.5
|
||||
|
||||
servers:
|
||||
- url: http://localhost:9014
|
||||
- url: https://localhost:9014
|
||||
- url: http://localhost:9015
|
||||
- url: https://localhost:9015
|
||||
|
||||
tags:
|
||||
- name: notifiers
|
||||
description: Everything about your Notifiers
|
||||
externalDocs:
|
||||
description: Find out more about notifiers
|
||||
url: https://magistrala.absmach.eu/docs/
|
||||
|
||||
paths:
|
||||
/subscriptions:
|
||||
post:
|
||||
operationId: createSubscription
|
||||
summary: Create subscription
|
||||
description: Creates a new subscription give a topic and contact.
|
||||
tags:
|
||||
- notifiers
|
||||
requestBody:
|
||||
$ref: "#/components/requestBodies/Create"
|
||||
responses:
|
||||
"201":
|
||||
$ref: "#/components/responses/Create"
|
||||
"400":
|
||||
description: Failed due to malformed JSON.
|
||||
"401":
|
||||
description: Missing or invalid access token provided.
|
||||
"403":
|
||||
description: Failed to perform authorization over the entity.
|
||||
"409":
|
||||
description: Failed due to using an existing topic and contact.
|
||||
"415":
|
||||
description: Missing or invalid content type.
|
||||
"422":
|
||||
description: Database can't process request.
|
||||
"500":
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
get:
|
||||
operationId: listSubscriptions
|
||||
summary: List subscriptions
|
||||
description: List subscriptions given list parameters.
|
||||
tags:
|
||||
- notifiers
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/Topic"
|
||||
- $ref: "#/components/parameters/Contact"
|
||||
- $ref: "#/components/parameters/Offset"
|
||||
- $ref: "#/components/parameters/Limit"
|
||||
responses:
|
||||
"200":
|
||||
$ref: "#/components/responses/Page"
|
||||
"400":
|
||||
description: Failed due to malformed query parameters.
|
||||
"401":
|
||||
description: Missing or invalid access token provided.
|
||||
"403":
|
||||
description: Failed to perform authorization over the entity.
|
||||
"404":
|
||||
description: A non-existent entity request.
|
||||
"422":
|
||||
description: Database can't process request.
|
||||
"500":
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
/subscriptions/{id}:
|
||||
get:
|
||||
operationId: viewSubscription
|
||||
summary: Get subscription with the provided id
|
||||
description: Retrieves a subscription with the provided id.
|
||||
tags:
|
||||
- notifiers
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/Id"
|
||||
responses:
|
||||
"200":
|
||||
$ref: "#/components/responses/View"
|
||||
"400":
|
||||
description: Failed due to malformed ID.
|
||||
"401":
|
||||
description: Missing or invalid access token provided.
|
||||
"403":
|
||||
description: Failed to perform authorization over the entity.
|
||||
"404":
|
||||
description: A non-existent entity request.
|
||||
"422":
|
||||
description: Database can't process request.
|
||||
"500":
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
delete:
|
||||
operationId: removeSubscription
|
||||
summary: Delete subscription with the provided id
|
||||
description: Removes a subscription with the provided id.
|
||||
tags:
|
||||
- notifiers
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/Id"
|
||||
responses:
|
||||
"204":
|
||||
description: Subscription removed
|
||||
"401":
|
||||
description: Missing or invalid access token provided.
|
||||
"403":
|
||||
description: Failed to perform authorization over the entity.
|
||||
"404":
|
||||
description: A non-existent entity request.
|
||||
"422":
|
||||
description: Database can't process request.
|
||||
"500":
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
/health:
|
||||
get:
|
||||
summary: Retrieves service health check info.
|
||||
tags:
|
||||
- health
|
||||
security: []
|
||||
responses:
|
||||
"200":
|
||||
$ref: "#/components/responses/HealthRes"
|
||||
"500":
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
|
||||
components:
|
||||
schemas:
|
||||
Subscription:
|
||||
type: object
|
||||
properties:
|
||||
id:
|
||||
type: string
|
||||
format: ulid
|
||||
example: 01EWDVKBQSG80B6PQRS9PAAY35
|
||||
description: ULID id of the subscription.
|
||||
owner_id:
|
||||
type: string
|
||||
format: uuid
|
||||
example: 18167738-f7a8-4e96-a123-58c3cd14de3a
|
||||
description: An id of the owner who created subscription.
|
||||
topic:
|
||||
type: string
|
||||
example: topic/subtopic
|
||||
description: Topic to which the user subscribes.
|
||||
contact:
|
||||
type: string
|
||||
example: user@example.com
|
||||
description: The contact of the user to which the notification will be sent.
|
||||
CreateSubscription:
|
||||
type: object
|
||||
properties:
|
||||
topic:
|
||||
type: string
|
||||
example: topic/subtopic
|
||||
description: Topic to which the user subscribes.
|
||||
contact:
|
||||
type: string
|
||||
example: user@example.com
|
||||
description: The contact of the user to which the notification will be sent.
|
||||
Page:
|
||||
type: object
|
||||
properties:
|
||||
subscriptions:
|
||||
type: array
|
||||
minItems: 0
|
||||
uniqueItems: true
|
||||
items:
|
||||
$ref: "#/components/schemas/Subscription"
|
||||
total:
|
||||
type: integer
|
||||
description: Total number of items.
|
||||
offset:
|
||||
type: integer
|
||||
description: Number of items to skip during retrieval.
|
||||
limit:
|
||||
type: integer
|
||||
description: Maximum number of items to return in one page.
|
||||
|
||||
parameters:
|
||||
Id:
|
||||
name: id
|
||||
description: Unique identifier.
|
||||
in: path
|
||||
schema:
|
||||
type: string
|
||||
format: ulid
|
||||
required: true
|
||||
Limit:
|
||||
name: limit
|
||||
description: Size of the subset to retrieve.
|
||||
in: query
|
||||
schema:
|
||||
type: integer
|
||||
default: 10
|
||||
maximum: 100
|
||||
minimum: 1
|
||||
required: false
|
||||
Offset:
|
||||
name: offset
|
||||
description: Number of items to skip during retrieval.
|
||||
in: query
|
||||
schema:
|
||||
type: integer
|
||||
default: 0
|
||||
minimum: 0
|
||||
required: false
|
||||
Topic:
|
||||
name: topic
|
||||
description: Topic name.
|
||||
in: query
|
||||
schema:
|
||||
type: string
|
||||
required: false
|
||||
Contact:
|
||||
name: contact
|
||||
description: Subscription contact.
|
||||
in: query
|
||||
schema:
|
||||
type: string
|
||||
required: false
|
||||
|
||||
requestBodies:
|
||||
Create:
|
||||
description: JSON-formatted document describing the new subscription to be created
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/CreateSubscription"
|
||||
|
||||
responses:
|
||||
Create:
|
||||
description: Created a new subscription.
|
||||
headers:
|
||||
Location:
|
||||
content:
|
||||
text/plain:
|
||||
schema:
|
||||
type: string
|
||||
description: Created subscription relative URL
|
||||
example: /subscriptions/{id}
|
||||
View:
|
||||
description: View subscription.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/Subscription"
|
||||
links:
|
||||
delete:
|
||||
operationId: removeSubscription
|
||||
parameters:
|
||||
id: $response.body#/id
|
||||
Page:
|
||||
description: Data retrieved.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/Page"
|
||||
ServiceError:
|
||||
description: Unexpected server-side error occurred.
|
||||
HealthRes:
|
||||
description: Service Health Check.
|
||||
content:
|
||||
application/health+json:
|
||||
schema:
|
||||
$ref: "./schemas/health_info.yaml"
|
||||
|
||||
securitySchemes:
|
||||
bearerAuth:
|
||||
type: http
|
||||
scheme: bearer
|
||||
bearerFormat: JWT
|
||||
description: |
|
||||
* Users access: "Authorization: Bearer <user_token>"
|
||||
|
||||
security:
|
||||
- bearerAuth: []
|
||||
@@ -0,0 +1,314 @@
|
||||
# Copyright (c) Abstract Machines
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
openapi: 3.0.1
|
||||
info:
|
||||
title: Magistrala reader service
|
||||
description: |
|
||||
HTTP API for reading messages.
|
||||
Some useful links:
|
||||
- [The Magistrala repository](https://github.com/absmach/magistrala)
|
||||
contact:
|
||||
email: info@absmach.eu
|
||||
license:
|
||||
name: Apache 2.0
|
||||
url: https://github.com/absmach/magistrala/blob/main/LICENSE
|
||||
version: 0.18.5
|
||||
|
||||
servers:
|
||||
- url: http://localhost:9003
|
||||
- url: https://localhost:9003
|
||||
- url: http://localhost:9005
|
||||
- url: https://localhost:9005
|
||||
- url: http://localhost:9009
|
||||
- url: https://localhost:9009
|
||||
- url: http://localhost:9011
|
||||
- url: https://localhost:9011
|
||||
|
||||
tags:
|
||||
- name: readers
|
||||
description: Everything about your Readers
|
||||
externalDocs:
|
||||
description: Find out more about readers
|
||||
url: https://magistrala.absmach.eu/docs/
|
||||
|
||||
paths:
|
||||
/{domainID}/channels/{chanId}/messages:
|
||||
get:
|
||||
operationId: getMessages
|
||||
summary: Retrieves messages sent to single channel
|
||||
description: |
|
||||
Retrieves a list of messages sent to specific channel. Due to
|
||||
performance concerns, data is retrieved in subsets. The API readers must
|
||||
ensure that the entire dataset is consumed either by making subsequent
|
||||
requests, or by increasing the subset size of the initial request.
|
||||
tags:
|
||||
- readers
|
||||
parameters:
|
||||
- $ref: "#/components/parameters/DomainID"
|
||||
- $ref: "#/components/parameters/ChanId"
|
||||
- $ref: "#/components/parameters/Limit"
|
||||
- $ref: "#/components/parameters/Offset"
|
||||
- $ref: "#/components/parameters/Publisher"
|
||||
- $ref: "#/components/parameters/Name"
|
||||
- $ref: "#/components/parameters/Value"
|
||||
- $ref: "#/components/parameters/BoolValue"
|
||||
- $ref: "#/components/parameters/StringValue"
|
||||
- $ref: "#/components/parameters/DataValue"
|
||||
- $ref: "#/components/parameters/From"
|
||||
- $ref: "#/components/parameters/To"
|
||||
- $ref: "#/components/parameters/Aggregation"
|
||||
- $ref: "#/components/parameters/Interval"
|
||||
responses:
|
||||
"200":
|
||||
$ref: "#/components/responses/MessagesPageRes"
|
||||
"400":
|
||||
description: Failed due to malformed query parameters.
|
||||
"401":
|
||||
description: Missing or invalid access token provided.
|
||||
"403":
|
||||
description: Failed to perform authorization over the entity.
|
||||
"500":
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
/health:
|
||||
get:
|
||||
operationId: health
|
||||
summary: Retrieves service health check info.
|
||||
tags:
|
||||
- health
|
||||
security: []
|
||||
responses:
|
||||
"200":
|
||||
$ref: "#/components/responses/HealthRes"
|
||||
"500":
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
|
||||
components:
|
||||
schemas:
|
||||
MessagesPage:
|
||||
type: object
|
||||
properties:
|
||||
total:
|
||||
type: number
|
||||
description: Total number of items that are present on the system.
|
||||
offset:
|
||||
type: number
|
||||
description: Number of items that were skipped during retrieval.
|
||||
limit:
|
||||
type: number
|
||||
description: Size of the subset that was retrieved.
|
||||
messages:
|
||||
type: array
|
||||
minItems: 0
|
||||
uniqueItems: true
|
||||
items:
|
||||
type: object
|
||||
properties:
|
||||
channel:
|
||||
type: integer
|
||||
description: Unique channel id.
|
||||
publisher:
|
||||
type: integer
|
||||
description: Unique publisher id.
|
||||
protocol:
|
||||
type: string
|
||||
description: Protocol name.
|
||||
name:
|
||||
type: string
|
||||
description: Measured parameter name.
|
||||
unit:
|
||||
type: string
|
||||
description: Value unit.
|
||||
value:
|
||||
type: number
|
||||
description: Measured value in number.
|
||||
stringValue:
|
||||
type: string
|
||||
description: Measured value in string format.
|
||||
boolValue:
|
||||
type: boolean
|
||||
description: Measured value in boolean format.
|
||||
dataValue:
|
||||
type: string
|
||||
description: Measured value in binary format.
|
||||
valueSum:
|
||||
type: number
|
||||
description: Sum value.
|
||||
time:
|
||||
type: number
|
||||
description: Time of measurement.
|
||||
updateTime:
|
||||
type: number
|
||||
description: Time of updating measurement.
|
||||
|
||||
parameters:
|
||||
DomainID:
|
||||
name: domainID
|
||||
description: Unique domain identifier.
|
||||
in: path
|
||||
schema:
|
||||
type: string
|
||||
format: uuid
|
||||
required: true
|
||||
ChanId:
|
||||
name: chanId
|
||||
description: Unique channel identifier.
|
||||
in: path
|
||||
schema:
|
||||
type: string
|
||||
format: uuid
|
||||
required: true
|
||||
Limit:
|
||||
name: limit
|
||||
description: Size of the subset to retrieve.
|
||||
in: query
|
||||
schema:
|
||||
type: integer
|
||||
default: 10
|
||||
maximum: 100
|
||||
minimum: 1
|
||||
required: false
|
||||
Offset:
|
||||
name: offset
|
||||
description: Number of items to skip during retrieval.
|
||||
in: query
|
||||
schema:
|
||||
type: integer
|
||||
default: 0
|
||||
minimum: 0
|
||||
required: false
|
||||
Publisher:
|
||||
name: Publisher
|
||||
description: Unique thing identifier.
|
||||
in: query
|
||||
schema:
|
||||
type: string
|
||||
format: uuid
|
||||
required: false
|
||||
Name:
|
||||
name: name
|
||||
description: SenML message name.
|
||||
in: query
|
||||
schema:
|
||||
type: string
|
||||
required: false
|
||||
Value:
|
||||
name: v
|
||||
description: SenML message value.
|
||||
in: query
|
||||
schema:
|
||||
type: string
|
||||
required: false
|
||||
BoolValue:
|
||||
name: vb
|
||||
description: SenML message bool value.
|
||||
in: query
|
||||
schema:
|
||||
type: boolean
|
||||
required: false
|
||||
StringValue:
|
||||
name: vs
|
||||
description: SenML message string value.
|
||||
in: query
|
||||
schema:
|
||||
type: string
|
||||
required: false
|
||||
DataValue:
|
||||
name: vd
|
||||
description: SenML message data value.
|
||||
in: query
|
||||
schema:
|
||||
type: string
|
||||
required: false
|
||||
Comparator:
|
||||
name: comparator
|
||||
description: Value comparison operator.
|
||||
in: query
|
||||
schema:
|
||||
type: string
|
||||
default: eq
|
||||
enum:
|
||||
- eq
|
||||
- lt
|
||||
- le
|
||||
- gt
|
||||
- ge
|
||||
required: false
|
||||
From:
|
||||
name: from
|
||||
description: SenML message time in nanoseconds (integer part represents seconds).
|
||||
in: query
|
||||
schema:
|
||||
type: number
|
||||
example: 1709218556069
|
||||
required: false
|
||||
To:
|
||||
name: to
|
||||
description: SenML message time in nanoseconds (integer part represents seconds).
|
||||
in: query
|
||||
schema:
|
||||
type: number
|
||||
example: 1709218757503
|
||||
required: false
|
||||
Aggregation:
|
||||
name: aggregation
|
||||
description: Aggregation function.
|
||||
in: query
|
||||
schema:
|
||||
type: string
|
||||
enum:
|
||||
- MAX
|
||||
- AVG
|
||||
- MIN
|
||||
- SUM
|
||||
- COUNT
|
||||
- max
|
||||
- min
|
||||
- sum
|
||||
- avg
|
||||
- count
|
||||
example: MAX
|
||||
required: false
|
||||
Interval:
|
||||
name: interval
|
||||
description: Aggregation interval.
|
||||
in: query
|
||||
schema:
|
||||
type: string
|
||||
example: 10s
|
||||
required: false
|
||||
|
||||
responses:
|
||||
MessagesPageRes:
|
||||
description: Data retrieved.
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: "#/components/schemas/MessagesPage"
|
||||
ServiceError:
|
||||
description: Unexpected server-side error occurred.
|
||||
HealthRes:
|
||||
description: Service Health Check.
|
||||
content:
|
||||
application/health+json:
|
||||
schema:
|
||||
$ref: "./schemas/health_info.yaml"
|
||||
|
||||
securitySchemes:
|
||||
bearerAuth:
|
||||
type: http
|
||||
scheme: bearer
|
||||
bearerFormat: JWT
|
||||
description: |
|
||||
* Users access: "Authorization: Bearer <user_token>"
|
||||
|
||||
thingAuth:
|
||||
type: http
|
||||
scheme: bearer
|
||||
bearerFormat: uuid
|
||||
description: |
|
||||
* Things access: "Authorization: Thing <thing_key>"
|
||||
|
||||
security:
|
||||
- bearerAuth: []
|
||||
- thingAuth: []
|
||||
@@ -0,0 +1,553 @@
|
||||
# Copyright (c) Abstract Machines
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
openapi: 3.0.1
|
||||
info:
|
||||
title: Magistrala Reports Service API
|
||||
description: |
|
||||
HTTP API for managing reports service.
|
||||
version: 0.18.5
|
||||
servers:
|
||||
- url: http://localhost:9017
|
||||
tags:
|
||||
- name: reports
|
||||
description: Operations related to report configurations and generation
|
||||
paths:
|
||||
/{domainID}/reports:
|
||||
post:
|
||||
operationId: generateReport
|
||||
summary: Generate a report
|
||||
description: Generates a report based on the provided configuration or an existing config. The action determines the response format.
|
||||
tags:
|
||||
- reports
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/DomainID'
|
||||
security:
|
||||
- bearerAuth: []
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/GenerateReportRequest'
|
||||
responses:
|
||||
'200':
|
||||
description: Report generated successfully (content varies by action)
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/GenerateReportResponse'
|
||||
application/octet-stream:
|
||||
schema:
|
||||
type: string
|
||||
format: binary
|
||||
'400':
|
||||
description: Invalid request parameters
|
||||
'401':
|
||||
description: Missing or invalid access token
|
||||
'500':
|
||||
$ref: '#/components/responses/ServiceError'
|
||||
|
||||
/{domainID}/reports/configs:
|
||||
post:
|
||||
operationId: addReportConfig
|
||||
summary: Create a report configuration
|
||||
description: Creates a new report configuration.
|
||||
tags:
|
||||
- reports
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/DomainID'
|
||||
security:
|
||||
- bearerAuth: []
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/AddReportConfigRequest'
|
||||
responses:
|
||||
'201':
|
||||
description: Report configuration created
|
||||
headers:
|
||||
Location:
|
||||
schema:
|
||||
type: string
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ReportConfig'
|
||||
'400':
|
||||
description: Invalid request body
|
||||
'401':
|
||||
description: Missing or invalid access token
|
||||
'500':
|
||||
$ref: '#/components/responses/ServiceError'
|
||||
get:
|
||||
operationId: listReportConfigs
|
||||
summary: List report configurations
|
||||
description: Retrieves a paginated list of report configurations.
|
||||
tags:
|
||||
- reports
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/DomainID'
|
||||
- $ref: '#/components/parameters/Offset'
|
||||
- $ref: '#/components/parameters/Limit'
|
||||
security:
|
||||
- bearerAuth: []
|
||||
responses:
|
||||
'200':
|
||||
description: List of report configurations
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ListReportsConfigResponse'
|
||||
'400':
|
||||
description: Invalid query parameters
|
||||
'401':
|
||||
description: Missing or invalid access token
|
||||
'500':
|
||||
$ref: '#/components/responses/ServiceError'
|
||||
|
||||
/{domainID}/reports/configs/{reportID}:
|
||||
get:
|
||||
operationId: viewReportConfig
|
||||
summary: View a report configuration
|
||||
description: Retrieves details of a specific report configuration.
|
||||
tags:
|
||||
- reports
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/DomainID'
|
||||
- $ref: '#/components/parameters/ReportID'
|
||||
security:
|
||||
- bearerAuth: []
|
||||
responses:
|
||||
'200':
|
||||
description: Report configuration details
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ReportConfig'
|
||||
'404':
|
||||
description: Report configuration not found
|
||||
'401':
|
||||
description: Missing or invalid access token
|
||||
'500':
|
||||
$ref: '#/components/responses/ServiceError'
|
||||
patch:
|
||||
operationId: updateReportConfig
|
||||
summary: Update a report configuration
|
||||
description: Updates specified fields of a report configuration.
|
||||
tags:
|
||||
- reports
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/DomainID'
|
||||
- $ref: '#/components/parameters/ReportID'
|
||||
security:
|
||||
- bearerAuth: []
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/UpdateReportConfigRequest'
|
||||
responses:
|
||||
'200':
|
||||
description: Report configuration updated
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ReportConfig'
|
||||
'400':
|
||||
description: Invalid request body
|
||||
'401':
|
||||
description: Missing or invalid access token
|
||||
'404':
|
||||
description: Report configuration not found
|
||||
'500':
|
||||
$ref: '#/components/responses/ServiceError'
|
||||
delete:
|
||||
operationId: deleteReportConfig
|
||||
summary: Delete a report configuration
|
||||
description: Permanently deletes a report configuration.
|
||||
tags:
|
||||
- reports
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/DomainID'
|
||||
- $ref: '#/components/parameters/ReportID'
|
||||
security:
|
||||
- bearerAuth: []
|
||||
responses:
|
||||
'204':
|
||||
description: Report configuration deleted
|
||||
'401':
|
||||
description: Missing or invalid access token
|
||||
'404':
|
||||
description: Report configuration not found
|
||||
'500':
|
||||
$ref: '#/components/responses/ServiceError'
|
||||
|
||||
/{domainID}/reports/configs/{reportID}/schedule:
|
||||
patch:
|
||||
operationId: updateReportSchedule
|
||||
summary: Update report schedule
|
||||
description: Updates the schedule of a report configuration.
|
||||
tags:
|
||||
- reports
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/DomainID'
|
||||
- $ref: '#/components/parameters/ReportID'
|
||||
security:
|
||||
- bearerAuth: []
|
||||
requestBody:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Schedule'
|
||||
responses:
|
||||
'200':
|
||||
description: Schedule updated
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ReportConfig'
|
||||
'400':
|
||||
description: Invalid schedule
|
||||
'401':
|
||||
description: Missing or invalid access token
|
||||
'404':
|
||||
description: Report configuration not found
|
||||
'500':
|
||||
$ref: '#/components/responses/ServiceError'
|
||||
|
||||
/{domainID}/reports/configs/{reportID}/enable:
|
||||
post:
|
||||
operationId: enableReportConfig
|
||||
summary: Enable a report configuration
|
||||
description: Enables a report configuration to generate scheduled reports.
|
||||
tags:
|
||||
- reports
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/DomainID'
|
||||
- $ref: '#/components/parameters/ReportID'
|
||||
security:
|
||||
- bearerAuth: []
|
||||
responses:
|
||||
'200':
|
||||
description: Report configuration enabled
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ReportConfig'
|
||||
'401':
|
||||
description: Missing or invalid access token
|
||||
'404':
|
||||
description: Report configuration not found
|
||||
'500':
|
||||
$ref: '#/components/responses/ServiceError'
|
||||
|
||||
/{domainID}/reports/configs/{reportID}/disable:
|
||||
post:
|
||||
operationId: disableReportConfig
|
||||
summary: Disable a report configuration
|
||||
description: Disables a report configuration, stopping scheduled reports.
|
||||
tags:
|
||||
- reports
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/DomainID'
|
||||
- $ref: '#/components/parameters/ReportID'
|
||||
security:
|
||||
- bearerAuth: []
|
||||
responses:
|
||||
'200':
|
||||
description: Report configuration disabled
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/ReportConfig'
|
||||
'401':
|
||||
description: Missing or invalid access token
|
||||
'404':
|
||||
description: Report configuration not found
|
||||
'500':
|
||||
$ref: '#/components/responses/ServiceError'
|
||||
|
||||
/health:
|
||||
get:
|
||||
summary: Service health check
|
||||
tags:
|
||||
- health
|
||||
responses:
|
||||
'200':
|
||||
$ref: '#/components/responses/HealthRes'
|
||||
|
||||
components:
|
||||
schemas:
|
||||
ReportConfig:
|
||||
type: object
|
||||
properties:
|
||||
id:
|
||||
type: string
|
||||
readOnly: true
|
||||
name:
|
||||
type: string
|
||||
description:
|
||||
type: string
|
||||
domain_id:
|
||||
type: string
|
||||
readOnly: true
|
||||
schedule:
|
||||
$ref: '#/components/schemas/Schedule'
|
||||
config:
|
||||
$ref: '#/components/schemas/MetricConfig'
|
||||
email:
|
||||
$ref: '#/components/schemas/EmailSetting'
|
||||
metrics:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/ReqMetric'
|
||||
status:
|
||||
$ref: '#/components/schemas/Status'
|
||||
created_at:
|
||||
type: string
|
||||
format: date-time
|
||||
readOnly: true
|
||||
created_by:
|
||||
type: string
|
||||
readOnly: true
|
||||
updated_at:
|
||||
type: string
|
||||
format: date-time
|
||||
readOnly: true
|
||||
updated_by:
|
||||
type: string
|
||||
readOnly: true
|
||||
required:
|
||||
- name
|
||||
- metrics
|
||||
- config
|
||||
|
||||
Schedule:
|
||||
type: object
|
||||
properties:
|
||||
recurring:
|
||||
type: string
|
||||
enum: [None, Daily, Weekly, Monthly]
|
||||
recurring_period:
|
||||
type: integer
|
||||
minimum: 1
|
||||
start_time:
|
||||
type: string
|
||||
format: date-time
|
||||
next_run:
|
||||
type: string
|
||||
format: date-time
|
||||
readOnly: true
|
||||
|
||||
MetricConfig:
|
||||
type: object
|
||||
properties:
|
||||
title:
|
||||
type: string
|
||||
maxLength: 100
|
||||
format:
|
||||
type: string
|
||||
enum: [pdf, csv, html]
|
||||
aggregation:
|
||||
$ref: '#/components/schemas/AggConfig'
|
||||
|
||||
AggConfig:
|
||||
type: object
|
||||
properties:
|
||||
window:
|
||||
type: string
|
||||
function:
|
||||
type: string
|
||||
enum: [sum, average, max, min]
|
||||
|
||||
EmailSetting:
|
||||
type: object
|
||||
properties:
|
||||
recipients:
|
||||
type: array
|
||||
items:
|
||||
type: string
|
||||
format: email
|
||||
subject:
|
||||
type: string
|
||||
body_template:
|
||||
type: string
|
||||
required:
|
||||
- recipients
|
||||
- subject
|
||||
|
||||
ReqMetric:
|
||||
type: object
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
type:
|
||||
type: string
|
||||
enum: [gauge, counter, histogram]
|
||||
parameters:
|
||||
type: object
|
||||
required:
|
||||
- name
|
||||
- type
|
||||
|
||||
Status:
|
||||
type: string
|
||||
enum: [enabled, disabled]
|
||||
|
||||
GenerateReportRequest:
|
||||
type: object
|
||||
properties:
|
||||
action:
|
||||
type: string
|
||||
enum: [view, download, email]
|
||||
config_id:
|
||||
type: string
|
||||
name:
|
||||
type: string
|
||||
description:
|
||||
type: string
|
||||
schedule:
|
||||
$ref: '#/components/schemas/Schedule'
|
||||
config:
|
||||
$ref: '#/components/schemas/MetricConfig'
|
||||
email:
|
||||
$ref: '#/components/schemas/EmailSetting'
|
||||
metrics:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/ReqMetric'
|
||||
required:
|
||||
- action
|
||||
|
||||
GenerateReportResponse:
|
||||
type: object
|
||||
properties:
|
||||
total:
|
||||
type: integer
|
||||
from:
|
||||
type: string
|
||||
format: date-time
|
||||
to:
|
||||
type: string
|
||||
format: date-time
|
||||
aggregation:
|
||||
$ref: '#/components/schemas/AggConfig'
|
||||
reports:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/Report'
|
||||
|
||||
Report:
|
||||
type: object
|
||||
properties:
|
||||
timestamp:
|
||||
type: string
|
||||
format: date-time
|
||||
value:
|
||||
type: number
|
||||
metric_name:
|
||||
type: string
|
||||
|
||||
AddReportConfigRequest:
|
||||
type: object
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
description:
|
||||
type: string
|
||||
schedule:
|
||||
$ref: '#/components/schemas/Schedule'
|
||||
config:
|
||||
$ref: '#/components/schemas/MetricConfig'
|
||||
email:
|
||||
$ref: '#/components/schemas/EmailSetting'
|
||||
metrics:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/ReqMetric'
|
||||
status:
|
||||
$ref: '#/components/schemas/Status'
|
||||
required:
|
||||
- name
|
||||
- metrics
|
||||
- config
|
||||
|
||||
UpdateReportConfigRequest:
|
||||
type: object
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
description:
|
||||
type: string
|
||||
schedule:
|
||||
$ref: '#/components/schemas/Schedule'
|
||||
config:
|
||||
$ref: '#/components/schemas/MetricConfig'
|
||||
email:
|
||||
$ref: '#/components/schemas/EmailSetting'
|
||||
metrics:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/ReqMetric'
|
||||
status:
|
||||
$ref: '#/components/schemas/Status'
|
||||
|
||||
ListReportsConfigResponse:
|
||||
type: object
|
||||
properties:
|
||||
total:
|
||||
type: integer
|
||||
offset:
|
||||
type: integer
|
||||
limit:
|
||||
type: integer
|
||||
report_configs:
|
||||
type: array
|
||||
items:
|
||||
$ref: '#/components/schemas/ReportConfig'
|
||||
|
||||
parameters:
|
||||
DomainID:
|
||||
name: domainID
|
||||
in: path
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
ReportID:
|
||||
name: reportID
|
||||
in: path
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
Offset:
|
||||
name: offset
|
||||
in: query
|
||||
schema:
|
||||
type: integer
|
||||
default: 0
|
||||
minimum: 0
|
||||
Limit:
|
||||
name: limit
|
||||
in: query
|
||||
schema:
|
||||
type: integer
|
||||
default: 10
|
||||
minimum: 1
|
||||
maximum: 100
|
||||
|
||||
responses:
|
||||
ServiceError:
|
||||
description: Unexpected server error
|
||||
HealthRes:
|
||||
description: Service Health Check.
|
||||
content:
|
||||
application/health+json:
|
||||
schema:
|
||||
$ref: './schemas/health_info.yaml'
|
||||
|
||||
securitySchemes:
|
||||
bearerAuth:
|
||||
type: http
|
||||
scheme: bearer
|
||||
bearerFormat: JWT
|
||||
@@ -0,0 +1,586 @@
|
||||
# Copyright (c) Abstract Machines
|
||||
# SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
openapi: 3.0.1
|
||||
info:
|
||||
title: Magistrala Rules Engine API
|
||||
description: |
|
||||
HTTP API for managing rules engine service.
|
||||
Some useful links:
|
||||
- [The Magistrala repository](https://github.com/absmach/magistrala)
|
||||
contact:
|
||||
email: info@absmach.eu
|
||||
license:
|
||||
name: Apache 2.0
|
||||
url: https://github.com/absmach/magistrala/blob/main/LICENSE
|
||||
version: 0.18.5
|
||||
|
||||
servers:
|
||||
- url: http://localhost:9008
|
||||
- url: http://localhost:9008
|
||||
|
||||
tags:
|
||||
- name: rules engine
|
||||
description: Everything about your Rules Engine
|
||||
externalDocs:
|
||||
description: Find out more about rules engine
|
||||
url: https://magistrala.absmach.eu/docs/
|
||||
|
||||
paths:
|
||||
/{domainID}/rules:
|
||||
post:
|
||||
operationId: createRule
|
||||
summary: Create Rule
|
||||
description: |
|
||||
Creates a new rule for message processing
|
||||
tags:
|
||||
- rules
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/DomainID'
|
||||
security:
|
||||
- bearerAuth: []
|
||||
requestBody:
|
||||
$ref: '#/components/requestBodies/RuleCreateReq'
|
||||
responses:
|
||||
'201':
|
||||
$ref: '#/components/responses/RuleCreateRes'
|
||||
'400':
|
||||
description: Failed due to malformed JSON
|
||||
'401':
|
||||
description: Missing or invalid access token
|
||||
'415':
|
||||
description: Missing or invalid content type
|
||||
"500":
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
"503":
|
||||
description: Failed to receive response from the clients service.
|
||||
get:
|
||||
operationId: getRules
|
||||
summary: List Rules
|
||||
description: |
|
||||
Retrieves a list of rules with optional filtering
|
||||
tags:
|
||||
- rules
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/DomainID'
|
||||
- $ref: '#/components/parameters/Offset'
|
||||
- $ref: '#/components/parameters/Limit'
|
||||
- $ref: '#/components/parameters/InputChannel'
|
||||
- $ref: '#/components/parameters/OutputChannel'
|
||||
- $ref: '#/components/parameters/Status'
|
||||
security:
|
||||
- bearerAuth: []
|
||||
responses:
|
||||
'200':
|
||||
$ref: '#/components/responses/RuleListRes'
|
||||
'400':
|
||||
description: Failed due to malformed query parameters
|
||||
'401':
|
||||
description: Missing or invalid access token
|
||||
"422":
|
||||
description: Database can't process request.
|
||||
"500":
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
|
||||
/{domainID}/rules/{ruleID}:
|
||||
get:
|
||||
operationId: getRule
|
||||
summary: View Rule
|
||||
description: Retrieves a rule by ID
|
||||
tags:
|
||||
- rules
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/DomainID'
|
||||
- $ref: '#/components/parameters/RuleID'
|
||||
security:
|
||||
- bearerAuth: []
|
||||
responses:
|
||||
'200':
|
||||
$ref: '#/components/responses/RuleRes'
|
||||
"400":
|
||||
description: Missing or invalid rule
|
||||
"403":
|
||||
description: Failed to perform authorization over the entity
|
||||
'401':
|
||||
description: Missing or invalid access token
|
||||
'404':
|
||||
description: Rule does not exist
|
||||
"422":
|
||||
description: Database can't process request
|
||||
"500":
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
put:
|
||||
operationId: updateRule
|
||||
summary: Update Rule
|
||||
description: Updates an existing rule
|
||||
tags:
|
||||
- rules
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/DomainID'
|
||||
- $ref: '#/components/parameters/RuleID'
|
||||
security:
|
||||
- bearerAuth: []
|
||||
requestBody:
|
||||
$ref: '#/components/requestBodies/RuleUpdateReq'
|
||||
responses:
|
||||
'200':
|
||||
$ref: '#/components/responses/RuleRes'
|
||||
'400':
|
||||
description: Failed due to malformed JSON
|
||||
'401':
|
||||
description: Missing or invalid access token
|
||||
'404':
|
||||
description: Rule does not exist
|
||||
"415":
|
||||
description: Missing or invalid content type.
|
||||
"422":
|
||||
description: Database can't process request.
|
||||
"500":
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
delete:
|
||||
operationId: removeRule
|
||||
summary: Delete Rule
|
||||
description: Deletes a rule
|
||||
tags:
|
||||
- rules
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/DomainID'
|
||||
- $ref: '#/components/parameters/RuleID'
|
||||
security:
|
||||
- bearerAuth: []
|
||||
responses:
|
||||
'204':
|
||||
description: Rule deleted successfully
|
||||
"400":
|
||||
description: Failed due to malformed rule ID
|
||||
'401':
|
||||
description: Missing or invalid access token
|
||||
"403":
|
||||
description: Failed to perform authorization over the entity
|
||||
"422":
|
||||
description: Database can't process request
|
||||
"500":
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
|
||||
/{domainID}/rules/{ruleID}/enable:
|
||||
put:
|
||||
operationId: enableRule
|
||||
summary: Enable Rule
|
||||
description: Enables a rule for processing
|
||||
tags:
|
||||
- rules
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/DomainID'
|
||||
- $ref: '#/components/parameters/RuleID'
|
||||
security:
|
||||
- bearerAuth: []
|
||||
responses:
|
||||
'200':
|
||||
description: Rule enabled successfully
|
||||
"400":
|
||||
description: Failed due to malformed JSON
|
||||
'401':
|
||||
description: Missing or invalid access token
|
||||
"403":
|
||||
description: Failed to perform authorization over the entity
|
||||
'404':
|
||||
description: Rule does not exist
|
||||
"422":
|
||||
description: Database can't process request.
|
||||
"500":
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
|
||||
/{domainID}/rules/{ruleID}/disable:
|
||||
put:
|
||||
operationId: disableRule
|
||||
summary: Disable Rule
|
||||
description: Disables a rule from processing
|
||||
tags:
|
||||
- Rules
|
||||
parameters:
|
||||
- $ref: '#/components/parameters/DomainID'
|
||||
- $ref: '#/components/parameters/RuleID'
|
||||
security:
|
||||
- bearerAuth: []
|
||||
responses:
|
||||
'200':
|
||||
description: Rule disabled successfully
|
||||
"400":
|
||||
description: Failed due to malformed JSON
|
||||
'401':
|
||||
description: Missing or invalid access token
|
||||
"403":
|
||||
description: Failed to perform authorization over the entity
|
||||
'404':
|
||||
description: Rule does not exist
|
||||
"422":
|
||||
description: Database can't process request
|
||||
"500":
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
|
||||
/health:
|
||||
get:
|
||||
summary: Retrieves service health check info.
|
||||
tags:
|
||||
- health
|
||||
security: []
|
||||
responses:
|
||||
"200":
|
||||
$ref: "#/components/responses/HealthRes"
|
||||
"500":
|
||||
$ref: "#/components/responses/ServiceError"
|
||||
|
||||
components:
|
||||
schemas:
|
||||
RulesListRes:
|
||||
type: object
|
||||
properties:
|
||||
total:
|
||||
type: integer
|
||||
description: Total number of results
|
||||
minimum: 0
|
||||
offset:
|
||||
type: integer
|
||||
description: Number of items to skip during retrieval
|
||||
minimum: 0
|
||||
default: 0
|
||||
limit:
|
||||
type: integer
|
||||
description: Size of the subset to retrieve
|
||||
maximum: 100
|
||||
default: 10
|
||||
rules:
|
||||
type: array
|
||||
minItems: 0
|
||||
uniqueItems: true
|
||||
items:
|
||||
$ref: '#/components/schemas/Rule'
|
||||
required:
|
||||
- rules
|
||||
|
||||
Rule:
|
||||
type: object
|
||||
properties:
|
||||
id:
|
||||
type: string
|
||||
description: Unique rule identifier
|
||||
name:
|
||||
type: string
|
||||
description: Rule name
|
||||
domain:
|
||||
type: string
|
||||
description: Domain ID this rule belongs to
|
||||
metadata:
|
||||
type: object
|
||||
description: Custom metadata
|
||||
additionalProperties:
|
||||
type: string
|
||||
input_channel:
|
||||
type: string
|
||||
description: Input channel for receiving messages
|
||||
input_topic:
|
||||
type: string
|
||||
description: Input topic for receiving messages
|
||||
logic:
|
||||
type: object
|
||||
description: Rule processing logic script
|
||||
properties:
|
||||
script:
|
||||
type: string
|
||||
description: Script content
|
||||
output_channel:
|
||||
type: string
|
||||
description: Output channel for processed messages
|
||||
output_topic:
|
||||
type: string
|
||||
description: Output topic for processed messages
|
||||
schedule:
|
||||
type: object
|
||||
description: Rule execution schedule
|
||||
properties:
|
||||
start_datetime:
|
||||
type: string
|
||||
format: date-time
|
||||
description: When the schedule becomes active
|
||||
time:
|
||||
type: string
|
||||
format: date-time
|
||||
description: Specific time for the rule to run
|
||||
recurring:
|
||||
type: string
|
||||
description: Schedule recurrence pattern
|
||||
enum: [None, Daily, Weekly, Monthly]
|
||||
recurring_period:
|
||||
type: integer
|
||||
minimum: 1
|
||||
description: Controls how many intervals to skip between executions (1 = every interval, 2 = every second interval, etc.)
|
||||
status:
|
||||
type: string
|
||||
description: Rule status
|
||||
enum: [enabled, disabled]
|
||||
created_at:
|
||||
type: string
|
||||
format: date-time
|
||||
description: Creation timestamp
|
||||
readOnly: true
|
||||
created_by:
|
||||
type: string
|
||||
description: User who created the rule
|
||||
updated_at:
|
||||
type: string
|
||||
format: date-time
|
||||
description: Last update timestamp
|
||||
readOnly: true
|
||||
updated_by:
|
||||
type: string
|
||||
description: User who last updated the rule
|
||||
required:
|
||||
- name
|
||||
- domain
|
||||
- input_channel
|
||||
- input_topic
|
||||
- logic
|
||||
- status
|
||||
|
||||
parameters:
|
||||
DomainID:
|
||||
name: domainID
|
||||
description: Domain ID
|
||||
in: path
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
RuleID:
|
||||
name: ruleID
|
||||
description: Rule ID
|
||||
in: path
|
||||
required: true
|
||||
schema:
|
||||
type: string
|
||||
Offset:
|
||||
name: offset
|
||||
description: Number of items to skip
|
||||
in: query
|
||||
required: false
|
||||
schema:
|
||||
type: integer
|
||||
default: 0
|
||||
minimum: 0
|
||||
Limit:
|
||||
name: limit
|
||||
description: Size of the subset
|
||||
in: query
|
||||
required: false
|
||||
schema:
|
||||
type: integer
|
||||
default: 10
|
||||
minimum: 1
|
||||
InputChannel:
|
||||
name: input_channel
|
||||
description: Filter by input channel
|
||||
in: query
|
||||
required: false
|
||||
schema:
|
||||
type: string
|
||||
OutputChannel:
|
||||
name: output_channel
|
||||
description: Filter by output channel
|
||||
in: query
|
||||
required: false
|
||||
schema:
|
||||
type: string
|
||||
Status:
|
||||
name: status
|
||||
description: Filter by rule status
|
||||
in: query
|
||||
required: false
|
||||
schema:
|
||||
type: string
|
||||
enum: [enabled, disabled]
|
||||
default: enabled
|
||||
|
||||
requestBodies:
|
||||
RuleCreateReq:
|
||||
description: JSON-formatted document describing the new rule
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
description: Rule name
|
||||
domain:
|
||||
type: string
|
||||
description: Domain ID this rule belongs to
|
||||
metadata:
|
||||
type: object
|
||||
description: Custom metadata
|
||||
additionalProperties:
|
||||
type: string
|
||||
input_channel:
|
||||
type: string
|
||||
description: Input channel for receiving messages
|
||||
input_topic:
|
||||
type: string
|
||||
description: Input topic for receiving messages
|
||||
logic:
|
||||
type: object
|
||||
description: Rule processing logic script
|
||||
properties:
|
||||
script:
|
||||
type: string
|
||||
description: Script content
|
||||
output_channel:
|
||||
type: string
|
||||
description: Output channel for processed messages
|
||||
output_topic:
|
||||
type: string
|
||||
description: Output topic for processed messages
|
||||
schedule:
|
||||
type: object
|
||||
description: Rule execution schedule
|
||||
properties:
|
||||
start_datetime:
|
||||
type: string
|
||||
format: date-time
|
||||
description: When the schedule becomes active
|
||||
time:
|
||||
type: string
|
||||
format: date-time
|
||||
description: Specific time for the rule to run
|
||||
recurring:
|
||||
type: string
|
||||
description: Schedule recurrence pattern
|
||||
enum: [None, Daily, Weekly, Monthly]
|
||||
recurring_period:
|
||||
type: integer
|
||||
minimum: 1
|
||||
description: Controls how many intervals to skip between executions
|
||||
status:
|
||||
type: string
|
||||
description: Rule status
|
||||
enum: [enabled, disabled]
|
||||
required:
|
||||
- name
|
||||
- domain
|
||||
- input_channel
|
||||
- input_topic
|
||||
- logic
|
||||
- schedule
|
||||
RuleUpdateReq:
|
||||
description: JSON-formatted document describing the rule update
|
||||
required: true
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
type: object
|
||||
properties:
|
||||
name:
|
||||
type: string
|
||||
description: Rule name
|
||||
metadata:
|
||||
type: object
|
||||
description: Custom metadata
|
||||
additionalProperties:
|
||||
type: string
|
||||
input_channel:
|
||||
type: string
|
||||
description: Input channel for receiving messages
|
||||
input_topic:
|
||||
type: string
|
||||
description: Input topic for receiving messages
|
||||
logic:
|
||||
type: object
|
||||
description: Rule processing logic script
|
||||
properties:
|
||||
script:
|
||||
type: string
|
||||
description: Script content
|
||||
output_channel:
|
||||
type: string
|
||||
description: Output channel for processed messages
|
||||
output_topic:
|
||||
type: string
|
||||
description: Output topic for processed messages
|
||||
schedule:
|
||||
type: object
|
||||
description: Rule execution schedule
|
||||
properties:
|
||||
start_datetime:
|
||||
type: string
|
||||
format: date-time
|
||||
description: When the schedule becomes active
|
||||
time:
|
||||
type: string
|
||||
format: date-time
|
||||
description: Specific time for the rule to run
|
||||
recurring:
|
||||
type: string
|
||||
description: Schedule recurrence pattern
|
||||
enum: [None, Daily, Weekly, Monthly]
|
||||
recurring_period:
|
||||
type: integer
|
||||
minimum: 1
|
||||
description: Controls how many intervals to skip between executions
|
||||
status:
|
||||
type: string
|
||||
description: Rule status
|
||||
enum: [enabled, disabled]
|
||||
|
||||
responses:
|
||||
RuleCreateRes:
|
||||
description: Rule registered
|
||||
headers:
|
||||
Location:
|
||||
content:
|
||||
text/plain:
|
||||
schema:
|
||||
type: string
|
||||
description: Created rule's relative URL (i.e. /rules/{ruleID})
|
||||
RuleListRes:
|
||||
description: Data retrieved
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/RulesListRes'
|
||||
RuleRes:
|
||||
description: Data retrieved
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/Rule'
|
||||
links:
|
||||
update:
|
||||
operationId: updateRule
|
||||
parameters:
|
||||
ruleID: $response.body#/id
|
||||
enable:
|
||||
operationId: enableRule
|
||||
parameters:
|
||||
ruleID: $response.body#/id
|
||||
disable:
|
||||
operationId: disableRule
|
||||
parameters:
|
||||
ruleID: $response.body#/id
|
||||
delete:
|
||||
operationId: removeRule
|
||||
parameters:
|
||||
ruleID: $response.body#/id
|
||||
ServiceError:
|
||||
description: Unexpected server-side error occurred
|
||||
HealthRes:
|
||||
description: Service Health Check
|
||||
content:
|
||||
application/health+json:
|
||||
schema:
|
||||
$ref: "./schemas/health_info.yaml"
|
||||
|
||||
securitySchemes:
|
||||
bearerAuth:
|
||||
type: http
|
||||
scheme: bearer
|
||||
bearerFormat: JWT
|
||||
description: |
|
||||
* Users access: "Authorization: Bearer <user_token>"
|
||||
@@ -3,16 +3,16 @@
|
||||
|
||||
openapi: 3.0.3
|
||||
info:
|
||||
title: SuperMQ Users Service
|
||||
title: Magistrala Users Service
|
||||
description: |
|
||||
This is the Users Server based on the OpenAPI 3.0 specification. It is the HTTP API for managing platform users. You can now help us improve the API whether it's by making changes to the definition itself or to the code.
|
||||
Some useful links:
|
||||
- [The SuperMQ repository](https://github.com/absmach/supermq)
|
||||
- [The Magistrala repository](https://github.com/absmach/magistrala)
|
||||
contact:
|
||||
email: info@absmach.eu
|
||||
license:
|
||||
name: Apache 2.0
|
||||
url: https://github.com/absmach/supermq/blob/main/LICENSE
|
||||
url: https://github.com/absmach/magistrala/blob/main/LICENSE
|
||||
version: 0.18.0
|
||||
|
||||
servers:
|
||||
@@ -24,12 +24,12 @@ tags:
|
||||
description: Everything about your Users
|
||||
externalDocs:
|
||||
description: Find out more about users
|
||||
url: https://docs.supermq.absmach.eu/
|
||||
url: https://magistrala.absmach.eu/docs/
|
||||
- name: Health
|
||||
description: Health check operations
|
||||
externalDocs:
|
||||
description: Find out more about health checks
|
||||
url: https://docs.supermq.absmach.eu/
|
||||
url: https://magistrala.absmach.eu/docs/
|
||||
|
||||
paths:
|
||||
/users:
|
||||
@@ -815,7 +815,7 @@ components:
|
||||
description: User tags.
|
||||
email:
|
||||
type: string
|
||||
example: "john.doe@supermq.com"
|
||||
example: "john.doe@magistrala.com"
|
||||
description: User email for example email address.
|
||||
credentials:
|
||||
type: object
|
||||
@@ -872,7 +872,7 @@ components:
|
||||
description: User's last name.
|
||||
email:
|
||||
type: string
|
||||
example: user@supermq.com
|
||||
example: user@magistrala.com
|
||||
description: User's email address.
|
||||
tags:
|
||||
type: array
|
||||
@@ -987,7 +987,7 @@ components:
|
||||
properties:
|
||||
email:
|
||||
type: string
|
||||
example: user@supermq.com
|
||||
example: user@magistrala.com
|
||||
description: User email address.
|
||||
required:
|
||||
- email
|
||||
|
||||
+92
-92
@@ -8,7 +8,7 @@ User service is using Auth service gRPC API to obtain login token or password re
|
||||
|
||||
- ID - key ID
|
||||
- Type - one of the three types described below
|
||||
- IssuerID - an ID of the SuperMQ User who issued the key
|
||||
- IssuerID - an ID of the Magistrala User who issued the key
|
||||
- Subject - user ID for which the key is issued
|
||||
- IssuedAt - the timestamp when the key is issued
|
||||
- ExpiresAt - the timestamp after which the key is invalid
|
||||
@@ -29,7 +29,7 @@ API keys are similar to the User keys. The main difference is that API keys have
|
||||
|
||||
Recovery key is the password recovery key. It's short-lived token used for password recovery process.
|
||||
|
||||
For in-depth explanation of the aforementioned scenarios, as well as thorough understanding of SuperMQ, please check out the [official documentation][doc].
|
||||
For in-depth explanation of the aforementioned scenarios, as well as thorough understanding of Magistrala, please check out the [official documentation][doc].
|
||||
|
||||
The following actions are supported:
|
||||
|
||||
@@ -59,63 +59,63 @@ Domain consists of the following fields:
|
||||
|
||||
The service is configured using the environment variables presented in the following table. Note that any unset variables will be replaced with their default values.
|
||||
|
||||
| Variable | Description | Default |
|
||||
| :--- | :--- | :--- |
|
||||
| `SMQ_AUTH_LOG_LEVEL` | Log level for the Auth service (debug, info, warn, error) | info |
|
||||
| `SMQ_AUTH_DB_HOST` | Database host address | localhost |
|
||||
| `SMQ_AUTH_DB_PORT` | Database host port | 5432 |
|
||||
| `SMQ_AUTH_DB_USER` | Database user | supermq |
|
||||
| `SMQ_AUTH_DB_PASSWORD` | Database password | supermq |
|
||||
| `SMQ_AUTH_DB_NAME` | Name of the database used by the service | auth |
|
||||
| `SMQ_AUTH_DB_SSL_MODE` | Database connection SSL mode (disable, require, verify-ca, verify-full) | disable |
|
||||
| `SMQ_AUTH_DB_SSL_CERT` | Path to the PEM encoded certificate file | "" |
|
||||
| `SMQ_AUTH_DB_SSL_KEY` | Path to the PEM encoded key file | "" |
|
||||
| `SMQ_AUTH_DB_SSL_ROOT_CERT` | Path to the PEM encoded root certificate file | "" |
|
||||
| `SMQ_AUTH_HTTP_HOST` | Auth service HTTP host | "" |
|
||||
| `SMQ_AUTH_HTTP_PORT` | Auth service HTTP port | 8189 |
|
||||
| `SMQ_AUTH_HTTP_SERVER_CERT` | Path to the PEM encoded HTTP server certificate file | "" |
|
||||
| `SMQ_AUTH_HTTP_SERVER_KEY` | Path to the PEM encoded HTTP server key file | "" |
|
||||
| `SMQ_AUTH_GRPC_HOST` | Auth service gRPC host | "" |
|
||||
| `SMQ_AUTH_GRPC_PORT` | Auth service gRPC port | 8181 |
|
||||
| `SMQ_AUTH_GRPC_SERVER_CERT` | Path to the PEM encoded gRPC server certificate file | "" |
|
||||
| `SMQ_AUTH_GRPC_SERVER_KEY` | Path to the PEM encoded gRPC server key file | "" |
|
||||
| `SMQ_AUTH_GRPC_SERVER_CA_CERTS` | Path to the PEM encoded gRPC server CA certificate file | "" |
|
||||
| `SMQ_AUTH_GRPC_CLIENT_CA_CERTS` | Path to the PEM encoded gRPC client CA certificate file | "" |
|
||||
| `SMQ_AUTH_SECRET_KEY` | String used for signing tokens | secret |
|
||||
| `SMQ_AUTH_ACCESS_TOKEN_DURATION` | The access token expiration period | 1h |
|
||||
| `SMQ_AUTH_REFRESH_TOKEN_DURATION` | The refresh token expiration period | 24h |
|
||||
| `SMQ_AUTH_INVITATION_DURATION` | The invitation token expiration period | 168h |
|
||||
| `SMQ_AUTH_CACHE_URL` | Redis URL for caching PAT scopes | redis://localhost:6379/0 |
|
||||
| `SMQ_AUTH_CACHE_KEY_DURATION` | Duration for which PAT scope cache keys are valid | 10m |
|
||||
| `SMQ_SPICEDB_HOST` | SpiceDB host address | localhost |
|
||||
| `SMQ_SPICEDB_PORT` | SpiceDB host port | 50051 |
|
||||
| `SMQ_SPICEDB_PRE_SHARED_KEY` | SpiceDB pre-shared key | 12345678 |
|
||||
| `SMQ_SPICEDB_SCHEMA_FILE` | Path to SpiceDB schema file | ./docker/spicedb/schema.zed |
|
||||
| `SMQ_JAEGER_URL` | Jaeger server URL | <http://jaeger:4318/v1/traces> |
|
||||
| `SMQ_JAEGER_TRACE_RATIO` | Jaeger sampling ratio | 1.0 |
|
||||
| `SMQ_SEND_TELEMETRY` | Send telemetry to supermq call home server | true |
|
||||
| `SMQ_ADAPTER_INSTANCE_ID` | Adapter instance ID | "" |
|
||||
| `SMQ_CALLOUT_URLS` | Comma-separated list of callout URLs | "" |
|
||||
| `SMQ_CALLOUT_METHOD` | Callout method | POST |
|
||||
| `SMQ_CALLOUT_TLS_VERIFICATION` | Enable TLS verification for callouts | true |
|
||||
| `SMQ_CALLOUT_TIMEOUT` | Callout timeout | 10s |
|
||||
| `SMQ_CALLOUT_CA_CERT` | Path to CA certificate file | "" |
|
||||
| `SMQ_CALLOUT_CERT` | Path to client certificate file | "" |
|
||||
| `SMQ_CALLOUT_KEY` | Path to client key file | "" |
|
||||
| `SMQ_CALLOUT_OPERATIONS` | Invoke callout if the authorization permission matches any of the given permissions. | "" |
|
||||
| Variable | Description | Default |
|
||||
| :------------------------------- | :----------------------------------------------------------------------------------- | :----------------------------- |
|
||||
| `MG_AUTH_LOG_LEVEL` | Log level for the Auth service (debug, info, warn, error) | info |
|
||||
| `MG_AUTH_DB_HOST` | Database host address | localhost |
|
||||
| `MG_AUTH_DB_PORT` | Database host port | 5432 |
|
||||
| `MG_AUTH_DB_USER` | Database user | magistrala |
|
||||
| `MG_AUTH_DB_PASSWORD` | Database password | magistrala |
|
||||
| `MG_AUTH_DB_NAME` | Name of the database used by the service | auth |
|
||||
| `MG_AUTH_DB_SSL_MODE` | Database connection SSL mode (disable, require, verify-ca, verify-full) | disable |
|
||||
| `MG_AUTH_DB_SSL_CERT` | Path to the PEM encoded certificate file | "" |
|
||||
| `MG_AUTH_DB_SSL_KEY` | Path to the PEM encoded key file | "" |
|
||||
| `MG_AUTH_DB_SSL_ROOT_CERT` | Path to the PEM encoded root certificate file | "" |
|
||||
| `MG_AUTH_HTTP_HOST` | Auth service HTTP host | "" |
|
||||
| `MG_AUTH_HTTP_PORT` | Auth service HTTP port | 8189 |
|
||||
| `MG_AUTH_HTTP_SERVER_CERT` | Path to the PEM encoded HTTP server certificate file | "" |
|
||||
| `MG_AUTH_HTTP_SERVER_KEY` | Path to the PEM encoded HTTP server key file | "" |
|
||||
| `MG_AUTH_GRPC_HOST` | Auth service gRPC host | "" |
|
||||
| `MG_AUTH_GRPC_PORT` | Auth service gRPC port | 8181 |
|
||||
| `MG_AUTH_GRPC_SERVER_CERT` | Path to the PEM encoded gRPC server certificate file | "" |
|
||||
| `MG_AUTH_GRPC_SERVER_KEY` | Path to the PEM encoded gRPC server key file | "" |
|
||||
| `MG_AUTH_GRPC_SERVER_CA_CERTS` | Path to the PEM encoded gRPC server CA certificate file | "" |
|
||||
| `MG_AUTH_GRPC_CLIENT_CA_CERTS` | Path to the PEM encoded gRPC client CA certificate file | "" |
|
||||
| `MG_AUTH_SECRET_KEY` | String used for signing tokens | secret |
|
||||
| `MG_AUTH_ACCESS_TOKEN_DURATION` | The access token expiration period | 1h |
|
||||
| `MG_AUTH_REFRESH_TOKEN_DURATION` | The refresh token expiration period | 24h |
|
||||
| `MG_AUTH_INVITATION_DURATION` | The invitation token expiration period | 168h |
|
||||
| `MG_AUTH_CACHE_URL` | Redis URL for caching PAT scopes | redis://localhost:6379/0 |
|
||||
| `MG_AUTH_CACHE_KEY_DURATION` | Duration for which PAT scope cache keys are valid | 10m |
|
||||
| `MG_SPICEDB_HOST` | SpiceDB host address | localhost |
|
||||
| `MG_SPICEDB_PORT` | SpiceDB host port | 50051 |
|
||||
| `MG_SPICEDB_PRE_SHARED_KEY` | SpiceDB pre-shared key | 12345678 |
|
||||
| `MG_SPICEDB_SCHEMA_FILE` | Path to SpiceDB schema file | ./docker/spicedb/schema.zed |
|
||||
| `MG_JAEGER_URL` | Jaeger server URL | <http://jaeger:4318/v1/traces> |
|
||||
| `MG_JAEGER_TRACE_RATIO` | Jaeger sampling ratio | 1.0 |
|
||||
| `MG_SEND_TELEMETRY` | Send telemetry to magistrala call home server | true |
|
||||
| `MG_ADAPTER_INSTANCE_ID` | Adapter instance ID | "" |
|
||||
| `MG_CALLOUT_URLS` | Comma-separated list of callout URLs | "" |
|
||||
| `MG_CALLOUT_METHOD` | Callout method | POST |
|
||||
| `MG_CALLOUT_TLS_VERIFICATION` | Enable TLS verification for callouts | true |
|
||||
| `MG_CALLOUT_TIMEOUT` | Callout timeout | 10s |
|
||||
| `MG_CALLOUT_CA_CERT` | Path to CA certificate file | "" |
|
||||
| `MG_CALLOUT_CERT` | Path to client certificate file | "" |
|
||||
| `MG_CALLOUT_KEY` | Path to client key file | "" |
|
||||
| `MG_CALLOUT_OPERATIONS` | Invoke callout if the authorization permission matches any of the given permissions. | "" |
|
||||
|
||||
## Deployment
|
||||
|
||||
The service itself is distributed as Docker container. Check the [`auth`](https://github.com/absmach/supermq/blob/main/docker/docker-compose.yaml) service section in docker-compose file to see how service is deployed.
|
||||
The service itself is distributed as Docker container. Check the [`auth`](https://github.com/absmach/magistrala/blob/main/docker/docker-compose.yaml) service section in docker-compose file to see how service is deployed.
|
||||
|
||||
Running this service outside of container requires working instance of the postgres database, SpiceDB, and Jaeger server.
|
||||
To start the service outside of the container, execute the following shell script:
|
||||
|
||||
```bash
|
||||
# download the latest version of the service
|
||||
git clone https://github.com/absmach/supermq
|
||||
git clone https://github.com/absmach/magistrala
|
||||
|
||||
cd supermq
|
||||
cd magistrala
|
||||
|
||||
# compile the service
|
||||
make auth
|
||||
@@ -124,54 +124,54 @@ make auth
|
||||
make install
|
||||
|
||||
# set the environment variables and run the service
|
||||
SMQ_AUTH_LOG_LEVEL=info \
|
||||
SMQ_AUTH_DB_HOST=localhost \
|
||||
SMQ_AUTH_DB_PORT=5432 \
|
||||
SMQ_AUTH_DB_USER=supermq \
|
||||
SMQ_AUTH_DB_PASSWORD=supermq \
|
||||
SMQ_AUTH_DB_NAME=auth \
|
||||
SMQ_AUTH_DB_SSL_MODE=disable \
|
||||
SMQ_AUTH_DB_SSL_CERT="" \
|
||||
SMQ_AUTH_DB_SSL_KEY="" \
|
||||
SMQ_AUTH_DB_SSL_ROOT_CERT="" \
|
||||
SMQ_AUTH_HTTP_HOST=localhost \
|
||||
SMQ_AUTH_HTTP_PORT=8189 \
|
||||
SMQ_AUTH_HTTP_SERVER_CERT="" \
|
||||
SMQ_AUTH_HTTP_SERVER_KEY="" \
|
||||
SMQ_AUTH_GRPC_HOST=localhost \
|
||||
SMQ_AUTH_GRPC_PORT=8181 \
|
||||
SMQ_AUTH_GRPC_SERVER_CERT="" \
|
||||
SMQ_AUTH_GRPC_SERVER_KEY="" \
|
||||
SMQ_AUTH_GRPC_SERVER_CA_CERTS="" \
|
||||
SMQ_AUTH_GRPC_CLIENT_CA_CERTS="" \
|
||||
SMQ_AUTH_SECRET_KEY=secret \
|
||||
SMQ_AUTH_ACCESS_TOKEN_DURATION=1h \
|
||||
SMQ_AUTH_REFRESH_TOKEN_DURATION=24h \
|
||||
SMQ_AUTH_INVITATION_DURATION=168h \
|
||||
SMQ_SPICEDB_HOST=localhost \
|
||||
SMQ_SPICEDB_PORT=50051 \
|
||||
SMQ_SPICEDB_PRE_SHARED_KEY=12345678 \
|
||||
SMQ_SPICEDB_SCHEMA_FILE=./docker/spicedb/schema.zed \
|
||||
SMQ_JAEGER_URL=http://localhost:14268/api/traces \
|
||||
SMQ_JAEGER_TRACE_RATIO=1.0 \
|
||||
SMQ_SEND_TELEMETRY=true \
|
||||
SMQ_AUTH_ADAPTER_INSTANCE_ID="" \
|
||||
SMQ_CALLOUT_URLS="" \
|
||||
SMQ_CALLOUT_METHOD="POST" \
|
||||
SMQ_CALLOUT_TLS_VERIFICATION=true \
|
||||
$GOBIN/supermq-auth
|
||||
MG_AUTH_LOG_LEVEL=info \
|
||||
MG_AUTH_DB_HOST=localhost \
|
||||
MG_AUTH_DB_PORT=5432 \
|
||||
MG_AUTH_DB_USER=magistrala \
|
||||
MG_AUTH_DB_PASSWORD=magistrala \
|
||||
MG_AUTH_DB_NAME=auth \
|
||||
MG_AUTH_DB_SSL_MODE=disable \
|
||||
MG_AUTH_DB_SSL_CERT="" \
|
||||
MG_AUTH_DB_SSL_KEY="" \
|
||||
MG_AUTH_DB_SSL_ROOT_CERT="" \
|
||||
MG_AUTH_HTTP_HOST=localhost \
|
||||
MG_AUTH_HTTP_PORT=8189 \
|
||||
MG_AUTH_HTTP_SERVER_CERT="" \
|
||||
MG_AUTH_HTTP_SERVER_KEY="" \
|
||||
MG_AUTH_GRPC_HOST=localhost \
|
||||
MG_AUTH_GRPC_PORT=8181 \
|
||||
MG_AUTH_GRPC_SERVER_CERT="" \
|
||||
MG_AUTH_GRPC_SERVER_KEY="" \
|
||||
MG_AUTH_GRPC_SERVER_CA_CERTS="" \
|
||||
MG_AUTH_GRPC_CLIENT_CA_CERTS="" \
|
||||
MG_AUTH_SECRET_KEY=secret \
|
||||
MG_AUTH_ACCESS_TOKEN_DURATION=1h \
|
||||
MG_AUTH_REFRESH_TOKEN_DURATION=24h \
|
||||
MG_AUTH_INVITATION_DURATION=168h \
|
||||
MG_SPICEDB_HOST=localhost \
|
||||
MG_SPICEDB_PORT=50051 \
|
||||
MG_SPICEDB_PRE_SHARED_KEY=12345678 \
|
||||
MG_SPICEDB_SCHEMA_FILE=./docker/spicedb/schema.zed \
|
||||
MG_JAEGER_URL=http://localhost:14268/api/traces \
|
||||
MG_JAEGER_TRACE_RATIO=1.0 \
|
||||
MG_SEND_TELEMETRY=true \
|
||||
MG_AUTH_ADAPTER_INSTANCE_ID="" \
|
||||
MG_CALLOUT_URLS="" \
|
||||
MG_CALLOUT_METHOD="POST" \
|
||||
MG_CALLOUT_TLS_VERIFICATION=true \
|
||||
$GOBIN/magistrala-auth
|
||||
```
|
||||
|
||||
Setting `SMQ_AUTH_HTTP_SERVER_CERT` and `SMQ_AUTH_HTTP_SERVER_KEY` will enable TLS against the service. The service expects a file in PEM format for both the certificate and the key.
|
||||
Setting `SMQ_AUTH_GRPC_SERVER_CERT` and `SMQ_AUTH_GRPC_SERVER_KEY` will enable TLS against the service. The service expects a file in PEM format for both the certificate and the key. Setting `SMQ_AUTH_GRPC_SERVER_CA_CERTS` will enable TLS against the service trusting only those CAs that are provided. The service expects a file in PEM format of trusted CAs. Setting `SMQ_AUTH_GRPC_CLIENT_CA_CERTS` will enable TLS against the service trusting only those CAs that are provided. The service expects a file in PEM format of trusted CAs.
|
||||
Setting `MG_AUTH_HTTP_SERVER_CERT` and `MG_AUTH_HTTP_SERVER_KEY` will enable TLS against the service. The service expects a file in PEM format for both the certificate and the key.
|
||||
Setting `MG_AUTH_GRPC_SERVER_CERT` and `MG_AUTH_GRPC_SERVER_KEY` will enable TLS against the service. The service expects a file in PEM format for both the certificate and the key. Setting `MG_AUTH_GRPC_SERVER_CA_CERTS` will enable TLS against the service trusting only those CAs that are provided. The service expects a file in PEM format of trusted CAs. Setting `MG_AUTH_GRPC_CLIENT_CA_CERTS` will enable TLS against the service trusting only those CAs that are provided. The service expects a file in PEM format of trusted CAs.
|
||||
|
||||
## Personal Access Tokens (PATs)
|
||||
|
||||
Personal Access Tokens (PATs) provide a secure way to authenticate with SuperMQ APIs without using your primary credentials. They are particularly useful for automation, CI/CD pipelines, and integrating with third-party services.
|
||||
Personal Access Tokens (PATs) provide a secure way to authenticate with Magistrala APIs without using your primary credentials. They are particularly useful for automation, CI/CD pipelines, and integrating with third-party services.
|
||||
|
||||
### Overview
|
||||
|
||||
PATs in SuperMQ are designed with the following features:
|
||||
PATs in Magistrala are designed with the following features:
|
||||
|
||||
- **Scoped Access**: Each token can be limited to specific operations on specific resources
|
||||
- **Expiration Control**: Set custom expiration times for tokens
|
||||
@@ -195,7 +195,7 @@ Where:
|
||||
|
||||
### PAT Operations
|
||||
|
||||
SuperMQ supports the following operations for PATs:
|
||||
Magistrala supports the following operations for PATs:
|
||||
|
||||
| Operation | Description |
|
||||
| ----------- | ------------------------------------ |
|
||||
@@ -444,6 +444,6 @@ When a PAT is used for authentication:
|
||||
|
||||
## Usage
|
||||
|
||||
For more information about service capabilities and its usage, please check out the [API documentation](https://docs.api.supermq.absmach.eu/?urls.primaryName=auth.yaml).
|
||||
For more information about service capabilities and its usage, please check out the [API documentation](https://docs.api.magistrala.absmach.eu/?urls.primaryName=auth.yaml).
|
||||
|
||||
[doc]: https://docs.supermq.absmach.eu/
|
||||
[doc]: https://magistrala.absmach.eu/docs/
|
||||
@@ -7,9 +7,9 @@ import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
grpcAuthV1 "github.com/absmach/supermq/api/grpc/auth/v1"
|
||||
"github.com/absmach/supermq/auth"
|
||||
grpcapi "github.com/absmach/supermq/auth/api/grpc"
|
||||
grpcAuthV1 "github.com/absmach/magistrala/api/grpc/auth/v1"
|
||||
"github.com/absmach/magistrala/auth"
|
||||
grpcapi "github.com/absmach/magistrala/auth/api/grpc"
|
||||
"github.com/go-kit/kit/endpoint"
|
||||
kitgrpc "github.com/go-kit/kit/transport/grpc"
|
||||
"google.golang.org/grpc"
|
||||
@@ -57,7 +57,7 @@ func (client authGrpcClient) Authenticate(ctx context.Context, token *grpcAuthV1
|
||||
return &grpcAuthV1.AuthNRes{}, grpcapi.DecodeError(err)
|
||||
}
|
||||
ir := res.(authenticateRes)
|
||||
return &grpcAuthV1.AuthNRes{Id: ir.id, UserId: ir.userID, UserRole: uint32(ir.userRole), Verified: ir.verified}, nil
|
||||
return &grpcAuthV1.AuthNRes{Id: ir.id, UserId: ir.userID, UserRole: uint32(ir.userRole), Verified: ir.verified, TokenType: uint32(ir.tokenType)}, nil
|
||||
}
|
||||
|
||||
func encodeIdentifyRequest(_ context.Context, grpcReq any) (any, error) {
|
||||
@@ -67,7 +67,7 @@ func encodeIdentifyRequest(_ context.Context, grpcReq any) (any, error) {
|
||||
|
||||
func decodeIdentifyResponse(_ context.Context, grpcRes any) (any, error) {
|
||||
res := grpcRes.(*grpcAuthV1.AuthNRes)
|
||||
return authenticateRes{id: res.GetId(), userID: res.GetUserId(), userRole: auth.Role(res.UserRole), verified: res.GetVerified()}, nil
|
||||
return authenticateRes{id: res.GetId(), userID: res.GetUserId(), userRole: auth.Role(res.UserRole), verified: res.GetVerified(), tokenType: auth.KeyType(res.GetTokenType())}, nil
|
||||
}
|
||||
|
||||
func (client authGrpcClient) Authorize(ctx context.Context, req *grpcAuthV1.AuthZReq, _ ...grpc.CallOption) (r *grpcAuthV1.AuthZRes, err error) {
|
||||
@@ -94,6 +94,9 @@ func (client authGrpcClient) Authorize(ctx context.Context, req *grpcAuthV1.Auth
|
||||
}
|
||||
|
||||
if patReq != nil {
|
||||
if patReq.GetDomain() != "" {
|
||||
authReqData.Domain = patReq.GetDomain()
|
||||
}
|
||||
authReqData.UserID = patReq.GetUserId()
|
||||
authReqData.PatID = patReq.GetPatId()
|
||||
authReqData.EntityType = patReq.GetEntityType()
|
||||
|
||||
@@ -6,8 +6,8 @@ package auth
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/absmach/supermq/auth"
|
||||
"github.com/absmach/supermq/pkg/policies"
|
||||
"github.com/absmach/magistrala/auth"
|
||||
"github.com/absmach/magistrala/pkg/policies"
|
||||
"github.com/go-kit/kit/endpoint"
|
||||
)
|
||||
|
||||
@@ -23,7 +23,7 @@ func authenticateEndpoint(svc auth.Service) endpoint.Endpoint {
|
||||
return authenticateRes{}, err
|
||||
}
|
||||
|
||||
return authenticateRes{id: key.ID, userID: key.Subject, userRole: key.Role, verified: key.Verified}, nil
|
||||
return authenticateRes{id: key.ID, userID: key.Subject, userRole: key.Role, verified: key.Verified, tokenType: key.Type}, nil
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,358 +0,0 @@
|
||||
// Copyright (c) Abstract Machines
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package auth_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
grpcAuthV1 "github.com/absmach/supermq/api/grpc/auth/v1"
|
||||
apiutil "github.com/absmach/supermq/api/http/util"
|
||||
"github.com/absmach/supermq/auth"
|
||||
grpcapi "github.com/absmach/supermq/auth/api/grpc/auth"
|
||||
"github.com/absmach/supermq/internal/testsutil"
|
||||
"github.com/absmach/supermq/pkg/errors"
|
||||
svcerr "github.com/absmach/supermq/pkg/errors/service"
|
||||
"github.com/absmach/supermq/pkg/policies"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/mock"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/credentials/insecure"
|
||||
)
|
||||
|
||||
const (
|
||||
port = 8081
|
||||
id = "testID"
|
||||
usersType = "users"
|
||||
adminPermission = "admin"
|
||||
authoritiesObj = "authorities"
|
||||
memberRelation = "member"
|
||||
validToken = "valid"
|
||||
inValidToken = "invalid"
|
||||
validPATToken = "valid"
|
||||
)
|
||||
|
||||
var (
|
||||
domainID = testsutil.GenerateUUID(&testing.T{})
|
||||
authAddr = fmt.Sprintf("localhost:%d", port)
|
||||
clientID = testsutil.GenerateUUID(&testing.T{})
|
||||
)
|
||||
|
||||
func startGRPCServer(svc auth.Service, port int) *grpc.Server {
|
||||
listener, _ := net.Listen("tcp", fmt.Sprintf(":%d", port))
|
||||
server := grpc.NewServer()
|
||||
grpcAuthV1.RegisterAuthServiceServer(server, grpcapi.NewAuthServer(svc))
|
||||
go func() {
|
||||
err := server.Serve(listener)
|
||||
assert.Nil(&testing.T{}, err, fmt.Sprintf(`"Unexpected error creating auth server %s"`, err))
|
||||
}()
|
||||
|
||||
return server
|
||||
}
|
||||
|
||||
func TestIdentify(t *testing.T) {
|
||||
conn, err := grpc.NewClient(authAddr, grpc.WithTransportCredentials(insecure.NewCredentials()))
|
||||
assert.Nil(t, err, fmt.Sprintf("Unexpected error creating client connection %s", err))
|
||||
defer conn.Close()
|
||||
grpcClient := grpcapi.NewAuthClient(conn, time.Second)
|
||||
|
||||
cases := []struct {
|
||||
desc string
|
||||
token string
|
||||
key auth.Key
|
||||
idt *grpcAuthV1.AuthNRes
|
||||
svcErr error
|
||||
err error
|
||||
}{
|
||||
{
|
||||
desc: "authenticate user with valid user token",
|
||||
token: validToken,
|
||||
key: auth.Key{ID: "", Subject: id, Role: auth.UserRole},
|
||||
idt: &grpcAuthV1.AuthNRes{UserId: id, UserRole: uint32(auth.UserRole)},
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "authenticate user with invalid user token",
|
||||
token: "invalid",
|
||||
key: auth.Key{},
|
||||
idt: &grpcAuthV1.AuthNRes{},
|
||||
svcErr: svcerr.ErrAuthentication,
|
||||
err: svcerr.ErrAuthentication,
|
||||
},
|
||||
{
|
||||
desc: "authenticate user with empty token",
|
||||
token: "",
|
||||
idt: &grpcAuthV1.AuthNRes{},
|
||||
err: apiutil.ErrBearerToken,
|
||||
},
|
||||
{
|
||||
desc: "authenticate user with valid PAT token",
|
||||
token: "pat_" + validPATToken,
|
||||
key: auth.Key{ID: id, Type: auth.PersonalAccessToken, Subject: clientID, Role: auth.UserRole},
|
||||
idt: &grpcAuthV1.AuthNRes{Id: id, UserId: clientID, UserRole: uint32(auth.UserRole)},
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "authenticate user with invalid PAT token",
|
||||
token: "pat_invalid",
|
||||
key: auth.Key{},
|
||||
idt: &grpcAuthV1.AuthNRes{},
|
||||
svcErr: svcerr.ErrAuthentication,
|
||||
err: svcerr.ErrAuthentication,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
svcCall := svc.On("Identify", mock.Anything, tc.token).Return(tc.key, tc.svcErr)
|
||||
idt, err := grpcClient.Authenticate(context.Background(), &grpcAuthV1.AuthNReq{Token: tc.token})
|
||||
if idt != nil {
|
||||
assert.Equal(t, tc.idt, idt, fmt.Sprintf("%s: expected %v got %v", tc.desc, tc.idt, idt))
|
||||
}
|
||||
assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err))
|
||||
svcCall.Unset()
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
func TestAuthorize(t *testing.T) {
|
||||
conn, err := grpc.NewClient(authAddr, grpc.WithTransportCredentials(insecure.NewCredentials()))
|
||||
assert.Nil(t, err, fmt.Sprintf("Unexpected error creating client connection %s", err))
|
||||
defer conn.Close()
|
||||
|
||||
grpcClient := grpcapi.NewAuthClient(conn, time.Second)
|
||||
|
||||
cases := []struct {
|
||||
desc string
|
||||
token string
|
||||
authRequest *grpcAuthV1.AuthZReq
|
||||
authResponse *grpcAuthV1.AuthZRes
|
||||
err error
|
||||
}{
|
||||
{
|
||||
desc: "authorize user with authorized token",
|
||||
token: validToken,
|
||||
authRequest: &grpcAuthV1.AuthZReq{
|
||||
PolicyReq: &grpcAuthV1.PolicyReq{
|
||||
Subject: id,
|
||||
SubjectType: usersType,
|
||||
Object: authoritiesObj,
|
||||
ObjectType: usersType,
|
||||
Relation: memberRelation,
|
||||
Permission: adminPermission,
|
||||
},
|
||||
},
|
||||
authResponse: &grpcAuthV1.AuthZRes{Authorized: true},
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "authorize user with unauthorized token",
|
||||
token: inValidToken,
|
||||
authRequest: &grpcAuthV1.AuthZReq{
|
||||
PolicyReq: &grpcAuthV1.PolicyReq{
|
||||
Subject: id,
|
||||
SubjectType: usersType,
|
||||
Object: authoritiesObj,
|
||||
ObjectType: usersType,
|
||||
Relation: memberRelation,
|
||||
Permission: adminPermission,
|
||||
},
|
||||
},
|
||||
authResponse: &grpcAuthV1.AuthZRes{Authorized: false},
|
||||
err: svcerr.ErrAuthorization,
|
||||
},
|
||||
{
|
||||
desc: "authorize user with empty subject",
|
||||
token: validToken,
|
||||
authRequest: &grpcAuthV1.AuthZReq{
|
||||
PolicyReq: &grpcAuthV1.PolicyReq{
|
||||
Subject: "",
|
||||
SubjectType: usersType,
|
||||
Object: authoritiesObj,
|
||||
ObjectType: usersType,
|
||||
Relation: memberRelation,
|
||||
Permission: adminPermission,
|
||||
},
|
||||
},
|
||||
authResponse: &grpcAuthV1.AuthZRes{Authorized: false},
|
||||
err: apiutil.ErrMissingPolicySub,
|
||||
},
|
||||
{
|
||||
desc: "authorize user with empty subject type",
|
||||
token: validToken,
|
||||
authRequest: &grpcAuthV1.AuthZReq{
|
||||
PolicyReq: &grpcAuthV1.PolicyReq{
|
||||
Subject: id,
|
||||
SubjectType: "",
|
||||
Object: authoritiesObj,
|
||||
ObjectType: usersType,
|
||||
Relation: memberRelation,
|
||||
Permission: adminPermission,
|
||||
},
|
||||
},
|
||||
authResponse: &grpcAuthV1.AuthZRes{Authorized: false},
|
||||
err: apiutil.ErrMissingPolicySub,
|
||||
},
|
||||
{
|
||||
desc: "authorize user with empty object",
|
||||
token: validToken,
|
||||
authRequest: &grpcAuthV1.AuthZReq{
|
||||
PolicyReq: &grpcAuthV1.PolicyReq{
|
||||
Subject: id,
|
||||
SubjectType: usersType,
|
||||
Object: "",
|
||||
ObjectType: usersType,
|
||||
Relation: memberRelation,
|
||||
Permission: adminPermission,
|
||||
},
|
||||
},
|
||||
authResponse: &grpcAuthV1.AuthZRes{Authorized: false},
|
||||
err: apiutil.ErrMissingPolicyObj,
|
||||
},
|
||||
{
|
||||
desc: "authorize user with empty object type",
|
||||
token: validToken,
|
||||
authRequest: &grpcAuthV1.AuthZReq{
|
||||
PolicyReq: &grpcAuthV1.PolicyReq{
|
||||
Subject: id,
|
||||
SubjectType: usersType,
|
||||
Object: authoritiesObj,
|
||||
ObjectType: "",
|
||||
Relation: memberRelation,
|
||||
Permission: adminPermission,
|
||||
},
|
||||
},
|
||||
authResponse: &grpcAuthV1.AuthZRes{Authorized: false},
|
||||
err: apiutil.ErrMissingPolicyObj,
|
||||
},
|
||||
{
|
||||
desc: "authorize user with empty permission",
|
||||
token: validToken,
|
||||
authRequest: &grpcAuthV1.AuthZReq{
|
||||
PolicyReq: &grpcAuthV1.PolicyReq{
|
||||
Subject: id,
|
||||
SubjectType: usersType,
|
||||
Object: authoritiesObj,
|
||||
ObjectType: usersType,
|
||||
Relation: memberRelation,
|
||||
Permission: "",
|
||||
},
|
||||
},
|
||||
authResponse: &grpcAuthV1.AuthZRes{Authorized: false},
|
||||
err: apiutil.ErrMalformedPolicyPer,
|
||||
},
|
||||
{
|
||||
desc: "authorize user with valid PAT token",
|
||||
token: validPATToken,
|
||||
authRequest: &grpcAuthV1.AuthZReq{
|
||||
PolicyReq: &grpcAuthV1.PolicyReq{
|
||||
Subject: id,
|
||||
SubjectType: policies.UserType,
|
||||
SubjectKind: policies.UsersKind,
|
||||
Permission: policies.ViewPermission,
|
||||
ObjectType: policies.ClientType,
|
||||
Domain: domainID,
|
||||
Object: clientID,
|
||||
},
|
||||
PatReq: &grpcAuthV1.PATReq{
|
||||
PatId: id,
|
||||
Domain: domainID,
|
||||
Operation: "view",
|
||||
UserId: id,
|
||||
EntityId: clientID,
|
||||
EntityType: auth.ClientsScopeStr,
|
||||
},
|
||||
},
|
||||
authResponse: &grpcAuthV1.AuthZRes{Authorized: true},
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "authorize user with unauthorized PAT token",
|
||||
token: inValidToken,
|
||||
authRequest: &grpcAuthV1.AuthZReq{
|
||||
PolicyReq: &grpcAuthV1.PolicyReq{
|
||||
Subject: id,
|
||||
SubjectType: policies.UserType,
|
||||
SubjectKind: policies.UsersKind,
|
||||
Permission: policies.ViewPermission,
|
||||
ObjectType: policies.ClientType,
|
||||
Domain: domainID,
|
||||
Object: clientID,
|
||||
},
|
||||
PatReq: &grpcAuthV1.PATReq{
|
||||
PatId: id,
|
||||
Domain: domainID,
|
||||
Operation: "view",
|
||||
UserId: id,
|
||||
EntityId: clientID,
|
||||
EntityType: auth.ClientsScopeStr,
|
||||
},
|
||||
},
|
||||
authResponse: &grpcAuthV1.AuthZRes{Authorized: false},
|
||||
err: svcerr.ErrAuthorization,
|
||||
},
|
||||
{
|
||||
desc: "authorize PAT with missing user id",
|
||||
token: validPATToken,
|
||||
authRequest: &grpcAuthV1.AuthZReq{
|
||||
PolicyReq: &grpcAuthV1.PolicyReq{
|
||||
Subject: id,
|
||||
SubjectType: policies.UserType,
|
||||
SubjectKind: policies.UsersKind,
|
||||
Permission: policies.ViewPermission,
|
||||
ObjectType: policies.ClientType,
|
||||
Domain: domainID,
|
||||
Object: clientID,
|
||||
},
|
||||
PatReq: &grpcAuthV1.PATReq{
|
||||
PatId: id,
|
||||
Domain: domainID,
|
||||
Operation: "view",
|
||||
EntityId: clientID,
|
||||
EntityType: auth.ClientsScopeStr,
|
||||
},
|
||||
},
|
||||
authResponse: &grpcAuthV1.AuthZRes{Authorized: false},
|
||||
err: apiutil.ErrMissingUserID,
|
||||
},
|
||||
{
|
||||
desc: "authorize PAT with missing entity id",
|
||||
token: validPATToken,
|
||||
authRequest: &grpcAuthV1.AuthZReq{
|
||||
PolicyReq: &grpcAuthV1.PolicyReq{
|
||||
Subject: id,
|
||||
SubjectType: policies.UserType,
|
||||
SubjectKind: policies.UsersKind,
|
||||
Permission: policies.ViewPermission,
|
||||
ObjectType: policies.ClientType,
|
||||
Domain: domainID,
|
||||
Object: clientID,
|
||||
},
|
||||
PatReq: &grpcAuthV1.PATReq{
|
||||
PatId: id,
|
||||
Domain: domainID,
|
||||
Operation: "view",
|
||||
UserId: id,
|
||||
EntityType: auth.ClientsScopeStr,
|
||||
},
|
||||
},
|
||||
authResponse: &grpcAuthV1.AuthZRes{Authorized: false},
|
||||
err: apiutil.ErrMissingID,
|
||||
},
|
||||
}
|
||||
for _, tc := range cases {
|
||||
t.Run(tc.desc, func(t *testing.T) {
|
||||
svcCall := svc.On("Authorize", mock.Anything, mock.Anything, mock.Anything).Return(tc.err)
|
||||
ar, err := grpcClient.Authorize(context.Background(), tc.authRequest)
|
||||
if ar != nil {
|
||||
assert.Equal(t, tc.authResponse, ar, fmt.Sprintf("%s: expected %v got %v", tc.desc, tc.authResponse, ar))
|
||||
}
|
||||
assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err))
|
||||
svcCall.Unset()
|
||||
})
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,7 @@
|
||||
package auth
|
||||
|
||||
import (
|
||||
apiutil "github.com/absmach/supermq/api/http/util"
|
||||
apiutil "github.com/absmach/magistrala/api/http/util"
|
||||
)
|
||||
|
||||
type authenticateReq struct {
|
||||
|
||||
@@ -3,13 +3,14 @@
|
||||
|
||||
package auth
|
||||
|
||||
import smqauth "github.com/absmach/supermq/auth"
|
||||
import "github.com/absmach/magistrala/auth"
|
||||
|
||||
type authenticateRes struct {
|
||||
id string
|
||||
userID string
|
||||
userRole smqauth.Role
|
||||
verified bool
|
||||
id string
|
||||
userID string
|
||||
userRole auth.Role
|
||||
verified bool
|
||||
tokenType auth.KeyType
|
||||
}
|
||||
|
||||
type authorizeRes struct {
|
||||
|
||||
@@ -6,9 +6,9 @@ package auth
|
||||
import (
|
||||
"context"
|
||||
|
||||
grpcAuthV1 "github.com/absmach/supermq/api/grpc/auth/v1"
|
||||
"github.com/absmach/supermq/auth"
|
||||
grpcapi "github.com/absmach/supermq/auth/api/grpc"
|
||||
grpcAuthV1 "github.com/absmach/magistrala/api/grpc/auth/v1"
|
||||
"github.com/absmach/magistrala/auth"
|
||||
grpcapi "github.com/absmach/magistrala/auth/api/grpc"
|
||||
kitgrpc "github.com/go-kit/kit/transport/grpc"
|
||||
)
|
||||
|
||||
@@ -60,7 +60,7 @@ func decodeAuthenticateRequest(_ context.Context, grpcReq any) (any, error) {
|
||||
|
||||
func encodeAuthenticateResponse(_ context.Context, grpcRes any) (any, error) {
|
||||
res := grpcRes.(authenticateRes)
|
||||
return &grpcAuthV1.AuthNRes{Id: res.id, UserId: res.userID, UserRole: uint32(res.userRole), Verified: res.verified}, nil
|
||||
return &grpcAuthV1.AuthNRes{Id: res.id, UserId: res.userID, UserRole: uint32(res.userRole), Verified: res.verified, TokenType: uint32(res.tokenType)}, nil
|
||||
}
|
||||
|
||||
func decodeAuthorizeRequest(_ context.Context, grpcReq any) (any, error) {
|
||||
@@ -88,6 +88,9 @@ func decodeAuthorizeRequest(_ context.Context, grpcReq any) (any, error) {
|
||||
}
|
||||
|
||||
if patReq != nil {
|
||||
if patReq.GetDomain() != "" {
|
||||
authRequest.Domain = patReq.GetDomain()
|
||||
}
|
||||
authRequest.UserID = patReq.GetUserId()
|
||||
authRequest.PatID = patReq.GetPatId()
|
||||
authRequest.EntityType = patReq.GetEntityType()
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
// Copyright (c) Abstract Machines
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package auth_test
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/absmach/supermq/auth/mocks"
|
||||
)
|
||||
|
||||
var svc *mocks.Service
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
svc = new(mocks.Service)
|
||||
server := startGRPCServer(svc, port)
|
||||
|
||||
code := m.Run()
|
||||
|
||||
server.GracefulStop()
|
||||
|
||||
os.Exit(code)
|
||||
}
|
||||
@@ -7,9 +7,9 @@ import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
grpcTokenV1 "github.com/absmach/supermq/api/grpc/token/v1"
|
||||
"github.com/absmach/supermq/auth"
|
||||
grpcapi "github.com/absmach/supermq/auth/api/grpc"
|
||||
grpcTokenV1 "github.com/absmach/magistrala/api/grpc/token/v1"
|
||||
"github.com/absmach/magistrala/auth"
|
||||
grpcapi "github.com/absmach/magistrala/auth/api/grpc"
|
||||
"github.com/go-kit/kit/endpoint"
|
||||
kitgrpc "github.com/go-kit/kit/transport/grpc"
|
||||
"google.golang.org/grpc"
|
||||
|
||||
@@ -6,7 +6,7 @@ package token
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/absmach/supermq/auth"
|
||||
"github.com/absmach/magistrala/auth"
|
||||
"github.com/go-kit/kit/endpoint"
|
||||
)
|
||||
|
||||
|
||||
@@ -1,245 +0,0 @@
|
||||
// Copyright (c) Abstract Machines
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package token_test
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"net"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
grpcTokenV1 "github.com/absmach/supermq/api/grpc/token/v1"
|
||||
apiutil "github.com/absmach/supermq/api/http/util"
|
||||
"github.com/absmach/supermq/auth"
|
||||
grpcapi "github.com/absmach/supermq/auth/api/grpc/token"
|
||||
"github.com/absmach/supermq/internal/testsutil"
|
||||
"github.com/absmach/supermq/pkg/errors"
|
||||
svcerr "github.com/absmach/supermq/pkg/errors/service"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/mock"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/credentials/insecure"
|
||||
)
|
||||
|
||||
const (
|
||||
port = 8082
|
||||
validToken = "valid"
|
||||
inValidToken = "invalid"
|
||||
invalidID = "invalid"
|
||||
)
|
||||
|
||||
var (
|
||||
validID = testsutil.GenerateUUID(&testing.T{})
|
||||
authAddr = fmt.Sprintf("localhost:%d", port)
|
||||
)
|
||||
|
||||
func startGRPCServer(svc auth.Service, port int) *grpc.Server {
|
||||
listener, _ := net.Listen("tcp", fmt.Sprintf(":%d", port))
|
||||
server := grpc.NewServer()
|
||||
grpcTokenV1.RegisterTokenServiceServer(server, grpcapi.NewTokenServer(svc))
|
||||
go func() {
|
||||
err := server.Serve(listener)
|
||||
assert.Nil(&testing.T{}, err, fmt.Sprintf(`"Unexpected error creating auth server %s"`, err))
|
||||
}()
|
||||
|
||||
return server
|
||||
}
|
||||
|
||||
func TestIssue(t *testing.T) {
|
||||
conn, err := grpc.NewClient(authAddr, grpc.WithTransportCredentials(insecure.NewCredentials()))
|
||||
assert.Nil(t, err, fmt.Sprintf("Unexpected error creating client connection %s", err))
|
||||
grpcClient := grpcapi.NewTokenClient(conn, time.Second)
|
||||
defer conn.Close()
|
||||
|
||||
cases := []struct {
|
||||
desc string
|
||||
userId string
|
||||
kind auth.KeyType
|
||||
issueResponse auth.Token
|
||||
err error
|
||||
}{
|
||||
{
|
||||
desc: "issue for user with valid token",
|
||||
userId: validID,
|
||||
kind: auth.AccessKey,
|
||||
issueResponse: auth.Token{
|
||||
AccessToken: validToken,
|
||||
RefreshToken: validToken,
|
||||
},
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "issue recovery key",
|
||||
userId: validID,
|
||||
kind: auth.RecoveryKey,
|
||||
issueResponse: auth.Token{
|
||||
AccessToken: validToken,
|
||||
RefreshToken: validToken,
|
||||
},
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "issue API key unauthenticated",
|
||||
userId: validID,
|
||||
kind: auth.APIKey,
|
||||
issueResponse: auth.Token{},
|
||||
err: svcerr.ErrAuthentication,
|
||||
},
|
||||
{
|
||||
desc: "issue for invalid key type",
|
||||
userId: validID,
|
||||
kind: 32,
|
||||
issueResponse: auth.Token{},
|
||||
err: errors.ErrMalformedEntity,
|
||||
},
|
||||
{
|
||||
desc: "issue for user that does notexist",
|
||||
userId: "",
|
||||
kind: auth.APIKey,
|
||||
issueResponse: auth.Token{},
|
||||
err: svcerr.ErrAuthentication,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
svcCall := svc.On("Issue", mock.Anything, mock.Anything, mock.Anything, mock.Anything).Return(tc.issueResponse, tc.err)
|
||||
_, err := grpcClient.Issue(context.Background(), &grpcTokenV1.IssueReq{UserId: tc.userId, Type: uint32(tc.kind)})
|
||||
assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err))
|
||||
svcCall.Unset()
|
||||
}
|
||||
}
|
||||
|
||||
func TestRefresh(t *testing.T) {
|
||||
conn, err := grpc.NewClient(authAddr, grpc.WithTransportCredentials(insecure.NewCredentials()))
|
||||
assert.Nil(t, err, fmt.Sprintf("Unexpected error creating client connection %s", err))
|
||||
grpcClient := grpcapi.NewTokenClient(conn, time.Second)
|
||||
defer conn.Close()
|
||||
|
||||
cases := []struct {
|
||||
desc string
|
||||
token string
|
||||
issueResponse auth.Token
|
||||
err error
|
||||
}{
|
||||
{
|
||||
desc: "refresh token with valid token",
|
||||
token: validToken,
|
||||
issueResponse: auth.Token{
|
||||
AccessToken: validToken,
|
||||
RefreshToken: validToken,
|
||||
},
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "refresh token with invalid token",
|
||||
token: inValidToken,
|
||||
issueResponse: auth.Token{},
|
||||
err: svcerr.ErrAuthentication,
|
||||
},
|
||||
{
|
||||
desc: "refresh token with empty token",
|
||||
token: "",
|
||||
issueResponse: auth.Token{},
|
||||
err: apiutil.ErrMissingSecret,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
svcCall := svc.On("Issue", mock.Anything, mock.Anything, mock.Anything).Return(tc.issueResponse, tc.err)
|
||||
_, err := grpcClient.Refresh(context.Background(), &grpcTokenV1.RefreshReq{RefreshToken: tc.token})
|
||||
assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err))
|
||||
svcCall.Unset()
|
||||
}
|
||||
}
|
||||
|
||||
func TestRevoke(t *testing.T) {
|
||||
conn, err := grpc.NewClient(authAddr, grpc.WithTransportCredentials(insecure.NewCredentials()))
|
||||
assert.Nil(t, err, fmt.Sprintf("Unexpected error creating client connection %s", err))
|
||||
grpcClient := grpcapi.NewTokenClient(conn, time.Second)
|
||||
defer conn.Close()
|
||||
|
||||
cases := []struct {
|
||||
desc string
|
||||
id string
|
||||
err error
|
||||
}{
|
||||
{
|
||||
desc: "revoke token with valid id",
|
||||
id: validID,
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "revoke token with invalid id",
|
||||
id: invalidID,
|
||||
err: svcerr.ErrAuthentication,
|
||||
},
|
||||
{
|
||||
desc: "revoke token with empty id",
|
||||
id: "",
|
||||
err: apiutil.ErrMissingID,
|
||||
},
|
||||
{
|
||||
desc: "revoke already revoked token",
|
||||
id: validID,
|
||||
err: svcerr.ErrConflict,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
svcCall := svc.On("RevokeToken", mock.Anything, mock.Anything, tc.id).Return(tc.err)
|
||||
_, err := grpcClient.Revoke(context.Background(), &grpcTokenV1.RevokeReq{TokenId: tc.id})
|
||||
assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err))
|
||||
svcCall.Unset()
|
||||
}
|
||||
}
|
||||
|
||||
func TestListUserRefreshTokens(t *testing.T) {
|
||||
conn, err := grpc.NewClient(authAddr, grpc.WithTransportCredentials(insecure.NewCredentials()))
|
||||
assert.Nil(t, err, fmt.Sprintf("Unexpected error creating client connection %s", err))
|
||||
grpcClient := grpcapi.NewTokenClient(conn, time.Second)
|
||||
defer conn.Close()
|
||||
|
||||
cases := []struct {
|
||||
desc string
|
||||
userID string
|
||||
listResponse []auth.TokenInfo
|
||||
err error
|
||||
}{
|
||||
{
|
||||
desc: "list tokens for user with valid id",
|
||||
userID: validID,
|
||||
listResponse: []auth.TokenInfo{
|
||||
{ID: testsutil.GenerateUUID(&testing.T{}), Description: "Token 1"},
|
||||
{ID: testsutil.GenerateUUID(&testing.T{}), Description: "Token 2"},
|
||||
},
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "list tokens for user with empty list",
|
||||
userID: validID,
|
||||
listResponse: []auth.TokenInfo{},
|
||||
err: nil,
|
||||
},
|
||||
{
|
||||
desc: "list tokens with invalid user id",
|
||||
userID: invalidID,
|
||||
listResponse: nil,
|
||||
err: svcerr.ErrAuthentication,
|
||||
},
|
||||
{
|
||||
desc: "list tokens with empty user id",
|
||||
userID: "",
|
||||
listResponse: nil,
|
||||
err: apiutil.ErrMissingID,
|
||||
},
|
||||
}
|
||||
|
||||
for _, tc := range cases {
|
||||
svcCall := svc.On("ListUserRefreshTokens", mock.Anything, tc.userID).Return(tc.listResponse, tc.err)
|
||||
_, err := grpcClient.ListUserRefreshTokens(context.Background(), &grpcTokenV1.ListUserRefreshTokensReq{UserId: tc.userID})
|
||||
assert.True(t, errors.Contains(err, tc.err), fmt.Sprintf("%s: expected %s got %s\n", tc.desc, tc.err, err))
|
||||
svcCall.Unset()
|
||||
}
|
||||
}
|
||||
@@ -4,8 +4,8 @@
|
||||
package token
|
||||
|
||||
import (
|
||||
apiutil "github.com/absmach/supermq/api/http/util"
|
||||
"github.com/absmach/supermq/auth"
|
||||
apiutil "github.com/absmach/magistrala/api/http/util"
|
||||
"github.com/absmach/magistrala/auth"
|
||||
)
|
||||
|
||||
type issueReq struct {
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
package token
|
||||
|
||||
import "github.com/absmach/supermq/auth"
|
||||
import "github.com/absmach/magistrala/auth"
|
||||
|
||||
type issueRes struct {
|
||||
accessToken string
|
||||
|
||||
@@ -6,9 +6,9 @@ package token
|
||||
import (
|
||||
"context"
|
||||
|
||||
grpcTokenV1 "github.com/absmach/supermq/api/grpc/token/v1"
|
||||
"github.com/absmach/supermq/auth"
|
||||
grpcapi "github.com/absmach/supermq/auth/api/grpc"
|
||||
grpcTokenV1 "github.com/absmach/magistrala/api/grpc/token/v1"
|
||||
"github.com/absmach/magistrala/auth"
|
||||
grpcapi "github.com/absmach/magistrala/auth/api/grpc"
|
||||
kitgrpc "github.com/go-kit/kit/transport/grpc"
|
||||
)
|
||||
|
||||
|
||||
@@ -1,24 +0,0 @@
|
||||
// Copyright (c) Abstract Machines
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
package token_test
|
||||
|
||||
import (
|
||||
"os"
|
||||
"testing"
|
||||
|
||||
"github.com/absmach/supermq/auth/mocks"
|
||||
)
|
||||
|
||||
var svc *mocks.Service
|
||||
|
||||
func TestMain(m *testing.M) {
|
||||
svc = new(mocks.Service)
|
||||
server := startGRPCServer(svc, port)
|
||||
|
||||
code := m.Run()
|
||||
|
||||
server.GracefulStop()
|
||||
|
||||
os.Exit(code)
|
||||
}
|
||||
@@ -6,10 +6,10 @@ package grpc
|
||||
import (
|
||||
"fmt"
|
||||
|
||||
apiutil "github.com/absmach/supermq/api/http/util"
|
||||
"github.com/absmach/supermq/auth"
|
||||
"github.com/absmach/supermq/pkg/errors"
|
||||
svcerr "github.com/absmach/supermq/pkg/errors/service"
|
||||
apiutil "github.com/absmach/magistrala/api/http/util"
|
||||
"github.com/absmach/magistrala/auth"
|
||||
"github.com/absmach/magistrala/pkg/errors"
|
||||
svcerr "github.com/absmach/magistrala/pkg/errors/service"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
)
|
||||
@@ -31,6 +31,7 @@ func EncodeError(err error) error {
|
||||
return status.Error(codes.InvalidArgument, err.Error())
|
||||
case errors.Contains(err, svcerr.ErrAuthentication),
|
||||
errors.Contains(err, auth.ErrKeyExpired),
|
||||
errors.Contains(err, auth.ErrRevokedToken),
|
||||
err == apiutil.ErrMissingEmail,
|
||||
err == apiutil.ErrBearerToken:
|
||||
return status.Error(codes.Unauthenticated, err.Error())
|
||||
|
||||
@@ -7,7 +7,7 @@ import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/absmach/supermq/auth"
|
||||
"github.com/absmach/magistrala/auth"
|
||||
"github.com/go-kit/kit/endpoint"
|
||||
)
|
||||
|
||||
|
||||
@@ -13,12 +13,12 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
apiutil "github.com/absmach/supermq/api/http/util"
|
||||
"github.com/absmach/supermq/auth"
|
||||
httpapi "github.com/absmach/supermq/auth/api/http"
|
||||
"github.com/absmach/supermq/auth/mocks"
|
||||
smqlog "github.com/absmach/supermq/logger"
|
||||
svcerr "github.com/absmach/supermq/pkg/errors/service"
|
||||
apiutil "github.com/absmach/magistrala/api/http/util"
|
||||
"github.com/absmach/magistrala/auth"
|
||||
httpapi "github.com/absmach/magistrala/auth/api/http"
|
||||
"github.com/absmach/magistrala/auth/mocks"
|
||||
mglog "github.com/absmach/magistrala/logger"
|
||||
svcerr "github.com/absmach/magistrala/pkg/errors/service"
|
||||
"github.com/stretchr/testify/assert"
|
||||
"github.com/stretchr/testify/mock"
|
||||
)
|
||||
@@ -66,7 +66,7 @@ func (tr testRequest) make() (*http.Response, error) {
|
||||
|
||||
func newServer() (*httptest.Server, *mocks.Service) {
|
||||
svc := new(mocks.Service)
|
||||
mux := httpapi.MakeHandler(svc, smqlog.NewMock(), "", 900, 60)
|
||||
mux := httpapi.MakeHandler(svc, mglog.NewMock(), "", 900, 60)
|
||||
|
||||
return httptest.NewServer(mux), svc
|
||||
}
|
||||
|
||||
@@ -6,8 +6,8 @@ package keys
|
||||
import (
|
||||
"time"
|
||||
|
||||
apiutil "github.com/absmach/supermq/api/http/util"
|
||||
"github.com/absmach/supermq/auth"
|
||||
apiutil "github.com/absmach/magistrala/api/http/util"
|
||||
"github.com/absmach/magistrala/auth"
|
||||
)
|
||||
|
||||
type issueKeyReq struct {
|
||||
|
||||
@@ -6,8 +6,8 @@ package keys
|
||||
import (
|
||||
"testing"
|
||||
|
||||
apiutil "github.com/absmach/supermq/api/http/util"
|
||||
"github.com/absmach/supermq/auth"
|
||||
apiutil "github.com/absmach/magistrala/api/http/util"
|
||||
"github.com/absmach/magistrala/auth"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
|
||||
@@ -9,15 +9,15 @@ import (
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/absmach/supermq"
|
||||
"github.com/absmach/supermq/auth"
|
||||
"github.com/absmach/magistrala"
|
||||
"github.com/absmach/magistrala/auth"
|
||||
)
|
||||
|
||||
var (
|
||||
_ supermq.Response = (*issueKeyRes)(nil)
|
||||
_ supermq.Response = (*revokeKeyRes)(nil)
|
||||
_ supermq.Response = (*retrieveKeyRes)(nil)
|
||||
_ supermq.Response = (*retrieveJWKSRes)(nil)
|
||||
_ magistrala.Response = (*issueKeyRes)(nil)
|
||||
_ magistrala.Response = (*revokeKeyRes)(nil)
|
||||
_ magistrala.Response = (*retrieveKeyRes)(nil)
|
||||
_ magistrala.Response = (*retrieveJWKSRes)(nil)
|
||||
)
|
||||
|
||||
type issueKeyRes struct {
|
||||
|
||||
@@ -10,10 +10,10 @@ import (
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
api "github.com/absmach/supermq/api/http"
|
||||
apiutil "github.com/absmach/supermq/api/http/util"
|
||||
"github.com/absmach/supermq/auth"
|
||||
"github.com/absmach/supermq/pkg/errors"
|
||||
api "github.com/absmach/magistrala/api/http"
|
||||
apiutil "github.com/absmach/magistrala/api/http/util"
|
||||
"github.com/absmach/magistrala/auth"
|
||||
"github.com/absmach/magistrala/pkg/errors"
|
||||
"github.com/go-chi/chi/v5"
|
||||
kithttp "github.com/go-kit/kit/transport/http"
|
||||
)
|
||||
|
||||
@@ -6,7 +6,7 @@ package pats
|
||||
import (
|
||||
"context"
|
||||
|
||||
"github.com/absmach/supermq/auth"
|
||||
"github.com/absmach/magistrala/auth"
|
||||
"github.com/go-kit/kit/endpoint"
|
||||
)
|
||||
|
||||
|
||||
@@ -8,9 +8,9 @@ import (
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
apiutil "github.com/absmach/supermq/api/http/util"
|
||||
"github.com/absmach/supermq/auth"
|
||||
"github.com/absmach/supermq/pkg/errors"
|
||||
apiutil "github.com/absmach/magistrala/api/http/util"
|
||||
"github.com/absmach/magistrala/auth"
|
||||
"github.com/absmach/magistrala/pkg/errors"
|
||||
)
|
||||
|
||||
type createPatReq struct {
|
||||
|
||||
@@ -8,8 +8,8 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
apiutil "github.com/absmach/supermq/api/http/util"
|
||||
"github.com/absmach/supermq/auth"
|
||||
apiutil "github.com/absmach/magistrala/api/http/util"
|
||||
"github.com/absmach/magistrala/auth"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
|
||||
@@ -6,20 +6,20 @@ package pats
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/absmach/supermq"
|
||||
"github.com/absmach/supermq/auth"
|
||||
"github.com/absmach/magistrala"
|
||||
"github.com/absmach/magistrala/auth"
|
||||
)
|
||||
|
||||
var (
|
||||
_ supermq.Response = (*createPatRes)(nil)
|
||||
_ supermq.Response = (*retrievePatRes)(nil)
|
||||
_ supermq.Response = (*updatePatNameRes)(nil)
|
||||
_ supermq.Response = (*updatePatDescriptionRes)(nil)
|
||||
_ supermq.Response = (*deletePatRes)(nil)
|
||||
_ supermq.Response = (*resetPatSecretRes)(nil)
|
||||
_ supermq.Response = (*revokePatSecretRes)(nil)
|
||||
_ supermq.Response = (*scopeRes)(nil)
|
||||
_ supermq.Response = (*clearAllRes)(nil)
|
||||
_ magistrala.Response = (*createPatRes)(nil)
|
||||
_ magistrala.Response = (*retrievePatRes)(nil)
|
||||
_ magistrala.Response = (*updatePatNameRes)(nil)
|
||||
_ magistrala.Response = (*updatePatDescriptionRes)(nil)
|
||||
_ magistrala.Response = (*deletePatRes)(nil)
|
||||
_ magistrala.Response = (*resetPatSecretRes)(nil)
|
||||
_ magistrala.Response = (*revokePatSecretRes)(nil)
|
||||
_ magistrala.Response = (*scopeRes)(nil)
|
||||
_ magistrala.Response = (*clearAllRes)(nil)
|
||||
)
|
||||
|
||||
type createPatRes struct {
|
||||
|
||||
@@ -10,10 +10,10 @@ import (
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
api "github.com/absmach/supermq/api/http"
|
||||
apiutil "github.com/absmach/supermq/api/http/util"
|
||||
"github.com/absmach/supermq/auth"
|
||||
"github.com/absmach/supermq/pkg/errors"
|
||||
api "github.com/absmach/magistrala/api/http"
|
||||
apiutil "github.com/absmach/magistrala/api/http/util"
|
||||
"github.com/absmach/magistrala/auth"
|
||||
"github.com/absmach/magistrala/pkg/errors"
|
||||
"github.com/go-chi/chi/v5"
|
||||
kithttp "github.com/go-kit/kit/transport/http"
|
||||
)
|
||||
|
||||
@@ -6,10 +6,10 @@ import (
|
||||
"log/slog"
|
||||
"net/http"
|
||||
|
||||
"github.com/absmach/supermq"
|
||||
"github.com/absmach/supermq/auth"
|
||||
"github.com/absmach/supermq/auth/api/http/keys"
|
||||
"github.com/absmach/supermq/auth/api/http/pats"
|
||||
"github.com/absmach/magistrala"
|
||||
"github.com/absmach/magistrala/auth"
|
||||
"github.com/absmach/magistrala/auth/api/http/keys"
|
||||
"github.com/absmach/magistrala/auth/api/http/pats"
|
||||
"github.com/go-chi/chi/v5"
|
||||
"github.com/prometheus/client_golang/prometheus/promhttp"
|
||||
)
|
||||
@@ -21,7 +21,7 @@ func MakeHandler(svc auth.Service, logger *slog.Logger, instanceID string, jwksC
|
||||
mux = keys.MakeHandler(svc, mux, logger, jwksCacheMaxAge, jwksCacheStaleWhileRevalidate)
|
||||
mux = pats.MakeHandler(svc, mux, logger)
|
||||
|
||||
mux.Get("/health", supermq.Health("auth", instanceID))
|
||||
mux.Get("/health", magistrala.Health("auth", instanceID))
|
||||
mux.Handle("/metrics", promhttp.Handler())
|
||||
|
||||
return mux
|
||||
|
||||
Vendored
+1
-1
@@ -2,5 +2,5 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Package cache contains the domain concept definitions needed to
|
||||
// support SuperMQ auth cache service functionality.
|
||||
// support Magistrala auth cache service functionality.
|
||||
package cache
|
||||
|
||||
Vendored
+3
-3
@@ -8,9 +8,9 @@ import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/absmach/supermq/auth"
|
||||
"github.com/absmach/supermq/pkg/errors"
|
||||
repoerr "github.com/absmach/supermq/pkg/errors/repository"
|
||||
"github.com/absmach/magistrala/auth"
|
||||
"github.com/absmach/magistrala/pkg/errors"
|
||||
repoerr "github.com/absmach/magistrala/pkg/errors/repository"
|
||||
"github.com/redis/go-redis/v9"
|
||||
)
|
||||
|
||||
|
||||
Vendored
+6
-14
@@ -8,8 +8,7 @@ import (
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"github.com/absmach/supermq/auth"
|
||||
"github.com/absmach/supermq/pkg/errors"
|
||||
"github.com/absmach/magistrala/auth"
|
||||
"github.com/redis/go-redis/v9"
|
||||
)
|
||||
|
||||
@@ -22,30 +21,23 @@ const (
|
||||
var _ auth.UserActiveTokensCache = (*tokensCache)(nil)
|
||||
|
||||
type tokensCache struct {
|
||||
client *redis.Client
|
||||
keyDuration time.Duration
|
||||
client *redis.Client
|
||||
}
|
||||
|
||||
// NewUserActiveTokensCache returns redis auth cache implementation.
|
||||
func NewUserActiveTokensCache(client *redis.Client, duration time.Duration) (auth.UserActiveTokensCache, error) {
|
||||
if duration == 0 {
|
||||
return nil, errors.New("token cache duration must not be zero")
|
||||
}
|
||||
return &tokensCache{
|
||||
client: client,
|
||||
keyDuration: duration,
|
||||
}, nil
|
||||
func NewUserActiveTokensCache(client *redis.Client) (auth.UserActiveTokensCache, error) {
|
||||
return &tokensCache{client: client}, nil
|
||||
}
|
||||
|
||||
// SaveActive saves an active refresh token ID for a user with optional description.
|
||||
func (tc *tokensCache) SaveActive(ctx context.Context, userID, tokenID, description string, expiry time.Time) error {
|
||||
ttl := min(tc.keyDuration, time.Until(expiry))
|
||||
ttl := time.Until(expiry)
|
||||
|
||||
pipe := tc.client.TxPipeline()
|
||||
|
||||
pipe.Set(ctx, tokenKey(tokenID), description, ttl)
|
||||
pipe.ZAdd(ctx, userTokensKey(userID), redis.Z{
|
||||
Score: float64(time.Now().Add(ttl).Unix()),
|
||||
Score: float64(expiry.Unix()),
|
||||
Member: tokenID,
|
||||
})
|
||||
|
||||
|
||||
Vendored
+5
-5
@@ -10,10 +10,10 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/absmach/supermq/auth"
|
||||
"github.com/absmach/supermq/auth/cache"
|
||||
"github.com/absmach/supermq/internal/testsutil"
|
||||
"github.com/absmach/supermq/pkg/errors"
|
||||
"github.com/absmach/magistrala/auth"
|
||||
"github.com/absmach/magistrala/auth/cache"
|
||||
"github.com/absmach/magistrala/pkg/errors"
|
||||
"github.com/absmach/magistrala/pkg/testsutil"
|
||||
"github.com/redis/go-redis/v9"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
@@ -29,7 +29,7 @@ func TestMain(m *testing.M) {
|
||||
}
|
||||
|
||||
func setupRedisTokensClient() auth.UserActiveTokensCache {
|
||||
tc, err := cache.NewUserActiveTokensCache(storeClient, 10*time.Minute)
|
||||
tc, err := cache.NewUserActiveTokensCache(storeClient)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
+1
-1
@@ -2,5 +2,5 @@
|
||||
// SPDX-License-Identifier: Apache-2.0
|
||||
|
||||
// Package hasher contains the domain concept definitions needed to
|
||||
// support Supermq users password hasher sub-service functionality.
|
||||
// support Magistrala users password hasher sub-service functionality.
|
||||
package hasher
|
||||
|
||||
@@ -9,8 +9,8 @@ import (
|
||||
"fmt"
|
||||
"strings"
|
||||
|
||||
"github.com/absmach/supermq/auth"
|
||||
"github.com/absmach/supermq/pkg/errors"
|
||||
"github.com/absmach/magistrala/auth"
|
||||
"github.com/absmach/magistrala/pkg/errors"
|
||||
"golang.org/x/crypto/scrypt"
|
||||
)
|
||||
|
||||
|
||||
+1
-1
@@ -7,7 +7,7 @@ import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"github.com/absmach/supermq/pkg/errors"
|
||||
"github.com/absmach/magistrala/pkg/errors"
|
||||
)
|
||||
|
||||
var (
|
||||
|
||||
+1
-1
@@ -8,7 +8,7 @@ import (
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/absmach/supermq/auth"
|
||||
"github.com/absmach/magistrala/auth"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user