mirror of
https://github.com/SigNoz/signoz.git
synced 2026-02-24 17:23:19 +00:00
Compare commits
8 Commits
feat/azure
...
SIG_3887
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b117ee77d4 | ||
|
|
f0a34dd460 | ||
|
|
0b91018bf8 | ||
|
|
e8ed22cafb | ||
|
|
4658232025 | ||
|
|
e8add5942e | ||
|
|
ddecf05d9f | ||
|
|
bf13b26a37 |
@@ -41,31 +41,23 @@ services:
|
||||
interval: 30s
|
||||
timeout: 5s
|
||||
retries: 3
|
||||
schema-migrator-sync:
|
||||
image: signoz/signoz-schema-migrator:v0.142.0
|
||||
container_name: schema-migrator-sync
|
||||
telemetrystore-migrator:
|
||||
image: signoz/signoz-otel-collector:v0.142.0
|
||||
container_name: telemetrystore-migrator
|
||||
environment:
|
||||
- SIGNOZ_OTEL_COLLECTOR_CLICKHOUSE_DSN=tcp://clickhouse:9000
|
||||
- SIGNOZ_OTEL_COLLECTOR_CLICKHOUSE_CLUSTER=cluster
|
||||
- SIGNOZ_OTEL_COLLECTOR_CLICKHOUSE_REPLICATION=true
|
||||
- SIGNOZ_OTEL_COLLECTOR_TIMEOUT=10m
|
||||
entrypoint:
|
||||
- /bin/sh
|
||||
command:
|
||||
- sync
|
||||
- --cluster-name=cluster
|
||||
- --dsn=tcp://clickhouse:9000
|
||||
- --replication=true
|
||||
- --up=
|
||||
- -c
|
||||
- |
|
||||
/signoz-otel-collector migrate bootstrap &&
|
||||
/signoz-otel-collector migrate sync up &&
|
||||
/signoz-otel-collector migrate async up
|
||||
depends_on:
|
||||
clickhouse:
|
||||
condition: service_healthy
|
||||
restart: on-failure
|
||||
schema-migrator-async:
|
||||
image: signoz/signoz-schema-migrator:v0.142.0
|
||||
container_name: schema-migrator-async
|
||||
command:
|
||||
- async
|
||||
- --cluster-name=cluster
|
||||
- --dsn=tcp://clickhouse:9000
|
||||
- --replication=true
|
||||
- --up=
|
||||
depends_on:
|
||||
clickhouse:
|
||||
condition: service_healthy
|
||||
schema-migrator-sync:
|
||||
condition: service_completed_successfully
|
||||
restart: on-failure
|
||||
|
||||
@@ -1,14 +1,23 @@
|
||||
services:
|
||||
signoz-otel-collector:
|
||||
image: signoz/signoz-otel-collector:v0.129.6
|
||||
image: signoz/signoz-otel-collector:v0.142.0
|
||||
container_name: signoz-otel-collector-dev
|
||||
entrypoint:
|
||||
- /bin/sh
|
||||
command:
|
||||
- --config=/etc/otel-collector-config.yaml
|
||||
- -c
|
||||
- |
|
||||
/signoz-otel-collector migrate sync check &&
|
||||
/signoz-otel-collector --config=/etc/otel-collector-config.yaml
|
||||
volumes:
|
||||
- ./otel-collector-config.yaml:/etc/otel-collector-config.yaml
|
||||
environment:
|
||||
- OTEL_RESOURCE_ATTRIBUTES=host.name=signoz-host,os.type=linux
|
||||
- LOW_CARDINAL_EXCEPTION_GROUPING=false
|
||||
- SIGNOZ_OTEL_COLLECTOR_CLICKHOUSE_DSN=tcp://clickhouse:9000
|
||||
- SIGNOZ_OTEL_COLLECTOR_CLICKHOUSE_CLUSTER=cluster
|
||||
- SIGNOZ_OTEL_COLLECTOR_CLICKHOUSE_REPLICATION=true
|
||||
- SIGNOZ_OTEL_COLLECTOR_TIMEOUT=10m
|
||||
ports:
|
||||
- "4317:4317" # OTLP gRPC receiver
|
||||
- "4318:4318" # OTLP HTTP receiver
|
||||
|
||||
1
.github/workflows/integrationci.yaml
vendored
1
.github/workflows/integrationci.yaml
vendored
@@ -48,6 +48,7 @@ jobs:
|
||||
- role
|
||||
- ttl
|
||||
- alerts
|
||||
- ingestionkeys
|
||||
sqlstore-provider:
|
||||
- postgres
|
||||
- sqlite
|
||||
|
||||
@@ -318,4 +318,5 @@ user:
|
||||
# The password of the root user. Must meet password requirements.
|
||||
password: ""
|
||||
# The name of the organization to create or look up for the root user.
|
||||
org_name: default
|
||||
org:
|
||||
name: default
|
||||
|
||||
@@ -61,7 +61,6 @@ x-db-depend: &db-depend
|
||||
- clickhouse
|
||||
- clickhouse-2
|
||||
- clickhouse-3
|
||||
- schema-migrator
|
||||
services:
|
||||
init-clickhouse:
|
||||
!!merge <<: *common
|
||||
@@ -136,12 +135,17 @@ services:
|
||||
# - "9000:9000"
|
||||
# - "8123:8123"
|
||||
# - "9181:9181"
|
||||
configs:
|
||||
- source: clickhouse-config
|
||||
target: /etc/clickhouse-server/config.xml
|
||||
- source: clickhouse-users
|
||||
target: /etc/clickhouse-server/users.xml
|
||||
- source: clickhouse-custom-function
|
||||
target: /etc/clickhouse-server/custom-function.xml
|
||||
- source: clickhouse-cluster
|
||||
target: /etc/clickhouse-server/config.d/cluster.ha.xml
|
||||
volumes:
|
||||
- ../common/clickhouse/config.xml:/etc/clickhouse-server/config.xml
|
||||
- ../common/clickhouse/users.xml:/etc/clickhouse-server/users.xml
|
||||
- ../common/clickhouse/custom-function.xml:/etc/clickhouse-server/custom-function.xml
|
||||
- ../common/clickhouse/user_scripts:/var/lib/clickhouse/user_scripts/
|
||||
- ../common/clickhouse/cluster.ha.xml:/etc/clickhouse-server/config.d/cluster.xml
|
||||
- ./clickhouse-setup/data/clickhouse/:/var/lib/clickhouse/
|
||||
# - ../common/clickhouse/storage.xml:/etc/clickhouse-server/config.d/storage.xml
|
||||
clickhouse-2:
|
||||
@@ -151,12 +155,17 @@ services:
|
||||
# - "9001:9000"
|
||||
# - "8124:8123"
|
||||
# - "9182:9181"
|
||||
configs:
|
||||
- source: clickhouse-config
|
||||
target: /etc/clickhouse-server/config.xml
|
||||
- source: clickhouse-users
|
||||
target: /etc/clickhouse-server/users.xml
|
||||
- source: clickhouse-custom-function
|
||||
target: /etc/clickhouse-server/custom-function.xml
|
||||
- source: clickhouse-cluster
|
||||
target: /etc/clickhouse-server/config.d/cluster.ha.xml
|
||||
volumes:
|
||||
- ../common/clickhouse/config.xml:/etc/clickhouse-server/config.xml
|
||||
- ../common/clickhouse/users.xml:/etc/clickhouse-server/users.xml
|
||||
- ../common/clickhouse/custom-function.xml:/etc/clickhouse-server/custom-function.xml
|
||||
- ../common/clickhouse/user_scripts:/var/lib/clickhouse/user_scripts/
|
||||
- ../common/clickhouse/cluster.ha.xml:/etc/clickhouse-server/config.d/cluster.xml
|
||||
- ./clickhouse-setup/data/clickhouse-2/:/var/lib/clickhouse/
|
||||
# - ../common/clickhouse/storage.xml:/etc/clickhouse-server/config.d/storage.xml
|
||||
clickhouse-3:
|
||||
@@ -166,37 +175,32 @@ services:
|
||||
# - "9002:9000"
|
||||
# - "8125:8123"
|
||||
# - "9183:9181"
|
||||
configs:
|
||||
- source: clickhouse-config
|
||||
target: /etc/clickhouse-server/config.xml
|
||||
- source: clickhouse-users
|
||||
target: /etc/clickhouse-server/users.xml
|
||||
- source: clickhouse-custom-function
|
||||
target: /etc/clickhouse-server/custom-function.xml
|
||||
- source: clickhouse-cluster
|
||||
target: /etc/clickhouse-server/config.d/cluster.ha.xml
|
||||
volumes:
|
||||
- ../common/clickhouse/config.xml:/etc/clickhouse-server/config.xml
|
||||
- ../common/clickhouse/users.xml:/etc/clickhouse-server/users.xml
|
||||
- ../common/clickhouse/custom-function.xml:/etc/clickhouse-server/custom-function.xml
|
||||
- ../common/clickhouse/user_scripts:/var/lib/clickhouse/user_scripts/
|
||||
- ../common/clickhouse/cluster.ha.xml:/etc/clickhouse-server/config.d/cluster.xml
|
||||
- ./clickhouse-setup/data/clickhouse-3/:/var/lib/clickhouse/
|
||||
# - ../common/clickhouse/storage.xml:/etc/clickhouse-server/config.d/storage.xml
|
||||
signoz:
|
||||
!!merge <<: *db-depend
|
||||
image: signoz/signoz:v0.112.0
|
||||
command:
|
||||
- --config=/root/config/prometheus.yml
|
||||
image: signoz/signoz:v0.112.1
|
||||
ports:
|
||||
- "8080:8080" # signoz port
|
||||
# - "6060:6060" # pprof port
|
||||
volumes:
|
||||
- ../common/signoz/prometheus.yml:/root/config/prometheus.yml
|
||||
- ../common/dashboards:/root/config/dashboards
|
||||
- ./clickhouse-setup/data/signoz/:/var/lib/signoz/
|
||||
environment:
|
||||
- SIGNOZ_ALERTMANAGER_PROVIDER=signoz
|
||||
- SIGNOZ_TELEMETRYSTORE_CLICKHOUSE_DSN=tcp://clickhouse:9000
|
||||
- SIGNOZ_SQLSTORE_SQLITE_PATH=/var/lib/signoz/signoz.db
|
||||
- DASHBOARDS_PATH=/root/config/dashboards
|
||||
- STORAGE=clickhouse
|
||||
- GODEBUG=netdns=go
|
||||
- TELEMETRY_ENABLED=true
|
||||
- DEPLOYMENT_TYPE=docker-swarm
|
||||
- SIGNOZ_TOKENIZER_JWT_SECRET=secret
|
||||
- DOT_METRICS_ENABLED=true
|
||||
healthcheck:
|
||||
test:
|
||||
- CMD
|
||||
@@ -209,40 +213,48 @@ services:
|
||||
retries: 3
|
||||
otel-collector:
|
||||
!!merge <<: *db-depend
|
||||
image: signoz/signoz-otel-collector:v0.142.0
|
||||
image: signoz/signoz-otel-collector:v0.142.1
|
||||
entrypoint:
|
||||
- /bin/sh
|
||||
command:
|
||||
- --config=/etc/otel-collector-config.yaml
|
||||
- --manager-config=/etc/manager-config.yaml
|
||||
- --copy-path=/var/tmp/collector-config.yaml
|
||||
volumes:
|
||||
- ./otel-collector-config.yaml:/etc/otel-collector-config.yaml
|
||||
- ../common/signoz/otel-collector-opamp-config.yaml:/etc/manager-config.yaml
|
||||
- -c
|
||||
- |
|
||||
/signoz-otel-collector migrate sync check &&
|
||||
/signoz-otel-collector --config=/etc/otel-collector-config.yaml --manager-config=/etc/manager-config.yaml --copy-path=/var/tmp/collector-config.yaml
|
||||
configs:
|
||||
- source: otel-collector-config
|
||||
target: /etc/otel-collector-config.yaml
|
||||
- source: otel-manager-config
|
||||
target: /etc/manager-config.yaml
|
||||
environment:
|
||||
- OTEL_RESOURCE_ATTRIBUTES=host.name={{.Node.Hostname}},os.type={{.Node.Platform.OS}}
|
||||
- LOW_CARDINAL_EXCEPTION_GROUPING=false
|
||||
- SIGNOZ_OTEL_COLLECTOR_CLICKHOUSE_DSN=tcp://clickhouse:9000
|
||||
- SIGNOZ_OTEL_COLLECTOR_CLICKHOUSE_CLUSTER=cluster
|
||||
- SIGNOZ_OTEL_COLLECTOR_CLICKHOUSE_REPLICATION=true
|
||||
- SIGNOZ_OTEL_COLLECTOR_TIMEOUT=10m
|
||||
ports:
|
||||
# - "1777:1777" # pprof extension
|
||||
- "4317:4317" # OTLP gRPC receiver
|
||||
- "4318:4318" # OTLP HTTP receiver
|
||||
deploy:
|
||||
replicas: 3
|
||||
depends_on:
|
||||
- clickhouse
|
||||
- schema-migrator
|
||||
- signoz
|
||||
schema-migrator:
|
||||
!!merge <<: *common
|
||||
image: signoz/signoz-schema-migrator:v0.142.0
|
||||
deploy:
|
||||
restart_policy:
|
||||
condition: on-failure
|
||||
delay: 5s
|
||||
entrypoint: sh
|
||||
signoz-telemetrystore-migrator:
|
||||
!!merge <<: *db-depend
|
||||
image: signoz/signoz-otel-collector:${OTELCOL_TAG:-v0.142.0}
|
||||
environment:
|
||||
- SIGNOZ_OTEL_COLLECTOR_CLICKHOUSE_DSN=tcp://clickhouse:9000
|
||||
- SIGNOZ_OTEL_COLLECTOR_CLICKHOUSE_CLUSTER=cluster
|
||||
- SIGNOZ_OTEL_COLLECTOR_CLICKHOUSE_REPLICATION=true
|
||||
- SIGNOZ_OTEL_COLLECTOR_TIMEOUT=10m
|
||||
entrypoint:
|
||||
- /bin/sh
|
||||
command:
|
||||
- -c
|
||||
- "/signoz-schema-migrator sync --dsn=tcp://clickhouse:9000 --up= && /signoz-schema-migrator async --dsn=tcp://clickhouse:9000 --up="
|
||||
depends_on:
|
||||
- clickhouse
|
||||
- |
|
||||
/signoz-otel-collector migrate bootstrap &&
|
||||
/signoz-otel-collector migrate sync up &&
|
||||
/signoz-otel-collector migrate async up
|
||||
networks:
|
||||
signoz-net:
|
||||
name: signoz-net
|
||||
@@ -261,3 +273,16 @@ volumes:
|
||||
name: signoz-zookeeper-2
|
||||
zookeeper-3:
|
||||
name: signoz-zookeeper-3
|
||||
configs:
|
||||
clickhouse-config:
|
||||
file: ../common/clickhouse/config.xml
|
||||
clickhouse-users:
|
||||
file: ../common/clickhouse/users.xml
|
||||
clickhouse-custom-function:
|
||||
file: ../common/clickhouse/custom-function.xml
|
||||
clickhouse-cluster:
|
||||
file: ../common/clickhouse/cluster.ha.xml
|
||||
otel-collector-config:
|
||||
file: ./otel-collector-config.yaml
|
||||
otel-manager-config:
|
||||
file: ../common/signoz/otel-collector-opamp-config.yaml
|
||||
|
||||
@@ -58,7 +58,6 @@ x-db-depend: &db-depend
|
||||
!!merge <<: *common
|
||||
depends_on:
|
||||
- clickhouse
|
||||
- schema-migrator
|
||||
services:
|
||||
init-clickhouse:
|
||||
!!merge <<: *common
|
||||
@@ -114,30 +113,20 @@ services:
|
||||
target: /etc/clickhouse-server/config.d/cluster.xml
|
||||
volumes:
|
||||
- clickhouse:/var/lib/clickhouse/
|
||||
- ../common/clickhouse/user_scripts:/var/lib/clickhouse/user_scripts/
|
||||
# - ../common/clickhouse/storage.xml:/etc/clickhouse-server/config.d/storage.xml
|
||||
signoz:
|
||||
!!merge <<: *db-depend
|
||||
image: signoz/signoz:v0.112.0
|
||||
command:
|
||||
- --config=/root/config/prometheus.yml
|
||||
image: signoz/signoz:v0.112.1
|
||||
ports:
|
||||
- "8080:8080" # signoz port
|
||||
# - "6060:6060" # pprof port
|
||||
volumes:
|
||||
- sqlite:/var/lib/signoz/
|
||||
configs:
|
||||
- source: signoz-prometheus-config
|
||||
target: /root/config/prometheus.yml
|
||||
environment:
|
||||
- SIGNOZ_ALERTMANAGER_PROVIDER=signoz
|
||||
- SIGNOZ_TELEMETRYSTORE_CLICKHOUSE_DSN=tcp://clickhouse:9000
|
||||
- SIGNOZ_SQLSTORE_SQLITE_PATH=/var/lib/signoz/signoz.db
|
||||
- DASHBOARDS_PATH=/root/config/dashboards
|
||||
- STORAGE=clickhouse
|
||||
- GODEBUG=netdns=go
|
||||
- TELEMETRY_ENABLED=true
|
||||
- DEPLOYMENT_TYPE=docker-swarm
|
||||
- DOT_METRICS_ENABLED=true
|
||||
- SIGNOZ_TOKENIZER_JWT_SECRET=secret
|
||||
healthcheck:
|
||||
test:
|
||||
- CMD
|
||||
@@ -150,11 +139,14 @@ services:
|
||||
retries: 3
|
||||
otel-collector:
|
||||
!!merge <<: *db-depend
|
||||
image: signoz/signoz-otel-collector:v0.142.0
|
||||
image: signoz/signoz-otel-collector:v0.142.1
|
||||
entrypoint:
|
||||
- /bin/sh
|
||||
command:
|
||||
- --config=/etc/otel-collector-config.yaml
|
||||
- --manager-config=/etc/manager-config.yaml
|
||||
- --copy-path=/var/tmp/collector-config.yaml
|
||||
- -c
|
||||
- |
|
||||
/signoz-otel-collector migrate sync check &&
|
||||
/signoz-otel-collector --config=/etc/otel-collector-config.yaml --manager-config=/etc/manager-config.yaml --copy-path=/var/tmp/collector-config.yaml
|
||||
configs:
|
||||
- source: otel-collector-config
|
||||
target: /etc/otel-collector-config.yaml
|
||||
@@ -163,29 +155,32 @@ services:
|
||||
environment:
|
||||
- OTEL_RESOURCE_ATTRIBUTES=host.name={{.Node.Hostname}},os.type={{.Node.Platform.OS}}
|
||||
- LOW_CARDINAL_EXCEPTION_GROUPING=false
|
||||
- SIGNOZ_OTEL_COLLECTOR_CLICKHOUSE_DSN=tcp://clickhouse:9000
|
||||
- SIGNOZ_OTEL_COLLECTOR_CLICKHOUSE_CLUSTER=cluster
|
||||
- SIGNOZ_OTEL_COLLECTOR_CLICKHOUSE_REPLICATION=true
|
||||
- SIGNOZ_OTEL_COLLECTOR_TIMEOUT=10m
|
||||
ports:
|
||||
# - "1777:1777" # pprof extension
|
||||
- "4317:4317" # OTLP gRPC receiver
|
||||
- "4318:4318" # OTLP HTTP receiver
|
||||
deploy:
|
||||
replicas: 3
|
||||
depends_on:
|
||||
- clickhouse
|
||||
- schema-migrator
|
||||
- signoz
|
||||
schema-migrator:
|
||||
!!merge <<: *common
|
||||
image: signoz/signoz-schema-migrator:v0.142.0
|
||||
deploy:
|
||||
restart_policy:
|
||||
condition: on-failure
|
||||
delay: 5s
|
||||
entrypoint: sh
|
||||
signoz-telemetrystore-migrator:
|
||||
!!merge <<: *db-depend
|
||||
image: signoz/signoz-otel-collector:${OTELCOL_TAG:-v0.142.0}
|
||||
environment:
|
||||
- SIGNOZ_OTEL_COLLECTOR_CLICKHOUSE_DSN=tcp://clickhouse:9000
|
||||
- SIGNOZ_OTEL_COLLECTOR_CLICKHOUSE_CLUSTER=cluster
|
||||
- SIGNOZ_OTEL_COLLECTOR_CLICKHOUSE_REPLICATION=true
|
||||
- SIGNOZ_OTEL_COLLECTOR_TIMEOUT=10m
|
||||
entrypoint:
|
||||
- /bin/sh
|
||||
command:
|
||||
- -c
|
||||
- "/signoz-schema-migrator sync --dsn=tcp://clickhouse:9000 --up= && /signoz-schema-migrator async --dsn=tcp://clickhouse:9000 --up="
|
||||
depends_on:
|
||||
- clickhouse
|
||||
- |
|
||||
/signoz-otel-collector migrate bootstrap &&
|
||||
/signoz-otel-collector migrate sync up &&
|
||||
/signoz-otel-collector migrate async up
|
||||
networks:
|
||||
signoz-net:
|
||||
name: signoz-net
|
||||
@@ -205,14 +200,6 @@ configs:
|
||||
file: ../common/clickhouse/custom-function.xml
|
||||
clickhouse-cluster:
|
||||
file: ../common/clickhouse/cluster.xml
|
||||
signoz-prometheus-config:
|
||||
file: ../common/signoz/prometheus.yml
|
||||
# If you have multiple dashboard files, you can list them individually:
|
||||
# dashboard-foo:
|
||||
# file: ../common/dashboards/foo.json
|
||||
# dashboard-bar:
|
||||
# file: ../common/dashboards/bar.json
|
||||
|
||||
otel-collector-config:
|
||||
file: ./otel-collector-config.yaml
|
||||
otel-manager-config:
|
||||
|
||||
@@ -62,8 +62,10 @@ x-db-depend: &db-depend
|
||||
depends_on:
|
||||
clickhouse:
|
||||
condition: service_healthy
|
||||
schema-migrator-sync:
|
||||
condition: service_completed_successfully
|
||||
clickhouse-2:
|
||||
condition: service_healthy
|
||||
clickhouse-3:
|
||||
condition: service_healthy
|
||||
services:
|
||||
init-clickhouse:
|
||||
!!merge <<: *common
|
||||
@@ -179,27 +181,17 @@ services:
|
||||
# - ../common/clickhouse/storage.xml:/etc/clickhouse-server/config.d/storage.xml
|
||||
signoz:
|
||||
!!merge <<: *db-depend
|
||||
image: signoz/signoz:${VERSION:-v0.112.0}
|
||||
image: signoz/signoz:${VERSION:-v0.112.1}
|
||||
container_name: signoz
|
||||
command:
|
||||
- --config=/root/config/prometheus.yml
|
||||
ports:
|
||||
- "8080:8080" # signoz port
|
||||
# - "6060:6060" # pprof port
|
||||
volumes:
|
||||
- ../common/signoz/prometheus.yml:/root/config/prometheus.yml
|
||||
- ../common/dashboards:/root/config/dashboards
|
||||
- sqlite:/var/lib/signoz/
|
||||
environment:
|
||||
- SIGNOZ_ALERTMANAGER_PROVIDER=signoz
|
||||
- SIGNOZ_TELEMETRYSTORE_CLICKHOUSE_DSN=tcp://clickhouse:9000
|
||||
- SIGNOZ_SQLSTORE_SQLITE_PATH=/var/lib/signoz/signoz.db
|
||||
- DASHBOARDS_PATH=/root/config/dashboards
|
||||
- STORAGE=clickhouse
|
||||
- GODEBUG=netdns=go
|
||||
- TELEMETRY_ENABLED=true
|
||||
- DEPLOYMENT_TYPE=docker-standalone-amd
|
||||
- DOT_METRICS_ENABLED=true
|
||||
- SIGNOZ_TOKENIZER_JWT_SECRET=secret
|
||||
healthcheck:
|
||||
test:
|
||||
- CMD
|
||||
@@ -210,51 +202,48 @@ services:
|
||||
interval: 30s
|
||||
timeout: 5s
|
||||
retries: 3
|
||||
# TODO: support otel-collector multiple replicas. Nginx/Traefik for loadbalancing?
|
||||
otel-collector:
|
||||
!!merge <<: *db-depend
|
||||
image: signoz/signoz-otel-collector:${OTELCOL_TAG:-v0.142.0}
|
||||
image: signoz/signoz-otel-collector:${OTELCOL_TAG:-v0.142.1}
|
||||
container_name: signoz-otel-collector
|
||||
entrypoint:
|
||||
- /bin/sh
|
||||
command:
|
||||
- --config=/etc/otel-collector-config.yaml
|
||||
- --manager-config=/etc/manager-config.yaml
|
||||
- --copy-path=/var/tmp/collector-config.yaml
|
||||
- -c
|
||||
- |
|
||||
/signoz-otel-collector migrate sync check &&
|
||||
/signoz-otel-collector --config=/etc/otel-collector-config.yaml --manager-config=/etc/manager-config.yaml --copy-path=/var/tmp/collector-config.yaml
|
||||
volumes:
|
||||
- ./otel-collector-config.yaml:/etc/otel-collector-config.yaml
|
||||
- ../common/signoz/otel-collector-opamp-config.yaml:/etc/manager-config.yaml
|
||||
environment:
|
||||
- OTEL_RESOURCE_ATTRIBUTES=host.name=signoz-host,os.type=linux
|
||||
- LOW_CARDINAL_EXCEPTION_GROUPING=false
|
||||
- SIGNOZ_OTEL_COLLECTOR_CLICKHOUSE_DSN=tcp://clickhouse:9000
|
||||
- SIGNOZ_OTEL_COLLECTOR_CLICKHOUSE_CLUSTER=cluster
|
||||
- SIGNOZ_OTEL_COLLECTOR_CLICKHOUSE_REPLICATION=true
|
||||
- SIGNOZ_OTEL_COLLECTOR_TIMEOUT=10m
|
||||
ports:
|
||||
# - "1777:1777" # pprof extension
|
||||
- "4317:4317" # OTLP gRPC receiver
|
||||
- "4318:4318" # OTLP HTTP receiver
|
||||
depends_on:
|
||||
clickhouse:
|
||||
condition: service_healthy
|
||||
schema-migrator-sync:
|
||||
condition: service_completed_successfully
|
||||
signoz:
|
||||
condition: service_healthy
|
||||
schema-migrator-sync:
|
||||
!!merge <<: *common
|
||||
image: signoz/signoz-schema-migrator:${OTELCOL_TAG:-v0.142.0}
|
||||
container_name: schema-migrator-sync
|
||||
command:
|
||||
- sync
|
||||
- --dsn=tcp://clickhouse:9000
|
||||
- --up=
|
||||
depends_on:
|
||||
clickhouse:
|
||||
condition: service_healthy
|
||||
schema-migrator-async:
|
||||
signoz-telemetrystore-migrator:
|
||||
!!merge <<: *db-depend
|
||||
image: signoz/signoz-schema-migrator:${OTELCOL_TAG:-v0.142.0}
|
||||
container_name: schema-migrator-async
|
||||
image: signoz/signoz-otel-collector:${OTELCOL_TAG:-v0.142.0}
|
||||
container_name: signoz-telemetrystore-migrator
|
||||
environment:
|
||||
- SIGNOZ_OTEL_COLLECTOR_CLICKHOUSE_DSN=tcp://clickhouse:9000
|
||||
- SIGNOZ_OTEL_COLLECTOR_CLICKHOUSE_CLUSTER=cluster
|
||||
- SIGNOZ_OTEL_COLLECTOR_CLICKHOUSE_REPLICATION=true
|
||||
- SIGNOZ_OTEL_COLLECTOR_TIMEOUT=10m
|
||||
entrypoint:
|
||||
- /bin/sh
|
||||
command:
|
||||
- async
|
||||
- --dsn=tcp://clickhouse:9000
|
||||
- --up=
|
||||
- -c
|
||||
- |
|
||||
/signoz-otel-collector migrate bootstrap &&
|
||||
/signoz-otel-collector migrate sync up &&
|
||||
/signoz-otel-collector migrate async up
|
||||
restart: on-failure
|
||||
networks:
|
||||
signoz-net:
|
||||
|
||||
@@ -57,8 +57,6 @@ x-db-depend: &db-depend
|
||||
depends_on:
|
||||
clickhouse:
|
||||
condition: service_healthy
|
||||
schema-migrator-sync:
|
||||
condition: service_completed_successfully
|
||||
services:
|
||||
init-clickhouse:
|
||||
!!merge <<: *common
|
||||
@@ -111,27 +109,17 @@ services:
|
||||
# - ../common/clickhouse/storage.xml:/etc/clickhouse-server/config.d/storage.xml
|
||||
signoz:
|
||||
!!merge <<: *db-depend
|
||||
image: signoz/signoz:${VERSION:-v0.112.0}
|
||||
image: signoz/signoz:${VERSION:-v0.112.1}
|
||||
container_name: signoz
|
||||
command:
|
||||
- --config=/root/config/prometheus.yml
|
||||
ports:
|
||||
- "8080:8080" # signoz port
|
||||
# - "6060:6060" # pprof port
|
||||
volumes:
|
||||
- ../common/signoz/prometheus.yml:/root/config/prometheus.yml
|
||||
- ../common/dashboards:/root/config/dashboards
|
||||
- sqlite:/var/lib/signoz/
|
||||
environment:
|
||||
- SIGNOZ_ALERTMANAGER_PROVIDER=signoz
|
||||
- SIGNOZ_TELEMETRYSTORE_CLICKHOUSE_DSN=tcp://clickhouse:9000
|
||||
- SIGNOZ_SQLSTORE_SQLITE_PATH=/var/lib/signoz/signoz.db
|
||||
- DASHBOARDS_PATH=/root/config/dashboards
|
||||
- STORAGE=clickhouse
|
||||
- GODEBUG=netdns=go
|
||||
- TELEMETRY_ENABLED=true
|
||||
- DEPLOYMENT_TYPE=docker-standalone-amd
|
||||
- DOT_METRICS_ENABLED=true
|
||||
- SIGNOZ_TOKENIZER_JWT_SECRET=secret
|
||||
healthcheck:
|
||||
test:
|
||||
- CMD
|
||||
@@ -144,45 +132,46 @@ services:
|
||||
retries: 3
|
||||
otel-collector:
|
||||
!!merge <<: *db-depend
|
||||
image: signoz/signoz-otel-collector:${OTELCOL_TAG:-v0.142.0}
|
||||
image: signoz/signoz-otel-collector:${OTELCOL_TAG:-v0.142.1}
|
||||
container_name: signoz-otel-collector
|
||||
entrypoint:
|
||||
- /bin/sh
|
||||
command:
|
||||
- --config=/etc/otel-collector-config.yaml
|
||||
- --manager-config=/etc/manager-config.yaml
|
||||
- --copy-path=/var/tmp/collector-config.yaml
|
||||
- -c
|
||||
- |
|
||||
/signoz-otel-collector migrate sync check &&
|
||||
/signoz-otel-collector --config=/etc/otel-collector-config.yaml --manager-config=/etc/manager-config.yaml --copy-path=/var/tmp/collector-config.yaml
|
||||
volumes:
|
||||
- ./otel-collector-config.yaml:/etc/otel-collector-config.yaml
|
||||
- ../common/signoz/otel-collector-opamp-config.yaml:/etc/manager-config.yaml
|
||||
environment:
|
||||
- OTEL_RESOURCE_ATTRIBUTES=host.name=signoz-host,os.type=linux
|
||||
- LOW_CARDINAL_EXCEPTION_GROUPING=false
|
||||
- SIGNOZ_OTEL_COLLECTOR_CLICKHOUSE_DSN=tcp://clickhouse:9000
|
||||
- SIGNOZ_OTEL_COLLECTOR_CLICKHOUSE_CLUSTER=cluster
|
||||
- SIGNOZ_OTEL_COLLECTOR_CLICKHOUSE_REPLICATION=true
|
||||
- SIGNOZ_OTEL_COLLECTOR_TIMEOUT=10m
|
||||
ports:
|
||||
# - "1777:1777" # pprof extension
|
||||
- "4317:4317" # OTLP gRPC receiver
|
||||
- "4318:4318" # OTLP HTTP receiver
|
||||
depends_on:
|
||||
signoz:
|
||||
condition: service_healthy
|
||||
schema-migrator-sync:
|
||||
!!merge <<: *common
|
||||
image: signoz/signoz-schema-migrator:${OTELCOL_TAG:-v0.142.0}
|
||||
container_name: schema-migrator-sync
|
||||
command:
|
||||
- sync
|
||||
- --dsn=tcp://clickhouse:9000
|
||||
- --up=
|
||||
depends_on:
|
||||
clickhouse:
|
||||
condition: service_healthy
|
||||
restart: on-failure
|
||||
schema-migrator-async:
|
||||
signoz-telemetrystore-migrator:
|
||||
!!merge <<: *db-depend
|
||||
image: signoz/signoz-schema-migrator:${OTELCOL_TAG:-v0.142.0}
|
||||
container_name: schema-migrator-async
|
||||
image: signoz/signoz-otel-collector:${OTELCOL_TAG:-v0.142.0}
|
||||
container_name: signoz-telemetrystore-migrator
|
||||
environment:
|
||||
- SIGNOZ_OTEL_COLLECTOR_CLICKHOUSE_DSN=tcp://clickhouse:9000
|
||||
- SIGNOZ_OTEL_COLLECTOR_CLICKHOUSE_CLUSTER=cluster
|
||||
- SIGNOZ_OTEL_COLLECTOR_CLICKHOUSE_REPLICATION=true
|
||||
- SIGNOZ_OTEL_COLLECTOR_TIMEOUT=10m
|
||||
entrypoint:
|
||||
- /bin/sh
|
||||
command:
|
||||
- async
|
||||
- --dsn=tcp://clickhouse:9000
|
||||
- --up=
|
||||
- -c
|
||||
- |
|
||||
/signoz-otel-collector migrate bootstrap &&
|
||||
/signoz-otel-collector migrate sync up &&
|
||||
/signoz-otel-collector migrate async up
|
||||
restart: on-failure
|
||||
networks:
|
||||
signoz-net:
|
||||
|
||||
@@ -80,6 +80,37 @@ components:
|
||||
updatedAt:
|
||||
format: date-time
|
||||
type: string
|
||||
required:
|
||||
- id
|
||||
type: object
|
||||
AuthtypesGettableObjects:
|
||||
properties:
|
||||
resource:
|
||||
$ref: '#/components/schemas/AuthtypesResource'
|
||||
selectors:
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
required:
|
||||
- resource
|
||||
- selectors
|
||||
type: object
|
||||
AuthtypesGettableResources:
|
||||
properties:
|
||||
relations:
|
||||
additionalProperties:
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
nullable: true
|
||||
type: object
|
||||
resources:
|
||||
items:
|
||||
$ref: '#/components/schemas/AuthtypesResource'
|
||||
type: array
|
||||
required:
|
||||
- resources
|
||||
- relations
|
||||
type: object
|
||||
AuthtypesGettableToken:
|
||||
properties:
|
||||
@@ -130,8 +161,6 @@ components:
|
||||
serviceAccountJson:
|
||||
type: string
|
||||
type: object
|
||||
AuthtypesName:
|
||||
type: object
|
||||
AuthtypesOIDCConfig:
|
||||
properties:
|
||||
claimMapping:
|
||||
@@ -154,7 +183,7 @@ components:
|
||||
resource:
|
||||
$ref: '#/components/schemas/AuthtypesResource'
|
||||
selector:
|
||||
$ref: '#/components/schemas/AuthtypesSelector'
|
||||
type: string
|
||||
required:
|
||||
- resource
|
||||
- selector
|
||||
@@ -175,6 +204,22 @@ components:
|
||||
provider:
|
||||
type: string
|
||||
type: object
|
||||
AuthtypesPatchableObjects:
|
||||
properties:
|
||||
additions:
|
||||
items:
|
||||
$ref: '#/components/schemas/AuthtypesGettableObjects'
|
||||
nullable: true
|
||||
type: array
|
||||
deletions:
|
||||
items:
|
||||
$ref: '#/components/schemas/AuthtypesGettableObjects'
|
||||
nullable: true
|
||||
type: array
|
||||
required:
|
||||
- additions
|
||||
- deletions
|
||||
type: object
|
||||
AuthtypesPostableAuthDomain:
|
||||
properties:
|
||||
config:
|
||||
@@ -199,7 +244,7 @@ components:
|
||||
AuthtypesResource:
|
||||
properties:
|
||||
name:
|
||||
$ref: '#/components/schemas/AuthtypesName'
|
||||
type: string
|
||||
type:
|
||||
type: string
|
||||
required:
|
||||
@@ -231,8 +276,6 @@ components:
|
||||
samlIdp:
|
||||
type: string
|
||||
type: object
|
||||
AuthtypesSelector:
|
||||
type: object
|
||||
AuthtypesSessionContext:
|
||||
properties:
|
||||
exists:
|
||||
@@ -245,8 +288,6 @@ components:
|
||||
type: object
|
||||
AuthtypesTransaction:
|
||||
properties:
|
||||
id:
|
||||
type: string
|
||||
object:
|
||||
$ref: '#/components/schemas/AuthtypesObject'
|
||||
relation:
|
||||
@@ -460,10 +501,10 @@ components:
|
||||
GatewaytypesLimitValue:
|
||||
properties:
|
||||
count:
|
||||
format: int64
|
||||
nullable: true
|
||||
type: integer
|
||||
size:
|
||||
format: int64
|
||||
nullable: true
|
||||
type: integer
|
||||
type: object
|
||||
GatewaytypesPagination:
|
||||
@@ -1668,40 +1709,6 @@ components:
|
||||
- status
|
||||
- error
|
||||
type: object
|
||||
RoletypesGettableResources:
|
||||
properties:
|
||||
relations:
|
||||
additionalProperties:
|
||||
items:
|
||||
type: string
|
||||
type: array
|
||||
nullable: true
|
||||
type: object
|
||||
resources:
|
||||
items:
|
||||
$ref: '#/components/schemas/AuthtypesResource'
|
||||
nullable: true
|
||||
type: array
|
||||
required:
|
||||
- resources
|
||||
- relations
|
||||
type: object
|
||||
RoletypesPatchableObjects:
|
||||
properties:
|
||||
additions:
|
||||
items:
|
||||
$ref: '#/components/schemas/AuthtypesObject'
|
||||
nullable: true
|
||||
type: array
|
||||
deletions:
|
||||
items:
|
||||
$ref: '#/components/schemas/AuthtypesObject'
|
||||
nullable: true
|
||||
type: array
|
||||
required:
|
||||
- additions
|
||||
- deletions
|
||||
type: object
|
||||
RoletypesPatchableRole:
|
||||
properties:
|
||||
description:
|
||||
@@ -1737,6 +1744,7 @@ components:
|
||||
format: date-time
|
||||
type: string
|
||||
required:
|
||||
- id
|
||||
- name
|
||||
- description
|
||||
- type
|
||||
@@ -1874,6 +1882,8 @@ components:
|
||||
$ref: '#/components/schemas/TypesUser'
|
||||
userId:
|
||||
type: string
|
||||
required:
|
||||
- id
|
||||
type: object
|
||||
TypesGettableGlobalConfig:
|
||||
properties:
|
||||
@@ -1886,6 +1896,8 @@ components:
|
||||
properties:
|
||||
id:
|
||||
type: string
|
||||
required:
|
||||
- id
|
||||
type: object
|
||||
TypesInvite:
|
||||
properties:
|
||||
@@ -1909,6 +1921,8 @@ components:
|
||||
updatedAt:
|
||||
format: date-time
|
||||
type: string
|
||||
required:
|
||||
- id
|
||||
type: object
|
||||
TypesOrganization:
|
||||
properties:
|
||||
@@ -1929,6 +1943,8 @@ components:
|
||||
updatedAt:
|
||||
format: date-time
|
||||
type: string
|
||||
required:
|
||||
- id
|
||||
type: object
|
||||
TypesPostableAPIKey:
|
||||
properties:
|
||||
@@ -1992,6 +2008,8 @@ components:
|
||||
type: string
|
||||
token:
|
||||
type: string
|
||||
required:
|
||||
- id
|
||||
type: object
|
||||
TypesStorableAPIKey:
|
||||
properties:
|
||||
@@ -2017,6 +2035,8 @@ components:
|
||||
type: string
|
||||
userId:
|
||||
type: string
|
||||
required:
|
||||
- id
|
||||
type: object
|
||||
TypesUser:
|
||||
properties:
|
||||
@@ -2038,6 +2058,8 @@ components:
|
||||
updatedAt:
|
||||
format: date-time
|
||||
type: string
|
||||
required:
|
||||
- id
|
||||
type: object
|
||||
ZeustypesGettableHost:
|
||||
properties:
|
||||
@@ -2170,6 +2192,35 @@ paths:
|
||||
summary: Check permissions
|
||||
tags:
|
||||
- authz
|
||||
/api/v1/authz/resources:
|
||||
get:
|
||||
deprecated: false
|
||||
description: Gets all the available resources
|
||||
operationId: AuthzResources
|
||||
responses:
|
||||
"200":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
properties:
|
||||
data:
|
||||
$ref: '#/components/schemas/AuthtypesGettableResources'
|
||||
status:
|
||||
type: string
|
||||
required:
|
||||
- status
|
||||
- data
|
||||
type: object
|
||||
description: OK
|
||||
"500":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/RenderErrorResponse'
|
||||
description: Internal Server Error
|
||||
summary: Get resources
|
||||
tags:
|
||||
- authz
|
||||
/api/v1/changePassword/{id}:
|
||||
post:
|
||||
deprecated: false
|
||||
@@ -4342,7 +4393,7 @@ paths:
|
||||
properties:
|
||||
data:
|
||||
items:
|
||||
$ref: '#/components/schemas/AuthtypesObject'
|
||||
$ref: '#/components/schemas/AuthtypesGettableObjects'
|
||||
type: array
|
||||
status:
|
||||
type: string
|
||||
@@ -4415,7 +4466,7 @@ paths:
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/RoletypesPatchableObjects'
|
||||
$ref: '#/components/schemas/AuthtypesPatchableObjects'
|
||||
responses:
|
||||
"204":
|
||||
content:
|
||||
@@ -4473,52 +4524,6 @@ paths:
|
||||
summary: Patch objects for a role by relation
|
||||
tags:
|
||||
- role
|
||||
/api/v1/roles/resources:
|
||||
get:
|
||||
deprecated: false
|
||||
description: Gets all the available resources for role assignment
|
||||
operationId: GetResources
|
||||
responses:
|
||||
"200":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
properties:
|
||||
data:
|
||||
$ref: '#/components/schemas/RoletypesGettableResources'
|
||||
status:
|
||||
type: string
|
||||
required:
|
||||
- status
|
||||
- data
|
||||
type: object
|
||||
description: OK
|
||||
"401":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/RenderErrorResponse'
|
||||
description: Unauthorized
|
||||
"403":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/RenderErrorResponse'
|
||||
description: Forbidden
|
||||
"500":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/RenderErrorResponse'
|
||||
description: Internal Server Error
|
||||
security:
|
||||
- api_key:
|
||||
- ADMIN
|
||||
- tokenizer:
|
||||
- ADMIN
|
||||
summary: Get resources
|
||||
tags:
|
||||
- role
|
||||
/api/v1/user:
|
||||
get:
|
||||
deprecated: false
|
||||
@@ -5091,7 +5096,7 @@ paths:
|
||||
schema:
|
||||
$ref: '#/components/schemas/GatewaytypesPostableIngestionKey'
|
||||
responses:
|
||||
"200":
|
||||
"201":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
@@ -5104,7 +5109,7 @@ paths:
|
||||
- status
|
||||
- data
|
||||
type: object
|
||||
description: OK
|
||||
description: Created
|
||||
"401":
|
||||
content:
|
||||
application/json:
|
||||
@@ -5532,6 +5537,12 @@ paths:
|
||||
schema:
|
||||
$ref: '#/components/schemas/RenderErrorResponse'
|
||||
description: Forbidden
|
||||
"404":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/RenderErrorResponse'
|
||||
description: Not Found
|
||||
"500":
|
||||
content:
|
||||
application/json:
|
||||
@@ -5601,6 +5612,12 @@ paths:
|
||||
schema:
|
||||
$ref: '#/components/schemas/RenderErrorResponse'
|
||||
description: Forbidden
|
||||
"404":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/RenderErrorResponse'
|
||||
description: Not Found
|
||||
"500":
|
||||
content:
|
||||
application/json:
|
||||
@@ -5659,6 +5676,12 @@ paths:
|
||||
schema:
|
||||
$ref: '#/components/schemas/RenderErrorResponse'
|
||||
description: Forbidden
|
||||
"404":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/RenderErrorResponse'
|
||||
description: Not Found
|
||||
"500":
|
||||
content:
|
||||
application/json:
|
||||
@@ -5718,6 +5741,12 @@ paths:
|
||||
schema:
|
||||
$ref: '#/components/schemas/RenderErrorResponse'
|
||||
description: Forbidden
|
||||
"404":
|
||||
content:
|
||||
application/json:
|
||||
schema:
|
||||
$ref: '#/components/schemas/RenderErrorResponse'
|
||||
description: Not Found
|
||||
"500":
|
||||
content:
|
||||
application/json:
|
||||
|
||||
@@ -171,8 +171,6 @@ func (provider *provider) GetResources(_ context.Context) []*authtypes.Resource
|
||||
for _, register := range provider.registry {
|
||||
typeables = append(typeables, register.MustGetTypeables()...)
|
||||
}
|
||||
// role module cannot self register itself!
|
||||
typeables = append(typeables, provider.MustGetTypeables()...)
|
||||
|
||||
resources := make([]*authtypes.Resource, 0)
|
||||
for _, typeable := range typeables {
|
||||
@@ -259,7 +257,7 @@ func (provider *provider) Delete(ctx context.Context, orgID valuer.UUID, id valu
|
||||
}
|
||||
|
||||
role := roletypes.NewRoleFromStorableRole(storableRole)
|
||||
err = role.CanEditDelete()
|
||||
err = role.ErrIfManaged()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
@@ -5,17 +5,24 @@
|
||||
* SigNoz
|
||||
*/
|
||||
import type {
|
||||
InvalidateOptions,
|
||||
MutationFunction,
|
||||
QueryClient,
|
||||
QueryFunction,
|
||||
QueryKey,
|
||||
UseMutationOptions,
|
||||
UseMutationResult,
|
||||
UseQueryOptions,
|
||||
UseQueryResult,
|
||||
} from 'react-query';
|
||||
import { useMutation } from 'react-query';
|
||||
import { useMutation, useQuery } from 'react-query';
|
||||
|
||||
import type { BodyType, ErrorType } from '../../../generatedAPIInstance';
|
||||
import { GeneratedAPIInstance } from '../../../generatedAPIInstance';
|
||||
import type {
|
||||
AuthtypesTransactionDTO,
|
||||
AuthzCheck200,
|
||||
AuthzResources200,
|
||||
RenderErrorResponseDTO,
|
||||
} from '../sigNoz.schemas';
|
||||
|
||||
@@ -106,3 +113,88 @@ export const useAuthzCheck = <
|
||||
|
||||
return useMutation(mutationOptions);
|
||||
};
|
||||
/**
|
||||
* Gets all the available resources
|
||||
* @summary Get resources
|
||||
*/
|
||||
export const authzResources = (signal?: AbortSignal) => {
|
||||
return GeneratedAPIInstance<AuthzResources200>({
|
||||
url: `/api/v1/authz/resources`,
|
||||
method: 'GET',
|
||||
signal,
|
||||
});
|
||||
};
|
||||
|
||||
export const getAuthzResourcesQueryKey = () => {
|
||||
return [`/api/v1/authz/resources`] as const;
|
||||
};
|
||||
|
||||
export const getAuthzResourcesQueryOptions = <
|
||||
TData = Awaited<ReturnType<typeof authzResources>>,
|
||||
TError = ErrorType<RenderErrorResponseDTO>
|
||||
>(options?: {
|
||||
query?: UseQueryOptions<
|
||||
Awaited<ReturnType<typeof authzResources>>,
|
||||
TError,
|
||||
TData
|
||||
>;
|
||||
}) => {
|
||||
const { query: queryOptions } = options ?? {};
|
||||
|
||||
const queryKey = queryOptions?.queryKey ?? getAuthzResourcesQueryKey();
|
||||
|
||||
const queryFn: QueryFunction<Awaited<ReturnType<typeof authzResources>>> = ({
|
||||
signal,
|
||||
}) => authzResources(signal);
|
||||
|
||||
return { queryKey, queryFn, ...queryOptions } as UseQueryOptions<
|
||||
Awaited<ReturnType<typeof authzResources>>,
|
||||
TError,
|
||||
TData
|
||||
> & { queryKey: QueryKey };
|
||||
};
|
||||
|
||||
export type AuthzResourcesQueryResult = NonNullable<
|
||||
Awaited<ReturnType<typeof authzResources>>
|
||||
>;
|
||||
export type AuthzResourcesQueryError = ErrorType<RenderErrorResponseDTO>;
|
||||
|
||||
/**
|
||||
* @summary Get resources
|
||||
*/
|
||||
|
||||
export function useAuthzResources<
|
||||
TData = Awaited<ReturnType<typeof authzResources>>,
|
||||
TError = ErrorType<RenderErrorResponseDTO>
|
||||
>(options?: {
|
||||
query?: UseQueryOptions<
|
||||
Awaited<ReturnType<typeof authzResources>>,
|
||||
TError,
|
||||
TData
|
||||
>;
|
||||
}): UseQueryResult<TData, TError> & { queryKey: QueryKey } {
|
||||
const queryOptions = getAuthzResourcesQueryOptions(options);
|
||||
|
||||
const query = useQuery(queryOptions) as UseQueryResult<TData, TError> & {
|
||||
queryKey: QueryKey;
|
||||
};
|
||||
|
||||
query.queryKey = queryOptions.queryKey;
|
||||
|
||||
return query;
|
||||
}
|
||||
|
||||
/**
|
||||
* @summary Get resources
|
||||
*/
|
||||
export const invalidateAuthzResources = async (
|
||||
queryClient: QueryClient,
|
||||
options?: InvalidateOptions,
|
||||
): Promise<QueryClient> => {
|
||||
await queryClient.invalidateQueries(
|
||||
{ queryKey: getAuthzResourcesQueryKey() },
|
||||
options,
|
||||
);
|
||||
|
||||
return queryClient;
|
||||
};
|
||||
|
||||
@@ -20,7 +20,7 @@ import { useMutation, useQuery } from 'react-query';
|
||||
import type { BodyType, ErrorType } from '../../../generatedAPIInstance';
|
||||
import { GeneratedAPIInstance } from '../../../generatedAPIInstance';
|
||||
import type {
|
||||
CreateIngestionKey200,
|
||||
CreateIngestionKey201,
|
||||
CreateIngestionKeyLimit201,
|
||||
CreateIngestionKeyLimitPathParameters,
|
||||
DeleteIngestionKeyLimitPathParameters,
|
||||
@@ -151,7 +151,7 @@ export const createIngestionKey = (
|
||||
gatewaytypesPostableIngestionKeyDTO: BodyType<GatewaytypesPostableIngestionKeyDTO>,
|
||||
signal?: AbortSignal,
|
||||
) => {
|
||||
return GeneratedAPIInstance<CreateIngestionKey200>({
|
||||
return GeneratedAPIInstance<CreateIngestionKey201>({
|
||||
url: `/api/v2/gateway/ingestion_keys`,
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
|
||||
@@ -20,18 +20,17 @@ import { useMutation, useQuery } from 'react-query';
|
||||
import type { BodyType, ErrorType } from '../../../generatedAPIInstance';
|
||||
import { GeneratedAPIInstance } from '../../../generatedAPIInstance';
|
||||
import type {
|
||||
AuthtypesPatchableObjectsDTO,
|
||||
CreateRole201,
|
||||
DeleteRolePathParameters,
|
||||
GetObjects200,
|
||||
GetObjectsPathParameters,
|
||||
GetResources200,
|
||||
GetRole200,
|
||||
GetRolePathParameters,
|
||||
ListRoles200,
|
||||
PatchObjectsPathParameters,
|
||||
PatchRolePathParameters,
|
||||
RenderErrorResponseDTO,
|
||||
RoletypesPatchableObjectsDTO,
|
||||
RoletypesPatchableRoleDTO,
|
||||
RoletypesPostableRoleDTO,
|
||||
} from '../sigNoz.schemas';
|
||||
@@ -575,13 +574,13 @@ export const invalidateGetObjects = async (
|
||||
*/
|
||||
export const patchObjects = (
|
||||
{ id, relation }: PatchObjectsPathParameters,
|
||||
roletypesPatchableObjectsDTO: BodyType<RoletypesPatchableObjectsDTO>,
|
||||
authtypesPatchableObjectsDTO: BodyType<AuthtypesPatchableObjectsDTO>,
|
||||
) => {
|
||||
return GeneratedAPIInstance<string>({
|
||||
url: `/api/v1/roles/${id}/relation/${relation}/objects`,
|
||||
method: 'PATCH',
|
||||
headers: { 'Content-Type': 'application/json' },
|
||||
data: roletypesPatchableObjectsDTO,
|
||||
data: authtypesPatchableObjectsDTO,
|
||||
});
|
||||
};
|
||||
|
||||
@@ -594,7 +593,7 @@ export const getPatchObjectsMutationOptions = <
|
||||
TError,
|
||||
{
|
||||
pathParams: PatchObjectsPathParameters;
|
||||
data: BodyType<RoletypesPatchableObjectsDTO>;
|
||||
data: BodyType<AuthtypesPatchableObjectsDTO>;
|
||||
},
|
||||
TContext
|
||||
>;
|
||||
@@ -603,7 +602,7 @@ export const getPatchObjectsMutationOptions = <
|
||||
TError,
|
||||
{
|
||||
pathParams: PatchObjectsPathParameters;
|
||||
data: BodyType<RoletypesPatchableObjectsDTO>;
|
||||
data: BodyType<AuthtypesPatchableObjectsDTO>;
|
||||
},
|
||||
TContext
|
||||
> => {
|
||||
@@ -620,7 +619,7 @@ export const getPatchObjectsMutationOptions = <
|
||||
Awaited<ReturnType<typeof patchObjects>>,
|
||||
{
|
||||
pathParams: PatchObjectsPathParameters;
|
||||
data: BodyType<RoletypesPatchableObjectsDTO>;
|
||||
data: BodyType<AuthtypesPatchableObjectsDTO>;
|
||||
}
|
||||
> = (props) => {
|
||||
const { pathParams, data } = props ?? {};
|
||||
@@ -634,7 +633,7 @@ export const getPatchObjectsMutationOptions = <
|
||||
export type PatchObjectsMutationResult = NonNullable<
|
||||
Awaited<ReturnType<typeof patchObjects>>
|
||||
>;
|
||||
export type PatchObjectsMutationBody = BodyType<RoletypesPatchableObjectsDTO>;
|
||||
export type PatchObjectsMutationBody = BodyType<AuthtypesPatchableObjectsDTO>;
|
||||
export type PatchObjectsMutationError = ErrorType<RenderErrorResponseDTO>;
|
||||
|
||||
/**
|
||||
@@ -649,7 +648,7 @@ export const usePatchObjects = <
|
||||
TError,
|
||||
{
|
||||
pathParams: PatchObjectsPathParameters;
|
||||
data: BodyType<RoletypesPatchableObjectsDTO>;
|
||||
data: BodyType<AuthtypesPatchableObjectsDTO>;
|
||||
},
|
||||
TContext
|
||||
>;
|
||||
@@ -658,7 +657,7 @@ export const usePatchObjects = <
|
||||
TError,
|
||||
{
|
||||
pathParams: PatchObjectsPathParameters;
|
||||
data: BodyType<RoletypesPatchableObjectsDTO>;
|
||||
data: BodyType<AuthtypesPatchableObjectsDTO>;
|
||||
},
|
||||
TContext
|
||||
> => {
|
||||
@@ -666,88 +665,3 @@ export const usePatchObjects = <
|
||||
|
||||
return useMutation(mutationOptions);
|
||||
};
|
||||
/**
|
||||
* Gets all the available resources for role assignment
|
||||
* @summary Get resources
|
||||
*/
|
||||
export const getResources = (signal?: AbortSignal) => {
|
||||
return GeneratedAPIInstance<GetResources200>({
|
||||
url: `/api/v1/roles/resources`,
|
||||
method: 'GET',
|
||||
signal,
|
||||
});
|
||||
};
|
||||
|
||||
export const getGetResourcesQueryKey = () => {
|
||||
return [`/api/v1/roles/resources`] as const;
|
||||
};
|
||||
|
||||
export const getGetResourcesQueryOptions = <
|
||||
TData = Awaited<ReturnType<typeof getResources>>,
|
||||
TError = ErrorType<RenderErrorResponseDTO>
|
||||
>(options?: {
|
||||
query?: UseQueryOptions<
|
||||
Awaited<ReturnType<typeof getResources>>,
|
||||
TError,
|
||||
TData
|
||||
>;
|
||||
}) => {
|
||||
const { query: queryOptions } = options ?? {};
|
||||
|
||||
const queryKey = queryOptions?.queryKey ?? getGetResourcesQueryKey();
|
||||
|
||||
const queryFn: QueryFunction<Awaited<ReturnType<typeof getResources>>> = ({
|
||||
signal,
|
||||
}) => getResources(signal);
|
||||
|
||||
return { queryKey, queryFn, ...queryOptions } as UseQueryOptions<
|
||||
Awaited<ReturnType<typeof getResources>>,
|
||||
TError,
|
||||
TData
|
||||
> & { queryKey: QueryKey };
|
||||
};
|
||||
|
||||
export type GetResourcesQueryResult = NonNullable<
|
||||
Awaited<ReturnType<typeof getResources>>
|
||||
>;
|
||||
export type GetResourcesQueryError = ErrorType<RenderErrorResponseDTO>;
|
||||
|
||||
/**
|
||||
* @summary Get resources
|
||||
*/
|
||||
|
||||
export function useGetResources<
|
||||
TData = Awaited<ReturnType<typeof getResources>>,
|
||||
TError = ErrorType<RenderErrorResponseDTO>
|
||||
>(options?: {
|
||||
query?: UseQueryOptions<
|
||||
Awaited<ReturnType<typeof getResources>>,
|
||||
TError,
|
||||
TData
|
||||
>;
|
||||
}): UseQueryResult<TData, TError> & { queryKey: QueryKey } {
|
||||
const queryOptions = getGetResourcesQueryOptions(options);
|
||||
|
||||
const query = useQuery(queryOptions) as UseQueryResult<TData, TError> & {
|
||||
queryKey: QueryKey;
|
||||
};
|
||||
|
||||
query.queryKey = queryOptions.queryKey;
|
||||
|
||||
return query;
|
||||
}
|
||||
|
||||
/**
|
||||
* @summary Get resources
|
||||
*/
|
||||
export const invalidateGetResources = async (
|
||||
queryClient: QueryClient,
|
||||
options?: InvalidateOptions,
|
||||
): Promise<QueryClient> => {
|
||||
await queryClient.invalidateQueries(
|
||||
{ queryKey: getGetResourcesQueryKey() },
|
||||
options,
|
||||
);
|
||||
|
||||
return queryClient;
|
||||
};
|
||||
|
||||
@@ -81,7 +81,7 @@ export interface AuthtypesGettableAuthDomainDTO {
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
id?: string;
|
||||
id: string;
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
@@ -108,6 +108,33 @@ export interface AuthtypesGettableAuthDomainDTO {
|
||||
updatedAt?: Date;
|
||||
}
|
||||
|
||||
export interface AuthtypesGettableObjectsDTO {
|
||||
resource: AuthtypesResourceDTO;
|
||||
/**
|
||||
* @type array
|
||||
*/
|
||||
selectors: string[];
|
||||
}
|
||||
|
||||
/**
|
||||
* @nullable
|
||||
*/
|
||||
export type AuthtypesGettableResourcesDTORelations = {
|
||||
[key: string]: string[];
|
||||
} | null;
|
||||
|
||||
export interface AuthtypesGettableResourcesDTO {
|
||||
/**
|
||||
* @type object
|
||||
* @nullable true
|
||||
*/
|
||||
relations: AuthtypesGettableResourcesDTORelations;
|
||||
/**
|
||||
* @type array
|
||||
*/
|
||||
resources: AuthtypesResourceDTO[];
|
||||
}
|
||||
|
||||
export interface AuthtypesGettableTokenDTO {
|
||||
/**
|
||||
* @type string
|
||||
@@ -182,10 +209,6 @@ export interface AuthtypesGoogleConfigDTO {
|
||||
serviceAccountJson?: string;
|
||||
}
|
||||
|
||||
export interface AuthtypesNameDTO {
|
||||
[key: string]: unknown;
|
||||
}
|
||||
|
||||
export interface AuthtypesOIDCConfigDTO {
|
||||
claimMapping?: AuthtypesAttributeMappingDTO;
|
||||
/**
|
||||
@@ -216,7 +239,10 @@ export interface AuthtypesOIDCConfigDTO {
|
||||
|
||||
export interface AuthtypesObjectDTO {
|
||||
resource: AuthtypesResourceDTO;
|
||||
selector: AuthtypesSelectorDTO;
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
selector: string;
|
||||
}
|
||||
|
||||
export interface AuthtypesOrgSessionContextDTO {
|
||||
@@ -239,6 +265,19 @@ export interface AuthtypesPasswordAuthNSupportDTO {
|
||||
provider?: string;
|
||||
}
|
||||
|
||||
export interface AuthtypesPatchableObjectsDTO {
|
||||
/**
|
||||
* @type array
|
||||
* @nullable true
|
||||
*/
|
||||
additions: AuthtypesGettableObjectsDTO[] | null;
|
||||
/**
|
||||
* @type array
|
||||
* @nullable true
|
||||
*/
|
||||
deletions: AuthtypesGettableObjectsDTO[] | null;
|
||||
}
|
||||
|
||||
export interface AuthtypesPostableAuthDomainDTO {
|
||||
config?: AuthtypesAuthDomainConfigDTO;
|
||||
/**
|
||||
@@ -270,7 +309,10 @@ export interface AuthtypesPostableRotateTokenDTO {
|
||||
}
|
||||
|
||||
export interface AuthtypesResourceDTO {
|
||||
name: AuthtypesNameDTO;
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
name: string;
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
@@ -320,10 +362,6 @@ export interface AuthtypesSamlConfigDTO {
|
||||
samlIdp?: string;
|
||||
}
|
||||
|
||||
export interface AuthtypesSelectorDTO {
|
||||
[key: string]: unknown;
|
||||
}
|
||||
|
||||
export interface AuthtypesSessionContextDTO {
|
||||
/**
|
||||
* @type boolean
|
||||
@@ -337,10 +375,6 @@ export interface AuthtypesSessionContextDTO {
|
||||
}
|
||||
|
||||
export interface AuthtypesTransactionDTO {
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
id?: string;
|
||||
object: AuthtypesObjectDTO;
|
||||
/**
|
||||
* @type string
|
||||
@@ -623,14 +657,14 @@ export interface GatewaytypesLimitMetricValueDTO {
|
||||
export interface GatewaytypesLimitValueDTO {
|
||||
/**
|
||||
* @type integer
|
||||
* @format int64
|
||||
* @nullable true
|
||||
*/
|
||||
count?: number;
|
||||
count?: number | null;
|
||||
/**
|
||||
* @type integer
|
||||
* @format int64
|
||||
* @nullable true
|
||||
*/
|
||||
size?: number;
|
||||
size?: number | null;
|
||||
}
|
||||
|
||||
export interface GatewaytypesPaginationDTO {
|
||||
@@ -1992,39 +2026,6 @@ export interface RenderErrorResponseDTO {
|
||||
status: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* @nullable
|
||||
*/
|
||||
export type RoletypesGettableResourcesDTORelations = {
|
||||
[key: string]: string[];
|
||||
} | null;
|
||||
|
||||
export interface RoletypesGettableResourcesDTO {
|
||||
/**
|
||||
* @type object
|
||||
* @nullable true
|
||||
*/
|
||||
relations: RoletypesGettableResourcesDTORelations;
|
||||
/**
|
||||
* @type array
|
||||
* @nullable true
|
||||
*/
|
||||
resources: AuthtypesResourceDTO[] | null;
|
||||
}
|
||||
|
||||
export interface RoletypesPatchableObjectsDTO {
|
||||
/**
|
||||
* @type array
|
||||
* @nullable true
|
||||
*/
|
||||
additions: AuthtypesObjectDTO[] | null;
|
||||
/**
|
||||
* @type array
|
||||
* @nullable true
|
||||
*/
|
||||
deletions: AuthtypesObjectDTO[] | null;
|
||||
}
|
||||
|
||||
export interface RoletypesPatchableRoleDTO {
|
||||
/**
|
||||
* @type string
|
||||
@@ -2056,7 +2057,7 @@ export interface RoletypesRoleDTO {
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
id?: string;
|
||||
id: string;
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
@@ -2197,7 +2198,7 @@ export interface TypesGettableAPIKeyDTO {
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
id?: string;
|
||||
id: string;
|
||||
/**
|
||||
* @type integer
|
||||
* @format int64
|
||||
@@ -2250,7 +2251,7 @@ export interface TypesIdentifiableDTO {
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
id?: string;
|
||||
id: string;
|
||||
}
|
||||
|
||||
export interface TypesInviteDTO {
|
||||
@@ -2266,7 +2267,7 @@ export interface TypesInviteDTO {
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
id?: string;
|
||||
id: string;
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
@@ -2311,7 +2312,7 @@ export interface TypesOrganizationDTO {
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
id?: string;
|
||||
id: string;
|
||||
/**
|
||||
* @type integer
|
||||
* @minimum 0
|
||||
@@ -2417,7 +2418,7 @@ export interface TypesResetPasswordTokenDTO {
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
id?: string;
|
||||
id: string;
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
@@ -2441,7 +2442,7 @@ export interface TypesStorableAPIKeyDTO {
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
id?: string;
|
||||
id: string;
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
@@ -2490,7 +2491,7 @@ export interface TypesUserDTO {
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
id?: string;
|
||||
id: string;
|
||||
/**
|
||||
* @type boolean
|
||||
*/
|
||||
@@ -2606,6 +2607,14 @@ export type AuthzCheck200 = {
|
||||
status: string;
|
||||
};
|
||||
|
||||
export type AuthzResources200 = {
|
||||
data: AuthtypesGettableResourcesDTO;
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
status: string;
|
||||
};
|
||||
|
||||
export type ChangePasswordPathParameters = {
|
||||
id: string;
|
||||
};
|
||||
@@ -3017,7 +3026,7 @@ export type GetObjects200 = {
|
||||
/**
|
||||
* @type array
|
||||
*/
|
||||
data: AuthtypesObjectDTO[];
|
||||
data: AuthtypesGettableObjectsDTO[];
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
@@ -3028,14 +3037,6 @@ export type PatchObjectsPathParameters = {
|
||||
id: string;
|
||||
relation: string;
|
||||
};
|
||||
export type GetResources200 = {
|
||||
data: RoletypesGettableResourcesDTO;
|
||||
/**
|
||||
* @type string
|
||||
*/
|
||||
status: string;
|
||||
};
|
||||
|
||||
export type ListUsers200 = {
|
||||
/**
|
||||
* @type array
|
||||
@@ -3137,7 +3138,7 @@ export type GetIngestionKeys200 = {
|
||||
status: string;
|
||||
};
|
||||
|
||||
export type CreateIngestionKey200 = {
|
||||
export type CreateIngestionKey201 = {
|
||||
data: GatewaytypesGettableCreatedIngestionKeyDTO;
|
||||
/**
|
||||
* @type string
|
||||
|
||||
@@ -70,9 +70,6 @@
|
||||
padding-left: 0;
|
||||
}
|
||||
transition: background-color 0.2s ease-in;
|
||||
&:hover {
|
||||
background-color: rgba(171, 189, 255, 0.04) !important;
|
||||
}
|
||||
}
|
||||
|
||||
.log-selected-fields {
|
||||
@@ -183,11 +180,6 @@
|
||||
.log-value {
|
||||
color: var(--text-slate-400);
|
||||
}
|
||||
.log-line {
|
||||
&:hover {
|
||||
background-color: var(--text-vanilla-200) !important;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
.dark {
|
||||
|
||||
@@ -49,6 +49,12 @@ export const Container = styled(Card)<{
|
||||
|
||||
${({ $isActiveLog, $isDarkMode, $logType }): string =>
|
||||
getActiveLogBackground($isActiveLog, $isDarkMode, $logType)}
|
||||
}
|
||||
|
||||
&:hover .ant-card-body {
|
||||
${({ $isDarkMode, $logType }): string =>
|
||||
getActiveLogBackground(true, $isDarkMode, $logType)}
|
||||
}
|
||||
`;
|
||||
|
||||
export const LogContainer = styled.div<LogContainerProps>`
|
||||
|
||||
@@ -8,7 +8,6 @@ import styled from 'styled-components';
|
||||
import {
|
||||
getActiveLogBackground,
|
||||
getCustomHighlightBackground,
|
||||
getDefaultLogBackground,
|
||||
} from 'utils/logs';
|
||||
|
||||
import { RawLogContentProps } from './types';
|
||||
@@ -48,7 +47,9 @@ export const RawLogViewContainer = styled(Row)<{
|
||||
${({ $isReadOnly, $isActiveLog, $isDarkMode, $logType }): string =>
|
||||
$isActiveLog
|
||||
? getActiveLogBackground($isActiveLog, $isDarkMode, $logType)
|
||||
: getDefaultLogBackground($isReadOnly, $isDarkMode)}
|
||||
: !$isReadOnly
|
||||
? `&:hover { ${getActiveLogBackground(true, $isDarkMode, $logType)} }`
|
||||
: ''}
|
||||
|
||||
${({ $isHightlightedLog, $isDarkMode }): string =>
|
||||
$isHightlightedLog
|
||||
|
||||
@@ -70,12 +70,8 @@ export const TableRowStyled = styled.tr<{
|
||||
|
||||
&:hover {
|
||||
${TableCellStyled} {
|
||||
${({ $isActiveLog, $isDarkMode }): string =>
|
||||
$isActiveLog
|
||||
? getActiveLogBackground()
|
||||
: `background-color: ${
|
||||
!$isDarkMode ? 'var(--bg-vanilla-200)' : 'rgba(171, 189, 255, 0.04)'
|
||||
}`}
|
||||
${({ $isDarkMode, $logType }): string =>
|
||||
getActiveLogBackground(true, $isDarkMode, $logType)}
|
||||
}
|
||||
.log-line-action-buttons {
|
||||
display: flex;
|
||||
|
||||
@@ -116,7 +116,7 @@ describe('SSOEnforcementToggle', () => {
|
||||
render(
|
||||
<SSOEnforcementToggle
|
||||
isDefaultChecked={true}
|
||||
record={{ ...mockGoogleAuthDomain, id: undefined }}
|
||||
record={{ ...mockGoogleAuthDomain, id: '' }}
|
||||
/>,
|
||||
);
|
||||
|
||||
|
||||
@@ -26,5 +26,22 @@ func (provider *provider) addAuthzRoutes(router *mux.Router) error {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := router.Handle("/api/v1/authz/resources", handler.New(provider.authZ.OpenAccess(provider.authzHandler.GetResources), handler.OpenAPIDef{
|
||||
ID: "AuthzResources",
|
||||
Tags: []string{"authz"},
|
||||
Summary: "Get resources",
|
||||
Description: "Gets all the available resources",
|
||||
Request: nil,
|
||||
RequestContentType: "",
|
||||
Response: new(authtypes.GettableResources),
|
||||
ResponseContentType: "application/json",
|
||||
SuccessStatusCode: http.StatusOK,
|
||||
ErrorStatusCodes: []int{},
|
||||
Deprecated: false,
|
||||
SecuritySchemes: nil,
|
||||
})).Methods(http.MethodGet).GetError(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -55,7 +55,7 @@ func (provider *provider) addGatewayRoutes(router *mux.Router) error {
|
||||
RequestContentType: "application/json",
|
||||
Response: new(gatewaytypes.GettableCreatedIngestionKey),
|
||||
ResponseContentType: "application/json",
|
||||
SuccessStatusCode: http.StatusOK,
|
||||
SuccessStatusCode: http.StatusCreated,
|
||||
ErrorStatusCodes: []int{},
|
||||
Deprecated: false,
|
||||
SecuritySchemes: newSecuritySchemes(types.RoleAdmin),
|
||||
|
||||
@@ -81,7 +81,7 @@ func (provider *provider) addMetricsExplorerRoutes(router *mux.Router) error {
|
||||
Response: new(metricsexplorertypes.MetricAttributesResponse),
|
||||
ResponseContentType: "application/json",
|
||||
SuccessStatusCode: http.StatusOK,
|
||||
ErrorStatusCodes: []int{http.StatusBadRequest, http.StatusUnauthorized, http.StatusInternalServerError},
|
||||
ErrorStatusCodes: []int{http.StatusBadRequest, http.StatusUnauthorized, http.StatusNotFound, http.StatusInternalServerError},
|
||||
Deprecated: false,
|
||||
SecuritySchemes: newSecuritySchemes(types.RoleViewer),
|
||||
})).Methods(http.MethodGet).GetError(); err != nil {
|
||||
@@ -138,7 +138,7 @@ func (provider *provider) addMetricsExplorerRoutes(router *mux.Router) error {
|
||||
Response: new(metricsexplorertypes.MetricHighlightsResponse),
|
||||
ResponseContentType: "application/json",
|
||||
SuccessStatusCode: http.StatusOK,
|
||||
ErrorStatusCodes: []int{http.StatusBadRequest, http.StatusUnauthorized, http.StatusInternalServerError},
|
||||
ErrorStatusCodes: []int{http.StatusBadRequest, http.StatusUnauthorized, http.StatusNotFound, http.StatusInternalServerError},
|
||||
Deprecated: false,
|
||||
SecuritySchemes: newSecuritySchemes(types.RoleViewer),
|
||||
})).Methods(http.MethodGet).GetError(); err != nil {
|
||||
@@ -157,7 +157,7 @@ func (provider *provider) addMetricsExplorerRoutes(router *mux.Router) error {
|
||||
Response: new(metricsexplorertypes.MetricAlertsResponse),
|
||||
ResponseContentType: "application/json",
|
||||
SuccessStatusCode: http.StatusOK,
|
||||
ErrorStatusCodes: []int{http.StatusBadRequest, http.StatusUnauthorized, http.StatusInternalServerError},
|
||||
ErrorStatusCodes: []int{http.StatusBadRequest, http.StatusUnauthorized, http.StatusNotFound, http.StatusInternalServerError},
|
||||
Deprecated: false,
|
||||
SecuritySchemes: newSecuritySchemes(types.RoleViewer),
|
||||
})).Methods(http.MethodGet).GetError(); err != nil {
|
||||
@@ -176,7 +176,7 @@ func (provider *provider) addMetricsExplorerRoutes(router *mux.Router) error {
|
||||
Response: new(metricsexplorertypes.MetricDashboardsResponse),
|
||||
ResponseContentType: "application/json",
|
||||
SuccessStatusCode: http.StatusOK,
|
||||
ErrorStatusCodes: []int{http.StatusBadRequest, http.StatusUnauthorized, http.StatusInternalServerError},
|
||||
ErrorStatusCodes: []int{http.StatusBadRequest, http.StatusUnauthorized, http.StatusNotFound, http.StatusInternalServerError},
|
||||
Deprecated: false,
|
||||
SecuritySchemes: newSecuritySchemes(types.RoleViewer),
|
||||
})).Methods(http.MethodGet).GetError(); err != nil {
|
||||
|
||||
@@ -45,23 +45,6 @@ func (provider *provider) addRoleRoutes(router *mux.Router) error {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := router.Handle("/api/v1/roles/resources", handler.New(provider.authZ.AdminAccess(provider.authzHandler.GetResources), handler.OpenAPIDef{
|
||||
ID: "GetResources",
|
||||
Tags: []string{"role"},
|
||||
Summary: "Get resources",
|
||||
Description: "Gets all the available resources for role assignment",
|
||||
Request: nil,
|
||||
RequestContentType: "",
|
||||
Response: new(roletypes.GettableResources),
|
||||
ResponseContentType: "application/json",
|
||||
SuccessStatusCode: http.StatusOK,
|
||||
ErrorStatusCodes: []int{},
|
||||
Deprecated: false,
|
||||
SecuritySchemes: newSecuritySchemes(types.RoleAdmin),
|
||||
})).Methods(http.MethodGet).GetError(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if err := router.Handle("/api/v1/roles/{id}", handler.New(provider.authZ.AdminAccess(provider.authzHandler.Get), handler.OpenAPIDef{
|
||||
ID: "GetRole",
|
||||
Tags: []string{"role"},
|
||||
@@ -86,7 +69,7 @@ func (provider *provider) addRoleRoutes(router *mux.Router) error {
|
||||
Description: "Gets all objects connected to the specified role via a given relation type",
|
||||
Request: nil,
|
||||
RequestContentType: "",
|
||||
Response: make([]*authtypes.Object, 0),
|
||||
Response: make([]*authtypes.GettableObjects, 0),
|
||||
ResponseContentType: "application/json",
|
||||
SuccessStatusCode: http.StatusOK,
|
||||
ErrorStatusCodes: []int{http.StatusNotFound, http.StatusNotImplemented, http.StatusUnavailableForLegalReasons},
|
||||
@@ -118,7 +101,7 @@ func (provider *provider) addRoleRoutes(router *mux.Router) error {
|
||||
Tags: []string{"role"},
|
||||
Summary: "Patch objects for a role by relation",
|
||||
Description: "Patches the objects connected to the specified role via a given relation type",
|
||||
Request: new(roletypes.PatchableObjects),
|
||||
Request: new(authtypes.PatchableObjects),
|
||||
RequestContentType: "",
|
||||
Response: nil,
|
||||
ResponseContentType: "application/json",
|
||||
|
||||
@@ -190,7 +190,7 @@ func (provider *provider) GetOrCreate(_ context.Context, _ valuer.UUID, _ *rolet
|
||||
}
|
||||
|
||||
func (provider *provider) GetResources(_ context.Context) []*authtypes.Resource {
|
||||
return nil
|
||||
return []*authtypes.Resource{}
|
||||
}
|
||||
|
||||
func (provider *provider) GetObjects(ctx context.Context, orgID valuer.UUID, id valuer.UUID, relation authtypes.Relation) ([]*authtypes.Object, error) {
|
||||
|
||||
@@ -110,13 +110,13 @@ func (handler *handler) GetObjects(rw http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
render.Success(rw, http.StatusOK, objects)
|
||||
render.Success(rw, http.StatusOK, authtypes.NewGettableObjects(objects))
|
||||
}
|
||||
|
||||
func (handler *handler) GetResources(rw http.ResponseWriter, r *http.Request) {
|
||||
resources := handler.authz.GetResources(r.Context())
|
||||
|
||||
render.Success(rw, http.StatusOK, roletypes.NewGettableResources(resources))
|
||||
render.Success(rw, http.StatusOK, authtypes.NewGettableResources(resources))
|
||||
}
|
||||
|
||||
func (handler *handler) List(rw http.ResponseWriter, r *http.Request) {
|
||||
@@ -197,25 +197,30 @@ func (handler *handler) PatchObjects(rw http.ResponseWriter, r *http.Request) {
|
||||
return
|
||||
}
|
||||
|
||||
req := new(roletypes.PatchableObjects)
|
||||
if err := binding.JSON.BindBody(r.Body, req); err != nil {
|
||||
render.Error(rw, err)
|
||||
return
|
||||
}
|
||||
|
||||
role, err := handler.authz.Get(ctx, valuer.MustNewUUID(claims.OrgID), id)
|
||||
if err != nil {
|
||||
render.Error(rw, err)
|
||||
return
|
||||
}
|
||||
|
||||
patchableObjects, err := role.NewPatchableObjects(req.Additions, req.Deletions, relation)
|
||||
if err := role.ErrIfManaged(); err != nil {
|
||||
render.Error(rw, err)
|
||||
return
|
||||
}
|
||||
|
||||
req := new(authtypes.PatchableObjects)
|
||||
if err := binding.JSON.BindBody(r.Body, req); err != nil {
|
||||
render.Error(rw, err)
|
||||
return
|
||||
}
|
||||
|
||||
additions, deletions, err := authtypes.NewPatchableObjects(req.Additions, req.Deletions, relation)
|
||||
if err != nil {
|
||||
render.Error(rw, err)
|
||||
return
|
||||
}
|
||||
|
||||
err = handler.authz.PatchObjects(ctx, valuer.MustNewUUID(claims.OrgID), role.Name, relation, patchableObjects.Additions, patchableObjects.Deletions)
|
||||
err = handler.authz.PatchObjects(ctx, valuer.MustNewUUID(claims.OrgID), role.Name, relation, additions, deletions)
|
||||
if err != nil {
|
||||
render.Error(rw, err)
|
||||
return
|
||||
|
||||
@@ -122,7 +122,7 @@ func (handler *handler) CreateIngestionKey(rw http.ResponseWriter, r *http.Reque
|
||||
return
|
||||
}
|
||||
|
||||
render.Success(rw, http.StatusOK, response)
|
||||
render.Success(rw, http.StatusCreated, response)
|
||||
}
|
||||
|
||||
func (handler *handler) UpdateIngestionKey(rw http.ResponseWriter, r *http.Request) {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package implmetricsexplorer
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
|
||||
"github.com/SigNoz/signoz/pkg/errors"
|
||||
@@ -187,6 +188,12 @@ func (h *handler) GetMetricAlerts(rw http.ResponseWriter, req *http.Request) {
|
||||
}
|
||||
|
||||
orgID := valuer.MustNewUUID(claims.OrgID)
|
||||
|
||||
if err := h.checkMetricExists(req.Context(), orgID, metricName); err != nil {
|
||||
render.Error(rw, err)
|
||||
return
|
||||
}
|
||||
|
||||
out, err := h.module.GetMetricAlerts(req.Context(), orgID, metricName)
|
||||
if err != nil {
|
||||
render.Error(rw, err)
|
||||
@@ -209,6 +216,12 @@ func (h *handler) GetMetricDashboards(rw http.ResponseWriter, req *http.Request)
|
||||
}
|
||||
|
||||
orgID := valuer.MustNewUUID(claims.OrgID)
|
||||
|
||||
if err := h.checkMetricExists(req.Context(), orgID, metricName); err != nil {
|
||||
render.Error(rw, err)
|
||||
return
|
||||
}
|
||||
|
||||
out, err := h.module.GetMetricDashboards(req.Context(), orgID, metricName)
|
||||
if err != nil {
|
||||
render.Error(rw, err)
|
||||
@@ -231,6 +244,12 @@ func (h *handler) GetMetricHighlights(rw http.ResponseWriter, req *http.Request)
|
||||
}
|
||||
|
||||
orgID := valuer.MustNewUUID(claims.OrgID)
|
||||
|
||||
if err := h.checkMetricExists(req.Context(), orgID, metricName); err != nil {
|
||||
render.Error(rw, err)
|
||||
return
|
||||
}
|
||||
|
||||
highlights, err := h.module.GetMetricHighlights(req.Context(), orgID, metricName)
|
||||
if err != nil {
|
||||
render.Error(rw, err)
|
||||
@@ -266,6 +285,12 @@ func (h *handler) GetMetricAttributes(rw http.ResponseWriter, req *http.Request)
|
||||
}
|
||||
|
||||
orgID := valuer.MustNewUUID(claims.OrgID)
|
||||
|
||||
if err := h.checkMetricExists(req.Context(), orgID, metricName); err != nil {
|
||||
render.Error(rw, err)
|
||||
return
|
||||
}
|
||||
|
||||
out, err := h.module.GetMetricAttributes(req.Context(), orgID, &in)
|
||||
if err != nil {
|
||||
render.Error(rw, err)
|
||||
@@ -274,3 +299,14 @@ func (h *handler) GetMetricAttributes(rw http.ResponseWriter, req *http.Request)
|
||||
|
||||
render.Success(rw, http.StatusOK, out)
|
||||
}
|
||||
|
||||
func (h *handler) checkMetricExists(ctx context.Context, orgID valuer.UUID, metricName string) error {
|
||||
exists, err := h.module.CheckMetricExists(ctx, orgID, metricName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !exists {
|
||||
return errors.NewNotFoundf(errors.CodeNotFound, "metric not found: %q", metricName)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -404,6 +404,26 @@ func (m *module) GetMetricAttributes(ctx context.Context, orgID valuer.UUID, req
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (m *module) CheckMetricExists(ctx context.Context, orgID valuer.UUID, metricName string) (bool, error) {
|
||||
sb := sqlbuilder.NewSelectBuilder()
|
||||
sb.Select("count(*) > 0 as metricExists")
|
||||
sb.From(fmt.Sprintf("%s.%s", telemetrymetrics.DBName, telemetrymetrics.AttributesMetadataTableName))
|
||||
sb.Where(sb.E("metric_name", metricName))
|
||||
|
||||
query, args := sb.BuildWithFlavor(sqlbuilder.ClickHouse)
|
||||
|
||||
db := m.telemetryStore.ClickhouseDB()
|
||||
var exists bool
|
||||
valueCtx := ctxtypes.SetClickhouseMaxThreads(ctx, m.config.TelemetryStore.Threads)
|
||||
|
||||
err := db.QueryRow(valueCtx, query, args...).Scan(&exists)
|
||||
if err != nil {
|
||||
return false, errors.WrapInternalf(err, errors.CodeInternal, "failed to check if metric exists")
|
||||
}
|
||||
|
||||
return exists, nil
|
||||
}
|
||||
|
||||
func (m *module) fetchMetadataFromCache(ctx context.Context, orgID valuer.UUID, metricNames []string) (map[string]*metricsexplorertypes.MetricMetadata, []string) {
|
||||
hits := make(map[string]*metricsexplorertypes.MetricMetadata)
|
||||
misses := make([]string, 0)
|
||||
|
||||
@@ -23,6 +23,7 @@ type Handler interface {
|
||||
|
||||
// Module represents the metrics module interface.
|
||||
type Module interface {
|
||||
CheckMetricExists(ctx context.Context, orgID valuer.UUID, metricName string) (bool, error)
|
||||
ListMetrics(ctx context.Context, orgID valuer.UUID, params *metricsexplorertypes.ListMetricsParams) (*metricsexplorertypes.ListMetricsResponse, error)
|
||||
GetStats(ctx context.Context, orgID valuer.UUID, req *metricsexplorertypes.StatsRequest) (*metricsexplorertypes.StatsResponse, error)
|
||||
GetTreemap(ctx context.Context, orgID valuer.UUID, req *metricsexplorertypes.TreemapRequest) (*metricsexplorertypes.TreemapResponse, error)
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package authtypes
|
||||
|
||||
import (
|
||||
"encoding"
|
||||
"encoding/json"
|
||||
"regexp"
|
||||
|
||||
@@ -10,8 +11,10 @@ import (
|
||||
var (
|
||||
nameRegex = regexp.MustCompile("^[a-z-]{1,50}$")
|
||||
|
||||
_ json.Marshaler = new(Name)
|
||||
_ json.Unmarshaler = new(Name)
|
||||
_ json.Marshaler = new(Name)
|
||||
_ json.Unmarshaler = new(Name)
|
||||
_ encoding.TextMarshaler = new(Name)
|
||||
_ encoding.TextUnmarshaler = new(Name)
|
||||
)
|
||||
|
||||
type Name struct {
|
||||
@@ -58,3 +61,16 @@ func (name *Name) UnmarshalJSON(data []byte) error {
|
||||
*name = shadow
|
||||
return nil
|
||||
}
|
||||
|
||||
func (name Name) MarshalText() ([]byte, error) {
|
||||
return []byte(name.val), nil
|
||||
}
|
||||
|
||||
func (name *Name) UnmarshalText(text []byte) error {
|
||||
shadow, err := NewName(string(text))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
*name = shadow
|
||||
return nil
|
||||
}
|
||||
|
||||
177
pkg/types/authtypes/object.go
Normal file
177
pkg/types/authtypes/object.go
Normal file
@@ -0,0 +1,177 @@
|
||||
package authtypes
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"slices"
|
||||
"strings"
|
||||
|
||||
"github.com/SigNoz/signoz/pkg/errors"
|
||||
)
|
||||
|
||||
type Resource struct {
|
||||
Name Name `json:"name" required:"true"`
|
||||
Type Type `json:"type" required:"true"`
|
||||
}
|
||||
|
||||
type GettableResources struct {
|
||||
Resources []*Resource `json:"resources" required:"true" nullable:"false"`
|
||||
Relations map[Relation][]Type `json:"relations" required:"true"`
|
||||
}
|
||||
|
||||
type Object struct {
|
||||
Resource Resource `json:"resource" required:"true"`
|
||||
Selector Selector `json:"selector" required:"true"`
|
||||
}
|
||||
|
||||
type GettableObjects struct {
|
||||
Resource Resource `json:"resource" required:"true"`
|
||||
Selectors []Selector `json:"selectors" required:"true" nullable:"false"`
|
||||
}
|
||||
|
||||
type PatchableObjects struct {
|
||||
Additions []*GettableObjects `json:"additions" required:"true" nullable:"true"`
|
||||
Deletions []*GettableObjects `json:"deletions" required:"true" nullable:"true"`
|
||||
}
|
||||
|
||||
func NewObject(resource Resource, selector Selector) (*Object, error) {
|
||||
err := IsValidSelector(resource.Type, selector.String())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &Object{Resource: resource, Selector: selector}, nil
|
||||
}
|
||||
|
||||
func NewObjectsFromGettableObjects(patchableObjects []*GettableObjects) ([]*Object, error) {
|
||||
objects := make([]*Object, 0)
|
||||
|
||||
for _, patchObject := range patchableObjects {
|
||||
for _, selector := range patchObject.Selectors {
|
||||
object, err := NewObject(patchObject.Resource, selector)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
objects = append(objects, object)
|
||||
}
|
||||
}
|
||||
|
||||
return objects, nil
|
||||
}
|
||||
|
||||
func NewPatchableObjects(additions []*GettableObjects, deletions []*GettableObjects, relation Relation) ([]*Object, []*Object, error) {
|
||||
if len(additions) == 0 && len(deletions) == 0 {
|
||||
return nil, nil, errors.New(errors.TypeInvalidInput, ErrCodeInvalidPatchObject, "empty object patch request received, at least one of additions or deletions must be present")
|
||||
}
|
||||
|
||||
for _, object := range additions {
|
||||
if !slices.Contains(TypeableRelations[object.Resource.Type], relation) {
|
||||
return nil, nil, errors.Newf(errors.TypeInvalidInput, ErrCodeAuthZInvalidRelation, "relation %s is invalid for type %s", relation.StringValue(), object.Resource.Type.StringValue())
|
||||
}
|
||||
}
|
||||
|
||||
for _, object := range deletions {
|
||||
if !slices.Contains(TypeableRelations[object.Resource.Type], relation) {
|
||||
return nil, nil, errors.Newf(errors.TypeInvalidInput, ErrCodeAuthZInvalidRelation, "relation %s is invalid for type %s", relation.StringValue(), object.Resource.Type.StringValue())
|
||||
}
|
||||
}
|
||||
|
||||
additionObjects, err := NewObjectsFromGettableObjects(additions)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
deletionsObjects, err := NewObjectsFromGettableObjects(deletions)
|
||||
if err != nil {
|
||||
return nil, nil, err
|
||||
}
|
||||
|
||||
return additionObjects, deletionsObjects, nil
|
||||
}
|
||||
|
||||
func NewGettableResources(resources []*Resource) *GettableResources {
|
||||
return &GettableResources{
|
||||
Resources: resources,
|
||||
Relations: RelationsTypeable,
|
||||
}
|
||||
}
|
||||
|
||||
func NewGettableObjects(objects []*Object) []*GettableObjects {
|
||||
grouped := make(map[Resource][]Selector)
|
||||
for _, obj := range objects {
|
||||
key := obj.Resource
|
||||
if _, ok := grouped[key]; !ok {
|
||||
grouped[key] = make([]Selector, 0)
|
||||
}
|
||||
|
||||
grouped[key] = append(grouped[key], obj.Selector)
|
||||
}
|
||||
|
||||
gettableObjects := make([]*GettableObjects, 0, len(grouped))
|
||||
for resource, selectors := range grouped {
|
||||
gettableObjects = append(gettableObjects, &GettableObjects{
|
||||
Resource: resource,
|
||||
Selectors: selectors,
|
||||
})
|
||||
}
|
||||
|
||||
return gettableObjects
|
||||
}
|
||||
|
||||
func MustNewObject(resource Resource, selector Selector) *Object {
|
||||
object, err := NewObject(resource, selector)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return object
|
||||
}
|
||||
|
||||
func MustNewObjectFromString(input string) *Object {
|
||||
parts := strings.Split(input, "/")
|
||||
if len(parts) != 4 {
|
||||
panic(errors.Newf(errors.TypeInternal, errors.CodeInternal, "invalid input format: %s", input))
|
||||
}
|
||||
|
||||
typeParts := strings.Split(parts[0], ":")
|
||||
if len(typeParts) != 2 {
|
||||
panic(errors.Newf(errors.TypeInternal, errors.CodeInternal, "invalid type format: %s", parts[0]))
|
||||
}
|
||||
|
||||
resource := Resource{
|
||||
Type: MustNewType(typeParts[0]),
|
||||
Name: MustNewName(parts[2]),
|
||||
}
|
||||
|
||||
selector := MustNewSelector(resource.Type, parts[3])
|
||||
|
||||
return &Object{Resource: resource, Selector: selector}
|
||||
}
|
||||
|
||||
func MustNewObjectsFromStringSlice(input []string) []*Object {
|
||||
objects := make([]*Object, 0, len(input))
|
||||
for _, str := range input {
|
||||
objects = append(objects, MustNewObjectFromString(str))
|
||||
}
|
||||
return objects
|
||||
}
|
||||
|
||||
func (object *Object) UnmarshalJSON(data []byte) error {
|
||||
var shadow = struct {
|
||||
Resource Resource
|
||||
Selector Selector
|
||||
}{}
|
||||
|
||||
err := json.Unmarshal(data, &shadow)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
obj, err := NewObject(shadow.Resource, shadow.Selector)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
*object = *obj
|
||||
return nil
|
||||
}
|
||||
@@ -7,6 +7,7 @@ import (
|
||||
|
||||
var (
|
||||
ErrCodeAuthZInvalidRelation = errors.MustNewCode("authz_invalid_relation")
|
||||
ErrCodeInvalidPatchObject = errors.MustNewCode("authz_invalid_patch_objects")
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -26,6 +27,14 @@ var TypeableRelations = map[Type][]Relation{
|
||||
TypeMetaResources: {RelationCreate, RelationList},
|
||||
}
|
||||
|
||||
var RelationsTypeable = map[Relation][]Type{
|
||||
RelationCreate: {TypeMetaResources},
|
||||
RelationRead: {TypeUser, TypeRole, TypeOrganization, TypeMetaResource},
|
||||
RelationList: {TypeMetaResources},
|
||||
RelationUpdate: {TypeUser, TypeRole, TypeOrganization, TypeMetaResource},
|
||||
RelationDelete: {TypeUser, TypeRole, TypeOrganization, TypeMetaResource},
|
||||
}
|
||||
|
||||
type Relation struct{ valuer.String }
|
||||
|
||||
func NewRelation(relation string) (Relation, error) {
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
package authtypes
|
||||
|
||||
import (
|
||||
"encoding"
|
||||
"encoding/json"
|
||||
"net/http"
|
||||
"regexp"
|
||||
@@ -15,8 +16,10 @@ var (
|
||||
)
|
||||
|
||||
var (
|
||||
_ json.Marshaler = new(Selector)
|
||||
_ json.Unmarshaler = new(Selector)
|
||||
_ json.Marshaler = new(Selector)
|
||||
_ json.Unmarshaler = new(Selector)
|
||||
_ encoding.TextMarshaler = new(Selector)
|
||||
_ encoding.TextUnmarshaler = new(Selector)
|
||||
)
|
||||
|
||||
var (
|
||||
@@ -79,6 +82,15 @@ func (typed *Selector) UnmarshalJSON(data []byte) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (selector Selector) MarshalText() ([]byte, error) {
|
||||
return []byte(selector.val), nil
|
||||
}
|
||||
|
||||
func (selector *Selector) UnmarshalText(text []byte) error {
|
||||
*selector = Selector{val: string(text)}
|
||||
return nil
|
||||
}
|
||||
|
||||
func IsValidSelector(typed Type, selector string) error {
|
||||
switch typed {
|
||||
case TypeUser:
|
||||
|
||||
@@ -3,24 +3,13 @@ package authtypes
|
||||
import (
|
||||
"encoding/json"
|
||||
"slices"
|
||||
"strings"
|
||||
|
||||
"github.com/SigNoz/signoz/pkg/errors"
|
||||
"github.com/SigNoz/signoz/pkg/valuer"
|
||||
)
|
||||
|
||||
type Resource struct {
|
||||
Name Name `json:"name" required:"true"`
|
||||
Type Type `json:"type" required:"true"`
|
||||
}
|
||||
|
||||
type Object struct {
|
||||
Resource Resource `json:"resource" required:"true"`
|
||||
Selector Selector `json:"selector" required:"true"`
|
||||
}
|
||||
|
||||
type Transaction struct {
|
||||
ID valuer.UUID `json:"id"`
|
||||
ID valuer.UUID `json:"-"`
|
||||
Relation Relation `json:"relation" required:"true"`
|
||||
Object Object `json:"object" required:"true"`
|
||||
}
|
||||
@@ -31,53 +20,6 @@ type GettableTransaction struct {
|
||||
Authorized bool `json:"authorized" required:"true"`
|
||||
}
|
||||
|
||||
func NewObject(resource Resource, selector Selector) (*Object, error) {
|
||||
err := IsValidSelector(resource.Type, selector.val)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &Object{Resource: resource, Selector: selector}, nil
|
||||
}
|
||||
|
||||
func MustNewObject(resource Resource, selector Selector) *Object {
|
||||
object, err := NewObject(resource, selector)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
return object
|
||||
}
|
||||
|
||||
func MustNewObjectFromString(input string) *Object {
|
||||
parts := strings.Split(input, "/")
|
||||
if len(parts) != 4 {
|
||||
panic(errors.Newf(errors.TypeInternal, errors.CodeInternal, "invalid input format: %s", input))
|
||||
}
|
||||
|
||||
typeParts := strings.Split(parts[0], ":")
|
||||
if len(typeParts) != 2 {
|
||||
panic(errors.Newf(errors.TypeInternal, errors.CodeInternal, "invalid type format: %s", parts[0]))
|
||||
}
|
||||
|
||||
resource := Resource{
|
||||
Type: MustNewType(typeParts[0]),
|
||||
Name: MustNewName(parts[2]),
|
||||
}
|
||||
|
||||
selector := MustNewSelector(resource.Type, parts[3])
|
||||
|
||||
return &Object{Resource: resource, Selector: selector}
|
||||
}
|
||||
|
||||
func MustNewObjectsFromStringSlice(input []string) []*Object {
|
||||
objects := make([]*Object, 0, len(input))
|
||||
for _, str := range input {
|
||||
objects = append(objects, MustNewObjectFromString(str))
|
||||
}
|
||||
return objects
|
||||
}
|
||||
|
||||
func NewTransaction(relation Relation, object Object) (*Transaction, error) {
|
||||
if !slices.Contains(TypeableRelations[object.Resource.Type], relation) {
|
||||
return nil, errors.Newf(errors.TypeInvalidInput, ErrCodeAuthZInvalidRelation, "invalid relation %s for type %s", relation.StringValue(), object.Resource.Type.StringValue())
|
||||
@@ -100,26 +42,6 @@ func NewGettableTransaction(transactions []*Transaction, results map[string]*Tup
|
||||
return gettableTransactions
|
||||
}
|
||||
|
||||
func (object *Object) UnmarshalJSON(data []byte) error {
|
||||
var shadow = struct {
|
||||
Resource Resource
|
||||
Selector Selector
|
||||
}{}
|
||||
|
||||
err := json.Unmarshal(data, &shadow)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
obj, err := NewObject(shadow.Resource, shadow.Selector)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
*object = *obj
|
||||
return nil
|
||||
}
|
||||
|
||||
func (transaction *Transaction) UnmarshalJSON(data []byte) error {
|
||||
var shadow = struct {
|
||||
Relation Relation
|
||||
|
||||
@@ -33,8 +33,8 @@ type LimitConfig struct {
|
||||
}
|
||||
|
||||
type LimitValue struct {
|
||||
Size int64 `json:"size"`
|
||||
Count int64 `json:"count"`
|
||||
Size *int64 `json:"size,omitempty"`
|
||||
Count *int64 `json:"count,omitempty"`
|
||||
}
|
||||
|
||||
type LimitMetric struct {
|
||||
|
||||
@@ -5,5 +5,5 @@ import (
|
||||
)
|
||||
|
||||
type Identifiable struct {
|
||||
ID valuer.UUID `json:"id" bun:"id,pk,type:text"`
|
||||
ID valuer.UUID `json:"id" bun:"id,pk,type:text" required:"true"`
|
||||
}
|
||||
|
||||
@@ -3,7 +3,6 @@ package roletypes
|
||||
import (
|
||||
"encoding/json"
|
||||
"regexp"
|
||||
"slices"
|
||||
"time"
|
||||
|
||||
"github.com/SigNoz/signoz/pkg/errors"
|
||||
@@ -84,16 +83,6 @@ type PatchableRole struct {
|
||||
Description string `json:"description" required:"true"`
|
||||
}
|
||||
|
||||
type PatchableObjects struct {
|
||||
Additions []*authtypes.Object `json:"additions" required:"true"`
|
||||
Deletions []*authtypes.Object `json:"deletions" required:"true"`
|
||||
}
|
||||
|
||||
type GettableResources struct {
|
||||
Resources []*authtypes.Resource `json:"resources" required:"true"`
|
||||
Relations map[authtypes.Type][]authtypes.Relation `json:"relations" required:"true"`
|
||||
}
|
||||
|
||||
func NewStorableRoleFromRole(role *Role) *StorableRole {
|
||||
return &StorableRole{
|
||||
Identifiable: role.Identifiable,
|
||||
@@ -142,15 +131,8 @@ func NewManagedRoles(orgID valuer.UUID) []*Role {
|
||||
|
||||
}
|
||||
|
||||
func NewGettableResources(resources []*authtypes.Resource) *GettableResources {
|
||||
return &GettableResources{
|
||||
Resources: resources,
|
||||
Relations: authtypes.TypeableRelations,
|
||||
}
|
||||
}
|
||||
|
||||
func (role *Role) PatchMetadata(description string) error {
|
||||
err := role.CanEditDelete()
|
||||
err := role.ErrIfManaged()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
@@ -160,32 +142,7 @@ func (role *Role) PatchMetadata(description string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (role *Role) NewPatchableObjects(additions []*authtypes.Object, deletions []*authtypes.Object, relation authtypes.Relation) (*PatchableObjects, error) {
|
||||
err := role.CanEditDelete()
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if len(additions) == 0 && len(deletions) == 0 {
|
||||
return nil, errors.New(errors.TypeInvalidInput, ErrCodeRoleEmptyPatch, "empty object patch request received, at least one of additions or deletions must be present")
|
||||
}
|
||||
|
||||
for _, object := range additions {
|
||||
if !slices.Contains(authtypes.TypeableRelations[object.Resource.Type], relation) {
|
||||
return nil, errors.Newf(errors.TypeInvalidInput, authtypes.ErrCodeAuthZInvalidRelation, "relation %s is invalid for type %s", relation.StringValue(), object.Resource.Type.StringValue())
|
||||
}
|
||||
}
|
||||
|
||||
for _, object := range deletions {
|
||||
if !slices.Contains(authtypes.TypeableRelations[object.Resource.Type], relation) {
|
||||
return nil, errors.Newf(errors.TypeInvalidInput, authtypes.ErrCodeAuthZInvalidRelation, "relation %s is invalid for type %s", relation.StringValue(), object.Resource.Type.StringValue())
|
||||
}
|
||||
}
|
||||
|
||||
return &PatchableObjects{Additions: additions, Deletions: deletions}, nil
|
||||
}
|
||||
|
||||
func (role *Role) CanEditDelete() error {
|
||||
func (role *Role) ErrIfManaged() error {
|
||||
if role.Type == RoleTypeManaged {
|
||||
return errors.Newf(errors.TypeInvalidInput, ErrCodeRoleInvalidInput, "cannot edit/delete managed role: %s", role.Name)
|
||||
}
|
||||
|
||||
48
tests/integration/fixtures/gatewayutils.py
Normal file
48
tests/integration/fixtures/gatewayutils.py
Normal file
@@ -0,0 +1,48 @@
|
||||
import json
|
||||
from typing import Optional
|
||||
|
||||
import requests
|
||||
from wiremock.client import WireMockMatchers
|
||||
|
||||
from fixtures import types
|
||||
|
||||
TEST_KEY_ID = "test-key-id-001"
|
||||
TEST_LIMIT_ID = "test-limit-id-001"
|
||||
|
||||
|
||||
def common_gateway_headers():
|
||||
"""Common headers expected on requests forwarded to the gateway."""
|
||||
return {
|
||||
"X-Signoz-Cloud-Api-Key": {WireMockMatchers.EQUAL_TO: "secret-key"},
|
||||
"X-Consumer-Username": {
|
||||
WireMockMatchers.EQUAL_TO: "lid:00000000-0000-0000-0000-000000000000"
|
||||
},
|
||||
"X-Consumer-Groups": {WireMockMatchers.EQUAL_TO: "ns:default"},
|
||||
}
|
||||
|
||||
|
||||
def get_gateway_requests(signoz: types.SigNoz, method: str, url: str) -> list:
|
||||
"""Return captured requests from the WireMock gateway journal.
|
||||
|
||||
Returns an empty list when no requests match or the admin API is unreachable.
|
||||
"""
|
||||
response = requests.post(
|
||||
signoz.gateway.host_configs["8080"].get("/__admin/requests/find"),
|
||||
json={"method": method, "url": url},
|
||||
timeout=5,
|
||||
)
|
||||
return response.json().get("requests", [])
|
||||
|
||||
|
||||
def get_latest_gateway_request_body(
|
||||
signoz: types.SigNoz, method: str, url: str
|
||||
) -> Optional[dict]:
|
||||
"""Return the parsed JSON body of the most recent matching gateway request.
|
||||
|
||||
WireMock returns requests in reverse chronological order, so ``matched[0]``
|
||||
is always the latest. Returns ``None`` when no matching request is found.
|
||||
"""
|
||||
matched = get_gateway_requests(signoz, method, url)
|
||||
if not matched:
|
||||
return None
|
||||
return json.loads(matched[0]["body"])
|
||||
424
tests/integration/src/ingestionkeys/01_ingestion_keys.py
Normal file
424
tests/integration/src/ingestionkeys/01_ingestion_keys.py
Normal file
@@ -0,0 +1,424 @@
|
||||
from http import HTTPStatus
|
||||
from typing import Callable, List
|
||||
|
||||
import requests
|
||||
from wiremock.client import (
|
||||
HttpMethods,
|
||||
Mapping,
|
||||
MappingRequest,
|
||||
MappingResponse,
|
||||
)
|
||||
|
||||
from fixtures import types
|
||||
from fixtures.auth import USER_ADMIN_EMAIL, USER_ADMIN_PASSWORD, add_license
|
||||
from fixtures.gatewayutils import (
|
||||
TEST_KEY_ID,
|
||||
common_gateway_headers,
|
||||
get_gateway_requests,
|
||||
get_latest_gateway_request_body,
|
||||
)
|
||||
from fixtures.logger import setup_logger
|
||||
|
||||
logger = setup_logger(__name__)
|
||||
|
||||
|
||||
def test_apply_license(
|
||||
signoz: types.SigNoz,
|
||||
create_user_admin: types.Operation, # pylint: disable=unused-argument
|
||||
make_http_mocks: Callable[[types.TestContainerDocker, List[Mapping]], None],
|
||||
get_token: Callable[[str, str], str],
|
||||
) -> None:
|
||||
"""Activate a license so that all subsequent gateway calls succeed."""
|
||||
add_license(signoz, make_http_mocks, get_token)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Ingestion key CRUD
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
def test_create_ingestion_key(
|
||||
signoz: types.SigNoz,
|
||||
create_user_admin: types.Operation, # pylint: disable=unused-argument
|
||||
make_http_mocks: Callable[[types.TestContainerDocker, list], None],
|
||||
get_token: Callable[[str, str], str],
|
||||
) -> None:
|
||||
"""POST /api/v2/gateway/ingestion_keys creates a key via the gateway."""
|
||||
admin_token = get_token(USER_ADMIN_EMAIL, USER_ADMIN_PASSWORD)
|
||||
|
||||
make_http_mocks(
|
||||
signoz.gateway,
|
||||
[
|
||||
Mapping(
|
||||
request=MappingRequest(
|
||||
method=HttpMethods.POST,
|
||||
url="/v1/workspaces/me/keys",
|
||||
headers=common_gateway_headers(),
|
||||
),
|
||||
response=MappingResponse(
|
||||
status=201,
|
||||
json_body={
|
||||
"status": "success",
|
||||
"data": {
|
||||
"id": TEST_KEY_ID,
|
||||
"value": "ingestion-key-secret-value",
|
||||
},
|
||||
},
|
||||
),
|
||||
persistent=False,
|
||||
),
|
||||
],
|
||||
)
|
||||
|
||||
response = requests.post(
|
||||
signoz.self.host_configs["8080"].get("/api/v2/gateway/ingestion_keys"),
|
||||
json={
|
||||
"name": "my-test-key",
|
||||
"tags": ["env:test", "team:platform"],
|
||||
"expires_at": "2030-01-01T00:00:00Z",
|
||||
},
|
||||
headers={"Authorization": f"Bearer {admin_token}"},
|
||||
timeout=10,
|
||||
)
|
||||
|
||||
assert (
|
||||
response.status_code == HTTPStatus.CREATED
|
||||
), f"Expected 201, got {response.status_code}: {response.text}"
|
||||
|
||||
data = response.json()["data"]
|
||||
assert data["id"] == TEST_KEY_ID
|
||||
assert data["value"] == "ingestion-key-secret-value"
|
||||
|
||||
# Verify the body forwarded to the gateway
|
||||
body = get_latest_gateway_request_body(signoz, "POST", "/v1/workspaces/me/keys")
|
||||
assert body is not None, "Expected a POST request to reach the gateway"
|
||||
assert body["name"] == "my-test-key"
|
||||
assert body["tags"] == ["env:test", "team:platform"]
|
||||
|
||||
|
||||
def test_get_ingestion_keys(
|
||||
signoz: types.SigNoz,
|
||||
create_user_admin: types.Operation, # pylint: disable=unused-argument
|
||||
make_http_mocks: Callable[[types.TestContainerDocker, list], None],
|
||||
get_token: Callable[[str, str], str],
|
||||
) -> None:
|
||||
"""GET /api/v2/gateway/ingestion_keys lists keys via the gateway."""
|
||||
admin_token = get_token(USER_ADMIN_EMAIL, USER_ADMIN_PASSWORD)
|
||||
|
||||
# Default page=1, per_page=10 → gateway gets ?page=1&per_page=10
|
||||
make_http_mocks(
|
||||
signoz.gateway,
|
||||
[
|
||||
Mapping(
|
||||
request=MappingRequest(
|
||||
method=HttpMethods.GET,
|
||||
url="/v1/workspaces/me/keys?page=1&per_page=10",
|
||||
headers=common_gateway_headers(),
|
||||
),
|
||||
response=MappingResponse(
|
||||
status=200,
|
||||
json_body={
|
||||
"data": [
|
||||
{
|
||||
"id": TEST_KEY_ID,
|
||||
"name": "my-test-key",
|
||||
"value": "secret",
|
||||
"expires_at": "2030-01-01T00:00:00Z",
|
||||
"tags": ["env:test"],
|
||||
"created_at": "2024-01-01T00:00:00Z",
|
||||
"updated_at": "2024-01-01T00:00:00Z",
|
||||
"workspace_id": "ws-1",
|
||||
"limits": [],
|
||||
}
|
||||
],
|
||||
"_pagination": {
|
||||
"page": 1,
|
||||
"per_page": 10,
|
||||
"pages": 1,
|
||||
"total": 1,
|
||||
},
|
||||
},
|
||||
),
|
||||
persistent=False,
|
||||
),
|
||||
],
|
||||
)
|
||||
|
||||
response = requests.get(
|
||||
signoz.self.host_configs["8080"].get("/api/v2/gateway/ingestion_keys"),
|
||||
headers={"Authorization": f"Bearer {admin_token}"},
|
||||
timeout=10,
|
||||
)
|
||||
|
||||
assert (
|
||||
response.status_code == HTTPStatus.OK
|
||||
), f"Expected 200, got {response.status_code}: {response.text}"
|
||||
|
||||
data = response.json()["data"]
|
||||
assert len(data["keys"]) == 1
|
||||
assert data["keys"][0]["id"] == TEST_KEY_ID
|
||||
assert data["keys"][0]["name"] == "my-test-key"
|
||||
assert data["_pagination"]["total"] == 1
|
||||
|
||||
|
||||
def test_get_ingestion_keys_custom_pagination(
|
||||
signoz: types.SigNoz,
|
||||
create_user_admin: types.Operation, # pylint: disable=unused-argument
|
||||
make_http_mocks: Callable[[types.TestContainerDocker, list], None],
|
||||
get_token: Callable[[str, str], str],
|
||||
) -> None:
|
||||
"""GET /api/v2/gateway/ingestion_keys with custom pagination params."""
|
||||
admin_token = get_token(USER_ADMIN_EMAIL, USER_ADMIN_PASSWORD)
|
||||
|
||||
make_http_mocks(
|
||||
signoz.gateway,
|
||||
[
|
||||
Mapping(
|
||||
request=MappingRequest(
|
||||
method=HttpMethods.GET,
|
||||
url="/v1/workspaces/me/keys?page=2&per_page=5",
|
||||
headers=common_gateway_headers(),
|
||||
),
|
||||
response=MappingResponse(
|
||||
status=200,
|
||||
json_body={
|
||||
"data": [],
|
||||
"_pagination": {
|
||||
"page": 2,
|
||||
"per_page": 5,
|
||||
"pages": 1,
|
||||
"total": 3,
|
||||
},
|
||||
},
|
||||
),
|
||||
persistent=False,
|
||||
),
|
||||
],
|
||||
)
|
||||
|
||||
response = requests.get(
|
||||
signoz.self.host_configs["8080"].get(
|
||||
"/api/v2/gateway/ingestion_keys?page=2&per_page=5"
|
||||
),
|
||||
headers={"Authorization": f"Bearer {admin_token}"},
|
||||
timeout=10,
|
||||
)
|
||||
|
||||
assert (
|
||||
response.status_code == HTTPStatus.OK
|
||||
), f"Expected 200, got {response.status_code}: {response.text}"
|
||||
|
||||
data = response.json()["data"]
|
||||
assert len(data["keys"]) == 0
|
||||
assert data["_pagination"]["page"] == 2
|
||||
assert data["_pagination"]["per_page"] == 5
|
||||
|
||||
|
||||
def test_search_ingestion_keys(
|
||||
signoz: types.SigNoz,
|
||||
create_user_admin: types.Operation, # pylint: disable=unused-argument
|
||||
make_http_mocks: Callable[[types.TestContainerDocker, list], None],
|
||||
get_token: Callable[[str, str], str],
|
||||
) -> None:
|
||||
"""GET /api/v2/gateway/ingestion_keys/search searches keys by name."""
|
||||
admin_token = get_token(USER_ADMIN_EMAIL, USER_ADMIN_PASSWORD)
|
||||
|
||||
# name, page, per_page are sorted alphabetically by Go url.Values.Encode()
|
||||
make_http_mocks(
|
||||
signoz.gateway,
|
||||
[
|
||||
Mapping(
|
||||
request=MappingRequest(
|
||||
method=HttpMethods.GET,
|
||||
url="/v1/workspaces/me/keys/search?name=my-test&page=1&per_page=10",
|
||||
headers=common_gateway_headers(),
|
||||
),
|
||||
response=MappingResponse(
|
||||
status=200,
|
||||
json_body={
|
||||
"data": [
|
||||
{
|
||||
"id": TEST_KEY_ID,
|
||||
"name": "my-test-key",
|
||||
"value": "secret",
|
||||
"expires_at": "2030-01-01T00:00:00Z",
|
||||
"tags": ["env:test"],
|
||||
"created_at": "2024-01-01T00:00:00Z",
|
||||
"updated_at": "2024-01-01T00:00:00Z",
|
||||
"workspace_id": "ws-1",
|
||||
"limits": [],
|
||||
}
|
||||
],
|
||||
"_pagination": {
|
||||
"page": 1,
|
||||
"per_page": 10,
|
||||
"pages": 1,
|
||||
"total": 1,
|
||||
},
|
||||
},
|
||||
),
|
||||
persistent=False,
|
||||
),
|
||||
],
|
||||
)
|
||||
|
||||
response = requests.get(
|
||||
signoz.self.host_configs["8080"].get(
|
||||
"/api/v2/gateway/ingestion_keys/search?name=my-test"
|
||||
),
|
||||
headers={"Authorization": f"Bearer {admin_token}"},
|
||||
timeout=10,
|
||||
)
|
||||
|
||||
assert (
|
||||
response.status_code == HTTPStatus.OK
|
||||
), f"Expected 200, got {response.status_code}: {response.text}"
|
||||
|
||||
data = response.json()["data"]
|
||||
assert len(data["keys"]) == 1
|
||||
assert data["keys"][0]["name"] == "my-test-key"
|
||||
|
||||
|
||||
def test_search_ingestion_keys_empty(
|
||||
signoz: types.SigNoz,
|
||||
create_user_admin: types.Operation, # pylint: disable=unused-argument
|
||||
make_http_mocks: Callable[[types.TestContainerDocker, list], None],
|
||||
get_token: Callable[[str, str], str],
|
||||
) -> None:
|
||||
"""Search returns an empty list when no keys match."""
|
||||
admin_token = get_token(USER_ADMIN_EMAIL, USER_ADMIN_PASSWORD)
|
||||
|
||||
make_http_mocks(
|
||||
signoz.gateway,
|
||||
[
|
||||
Mapping(
|
||||
request=MappingRequest(
|
||||
method=HttpMethods.GET,
|
||||
url="/v1/workspaces/me/keys/search?name=nonexistent&page=1&per_page=10",
|
||||
headers=common_gateway_headers(),
|
||||
),
|
||||
response=MappingResponse(
|
||||
status=200,
|
||||
json_body={
|
||||
"data": [],
|
||||
"_pagination": {
|
||||
"page": 1,
|
||||
"per_page": 10,
|
||||
"pages": 0,
|
||||
"total": 0,
|
||||
},
|
||||
},
|
||||
),
|
||||
persistent=False,
|
||||
),
|
||||
],
|
||||
)
|
||||
|
||||
response = requests.get(
|
||||
signoz.self.host_configs["8080"].get(
|
||||
"/api/v2/gateway/ingestion_keys/search?name=nonexistent"
|
||||
),
|
||||
headers={"Authorization": f"Bearer {admin_token}"},
|
||||
timeout=10,
|
||||
)
|
||||
|
||||
assert (
|
||||
response.status_code == HTTPStatus.OK
|
||||
), f"Expected 200, got {response.status_code}: {response.text}"
|
||||
|
||||
data = response.json()["data"]
|
||||
assert len(data["keys"]) == 0
|
||||
assert data["_pagination"]["total"] == 0
|
||||
|
||||
|
||||
def test_update_ingestion_key(
|
||||
signoz: types.SigNoz,
|
||||
create_user_admin: types.Operation, # pylint: disable=unused-argument
|
||||
make_http_mocks: Callable[[types.TestContainerDocker, list], None],
|
||||
get_token: Callable[[str, str], str],
|
||||
) -> None:
|
||||
"""PATCH /api/v2/gateway/ingestion_keys/{keyId} updates a key via the gateway."""
|
||||
admin_token = get_token(USER_ADMIN_EMAIL, USER_ADMIN_PASSWORD)
|
||||
|
||||
gateway_url = f"/v1/workspaces/me/keys/{TEST_KEY_ID}"
|
||||
|
||||
make_http_mocks(
|
||||
signoz.gateway,
|
||||
[
|
||||
Mapping(
|
||||
request=MappingRequest(
|
||||
method=HttpMethods.PATCH,
|
||||
url=gateway_url,
|
||||
headers=common_gateway_headers(),
|
||||
),
|
||||
response=MappingResponse(status=204),
|
||||
persistent=False,
|
||||
),
|
||||
],
|
||||
)
|
||||
|
||||
response = requests.patch(
|
||||
signoz.self.host_configs["8080"].get(
|
||||
f"/api/v2/gateway/ingestion_keys/{TEST_KEY_ID}"
|
||||
),
|
||||
json={
|
||||
"name": "renamed-key",
|
||||
"tags": ["env:prod"],
|
||||
"expires_at": "2031-06-15T00:00:00Z",
|
||||
},
|
||||
headers={"Authorization": f"Bearer {admin_token}"},
|
||||
timeout=10,
|
||||
)
|
||||
|
||||
assert (
|
||||
response.status_code == HTTPStatus.NO_CONTENT
|
||||
), f"Expected 204, got {response.status_code}: {response.text}"
|
||||
|
||||
# Verify the body forwarded to the gateway
|
||||
body = get_latest_gateway_request_body(signoz, "PATCH", gateway_url)
|
||||
assert body is not None, "Expected a PATCH request to reach the gateway"
|
||||
assert body["name"] == "renamed-key"
|
||||
assert body["tags"] == ["env:prod"]
|
||||
|
||||
|
||||
def test_delete_ingestion_key(
|
||||
signoz: types.SigNoz,
|
||||
create_user_admin: types.Operation, # pylint: disable=unused-argument
|
||||
make_http_mocks: Callable[[types.TestContainerDocker, list], None],
|
||||
get_token: Callable[[str, str], str],
|
||||
) -> None:
|
||||
"""DELETE /api/v2/gateway/ingestion_keys/{keyId} deletes a key via the gateway."""
|
||||
admin_token = get_token(USER_ADMIN_EMAIL, USER_ADMIN_PASSWORD)
|
||||
|
||||
gateway_url = f"/v1/workspaces/me/keys/{TEST_KEY_ID}"
|
||||
|
||||
make_http_mocks(
|
||||
signoz.gateway,
|
||||
[
|
||||
Mapping(
|
||||
request=MappingRequest(
|
||||
method=HttpMethods.DELETE,
|
||||
url=gateway_url,
|
||||
headers=common_gateway_headers(),
|
||||
),
|
||||
response=MappingResponse(status=204),
|
||||
persistent=False,
|
||||
),
|
||||
],
|
||||
)
|
||||
|
||||
response = requests.delete(
|
||||
signoz.self.host_configs["8080"].get(
|
||||
f"/api/v2/gateway/ingestion_keys/{TEST_KEY_ID}"
|
||||
),
|
||||
headers={"Authorization": f"Bearer {admin_token}"},
|
||||
timeout=10,
|
||||
)
|
||||
|
||||
assert (
|
||||
response.status_code == HTTPStatus.NO_CONTENT
|
||||
), f"Expected 204, got {response.status_code}: {response.text}"
|
||||
|
||||
# Verify at least one DELETE reached the gateway
|
||||
matched = get_gateway_requests(signoz, "DELETE", gateway_url)
|
||||
assert len(matched) >= 1, "Expected a DELETE request to reach the gateway"
|
||||
418
tests/integration/src/ingestionkeys/02_ingestion_keys_limits.py
Normal file
418
tests/integration/src/ingestionkeys/02_ingestion_keys_limits.py
Normal file
@@ -0,0 +1,418 @@
|
||||
from http import HTTPStatus
|
||||
from typing import Callable, List
|
||||
|
||||
import requests
|
||||
from wiremock.client import (
|
||||
HttpMethods,
|
||||
Mapping,
|
||||
MappingRequest,
|
||||
MappingResponse,
|
||||
)
|
||||
|
||||
from fixtures import types
|
||||
from fixtures.auth import USER_ADMIN_EMAIL, USER_ADMIN_PASSWORD, add_license
|
||||
from fixtures.gatewayutils import (
|
||||
TEST_KEY_ID,
|
||||
TEST_LIMIT_ID,
|
||||
common_gateway_headers,
|
||||
get_gateway_requests,
|
||||
get_latest_gateway_request_body,
|
||||
)
|
||||
from fixtures.logger import setup_logger
|
||||
|
||||
logger = setup_logger(__name__)
|
||||
|
||||
|
||||
def test_apply_license(
|
||||
signoz: types.SigNoz,
|
||||
create_user_admin: types.Operation, # pylint: disable=unused-argument
|
||||
make_http_mocks: Callable[[types.TestContainerDocker, List[Mapping]], None],
|
||||
get_token: Callable[[str, str], str],
|
||||
) -> None:
|
||||
"""Activate a license so that all subsequent gateway calls succeed."""
|
||||
add_license(signoz, make_http_mocks, get_token)
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Create ingestion key limit
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
def test_create_ingestion_key_limit_only_size(
|
||||
signoz: types.SigNoz,
|
||||
create_user_admin: types.Operation, # pylint: disable=unused-argument
|
||||
make_http_mocks: Callable[[types.TestContainerDocker, list], None],
|
||||
get_token: Callable[[str, str], str],
|
||||
) -> None:
|
||||
"""Creating a limit with only size omits count from the gateway payload."""
|
||||
admin_token = get_token(USER_ADMIN_EMAIL, USER_ADMIN_PASSWORD)
|
||||
|
||||
gateway_url = f"/v1/workspaces/me/keys/{TEST_KEY_ID}/limits"
|
||||
|
||||
make_http_mocks(
|
||||
signoz.gateway,
|
||||
[
|
||||
Mapping(
|
||||
request=MappingRequest(
|
||||
method=HttpMethods.POST,
|
||||
url=gateway_url,
|
||||
headers=common_gateway_headers(),
|
||||
),
|
||||
response=MappingResponse(
|
||||
status=201,
|
||||
json_body={
|
||||
"status": "success",
|
||||
"data": {"id": "limit-created-1"},
|
||||
},
|
||||
),
|
||||
persistent=False,
|
||||
),
|
||||
],
|
||||
)
|
||||
|
||||
response = requests.post(
|
||||
signoz.self.host_configs["8080"].get(
|
||||
f"/api/v2/gateway/ingestion_keys/{TEST_KEY_ID}/limits"
|
||||
),
|
||||
json={
|
||||
"signal": "logs",
|
||||
"config": {"day": {"size": 1000}},
|
||||
"tags": ["test"],
|
||||
},
|
||||
headers={"Authorization": f"Bearer {admin_token}"},
|
||||
timeout=10,
|
||||
)
|
||||
|
||||
assert (
|
||||
response.status_code == HTTPStatus.CREATED
|
||||
), f"Expected 201, got {response.status_code}: {response.text}"
|
||||
|
||||
assert response.json()["data"]["id"] == "limit-created-1"
|
||||
|
||||
body = get_latest_gateway_request_body(signoz, "POST", gateway_url)
|
||||
assert body is not None, "Expected a POST request to reach the gateway"
|
||||
assert body["signal"] == "logs"
|
||||
assert body["config"]["day"]["size"] == 1000
|
||||
assert "count" not in body["config"]["day"], "count should be absent when not set"
|
||||
assert "second" not in body["config"], "second should be absent when not set"
|
||||
assert body["tags"] == ["test"]
|
||||
|
||||
|
||||
def test_create_ingestion_key_limit_only_count(
|
||||
signoz: types.SigNoz,
|
||||
create_user_admin: types.Operation, # pylint: disable=unused-argument
|
||||
make_http_mocks: Callable[[types.TestContainerDocker, list], None],
|
||||
get_token: Callable[[str, str], str],
|
||||
) -> None:
|
||||
"""Creating a limit with only count omits size from the gateway payload."""
|
||||
admin_token = get_token(USER_ADMIN_EMAIL, USER_ADMIN_PASSWORD)
|
||||
|
||||
gateway_url = f"/v1/workspaces/me/keys/{TEST_KEY_ID}/limits"
|
||||
|
||||
make_http_mocks(
|
||||
signoz.gateway,
|
||||
[
|
||||
Mapping(
|
||||
request=MappingRequest(
|
||||
method=HttpMethods.POST,
|
||||
url=gateway_url,
|
||||
headers=common_gateway_headers(),
|
||||
),
|
||||
response=MappingResponse(
|
||||
status=201,
|
||||
json_body={
|
||||
"status": "success",
|
||||
"data": {"id": "limit-created-2"},
|
||||
},
|
||||
),
|
||||
persistent=False,
|
||||
),
|
||||
],
|
||||
)
|
||||
|
||||
response = requests.post(
|
||||
signoz.self.host_configs["8080"].get(
|
||||
f"/api/v2/gateway/ingestion_keys/{TEST_KEY_ID}/limits"
|
||||
),
|
||||
json={
|
||||
"signal": "traces",
|
||||
"config": {"day": {"count": 500}},
|
||||
"tags": ["test"],
|
||||
},
|
||||
headers={"Authorization": f"Bearer {admin_token}"},
|
||||
timeout=10,
|
||||
)
|
||||
|
||||
assert (
|
||||
response.status_code == HTTPStatus.CREATED
|
||||
), f"Expected 201, got {response.status_code}: {response.text}"
|
||||
|
||||
body = get_latest_gateway_request_body(signoz, "POST", gateway_url)
|
||||
assert body is not None, "Expected a POST request to reach the gateway"
|
||||
assert body["signal"] == "traces"
|
||||
assert body["config"]["day"]["count"] == 500
|
||||
assert "size" not in body["config"]["day"], "size should be absent when not set"
|
||||
assert body["tags"] == ["test"]
|
||||
|
||||
|
||||
def test_create_ingestion_key_limit_both_size_and_count(
|
||||
signoz: types.SigNoz,
|
||||
create_user_admin: types.Operation, # pylint: disable=unused-argument
|
||||
make_http_mocks: Callable[[types.TestContainerDocker, list], None],
|
||||
get_token: Callable[[str, str], str],
|
||||
) -> None:
|
||||
"""Creating a limit with both size and count includes both in the gateway payload."""
|
||||
admin_token = get_token(USER_ADMIN_EMAIL, USER_ADMIN_PASSWORD)
|
||||
|
||||
gateway_url = f"/v1/workspaces/me/keys/{TEST_KEY_ID}/limits"
|
||||
|
||||
make_http_mocks(
|
||||
signoz.gateway,
|
||||
[
|
||||
Mapping(
|
||||
request=MappingRequest(
|
||||
method=HttpMethods.POST,
|
||||
url=gateway_url,
|
||||
headers=common_gateway_headers(),
|
||||
),
|
||||
response=MappingResponse(
|
||||
status=201,
|
||||
json_body={
|
||||
"status": "success",
|
||||
"data": {"id": "limit-created-3"},
|
||||
},
|
||||
),
|
||||
persistent=False,
|
||||
),
|
||||
],
|
||||
)
|
||||
|
||||
response = requests.post(
|
||||
signoz.self.host_configs["8080"].get(
|
||||
f"/api/v2/gateway/ingestion_keys/{TEST_KEY_ID}/limits"
|
||||
),
|
||||
json={
|
||||
"signal": "metrics",
|
||||
"config": {
|
||||
"day": {"size": 2000, "count": 750},
|
||||
"second": {"size": 100, "count": 50},
|
||||
},
|
||||
"tags": ["test"],
|
||||
},
|
||||
headers={"Authorization": f"Bearer {admin_token}"},
|
||||
timeout=10,
|
||||
)
|
||||
|
||||
assert (
|
||||
response.status_code == HTTPStatus.CREATED
|
||||
), f"Expected 201, got {response.status_code}: {response.text}"
|
||||
|
||||
body = get_latest_gateway_request_body(signoz, "POST", gateway_url)
|
||||
assert body is not None, "Expected a POST request to reach the gateway"
|
||||
assert body["signal"] == "metrics"
|
||||
assert body["config"]["day"]["size"] == 2000
|
||||
assert body["config"]["day"]["count"] == 750
|
||||
assert body["config"]["second"]["size"] == 100
|
||||
assert body["config"]["second"]["count"] == 50
|
||||
assert body["tags"] == ["test"]
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Update ingestion key limit
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
def test_update_ingestion_key_limit_only_size(
|
||||
signoz: types.SigNoz,
|
||||
create_user_admin: types.Operation, # pylint: disable=unused-argument
|
||||
make_http_mocks: Callable[[types.TestContainerDocker, list], None],
|
||||
get_token: Callable[[str, str], str],
|
||||
) -> None:
|
||||
"""Updating a limit with only size omits count from the gateway payload."""
|
||||
admin_token = get_token(USER_ADMIN_EMAIL, USER_ADMIN_PASSWORD)
|
||||
|
||||
gateway_url = f"/v1/workspaces/me/limits/{TEST_LIMIT_ID}"
|
||||
|
||||
make_http_mocks(
|
||||
signoz.gateway,
|
||||
[
|
||||
Mapping(
|
||||
request=MappingRequest(
|
||||
method=HttpMethods.PATCH,
|
||||
url=gateway_url,
|
||||
headers=common_gateway_headers(),
|
||||
),
|
||||
response=MappingResponse(status=204),
|
||||
persistent=False,
|
||||
),
|
||||
],
|
||||
)
|
||||
|
||||
response = requests.patch(
|
||||
signoz.self.host_configs["8080"].get(
|
||||
f"/api/v2/gateway/ingestion_keys/limits/{TEST_LIMIT_ID}"
|
||||
),
|
||||
json={
|
||||
"config": {"day": {"size": 2000}},
|
||||
"tags": ["test"],
|
||||
},
|
||||
headers={"Authorization": f"Bearer {admin_token}"},
|
||||
timeout=10,
|
||||
)
|
||||
|
||||
assert (
|
||||
response.status_code == HTTPStatus.NO_CONTENT
|
||||
), f"Expected 204, got {response.status_code}: {response.text}"
|
||||
|
||||
body = get_latest_gateway_request_body(signoz, "PATCH", gateway_url)
|
||||
assert body is not None, "Expected a PATCH request to reach the gateway"
|
||||
assert body["config"]["day"]["size"] == 2000
|
||||
assert "count" not in body["config"]["day"], "count should be absent when not set"
|
||||
assert "second" not in body["config"], "second should be absent when not set"
|
||||
assert body["tags"] == ["test"]
|
||||
|
||||
|
||||
def test_update_ingestion_key_limit_only_count(
|
||||
signoz: types.SigNoz,
|
||||
create_user_admin: types.Operation, # pylint: disable=unused-argument
|
||||
make_http_mocks: Callable[[types.TestContainerDocker, list], None],
|
||||
get_token: Callable[[str, str], str],
|
||||
) -> None:
|
||||
"""Updating a limit with only count omits size from the gateway payload."""
|
||||
admin_token = get_token(USER_ADMIN_EMAIL, USER_ADMIN_PASSWORD)
|
||||
|
||||
gateway_url = f"/v1/workspaces/me/limits/{TEST_LIMIT_ID}"
|
||||
|
||||
make_http_mocks(
|
||||
signoz.gateway,
|
||||
[
|
||||
Mapping(
|
||||
request=MappingRequest(
|
||||
method=HttpMethods.PATCH,
|
||||
url=gateway_url,
|
||||
headers=common_gateway_headers(),
|
||||
),
|
||||
response=MappingResponse(status=204),
|
||||
persistent=False,
|
||||
),
|
||||
],
|
||||
)
|
||||
|
||||
response = requests.patch(
|
||||
signoz.self.host_configs["8080"].get(
|
||||
f"/api/v2/gateway/ingestion_keys/limits/{TEST_LIMIT_ID}"
|
||||
),
|
||||
json={
|
||||
"config": {"day": {"count": 750}},
|
||||
"tags": ["test"],
|
||||
},
|
||||
headers={"Authorization": f"Bearer {admin_token}"},
|
||||
timeout=10,
|
||||
)
|
||||
|
||||
assert (
|
||||
response.status_code == HTTPStatus.NO_CONTENT
|
||||
), f"Expected 204, got {response.status_code}: {response.text}"
|
||||
|
||||
body = get_latest_gateway_request_body(signoz, "PATCH", gateway_url)
|
||||
assert body is not None, "Expected a PATCH request to reach the gateway"
|
||||
assert body["config"]["day"]["count"] == 750
|
||||
assert "size" not in body["config"]["day"], "size should be absent when not set"
|
||||
assert body["tags"] == ["test"]
|
||||
|
||||
|
||||
def test_update_ingestion_key_limit_both_size_and_count(
|
||||
signoz: types.SigNoz,
|
||||
create_user_admin: types.Operation, # pylint: disable=unused-argument
|
||||
make_http_mocks: Callable[[types.TestContainerDocker, list], None],
|
||||
get_token: Callable[[str, str], str],
|
||||
) -> None:
|
||||
"""Updating a limit with both size and count includes both in the gateway payload."""
|
||||
admin_token = get_token(USER_ADMIN_EMAIL, USER_ADMIN_PASSWORD)
|
||||
|
||||
gateway_url = f"/v1/workspaces/me/limits/{TEST_LIMIT_ID}"
|
||||
|
||||
make_http_mocks(
|
||||
signoz.gateway,
|
||||
[
|
||||
Mapping(
|
||||
request=MappingRequest(
|
||||
method=HttpMethods.PATCH,
|
||||
url=gateway_url,
|
||||
headers=common_gateway_headers(),
|
||||
),
|
||||
response=MappingResponse(status=204),
|
||||
persistent=False,
|
||||
),
|
||||
],
|
||||
)
|
||||
|
||||
response = requests.patch(
|
||||
signoz.self.host_configs["8080"].get(
|
||||
f"/api/v2/gateway/ingestion_keys/limits/{TEST_LIMIT_ID}"
|
||||
),
|
||||
json={
|
||||
"config": {"day": {"size": 1000, "count": 500}},
|
||||
"tags": ["test"],
|
||||
},
|
||||
headers={"Authorization": f"Bearer {admin_token}"},
|
||||
timeout=10,
|
||||
)
|
||||
|
||||
assert (
|
||||
response.status_code == HTTPStatus.NO_CONTENT
|
||||
), f"Expected 204, got {response.status_code}: {response.text}"
|
||||
|
||||
body = get_latest_gateway_request_body(signoz, "PATCH", gateway_url)
|
||||
assert body is not None, "Expected a PATCH request to reach the gateway"
|
||||
assert body["config"]["day"]["size"] == 1000
|
||||
assert body["config"]["day"]["count"] == 500
|
||||
assert body["tags"] == ["test"]
|
||||
|
||||
|
||||
# ---------------------------------------------------------------------------
|
||||
# Delete ingestion key limit
|
||||
# ---------------------------------------------------------------------------
|
||||
|
||||
|
||||
def test_delete_ingestion_key_limit(
|
||||
signoz: types.SigNoz,
|
||||
create_user_admin: types.Operation, # pylint: disable=unused-argument
|
||||
make_http_mocks: Callable[[types.TestContainerDocker, list], None],
|
||||
get_token: Callable[[str, str], str],
|
||||
) -> None:
|
||||
"""DELETE /api/v2/gateway/ingestion_keys/limits/{limitId} deletes a limit."""
|
||||
admin_token = get_token(USER_ADMIN_EMAIL, USER_ADMIN_PASSWORD)
|
||||
|
||||
gateway_url = f"/v1/workspaces/me/limits/{TEST_LIMIT_ID}"
|
||||
|
||||
make_http_mocks(
|
||||
signoz.gateway,
|
||||
[
|
||||
Mapping(
|
||||
request=MappingRequest(
|
||||
method=HttpMethods.DELETE,
|
||||
url=gateway_url,
|
||||
headers=common_gateway_headers(),
|
||||
),
|
||||
response=MappingResponse(status=204),
|
||||
persistent=False,
|
||||
),
|
||||
],
|
||||
)
|
||||
|
||||
response = requests.delete(
|
||||
signoz.self.host_configs["8080"].get(
|
||||
f"/api/v2/gateway/ingestion_keys/limits/{TEST_LIMIT_ID}"
|
||||
),
|
||||
headers={"Authorization": f"Bearer {admin_token}"},
|
||||
timeout=10,
|
||||
)
|
||||
|
||||
assert (
|
||||
response.status_code == HTTPStatus.NO_CONTENT
|
||||
), f"Expected 204, got {response.status_code}: {response.text}"
|
||||
|
||||
# Verify at least one DELETE reached the gateway
|
||||
matched = get_gateway_requests(signoz, "DELETE", gateway_url)
|
||||
assert len(matched) >= 1, "Expected a DELETE request to reach the gateway"
|
||||
0
tests/integration/src/ingestionkeys/__init__.py
Normal file
0
tests/integration/src/ingestionkeys/__init__.py
Normal file
Reference in New Issue
Block a user