Compare commits

..

2 Commits

Author SHA1 Message Date
swapnil-signoz
faf2ff1f9b fix: adding missing response writer in error 2026-06-03 15:09:46 +05:30
swapnil-signoz
75ceabc6d9 feat: adding endpoint services metadata for account 2026-06-03 13:40:40 +05:30
16 changed files with 309 additions and 255 deletions

View File

@@ -2380,26 +2380,6 @@ components:
repeatVariable:
type: string
type: object
DashboardLink:
properties:
name:
type: string
renderVariables:
type: boolean
targetBlank:
type: boolean
tooltip:
type: string
url:
type: string
type: object
DashboardPanelDisplay:
properties:
description:
type: string
name:
type: string
type: object
DashboardTextVariableSpec:
properties:
constant:
@@ -2530,7 +2510,7 @@ components:
type: array
links:
items:
$ref: '#/components/schemas/DashboardLink'
$ref: '#/components/schemas/V1Link'
type: array
panels:
additionalProperties:
@@ -2667,8 +2647,8 @@ components:
type: object
DashboardtypesLayout:
oneOf:
- $ref: '#/components/schemas/DashboardtypesLayoutEnvelopeGithubComPersesSpecGoDashboardGridLayoutSpec'
DashboardtypesLayoutEnvelopeGithubComPersesSpecGoDashboardGridLayoutSpec:
- $ref: '#/components/schemas/DashboardtypesLayoutEnvelopeGithubComPersesPersesPkgModelApiV1DashboardGridLayoutSpec'
DashboardtypesLayoutEnvelopeGithubComPersesPersesPkgModelApiV1DashboardGridLayoutSpec:
properties:
kind:
enum:
@@ -2751,7 +2731,7 @@ components:
DashboardtypesPanel:
properties:
kind:
$ref: '#/components/schemas/DashboardtypesPanelKind'
type: string
spec:
$ref: '#/components/schemas/DashboardtypesPanelSpec'
type: object
@@ -2762,10 +2742,6 @@ components:
unit:
type: string
type: object
DashboardtypesPanelKind:
enum:
- Panel
type: string
DashboardtypesPanelPlugin:
oneOf:
- $ref: '#/components/schemas/DashboardtypesPanelPluginVariantGithubComSigNozSignozPkgTypesDashboardtypesTimeSeriesPanelSpec'
@@ -2872,10 +2848,10 @@ components:
DashboardtypesPanelSpec:
properties:
display:
$ref: '#/components/schemas/DashboardPanelDisplay'
$ref: '#/components/schemas/V1PanelDisplay'
links:
items:
$ref: '#/components/schemas/DashboardLink'
$ref: '#/components/schemas/V1Link'
type: array
plugin:
$ref: '#/components/schemas/DashboardtypesPanelPlugin'
@@ -2934,18 +2910,10 @@ components:
DashboardtypesQuery:
properties:
kind:
$ref: '#/components/schemas/DashboardtypesQueryKind'
type: string
spec:
$ref: '#/components/schemas/DashboardtypesQuerySpec'
type: object
DashboardtypesQueryKind:
enum:
- scalar
- time_series
- raw
- raw_stream
- trace
type: string
DashboardtypesQueryPlugin:
oneOf:
- $ref: '#/components/schemas/DashboardtypesQueryPluginVariantGithubComSigNozSignozPkgTypesDashboardtypesBuilderQuerySpec'
@@ -3189,8 +3157,8 @@ components:
DashboardtypesVariable:
oneOf:
- $ref: '#/components/schemas/DashboardtypesVariableEnvelopeGithubComSigNozSignozPkgTypesDashboardtypesListVariableSpec'
- $ref: '#/components/schemas/DashboardtypesVariableEnvelopeGithubComPersesSpecGoDashboardTextVariableSpec'
DashboardtypesVariableEnvelopeGithubComPersesSpecGoDashboardTextVariableSpec:
- $ref: '#/components/schemas/DashboardtypesVariableEnvelopeGithubComPersesPersesPkgModelApiV1DashboardTextVariableSpec'
DashboardtypesVariableEnvelopeGithubComPersesPersesPkgModelApiV1DashboardTextVariableSpec:
properties:
kind:
enum:
@@ -7208,6 +7176,26 @@ components:
required:
- id
type: object
V1Link:
properties:
name:
type: string
renderVariables:
type: boolean
targetBlank:
type: boolean
tooltip:
type: string
url:
type: string
type: object
V1PanelDisplay:
properties:
description:
type: string
name:
type: string
type: object
VariableDefaultValue:
type: object
VariableDisplay:
@@ -8040,6 +8028,64 @@ paths:
summary: Update account
tags:
- cloudintegration
/api/v1/cloud_integrations/{cloud_provider}/accounts/{id}/services:
get:
deprecated: false
description: This endpoint lists the services metadata for the specified account
and cloud provider
operationId: ListAccountServicesMetadata
parameters:
- in: path
name: cloud_provider
required: true
schema:
type: string
- in: path
name: id
required: true
schema:
type: string
responses:
"200":
content:
application/json:
schema:
properties:
data:
$ref: '#/components/schemas/CloudintegrationtypesGettableServicesMetadata'
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: List account services metadata
tags:
- cloudintegration
/api/v1/cloud_integrations/{cloud_provider}/accounts/{id}/services/{service_id}:
put:
deprecated: false

View File

