diff --git a/pkg/services/correlations/api.go b/pkg/services/correlations/api.go index fca5c38b151..aebba66f847 100644 --- a/pkg/services/correlations/api.go +++ b/pkg/services/correlations/api.go @@ -150,6 +150,10 @@ type DeleteCorrelationResponse struct { func (s *CorrelationsService) updateHandler(c *models.ReqContext) response.Response { cmd := UpdateCorrelationCommand{} if err := web.Bind(c.Req, &cmd); err != nil { + if errors.Is(err, ErrUpdateCorrelationEmptyParams) { + return response.Error(http.StatusBadRequest, "At least one of label, description or config is required", err) + } + return response.Error(http.StatusBadRequest, "bad request data", err) } @@ -159,10 +163,6 @@ func (s *CorrelationsService) updateHandler(c *models.ReqContext) response.Respo correlation, err := s.UpdateCorrelation(c.Req.Context(), cmd) if err != nil { - if errors.Is(err, ErrUpdateCorrelationEmptyParams) { - return response.Error(http.StatusBadRequest, "At least one of label, description or config is required", err) - } - if errors.Is(err, ErrSourceDataSourceDoesNotExists) { return response.Error(http.StatusNotFound, "Data source not found", err) } diff --git a/pkg/services/correlations/database.go b/pkg/services/correlations/database.go index efb51675d3a..d546edb57af 100644 --- a/pkg/services/correlations/database.go +++ b/pkg/services/correlations/database.go @@ -99,9 +99,6 @@ func (s CorrelationsService) updateCorrelation(ctx context.Context, cmd UpdateCo return ErrSourceDataSourceReadOnly } - if cmd.Label == nil && cmd.Description == nil && (cmd.Config == nil || (cmd.Config.Field == nil && cmd.Config.Target == nil && cmd.Config.Type == nil)) { - return ErrUpdateCorrelationEmptyParams - } found, err := session.Get(&correlation) if !found { return ErrCorrelationNotFound diff --git a/pkg/services/correlations/models.go b/pkg/services/correlations/models.go index a64ba7c9601..58e3ebcb247 100644 --- a/pkg/services/correlations/models.go +++ b/pkg/services/correlations/models.go @@ -33,12 +33,14 @@ func (t CorrelationConfigType) Validate() error { type CorrelationConfig struct { // Field used to attach the correlation link // required:true + // example: message Field string `json:"field" binding:"Required"` // Target type // required:true Type CorrelationConfigType `json:"type" binding:"Required"` // Target data query // required:true + // example: { "expr": "job=app" } Target map[string]interface{} `json:"target" binding:"Required"` } @@ -58,18 +60,6 @@ func (c CorrelationConfig) MarshalJSON() ([]byte, error) { }) } -type CorrelationConfigUpdateDTO struct { - // Field used to attach the correlation link - // required:true - Field *string `json:"field"` - // Target type - // required:true - Type *CorrelationConfigType `json:"type"` - // Target data query - // required:true - Target *map[string]interface{} `json:"target"` -} - // Correlation is the model for correlations definitions // swagger:model type Correlation struct { @@ -89,7 +79,6 @@ type Correlation struct { // example: Logs to Traces Description string `json:"description" xorm:"description"` // Correlation Configuration - // example: { field: "job", type: "query", target: { query: "job=app" } } Config CorrelationConfig `json:"config" xorm:"jsonb config"` } @@ -108,7 +97,7 @@ type CreateCorrelationCommand struct { SourceUID string `json:"-"` OrgId int64 `json:"-"` SkipReadOnlyCheck bool `json:"-"` - // Target data source UID to which the correlation is created + // Target data source UID to which the correlation is created. required if config.type = query // example:PE1C5CBDA0504A6A3 TargetUID *string `json:"targetUID"` // Optional label identifying the correlation @@ -118,7 +107,6 @@ type CreateCorrelationCommand struct { // example: Logs to Traces Description string `json:"description"` // Arbitrary configuration object handled in frontend - // example: { field: "job", type: "query", target: { query: "job=app" } } Config CorrelationConfig `json:"config" binding:"Required"` } @@ -153,9 +141,32 @@ type UpdateCorrelationResponseBody struct { Message string `json:"message"` } +// swagger:model +type CorrelationConfigUpdateDTO struct { + // Field used to attach the correlation link + // example: message + Field *string `json:"field"` + // Target type + Type *CorrelationConfigType `json:"type"` + // Target data query + // example: { "expr": "job=app" } + Target *map[string]interface{} `json:"target"` +} + +func (c CorrelationConfigUpdateDTO) Validate() error { + if c.Type != nil { + if err := c.Type.Validate(); err != nil { + return err + } + } + + return nil +} + // UpdateCorrelationCommand is the command for updating a correlation +// swagger:model type UpdateCorrelationCommand struct { - // UID of the correlation to be deleted. + // UID of the correlation to be updated. UID string `json:"-"` SourceUID string `json:"-"` OrgId int64 `json:"-"` @@ -167,10 +178,23 @@ type UpdateCorrelationCommand struct { // example: Logs to Traces Description *string `json:"description"` // Correlation Configuration - // example: { field: "job", type: "query", target: { query: "job=app" } } Config *CorrelationConfigUpdateDTO `json:"config"` } +func (c UpdateCorrelationCommand) Validate() error { + if c.Config != nil { + if err := c.Config.Validate(); err != nil { + return err + } + } + + if c.Label == nil && c.Description == nil && (c.Config == nil || (c.Config.Field == nil && c.Config.Type == nil && c.Config.Target == nil)) { + return ErrUpdateCorrelationEmptyParams + } + + return nil +} + // GetCorrelationQuery is the query to retrieve a single correlation type GetCorrelationQuery struct { // UID of the correlation diff --git a/pkg/tests/api/correlations/correlations_update_test.go b/pkg/tests/api/correlations/correlations_update_test.go index 60ae93712c2..5b603f9eb71 100644 --- a/pkg/tests/api/correlations/correlations_update_test.go +++ b/pkg/tests/api/correlations/correlations_update_test.go @@ -99,8 +99,10 @@ func TestIntegrationUpdateCorrelation(t *testing.T) { t.Run("inexistent source data source should result in a 404", func(t *testing.T) { res := ctx.Patch(PatchParams{ - url: fmt.Sprintf("/api/datasources/uid/%s/correlations/%s", "some-ds-uid", "some-correlation-uid"), - body: `{}`, + url: fmt.Sprintf("/api/datasources/uid/%s/correlations/%s", "some-ds-uid", "some-correlation-uid"), + body: `{ + "label": "some-label" + }`, user: adminUser, }) require.Equal(t, http.StatusNotFound, res.StatusCode) @@ -145,7 +147,9 @@ func TestIntegrationUpdateCorrelation(t *testing.T) { res := ctx.Patch(PatchParams{ url: fmt.Sprintf("/api/datasources/uid/%s/correlations/%s", readOnlyDS, "nonexistent-correlation-uid"), user: adminUser, - body: `{}`, + body: `{ + "label": "some-label" + }`, }) require.Equal(t, http.StatusForbidden, res.StatusCode) diff --git a/public/api-merged.json b/public/api-merged.json index 5a070db9539..0b8b1d7e0a3 100644 --- a/public/api-merged.json +++ b/public/api-merged.json @@ -8524,7 +8524,7 @@ "tags": [ "service_accounts" ], - "summary": "Create service account", + "summary": "# Create service account", "operationId": "createServiceAccount", "parameters": [ { @@ -8560,7 +8560,7 @@ "tags": [ "service_accounts" ], - "summary": "Search service accounts with paging", + "summary": "# Search service accounts with paging", "operationId": "searchOrgServiceAccountsWithPaging", "parameters": [ { @@ -8616,7 +8616,7 @@ "tags": [ "service_accounts" ], - "summary": "Get single serviceaccount by Id", + "summary": "# Get single serviceaccount by Id", "operationId": "retrieveServiceAccount", "parameters": [ { @@ -8653,7 +8653,7 @@ "tags": [ "service_accounts" ], - "summary": "Delete service account", + "summary": "# Delete service account", "operationId": "deleteServiceAccount", "parameters": [ { @@ -8687,7 +8687,7 @@ "tags": [ "service_accounts" ], - "summary": "Update service account", + "summary": "# Update service account", "operationId": "updateServiceAccount", "parameters": [ { @@ -8733,7 +8733,7 @@ "tags": [ "service_accounts" ], - "summary": "Get service account tokens", + "summary": "# Get service account tokens", "operationId": "listTokens", "parameters": [ { @@ -8767,7 +8767,7 @@ "tags": [ "service_accounts" ], - "summary": "CreateNewToken adds a token to a service account", + "summary": "# CreateNewToken adds a token to a service account", "operationId": "createToken", "parameters": [ { @@ -8816,7 +8816,7 @@ "tags": [ "service_accounts" ], - "summary": "DeleteToken deletes service account tokens", + "summary": "# DeleteToken deletes service account tokens", "operationId": "deleteToken", "parameters": [ { @@ -11493,12 +11493,16 @@ "properties": { "field": { "description": "Field used to attach the correlation link", - "type": "string" + "type": "string", + "example": "message" }, "target": { "description": "Target data query", "type": "object", - "additionalProperties": false + "additionalProperties": false, + "example": { + "expr": "job=app" + } }, "type": { "$ref": "#/definitions/CorrelationConfigType" @@ -11508,6 +11512,27 @@ "CorrelationConfigType": { "type": "string" }, + "CorrelationConfigUpdateDTO": { + "type": "object", + "properties": { + "field": { + "description": "Field used to attach the correlation link", + "type": "string", + "example": "message" + }, + "target": { + "description": "Target data query", + "type": "object", + "additionalProperties": false, + "example": { + "expr": "job=app" + } + }, + "type": { + "$ref": "#/definitions/CorrelationConfigType" + } + } + }, "CreateAlertNotificationCommand": { "type": "object", "properties": { @@ -11561,7 +11586,7 @@ "example": "My label" }, "targetUID": { - "description": "Target data source UID to which the correlation is created", + "description": "Target data source UID to which the correlation is created. required if config.type = query", "type": "string", "example": "PE1C5CBDA0504A6A3" } @@ -14338,7 +14363,7 @@ "type": "string" }, "items": { - "description": "The ordered list of items that the playlist will iterate over.", + "description": "The ordered list of items that the playlist will iterate over.\nFIXME! This should not be optional, but changing it makes the godegen awkward", "type": "array", "items": { "$ref": "#/definitions/PlaylistItem" @@ -17626,6 +17651,9 @@ "description": "UpdateCorrelationCommand is the command for updating a correlation", "type": "object", "properties": { + "config": { + "$ref": "#/definitions/CorrelationConfigUpdateDTO" + }, "description": { "description": "Optional description of the correlation", "type": "string", diff --git a/public/api-spec.json b/public/api-spec.json index 2e64db251ec..89fbf83a47d 100644 --- a/public/api-spec.json +++ b/public/api-spec.json @@ -7877,7 +7877,7 @@ "tags": [ "service_accounts" ], - "summary": "Create service account", + "summary": "# Create service account", "operationId": "createServiceAccount", "parameters": [ { @@ -7913,7 +7913,7 @@ "tags": [ "service_accounts" ], - "summary": "Search service accounts with paging", + "summary": "# Search service accounts with paging", "operationId": "searchOrgServiceAccountsWithPaging", "parameters": [ { @@ -7969,7 +7969,7 @@ "tags": [ "service_accounts" ], - "summary": "Get single serviceaccount by Id", + "summary": "# Get single serviceaccount by Id", "operationId": "retrieveServiceAccount", "parameters": [ { @@ -8006,7 +8006,7 @@ "tags": [ "service_accounts" ], - "summary": "Delete service account", + "summary": "# Delete service account", "operationId": "deleteServiceAccount", "parameters": [ { @@ -8040,7 +8040,7 @@ "tags": [ "service_accounts" ], - "summary": "Update service account", + "summary": "# Update service account", "operationId": "updateServiceAccount", "parameters": [ { @@ -8086,7 +8086,7 @@ "tags": [ "service_accounts" ], - "summary": "Get service account tokens", + "summary": "# Get service account tokens", "operationId": "listTokens", "parameters": [ { @@ -8120,7 +8120,7 @@ "tags": [ "service_accounts" ], - "summary": "CreateNewToken adds a token to a service account", + "summary": "# CreateNewToken adds a token to a service account", "operationId": "createToken", "parameters": [ { @@ -8169,7 +8169,7 @@ "tags": [ "service_accounts" ], - "summary": "DeleteToken deletes service account tokens", + "summary": "# DeleteToken deletes service account tokens", "operationId": "deleteToken", "parameters": [ { @@ -10513,12 +10513,16 @@ "properties": { "field": { "description": "Field used to attach the correlation link", - "type": "string" + "type": "string", + "example": "message" }, "target": { "description": "Target data query", "type": "object", - "additionalProperties": {} + "additionalProperties": {}, + "example": { + "expr": "job=app" + } }, "type": { "$ref": "#/definitions/CorrelationConfigType" @@ -10528,6 +10532,27 @@ "CorrelationConfigType": { "type": "string" }, + "CorrelationConfigUpdateDTO": { + "type": "object", + "properties": { + "field": { + "description": "Field used to attach the correlation link", + "type": "string", + "example": "message" + }, + "target": { + "description": "Target data query", + "type": "object", + "additionalProperties": {}, + "example": { + "expr": "job=app" + } + }, + "type": { + "$ref": "#/definitions/CorrelationConfigType" + } + } + }, "CreateAlertNotificationCommand": { "type": "object", "properties": { @@ -10581,7 +10606,7 @@ "example": "My label" }, "targetUID": { - "description": "Target data source UID to which the correlation is created", + "description": "Target data source UID to which the correlation is created. required if config.type = query", "type": "string", "example": "PE1C5CBDA0504A6A3" } @@ -12549,7 +12574,7 @@ "type": "string" }, "items": { - "description": "The ordered list of items that the playlist will iterate over.", + "description": "The ordered list of items that the playlist will iterate over.\nFIXME! This should not be optional, but changing it makes the godegen awkward", "type": "array", "items": { "$ref": "#/definitions/PlaylistItem" @@ -14337,6 +14362,9 @@ "description": "UpdateCorrelationCommand is the command for updating a correlation", "type": "object", "properties": { + "config": { + "$ref": "#/definitions/CorrelationConfigUpdateDTO" + }, "description": { "description": "Optional description of the correlation", "type": "string",