@@ -3089,40 +3089,6 @@ export interface DashboardGridLayoutSpecDTO {
repeatVariable?: string;
}
export interface DashboardLinkDTO {
/**
* @type string
*/
name?: string;
/**
* @type boolean
*/
renderVariables?: boolean;
/**
* @type boolean
*/
targetBlank?: boolean;
/**
* @type string
*/
tooltip?: string;
/**
* @type string
*/
url?: string;
}
export interface DashboardPanelDisplayDTO {
/**
* @type string
*/
description?: string;
/**
* @type string
*/
name?: string;
}
export interface VariableDisplayDTO {
/**
* @type string
@@ -3820,9 +3786,40 @@ export type DashboardtypesDashboardSpecDTODatasources = {
[key: string]: DashboardtypesDatasourceSpecDTO;
};
export enum DashboardtypesPanelKindDTO {
Panel = 'Panel',
export interface V1PanelDisplayDTO {
/**
* @type string
*/
description?: string;
/**
* @type string
*/
name?: string;
}
export interface V1LinkDTO {
/**
* @type string
*/
name?: string;
/**
* @type boolean
*/
renderVariables?: boolean;
/**
* @type boolean
*/
targetBlank?: boolean;
/**
* @type string
*/
tooltip?: string;
/**
* @type string
*/
url?: string;
}
export enum DashboardtypesPanelPluginVariantGithubComSigNozSignozPkgTypesDashboardtypesTimeSeriesPanelSpecDTOKind {
'signoz/TimeSeriesPanel' = 'signoz/TimeSeriesPanel',
}
@@ -4064,13 +4061,6 @@ export type DashboardtypesPanelPluginDTO =
| DashboardtypesPanelPluginVariantGithubComSigNozSignozPkgTypesDashboardtypesHistogramPanelSpecDTO
| DashboardtypesPanelPluginVariantGithubComSigNozSignozPkgTypesDashboardtypesListPanelSpecDTO;
export enum DashboardtypesQueryKindDTO {
scalar = 'scalar',
time_series = 'time_series',
raw = 'raw',
raw_stream = 'raw_stream',
trace = 'trace',
}
export enum DashboardtypesQueryPluginVariantGithubComSigNozSignozPkgTypesDashboardtypesBuilderQuerySpecDTOKind {
'signoz/BuilderQuery' = 'signoz/BuilderQuery',
}
@@ -4375,16 +4365,19 @@ export interface DashboardtypesQuerySpecDTO {
}
export interface DashboardtypesQueryDTO {
kind?: DashboardtypesQueryKindDTO;
/**
* @type string
*/
kind?: string;
spec?: DashboardtypesQuerySpecDTO;
}
export interface DashboardtypesPanelSpecDTO {
display?: DashboardPanelDisplayDTO;
display?: V1PanelDisplayDTO;
/**
* @type array
*/
links?: DashboardLinkDTO[];
links?: V1LinkDTO[];
plugin?: DashboardtypesPanelPluginDTO;
/**
* @type array
@@ -4393,7 +4386,10 @@ export interface DashboardtypesPanelSpecDTO {
}
export interface DashboardtypesPanelDTO {
kind?: DashboardtypesPanelKindDTO;
/**
* @type string
*/
kind?: string;
spec?: DashboardtypesPanelSpecDTO;
}
@@ -4407,20 +4403,20 @@ export type DashboardtypesDashboardSpecDTOPanelsAnyOf = {
export type DashboardtypesDashboardSpecDTOPanels =
DashboardtypesDashboardSpecDTOPanelsAnyOf | null;
export enum DashboardtypesLayoutEnvelopeGithubComPersesSpecGoDashboardGridLayoutSpecDTOKind {
export enum DashboardtypesLayoutEnvelopeGithubComPersesPersesPkgModelApiV1DashboardGridLayoutSpecDTOKind {
Grid = 'Grid',
}
export interface DashboardtypesLayoutEnvelopeGithubComPersesSpecGoDashboardGridLayoutSpecDTO {
export interface DashboardtypesLayoutEnvelopeGithubComPersesPersesPkgModelApiV1DashboardGridLayoutSpecDTO {
/**
* @enum Grid
* @type string
*/
kind: DashboardtypesLayoutEnvelopeGithubComPersesSpecGoDashboardGridLayoutSpecDTOKind;
kind: DashboardtypesLayoutEnvelopeGithubComPersesPersesPkgModelApiV1DashboardGridLayoutSpecDTOKind;
spec: DashboardGridLayoutSpecDTO;
}
export type DashboardtypesLayoutDTO =
DashboardtypesLayoutEnvelopeGithubComPersesSpecGoDashboardGridLayoutSpecDTO;
DashboardtypesLayoutEnvelopeGithubComPersesPersesPkgModelApiV1DashboardGridLayoutSpecDTO;
export enum DashboardtypesVariableEnvelopeGithubComSigNozSignozPkgTypesDashboardtypesListVariableSpecDTOKind {
ListVariable = 'ListVariable',
@@ -4524,21 +4520,21 @@ export interface DashboardtypesVariableEnvelopeGithubComSigNozSignozPkgTypesDash
spec: DashboardtypesListVariableSpecDTO;
}
export enum DashboardtypesVariableEnvelopeGithubComPersesSpecGoDashboardTextVariableSpecDTOKind {
export enum DashboardtypesVariableEnvelopeGithubComPersesPersesPkgModelApiV1DashboardTextVariableSpecDTOKind {
TextVariable = 'TextVariable',
}
export interface DashboardtypesVariableEnvelopeGithubComPersesSpecGoDashboardTextVariableSpecDTO {
export interface DashboardtypesVariableEnvelopeGithubComPersesPersesPkgModelApiV1DashboardTextVariableSpecDTO {
/**
* @enum TextVariable
* @type string
*/
kind: DashboardtypesVariableEnvelopeGithubComPersesSpecGoDashboardTextVariableSpecDTOKind;
kind: DashboardtypesVariableEnvelopeGithubComPersesPersesPkgModelApiV1DashboardTextVariableSpecDTOKind;
spec: DashboardTextVariableSpecDTO;
}
export type DashboardtypesVariableDTO =
| DashboardtypesVariableEnvelopeGithubComSigNozSignozPkgTypesDashboardtypesListVariableSpecDTO
| DashboardtypesVariableEnvelopeGithubComPersesSpecGoDashboardTextVariableSpecDTO;
| DashboardtypesVariableEnvelopeGithubComPersesPersesPkgModelApiV1DashboardTextVariableSpecDTO;
export interface DashboardtypesDashboardSpecDTO {
/**
@@ -4557,7 +4553,7 @@ export interface DashboardtypesDashboardSpecDTO {
/**
* @type array
*/
links?: DashboardLinkDTO[];
links?: V1LinkDTO[];
/**
* @type object,null
*/

7
go.mod
View File

@@ -42,7 +42,7 @@ require (
github.com/openfga/api/proto v0.0.0-20260319214821-f153694bfc20
github.com/openfga/language/pkg/go v0.2.1
github.com/opentracing/opentracing-go v1.2.0
github.com/perses/spec v0.1.2
github.com/perses/perses v0.53.1
github.com/pkg/errors v0.9.1
github.com/prometheus/alertmanager v0.31.1
github.com/prometheus/client_golang v1.23.2
@@ -137,8 +137,9 @@ require (
github.com/huandu/go-clone v1.7.3 // indirect
github.com/leodido/go-urn v1.4.0 // indirect
github.com/mattn/go-isatty v0.0.20 // indirect
github.com/muhlemmer/gu v0.3.1 // indirect
github.com/ncruces/go-strftime v1.0.0 // indirect
github.com/nxadm/tail v1.4.11 // indirect
github.com/perses/common v0.30.2 // indirect
github.com/prometheus/client_golang/exp v0.0.0-20260325093428-d8591d0db856 // indirect
github.com/puzpuzpuz/xsync/v4 v4.4.0 // indirect
github.com/redis/go-redis/extra/rediscmd/v9 v9.15.1 // indirect
@@ -149,6 +150,8 @@ require (
github.com/ugorji/go/codec v1.3.0 // indirect
github.com/uptrace/opentelemetry-go-extra/otelsql v0.3.2 // indirect
github.com/x448/float16 v0.8.4 // indirect
github.com/zitadel/oidc/v3 v3.45.4 // indirect
github.com/zitadel/schema v1.3.2 // indirect
go.opentelemetry.io/collector/client v1.54.0 // indirect
go.opentelemetry.io/collector/config/configoptional v1.50.0 // indirect
go.opentelemetry.io/collector/config/configretry v1.50.0 // indirect

16
go.sum
View File

@@ -330,7 +330,6 @@ github.com/frankban/quicktest v1.14.6 h1:7Xjx+VpznH+oBnejlPUj8oUpdxnVs4f8XU8WnHk
github.com/frankban/quicktest v1.14.6/go.mod h1:4ptaffx2x8+WTWXmUCuVU6aPUX1/Mz7zb5vbUoiM6w0=
github.com/fsnotify/fsnotify v1.4.9/go.mod h1:znqG4EE+3YCdAaPaxE2ZRY/06pZUdp0tY4IgpuI1SZQ=
github.com/fsnotify/fsnotify v1.5.4/go.mod h1:OVB6XrOHzAwXMpEM7uPOzcehqUV2UqJxmVXmkdnm1bU=
github.com/fsnotify/fsnotify v1.6.0/go.mod h1:sl3t1tCWJFWoRz9R8WJCbQihKKwmorjAbSClcnxKAGw=
github.com/fsnotify/fsnotify v1.9.0 h1:2Ml+OJNzbYCTzsxtv8vKSFD9PbJjmhYF14k/jKC7S9k=
github.com/fsnotify/fsnotify v1.9.0/go.mod h1:8jBTzvmWwFyi3Pb8djgCCO5IBqzKJ/Jwo8TRcHyHii0=
github.com/fxamacker/cbor/v2 v2.9.0 h1:NpKPmjDBgUfBms6tr6JZkTHtfFGcMKsw3eGcmD/sapM=
@@ -831,6 +830,8 @@ github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjY
github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee h1:W5t00kpgFdJifH4BDsTlE89Zl93FEloxaWZfGcifgq8=
github.com/modern-go/reflect2 v1.0.3-0.20250322232337-35a7c28c31ee/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc=
github.com/muhlemmer/gu v0.3.1 h1:7EAqmFrW7n3hETvuAdmFmn4hS8W+z3LgKtrnow+YzNM=
github.com/muhlemmer/gu v0.3.1/go.mod h1:YHtHR+gxM+bKEIIs7Hmi9sPT3ZDUvTN/i88wQpZkrdM=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822 h1:C3w9PqII01/Oq1c1nUAm88MOHcQC9l5mIlSMApZMrHA=
github.com/munnerz/goautoneg v0.0.0-20191010083416-a7dc8b61c822/go.mod h1:+n7T8mK8HuQTcFwEeznm/DIxMOiR9yIdICNftLE1DvQ=
github.com/mwitkow/go-conntrack v0.0.0-20161129095857-cc309e4a2223/go.mod h1:qRWi+5nqEBWmkhHvq77mSJWrCKwh8bxhgT7d/eI7P4U=
@@ -840,6 +841,8 @@ github.com/natefinch/wrap v0.2.0 h1:IXzc/pw5KqxJv55gV0lSOcKHYuEZPGbQrOOXr/bamRk=
github.com/natefinch/wrap v0.2.0/go.mod h1:6gMHlAl12DwYEfKP3TkuykYUfLSEAvHw67itm4/KAS8=
github.com/ncruces/go-strftime v1.0.0 h1:HMFp8mLCTPp341M/ZnA4qaf7ZlsbTc+miZjCLOFAw7w=
github.com/ncruces/go-strftime v1.0.0/go.mod h1:Fwc5htZGVVkseilnfgOVb9mKy6w1naJmn9CehxcKcls=
github.com/nexucis/lamenv v0.5.2 h1:tK/u3XGhCq9qIoVNcXsK9LZb8fKopm0A5weqSRvHd7M=
github.com/nexucis/lamenv v0.5.2/go.mod h1:HusJm6ltmmT7FMG8A750mOLuME6SHCsr2iFYxp5fFi0=
github.com/npillmayer/nestext v0.1.3/go.mod h1:h2lrijH8jpicr25dFY+oAJLyzlya6jhnuG+zWp9L0Uk=
github.com/nxadm/tail v1.4.11 h1:8feyoE3OzPrcshW5/MJ4sGESc5cqmGkGCWlco4l0bqY=
github.com/nxadm/tail v1.4.11/go.mod h1:OTaG3NK980DZzxbRq6lEuzgU+mug70nY11sMd4JXXHc=
@@ -902,8 +905,10 @@ github.com/pelletier/go-toml v1.9.5/go.mod h1:u1nR/EPcESfeI/szUZKdtJ0xRNbUoANCko
github.com/pelletier/go-toml/v2 v2.0.5/go.mod h1:OMHamSCAODeSsVrwwvcJOaoN0LIUIaFVNZzmWyNfXas=
github.com/pelletier/go-toml/v2 v2.2.4 h1:mye9XuhQ6gvn5h28+VilKrrPoQVanw5PMw/TB0t5Ec4=
github.com/pelletier/go-toml/v2 v2.2.4/go.mod h1:2gIqNv+qfxSVS7cM2xJQKtLSTLUE9V8t9Stt+h56mCY=
github.com/perses/spec v0.1.2 h1:yGoygcR3ZusuGDCmRMwsVXCMvMwi1qZndKV6NYNreEw=
github.com/perses/spec v0.1.2/go.mod h1:NoGI5jmGwRdkdPgyYSZJTBL4/Py+dqIPKS2QV8NOvGE=
github.com/perses/common v0.30.2 h1:RAiVxUpX76lTCb4X7pfcXSvYdXQmZwKi4oDKAEO//u0=
github.com/perses/common v0.30.2/go.mod h1:DFtur1QPah2/ChXbKKhw7djYdwNgz27s5fPKpiK0Xao=
github.com/perses/perses v0.53.1 h1:9VY/6p9QWrZwPSV7qiwTMSOsgcB37Lb1AXKT0ORXc6I=
github.com/perses/perses v0.53.1/go.mod h1:ro8fsgBkHYOdrL/MV+fdP9mflKzYCy/+gcbxiaReI/A=
github.com/pierrec/lz4 v2.0.5+incompatible/go.mod h1:pdkljMzZIN41W+lC3N2tnIh5sFi+IEE17M5jbnwPHcY=
github.com/pierrec/lz4/v4 v4.1.25 h1:kocOqRffaIbU5djlIBr7Wh+cx82C0vtFb0fOurZHqD0=
github.com/pierrec/lz4/v4 v4.1.25/go.mod h1:EoQMVJgeeEOMsCqCzqFm2O0cJvljX2nGZjcRIPL34O4=
@@ -1164,6 +1169,10 @@ github.com/zeebo/assert v1.3.1 h1:vukIABvugfNMZMQO1ABsyQDJDTVQbn+LWSMy1ol1h6A=
github.com/zeebo/assert v1.3.1/go.mod h1:Pq9JiuJQpG8JLJdtkwrJESF0Foym2/D9XMU5ciN/wJ0=
github.com/zeebo/xxh3 v1.0.2 h1:xZmwmqxHZA8AI603jOQ0tMqmBr9lPeFwGg6d+xy9DC0=
github.com/zeebo/xxh3 v1.0.2/go.mod h1:5NWz9Sef7zIDm2JHfFlcQvNekmcEl9ekUZQQKCYaDcA=
github.com/zitadel/oidc/v3 v3.45.4 h1:GKyWaPRVQ8sCu9XgJ3NgNGtG52FzwVJpzXjIUG2+YrI=
github.com/zitadel/oidc/v3 v3.45.4/go.mod h1:XALmFXS9/kSom9B6uWin1yJ2WTI/E4Ti5aXJdewAVEs=
github.com/zitadel/schema v1.3.2 h1:gfJvt7dOMfTmxzhscZ9KkapKo3Nei3B6cAxjav+lyjI=
github.com/zitadel/schema v1.3.2/go.mod h1:IZmdfF9Wu62Zu6tJJTH3UsArevs3Y4smfJIj3L8fzxw=
go.etcd.io/etcd/api/v3 v3.5.4/go.mod h1:5GB2vv4A4AOn3yk7MftYGHkUfGtDHnEraIjym4dYz5A=
go.etcd.io/etcd/client/pkg/v3 v3.5.4/go.mod h1:IJHfcCEKxYu1Os13ZdwCwIUTUVGYTSAM3YSwc9/Ac1g=
go.etcd.io/etcd/client/v2 v2.305.4/go.mod h1:Ud+VUwIi9/uQHOMA+4ekToJ12lTxlv0zB/+DHwTGEbU=
@@ -1608,7 +1617,6 @@ golang.org/x/sys v0.0.0-20220328115105-d36c6a25d886/go.mod h1:oPkhp1MJrh7nUepCBc
golang.org/x/sys v0.0.0-20220412211240-33da011f77ad/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220502124256-b6088ccd6cba/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220908164124-27713097b956/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.1.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.6.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.42.0 h1:omrd2nAlyT5ESRdCLYdm3+fMfNFE/+Rf4bDIQImRJeo=

View File

@@ -151,6 +151,26 @@ func (provider *provider) addCloudIntegrationRoutes(router *mux.Router) error {
return err
}
if err := router.Handle("/api/v1/cloud_integrations/{cloud_provider}/accounts/{id}/services", handler.New(
provider.authzMiddleware.AdminAccess(provider.cloudIntegrationHandler.ListAccountServicesMetadata),
handler.OpenAPIDef{
ID: "ListAccountServicesMetadata",
Tags: []string{"cloudintegration"},
Summary: "List account services metadata",
Description: "This endpoint lists the services metadata for the specified account and cloud provider",
Request: nil,
RequestContentType: "",
Response: new(citypes.GettableServicesMetadata),
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/cloud_integrations/{cloud_provider}/services/{service_id}", handler.New(
provider.authzMiddleware.AdminAccess(provider.cloudIntegrationHandler.GetService),
handler.OpenAPIDef{

View File

@@ -75,6 +75,7 @@ type Handler interface {
UpdateAccount(http.ResponseWriter, *http.Request)
DisconnectAccount(http.ResponseWriter, *http.Request)
ListServicesMetadata(http.ResponseWriter, *http.Request)
ListAccountServicesMetadata(http.ResponseWriter, *http.Request)
GetService(http.ResponseWriter, *http.Request)
UpdateService(http.ResponseWriter, *http.Request)
AgentCheckIn(http.ResponseWriter, *http.Request)

View File

@@ -276,6 +276,44 @@ func (handler *handler) ListServicesMetadata(rw http.ResponseWriter, r *http.Req
render.Success(rw, http.StatusOK, cloudintegrationtypes.NewGettableServicesMetadata(services))
}
func (handler *handler) ListAccountServicesMetadata(rw http.ResponseWriter, r *http.Request) {
ctx, cancel := context.WithTimeout(r.Context(), 10*time.Second)
defer cancel()
claims, err := authtypes.ClaimsFromContext(ctx)
if err != nil {
render.Error(rw, err)
return
}
provider, err := cloudintegrationtypes.NewCloudProvider(mux.Vars(r)["cloud_provider"])
if err != nil {
render.Error(rw, err)
return
}
accountID, err := valuer.NewUUID(mux.Vars(r)["id"])
if err != nil {
render.Error(rw, err)
return
}
// check if integration account exists and is not removed.
_, err = handler.module.GetConnectedAccount(ctx, valuer.MustNewUUID(claims.OrgID), accountID, provider)
if err != nil {
render.Error(rw, err)
return
}
services, err := handler.module.ListServicesMetadata(ctx, valuer.MustNewUUID(claims.OrgID), provider, accountID)
if err != nil {
render.Error(rw, err)
return
}
render.Success(rw, http.StatusOK, cloudintegrationtypes.NewGettableServicesMetadata(services))
}
func (handler *handler) GetService(rw http.ResponseWriter, r *http.Request) {
ctx, cancel := context.WithTimeout(r.Context(), 10*time.Second)
defer cancel()
@@ -440,4 +478,3 @@ func (handler *handler) AgentCheckIn(rw http.ResponseWriter, r *http.Request) {
render.Success(rw, http.StatusOK, cloudintegrationtypes.NewGettableAgentCheckIn(provider, resp))
}

View File

@@ -12,7 +12,7 @@ import (
"github.com/SigNoz/signoz/pkg/types/coretypes"
"github.com/SigNoz/signoz/pkg/types/tagtypes"
"github.com/SigNoz/signoz/pkg/valuer"
"github.com/perses/spec/go/common"
"github.com/perses/perses/pkg/model/api/v1/common"
"k8s.io/apimachinery/pkg/util/validation"
)

View File

@@ -9,9 +9,8 @@ import (
"github.com/SigNoz/signoz/pkg/types"
"github.com/SigNoz/signoz/pkg/types/coretypes"
"github.com/SigNoz/signoz/pkg/types/tagtypes"
qb "github.com/SigNoz/signoz/pkg/types/querybuildertypes/querybuildertypesv5"
"github.com/SigNoz/signoz/pkg/valuer"
"github.com/perses/spec/go/common"
"github.com/perses/perses/pkg/model/api/v1/common"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require"
)
@@ -44,7 +43,7 @@ func newTestDashboardV2(t *testing.T, orgID valuer.UUID, source Source) *Dashboa
},
Queries: []Query{
{
Kind: QueryKind(qb.RequestTypeTimeSeries),
Kind: "TimeSeriesQuery",
Spec: QuerySpec{
Plugin: QueryPlugin{
Kind: QueryKindPromQL,

View File

@@ -8,12 +8,12 @@ import (
"github.com/SigNoz/signoz/pkg/errors"
qb "github.com/SigNoz/signoz/pkg/types/querybuildertypes/querybuildertypesv5"
"github.com/perses/spec/go/common"
"github.com/perses/spec/go/dashboard"
v1 "github.com/perses/perses/pkg/model/api/v1"
"github.com/perses/perses/pkg/model/api/v1/common"
)
// DashboardSpec is the SigNoz dashboard v2 spec shape. It mirrors
// dashboard.Spec (Perses) field-for-field, except every common.Plugin
// v1.DashboardSpec (Perses) field-for-field, except every common.Plugin
// occurrence is replaced with a typed SigNoz plugin whose OpenAPI schema is a
// per-site discriminated oneOf.
type DashboardSpec struct {
@@ -24,7 +24,7 @@ type DashboardSpec struct {
Layouts []Layout `json:"layouts"`
Duration common.DurationString `json:"duration"`
RefreshInterval common.DurationString `json:"refreshInterval,omitempty"`
Links []dashboard.Link `json:"links,omitempty"`
Links []v1.Link `json:"links,omitempty"`
}
// ══════════════════════════════════════════════

View File

@@ -133,21 +133,6 @@ func TestInvalidateUnknownPluginKind(t *testing.T) {
}`,
wantContain: "NonExistentPanel",
},
{
name: "unknown panel envelope kind",
data: `{
"panels": {
"p1": {
"kind": "Row",
"spec": {
"plugin": {"kind": "signoz/TimeSeriesPanel", "spec": {}}
}
}
},
"layouts": []
}`,
wantContain: "unknown panel kind",
},
{
name: "unknown query plugin",
data: `{
@@ -157,7 +142,7 @@ func TestInvalidateUnknownPluginKind(t *testing.T) {
"spec": {
"plugin": {"kind": "signoz/TimeSeriesPanel", "spec": {}},
"queries": [{
"kind": "time_series",
"kind": "TimeSeriesQuery",
"spec": {
"plugin": {"kind": "FakeQueryPlugin", "spec": {}}
}
@@ -169,48 +154,6 @@ func TestInvalidateUnknownPluginKind(t *testing.T) {
}`,
wantContain: "FakeQueryPlugin",
},
{
name: "unknown query envelope kind",
data: `{
"panels": {
"p1": {
"kind": "Panel",
"spec": {
"plugin": {"kind": "signoz/TimeSeriesPanel", "spec": {}},
"queries": [{
"kind": "TimeSeriesQuery",
"spec": {
"plugin": {"kind": "signoz/BuilderQuery", "spec": {"name": "A", "signal": "metrics"}}
}
}]
}
}
},
"layouts": []
}`,
wantContain: "unknown query kind",
},
{
name: "empty query envelope kind",
data: `{
"panels": {
"p1": {
"kind": "Panel",
"spec": {
"plugin": {"kind": "signoz/TimeSeriesPanel", "spec": {}},
"queries": [{
"kind": "",
"spec": {
"plugin": {"kind": "signoz/BuilderQuery", "spec": {"name": "A", "signal": "metrics"}}
}
}]
}
}
},
"layouts": []
}`,
wantContain: "unknown query kind",
},
{
name: "unknown variable plugin",
data: `{
@@ -303,7 +246,7 @@ func TestRejectUnknownFieldsInPluginSpec(t *testing.T) {
"spec": {
"plugin": {"kind": "signoz/TimeSeriesPanel", "spec": {}},
"queries": [{
"kind": "time_series",
"kind": "TimeSeriesQuery",
"spec": {
"plugin": {
"kind": "signoz/PromQLQuery",
@@ -381,7 +324,7 @@ func TestInvalidateWrongFieldTypeInPluginSpec(t *testing.T) {
"spec": {
"plugin": {"kind": "signoz/TimeSeriesPanel", "spec": {}},
"queries": [{
"kind": "time_series",
"kind": "TimeSeriesQuery",
"spec": {
"plugin": {
"kind": "signoz/PromQLQuery",
@@ -446,7 +389,7 @@ func TestInvalidateBadPanelSpecValues(t *testing.T) {
"spec": {}
},
"queries": [{
"kind": "time_series",
"kind": "TimeSeriesQuery",
"spec": {
"plugin": {
"kind": "signoz/BuilderQuery",
@@ -677,8 +620,8 @@ func TestInvalidatePanelWithMultipleDirectQueries(t *testing.T) {
"spec": {
"plugin": {"kind": "signoz/TimeSeriesPanel", "spec": {}},
"queries": [
{"kind": "time_series", "spec": {"plugin": {"kind": "signoz/BuilderQuery", "spec": {"name": "A", "signal": "metrics"}}}},
{"kind": "time_series", "spec": {"plugin": {"kind": "signoz/BuilderQuery", "spec": {"name": "B", "signal": "metrics"}}}}
{"kind": "TimeSeriesQuery", "spec": {"plugin": {"kind": "signoz/BuilderQuery", "spec": {"name": "A", "signal": "metrics"}}}},
{"kind": "TimeSeriesQuery", "spec": {"plugin": {"kind": "signoz/BuilderQuery", "spec": {"name": "B", "signal": "metrics"}}}}
]
}
}
@@ -795,7 +738,7 @@ func TestTimeSeriesPanelDefaults(t *testing.T) {
"kind": "signoz/TimeSeriesPanel",
"spec": {}
},
"queries": [{"kind": "time_series", "spec": {"plugin": {"kind": "signoz/PromQLQuery", "spec": {"name": "A", "query": "up"}}}}]
"queries": [{"kind": "TimeSeriesQuery", "spec": {"plugin": {"kind": "signoz/PromQLQuery", "spec": {"name": "A", "query": "up"}}}}]
}
}
},
@@ -843,7 +786,7 @@ func TestNumberPanelDefaults(t *testing.T) {
"kind": "signoz/NumberPanel",
"spec": {"thresholds": [{"value": 100, "color": "Red"}]}
},
"queries": [{"kind": "time_series", "spec": {"plugin": {"kind": "signoz/PromQLQuery", "spec": {"name": "A", "query": "up"}}}}]
"queries": [{"kind": "TimeSeriesQuery", "spec": {"plugin": {"kind": "signoz/PromQLQuery", "spec": {"name": "A", "query": "up"}}}}]
}
}
},
@@ -904,7 +847,7 @@ func TestStorageRoundTrip(t *testing.T) {
"kind": "signoz/TimeSeriesPanel",
"spec": {}
},
"queries": [{"kind": "time_series", "spec": {"plugin": {"kind": "signoz/PromQLQuery", "spec": {"name": "A", "query": "up"}}}}]
"queries": [{"kind": "TimeSeriesQuery", "spec": {"plugin": {"kind": "signoz/PromQLQuery", "spec": {"name": "A", "query": "up"}}}}]
}
},
"p2": {
@@ -914,7 +857,7 @@ func TestStorageRoundTrip(t *testing.T) {
"kind": "signoz/NumberPanel",
"spec": {"thresholds": [{"value": 100, "color": "Red"}]}
},
"queries": [{"kind": "time_series", "spec": {"plugin": {"kind": "signoz/PromQLQuery", "spec": {"name": "A", "query": "up"}}}}]
"queries": [{"kind": "TimeSeriesQuery", "spec": {"plugin": {"kind": "signoz/PromQLQuery", "spec": {"name": "A", "query": "up"}}}}]
}
}
},
@@ -1119,7 +1062,7 @@ func TestPanelTypeQueryTypeCompatibility(t *testing.T) {
return []byte(`{
"panels": {"p1": {"kind": "Panel", "spec": {
"plugin": {"kind": "` + panelKind + `", "spec": {}},
"queries": [{"kind": "time_series", "spec": {"plugin": {"kind": "` + queryKind + `", "spec": ` + querySpec + `}}}]
"queries": [{"kind": "TimeSeriesQuery", "spec": {"plugin": {"kind": "` + queryKind + `", "spec": ` + querySpec + `}}}]
}}},
"layouts": []
}`)
@@ -1128,7 +1071,7 @@ func TestPanelTypeQueryTypeCompatibility(t *testing.T) {
return []byte(`{
"panels": {"p1": {"kind": "Panel", "spec": {
"plugin": {"kind": "` + panelKind + `", "spec": {}},
"queries": [{"kind": "time_series", "spec": {"plugin": {"kind": "signoz/CompositeQuery", "spec": {
"queries": [{"kind": "TimeSeriesQuery", "spec": {"plugin": {"kind": "signoz/CompositeQuery", "spec": {
"queries": [{"type": "` + subType + `", "spec": ` + subSpec + `}]
}}}}]
}}},

View File

@@ -10,8 +10,8 @@ import (
"strings"
"testing"
"github.com/perses/spec/go/dashboard"
"github.com/perses/spec/go/datasource"
v1 "github.com/perses/perses/pkg/model/api/v1"
"github.com/perses/perses/pkg/model/api/v1/dashboard"
"github.com/stretchr/testify/assert"
)
@@ -22,12 +22,12 @@ func TestDashboardSpecMatchesPerses(t *testing.T) {
ours reflect.Type
perses reflect.Type
}{
{"DashboardSpec", typeOf[DashboardSpec](), typeOf[dashboard.Spec]()},
{"Panel", typeOf[Panel](), typeOf[dashboard.Panel]()},
{"PanelSpec", typeOf[PanelSpec](), typeOf[dashboard.PanelSpec]()},
{"Query", typeOf[Query](), typeOf[dashboard.Query]()},
{"QuerySpec", typeOf[QuerySpec](), typeOf[dashboard.QuerySpec]()},
{"DatasourceSpec", typeOf[DatasourceSpec](), typeOf[datasource.Spec]()},
{"DashboardSpec", typeOf[DashboardSpec](), typeOf[v1.DashboardSpec]()},
{"Panel", typeOf[Panel](), typeOf[v1.Panel]()},
{"PanelSpec", typeOf[PanelSpec](), typeOf[v1.PanelSpec]()},
{"Query", typeOf[Query](), typeOf[v1.Query]()},
{"QuerySpec", typeOf[QuerySpec](), typeOf[v1.QuerySpec]()},
{"DatasourceSpec", typeOf[DatasourceSpec](), typeOf[v1.DatasourceSpec]()},
{"Variable", typeOf[Variable](), typeOf[dashboard.Variable]()},
{"ListVariableSpec", typeOf[ListVariableSpec](), typeOf[dashboard.ListVariableSpec]()},
{"Layout", typeOf[Layout](), typeOf[dashboard.Layout]()},

View File

@@ -1,16 +1,14 @@
package dashboardtypes
import (
"encoding/json"
"maps"
"slices"
"github.com/SigNoz/signoz/pkg/errors"
qb "github.com/SigNoz/signoz/pkg/types/querybuildertypes/querybuildertypesv5"
"github.com/SigNoz/signoz/pkg/valuer"
"github.com/perses/spec/go/common"
"github.com/perses/spec/go/dashboard"
"github.com/perses/spec/go/dashboard/variable"
v1 "github.com/perses/perses/pkg/model/api/v1"
"github.com/perses/perses/pkg/model/api/v1/common"
"github.com/perses/perses/pkg/model/api/v1/dashboard"
"github.com/perses/perses/pkg/model/api/v1/variable"
"github.com/swaggest/jsonschema-go"
)
@@ -29,36 +27,15 @@ type DatasourceSpec struct {
// ══════════════════════════════════════════════
type Panel struct {
Kind PanelKind `json:"kind"`
Kind string `json:"kind"`
Spec PanelSpec `json:"spec"`
}
// PanelKind is the panel envelope discriminator. Perses leaves it a free
// string; SigNoz locks it to the single valid value.
type PanelKind string
const PanelKindPanel PanelKind = "Panel"
// Enum surfaces the allowed value in the generated OpenAPI schema.
func (PanelKind) Enum() []any { return []any{PanelKindPanel} }
func (k *PanelKind) UnmarshalJSON(data []byte) error {
var s string
if err := json.Unmarshal(data, &s); err != nil {
return errors.WrapInvalidInputf(err, ErrCodeDashboardInvalidInput, "invalid panel kind")
}
if PanelKind(s) != PanelKindPanel {
return errors.NewInvalidInputf(ErrCodeDashboardInvalidInput, "unknown panel kind %q; allowed values: %s", s, allowedValuesForKind([]PanelKind{PanelKindPanel}))
}
*k = PanelKind(s)
return nil
}
type PanelSpec struct {
Display *dashboard.PanelDisplay `json:"display,omitempty"`
Plugin PanelPlugin `json:"plugin"`
Queries []Query `json:"queries,omitempty"`
Links []dashboard.Link `json:"links,omitempty"`
Display *v1.PanelDisplay `json:"display,omitempty"`
Plugin PanelPlugin `json:"plugin"`
Queries []Query `json:"queries,omitempty"`
Links []v1.Link `json:"links,omitempty"`
}
// ══════════════════════════════════════════════
@@ -66,29 +43,10 @@ type PanelSpec struct {
// ══════════════════════════════════════════════
type Query struct {
Kind QueryKind `json:"kind"`
Kind string `json:"kind"`
Spec QuerySpec `json:"spec"`
}
type QueryKind qb.RequestType
func (QueryKind) Enum() []any { return (qb.RequestType{}).Enum() }
func (k *QueryKind) UnmarshalJSON(data []byte) error {
var s string
if err := json.Unmarshal(data, &s); err != nil {
return errors.WrapInvalidInputf(err, ErrCodeDashboardInvalidInput, "invalid query kind")
}
rt := qb.RequestType{String: valuer.NewString(s)}
for _, allowed := range (qb.RequestType{}).Enum() {
if allowed == rt {
*k = QueryKind(rt)
return nil
}
}
return errors.NewInvalidInputf(ErrCodeDashboardInvalidInput, "unknown query kind %q; allowed values: %s", s, "`scalar`, `time_series`, `raw`, `raw_stream`, `trace`")
}
type QuerySpec struct {
Name string `json:"name,omitempty"`
Plugin QueryPlugin `json:"plugin"`

View File

@@ -132,7 +132,7 @@
],
"queries": [
{
"kind": "time_series",
"kind": "TimeSeriesQuery",
"spec": {
"plugin": {
"kind": "signoz/BuilderQuery",
@@ -191,7 +191,7 @@
},
"queries": [
{
"kind": "time_series",
"kind": "TimeSeriesQuery",
"spec": {
"plugin": {
"kind": "signoz/CompositeQuery",
@@ -269,7 +269,7 @@
},
"queries": [
{
"kind": "time_series",
"kind": "TimeSeriesQuery",
"spec": {
"plugin": {
"kind": "signoz/BuilderQuery",
@@ -334,7 +334,7 @@
},
"queries": [
{
"kind": "time_series",
"kind": "TimeSeriesQuery",
"spec": {
"plugin": {
"kind": "signoz/BuilderQuery",
@@ -373,7 +373,7 @@
},
"queries": [
{
"kind": "time_series",
"kind": "TimeSeriesQuery",
"spec": {
"plugin": {
"kind": "signoz/BuilderQuery",
@@ -418,7 +418,7 @@
},
"queries": [
{
"kind": "time_series",
"kind": "TimeSeriesQuery",
"spec": {
"plugin": {
"kind": "signoz/BuilderQuery",
@@ -476,7 +476,7 @@
},
"queries": [
{
"kind": "time_series",
"kind": "TimeSeriesQuery",
"spec": {
"plugin": {
"kind": "signoz/ClickHouseSQL",
@@ -517,7 +517,7 @@
},
"queries": [
{
"kind": "raw",
"kind": "LogQuery",
"spec": {
"plugin": {
"kind": "signoz/BuilderQuery",
@@ -571,7 +571,7 @@
},
"queries": [
{
"kind": "time_series",
"kind": "TimeSeriesQuery",
"spec": {
"plugin": {
"kind": "signoz/BuilderQuery",
@@ -610,7 +610,7 @@
},
"queries": [
{
"kind": "time_series",
"kind": "TimeSeriesQuery",
"spec": {
"plugin": {
"kind": "signoz/CompositeQuery",
@@ -681,7 +681,7 @@
},
"queries": [
{
"kind": "time_series",
"kind": "TimeSeriesQuery",
"spec": {
"plugin": {
"kind": "signoz/CompositeQuery",
@@ -722,7 +722,7 @@
},
"queries": [
{
"kind": "time_series",
"kind": "TimeSeriesQuery",
"spec": {
"plugin": {
"kind": "signoz/PromQLQuery",

View File

@@ -30,7 +30,7 @@
},
"queries": [
{
"kind": "time_series",
"kind": "TimeSeriesQuery",
"spec": {
"plugin": {
"kind": "signoz/BuilderQuery",
@@ -85,7 +85,7 @@
},
"queries": [
{
"kind": "time_series",
"kind": "TimeSeriesQuery",
"spec": {
"plugin": {
"kind": "signoz/BuilderQuery",

View File

@@ -86,6 +86,49 @@ def test_list_services_with_account(
assert svc["enabled"] is False, f"Service {svc['id']} should be disabled before any config is set"
EC2_SERVICE_ID = "ec2"
def test_list_account_services(
signoz: types.SigNoz,
create_user_admin: types.Operation, # pylint: disable=unused-argument
get_token: Callable[[str, str], str],
create_cloud_integration_account: Callable,
) -> None:
"""ListAccountServicesMetadata reflects enabled state after enabling a service."""
admin_token = get_token(USER_ADMIN_EMAIL, USER_ADMIN_PASSWORD)
account = create_cloud_integration_account(admin_token, CLOUD_PROVIDER)
account_id = account["id"]
checkin = simulate_agent_checkin(signoz, admin_token, CLOUD_PROVIDER, account_id, str(uuid.uuid4()))
assert checkin.status_code == HTTPStatus.OK, f"Check-in failed: {checkin.text}"
put_response = requests.put(
signoz.self.host_configs["8080"].get(f"/api/v1/cloud_integrations/{CLOUD_PROVIDER}/accounts/{account_id}/services/{EC2_SERVICE_ID}"),
headers={"Authorization": f"Bearer {admin_token}"},
json={"config": {"aws": {"metrics": {"enabled": True}, "logs": {"enabled": True}}}},
timeout=10,
)
assert put_response.status_code == HTTPStatus.NO_CONTENT, f"Enable ec2 failed: {put_response.status_code}: {put_response.text}"
list_response = requests.get(
signoz.self.host_configs["8080"].get(f"/api/v1/cloud_integrations/{CLOUD_PROVIDER}/accounts/{account_id}/services"),
headers={"Authorization": f"Bearer {admin_token}"},
timeout=10,
)
assert list_response.status_code == HTTPStatus.OK, f"Expected 200, got {list_response.status_code}"
data = list_response.json()["data"]
assert "services" in data, "Response should contain 'services' field"
assert isinstance(data["services"], list), "services should be a list"
assert len(data["services"]) > 0, "services list should be non-empty"
ec2_service = next((s for s in data["services"] if s["id"] == EC2_SERVICE_ID), None)
assert ec2_service is not None, f"EC2 service '{EC2_SERVICE_ID}' not found in services list"
assert ec2_service["enabled"] is True, f"EC2 service should be enabled, got: {ec2_service['enabled']}"
def test_get_service_details_without_account(
signoz: types.SigNoz,
create_user_admin: types.Operation, # pylint: disable=unused-argument