mirror of
https://github.com/grafana/grafana.git
synced 2025-07-28 03:42:12 +08:00
Correlations: Add GetCorrelation(s) HTTP APIs (#52517)
* Correlations: Get Single correlations * Correlations: Get all correlations for given source ds * Correlations: Get all correlations * add tests * add DB indices * fix lint errors * remove skip from tests * use DatasourceService in test
This commit is contained in:
@ -150,3 +150,126 @@ Status codes:
|
||||
|
||||
- **200** – OK
|
||||
- **401** – Unauthorized
|
||||
- **404** – Not found, either source data source or correlation were not found
|
||||
- **500** – Internal error
|
||||
|
||||
## Get all correlations originating from a given data source
|
||||
|
||||
`GET /api/datasources/uid/:sourceUID/correlations`
|
||||
|
||||
Get all correlations originating from the data source identified by the given `sourceUID` in the path.
|
||||
|
||||
**Example request:**
|
||||
|
||||
```http
|
||||
GET /api/datasources/uid/uyBf2637k/correlations HTTP/1.1
|
||||
Accept: application/json
|
||||
Authorization: Bearer eyJrIjoiT0tTcG1pUlY2RnVKZTFVaDFsNFZXdE9ZWmNrMkZYbk
|
||||
```
|
||||
|
||||
**Example response:**
|
||||
|
||||
```http
|
||||
HTTP/1.1 200
|
||||
Content-Type: application/json
|
||||
[
|
||||
```
|
||||
|
||||
Status codes:
|
||||
|
||||
- **200** – OK
|
||||
- **401** – Unauthorized
|
||||
- **404** – Not found, either source data source is not found or no correlation exists originating from the given data source
|
||||
- **500** – Internal error
|
||||
|
||||
## Get all correlations
|
||||
|
||||
`GET /api/datasources/correlations`
|
||||
|
||||
Get all correlations.
|
||||
|
||||
**Example request:**
|
||||
|
||||
```http
|
||||
GET /api/datasources/correlations HTTP/1.1
|
||||
Accept: application/json
|
||||
Authorization: Bearer eyJrIjoiT0tTcG1pUlY2RnVKZTFVaDFsNFZXdE9ZWmNrMkZYbk
|
||||
```
|
||||
|
||||
**Example response:**
|
||||
|
||||
```http
|
||||
HTTP/1.1 200
|
||||
Content-Type: application/json
|
||||
[
|
||||
```
|
||||
|
||||
Status codes:
|
||||
|
||||
- **200** – OK
|
||||
- **401** – Unauthorized
|
||||
- **404** – Not found, no correlation is found
|
||||
- **500** – Internal error
|
||||
"targetUID": "PDDA8E780A17E7EF1",
|
||||
"uid": "J6gn7d31L"
|
||||
},
|
||||
{
|
||||
"description": "Logs to Metrics",
|
||||
"label": "Another Label",
|
||||
"sourceUID": "uyBf2637k",
|
||||
"targetUID": "P15396BDD62B2BE29",
|
||||
"uid": "uWCpURgVk"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
Status codes:
|
||||
|
||||
- **200** – OK
|
||||
- **401** – Unauthorized
|
||||
- **404** – Not found, either source data source is not found or no correlation exists originating from the given data source
|
||||
- **500** – Internal error
|
||||
|
||||
## Get all correlations
|
||||
|
||||
`GET /api/datasources/correlations`
|
||||
|
||||
Get all correlations.
|
||||
|
||||
**Example request:**
|
||||
|
||||
```http
|
||||
GET /api/datasources/correlations HTTP/1.1
|
||||
Accept: application/json
|
||||
Authorization: Bearer eyJrIjoiT0tTcG1pUlY2RnVKZTFVaDFsNFZXdE9ZWmNrMkZYbk
|
||||
```
|
||||
|
||||
**Example response:**
|
||||
|
||||
```http
|
||||
HTTP/1.1 200
|
||||
Content-Type: application/json
|
||||
[
|
||||
{
|
||||
"description": "Prometheus to Loki",
|
||||
"label": "My Label",
|
||||
"sourceUID": "uyBf2637k",
|
||||
"targetUID": "PDDA8E780A17E7EF1",
|
||||
"uid": "J6gn7d31L"
|
||||
},
|
||||
{
|
||||
"description": "Loki to Tempo",
|
||||
"label": "Another Label",
|
||||
"sourceUID": "PDDA8E780A17E7EF1",
|
||||
"targetUID": "P15396BDD62B2BE29",
|
||||
"uid": "uWCpURgVk"
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
Status codes:
|
||||
|
||||
- **200** – OK
|
||||
- **401** – Unauthorized
|
||||
- **404** – Not found, no correlation is found
|
||||
- **500** – Internal error
|
||||
|
@ -18,10 +18,17 @@ func (s *CorrelationsService) registerAPIEndpoints() {
|
||||
uidScope := datasources.ScopeProvider.GetResourceScopeUID(ac.Parameter(":uid"))
|
||||
authorize := ac.Middleware(s.AccessControl)
|
||||
|
||||
s.RouteRegister.Get("/api/datasources/correlations", middleware.ReqSignedIn, authorize(ac.ReqViewer, ac.EvalPermission(datasources.ActionRead)), routing.Wrap(s.getCorrelationsHandler))
|
||||
|
||||
s.RouteRegister.Group("/api/datasources/uid/:uid/correlations", func(entities routing.RouteRegister) {
|
||||
entities.Get("/", middleware.ReqSignedIn, authorize(ac.ReqViewer, ac.EvalPermission(datasources.ActionRead)), routing.Wrap(s.getCorrelationsBySourceUIDHandler))
|
||||
entities.Post("/", middleware.ReqSignedIn, authorize(ac.ReqOrgAdmin, ac.EvalPermission(datasources.ActionWrite, uidScope)), routing.Wrap(s.createHandler))
|
||||
entities.Delete("/:correlationUID", middleware.ReqSignedIn, authorize(ac.ReqOrgAdmin, ac.EvalPermission(datasources.ActionWrite, uidScope)), routing.Wrap(s.deleteHandler))
|
||||
entities.Patch("/:correlationUID", middleware.ReqSignedIn, authorize(ac.ReqOrgAdmin, ac.EvalPermission(datasources.ActionWrite, uidScope)), routing.Wrap(s.updateHandler))
|
||||
|
||||
entities.Group("/:correlationUID", func(entities routing.RouteRegister) {
|
||||
entities.Get("/", middleware.ReqSignedIn, authorize(ac.ReqViewer, ac.EvalPermission(datasources.ActionRead)), routing.Wrap(s.getCorrelationHandler))
|
||||
entities.Delete("/", middleware.ReqSignedIn, authorize(ac.ReqOrgAdmin, ac.EvalPermission(datasources.ActionWrite, uidScope)), routing.Wrap(s.deleteHandler))
|
||||
entities.Patch("/", middleware.ReqSignedIn, authorize(ac.ReqOrgAdmin, ac.EvalPermission(datasources.ActionWrite, uidScope)), routing.Wrap(s.updateHandler))
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
@ -191,3 +198,125 @@ type UpdateCorrelationResponse struct {
|
||||
// in: body
|
||||
Body UpdateCorrelationResponseBody `json:"body"`
|
||||
}
|
||||
|
||||
// swagger:route GET /datasources/uid/{sourceUID}/correlations/{correlationUID} correlations getCorrelation
|
||||
//
|
||||
// Gets a correlation.
|
||||
//
|
||||
// Responses:
|
||||
// 200: getCorrelationResponse
|
||||
// 401: unauthorisedError
|
||||
// 404: notFoundError
|
||||
// 500: internalServerError
|
||||
func (s *CorrelationsService) getCorrelationHandler(c *models.ReqContext) response.Response {
|
||||
query := GetCorrelationQuery{
|
||||
UID: web.Params(c.Req)[":correlationUID"],
|
||||
SourceUID: web.Params(c.Req)[":uid"],
|
||||
OrgId: c.OrgId,
|
||||
}
|
||||
|
||||
correlation, err := s.getCorrelation(c.Req.Context(), query)
|
||||
if err != nil {
|
||||
if errors.Is(err, ErrCorrelationNotFound) {
|
||||
return response.Error(http.StatusNotFound, "Correlation not found", err)
|
||||
}
|
||||
if errors.Is(err, ErrSourceDataSourceDoesNotExists) {
|
||||
return response.Error(http.StatusNotFound, "Source data source not found", err)
|
||||
}
|
||||
|
||||
return response.Error(http.StatusInternalServerError, "Failed to update correlation", err)
|
||||
}
|
||||
|
||||
return response.JSON(http.StatusOK, correlation)
|
||||
}
|
||||
|
||||
// swagger:parameters getCorrelation
|
||||
type GetCorrelationParams struct {
|
||||
// in:path
|
||||
// required:true
|
||||
DatasourceUID string `json:"sourceUID"`
|
||||
// in:path
|
||||
// required:true
|
||||
CorrelationUID string `json:"correlationUID"`
|
||||
}
|
||||
|
||||
//swagger:response getCorrelationResponse
|
||||
type GetCorrelationResponse struct {
|
||||
// in: body
|
||||
Body Correlation `json:"body"`
|
||||
}
|
||||
|
||||
// swagger:route GET /datasources/uid/{sourceUID}/correlations correlations getCorrelationsBySourceUID
|
||||
//
|
||||
// Gets all correlations originating from the given data source.
|
||||
//
|
||||
// Responses:
|
||||
// 200: getCorrelationsBySourceUIDResponse
|
||||
// 401: unauthorisedError
|
||||
// 404: notFoundError
|
||||
// 500: internalServerError
|
||||
func (s *CorrelationsService) getCorrelationsBySourceUIDHandler(c *models.ReqContext) response.Response {
|
||||
query := GetCorrelationsBySourceUIDQuery{
|
||||
SourceUID: web.Params(c.Req)[":uid"],
|
||||
OrgId: c.OrgId,
|
||||
}
|
||||
|
||||
correlations, err := s.getCorrelationsBySourceUID(c.Req.Context(), query)
|
||||
if err != nil {
|
||||
if errors.Is(err, ErrCorrelationNotFound) {
|
||||
return response.Error(http.StatusNotFound, "No correlation found", err)
|
||||
}
|
||||
if errors.Is(err, ErrSourceDataSourceDoesNotExists) {
|
||||
return response.Error(http.StatusNotFound, "Source data source not found", err)
|
||||
}
|
||||
|
||||
return response.Error(http.StatusInternalServerError, "Failed to update correlation", err)
|
||||
}
|
||||
|
||||
return response.JSON(http.StatusOK, correlations)
|
||||
}
|
||||
|
||||
// swagger:parameters getCorrelationsBySourceUID
|
||||
type GetCorrelationsBySourceUIDParams struct {
|
||||
// in:path
|
||||
// required:true
|
||||
DatasourceUID string `json:"sourceUID"`
|
||||
}
|
||||
|
||||
//swagger:response getCorrelationsBySourceUIDResponse
|
||||
type GetCorrelationsBySourceUIDResponse struct {
|
||||
// in: body
|
||||
Body []Correlation `json:"body"`
|
||||
}
|
||||
|
||||
// swagger:route GET /datasources/correlations correlations getCorrelations
|
||||
//
|
||||
// Gets all correlations.
|
||||
//
|
||||
// Responses:
|
||||
// 200: getCorrelationsResponse
|
||||
// 401: unauthorisedError
|
||||
// 404: notFoundError
|
||||
// 500: internalServerError
|
||||
func (s *CorrelationsService) getCorrelationsHandler(c *models.ReqContext) response.Response {
|
||||
query := GetCorrelationsQuery{
|
||||
OrgId: c.OrgId,
|
||||
}
|
||||
|
||||
correlations, err := s.getCorrelations(c.Req.Context(), query)
|
||||
if err != nil {
|
||||
if errors.Is(err, ErrCorrelationNotFound) {
|
||||
return response.Error(http.StatusNotFound, "No correlation found", err)
|
||||
}
|
||||
|
||||
return response.Error(http.StatusInternalServerError, "Failed to update correlation", err)
|
||||
}
|
||||
|
||||
return response.JSON(http.StatusOK, correlations)
|
||||
}
|
||||
|
||||
//swagger:response getCorrelationsResponse
|
||||
type GetCorrelationsResponse struct {
|
||||
// in: body
|
||||
Body []Correlation `json:"body"`
|
||||
}
|
||||
|
@ -56,6 +56,18 @@ func (s CorrelationsService) UpdateCorrelation(ctx context.Context, cmd UpdateCo
|
||||
return s.updateCorrelation(ctx, cmd)
|
||||
}
|
||||
|
||||
func (s CorrelationsService) GetCorrelation(ctx context.Context, cmd GetCorrelationQuery) (Correlation, error) {
|
||||
return s.getCorrelation(ctx, cmd)
|
||||
}
|
||||
|
||||
func (s CorrelationsService) GetCorrelationsBySourceUID(ctx context.Context, cmd GetCorrelationsBySourceUIDQuery) ([]Correlation, error) {
|
||||
return s.getCorrelationsBySourceUID(ctx, cmd)
|
||||
}
|
||||
|
||||
func (s CorrelationsService) GetCorrelations(ctx context.Context, cmd GetCorrelationsQuery) ([]Correlation, error) {
|
||||
return s.getCorrelations(ctx, cmd)
|
||||
}
|
||||
|
||||
func (s CorrelationsService) DeleteCorrelationsBySourceUID(ctx context.Context, cmd DeleteCorrelationsBySourceUIDCommand) error {
|
||||
return s.deleteCorrelationsBySourceUID(ctx, cmd)
|
||||
}
|
||||
|
@ -132,6 +132,90 @@ func (s CorrelationsService) updateCorrelation(ctx context.Context, cmd UpdateCo
|
||||
return correlation, nil
|
||||
}
|
||||
|
||||
func (s CorrelationsService) getCorrelation(ctx context.Context, cmd GetCorrelationQuery) (Correlation, error) {
|
||||
correlation := Correlation{
|
||||
UID: cmd.UID,
|
||||
SourceUID: cmd.SourceUID,
|
||||
}
|
||||
|
||||
err := s.SQLStore.WithTransactionalDbSession(ctx, func(session *sqlstore.DBSession) error {
|
||||
query := &datasources.GetDataSourceQuery{
|
||||
OrgId: cmd.OrgId,
|
||||
Uid: cmd.SourceUID,
|
||||
}
|
||||
if err := s.DataSourceService.GetDataSource(ctx, query); err != nil {
|
||||
return ErrSourceDataSourceDoesNotExists
|
||||
}
|
||||
|
||||
found, err := session.Where("uid = ? AND source_uid = ?", correlation.UID, correlation.SourceUID).Get(&correlation)
|
||||
if !found {
|
||||
return ErrCorrelationNotFound
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return err
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return Correlation{}, err
|
||||
}
|
||||
|
||||
return correlation, nil
|
||||
}
|
||||
|
||||
func (s CorrelationsService) getCorrelationsBySourceUID(ctx context.Context, cmd GetCorrelationsBySourceUIDQuery) ([]Correlation, error) {
|
||||
correlationsCondiBean := Correlation{
|
||||
SourceUID: cmd.SourceUID,
|
||||
}
|
||||
correlations := make([]Correlation, 0)
|
||||
|
||||
err := s.SQLStore.WithTransactionalDbSession(ctx, func(session *sqlstore.DBSession) error {
|
||||
query := &datasources.GetDataSourceQuery{
|
||||
OrgId: cmd.OrgId,
|
||||
Uid: cmd.SourceUID,
|
||||
}
|
||||
if err := s.DataSourceService.GetDataSource(ctx, query); err != nil {
|
||||
return ErrSourceDataSourceDoesNotExists
|
||||
}
|
||||
|
||||
err := session.Find(&correlations, correlationsCondiBean)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return err
|
||||
})
|
||||
|
||||
if err != nil {
|
||||
return []Correlation{}, err
|
||||
}
|
||||
|
||||
if len(correlations) == 0 {
|
||||
return []Correlation{}, ErrCorrelationNotFound
|
||||
}
|
||||
|
||||
return correlations, nil
|
||||
}
|
||||
|
||||
func (s CorrelationsService) getCorrelations(ctx context.Context, cmd GetCorrelationsQuery) ([]Correlation, error) {
|
||||
correlations := make([]Correlation, 0)
|
||||
|
||||
err := s.SQLStore.WithDbSession(ctx, func(session *sqlstore.DBSession) error {
|
||||
return session.Select("correlation.*").Join("", "data_source", "correlation.source_uid = data_source.uid").Where("data_source.org_id = ?", cmd.OrgId).Find(&correlations)
|
||||
})
|
||||
if err != nil {
|
||||
return []Correlation{}, err
|
||||
}
|
||||
|
||||
if len(correlations) == 0 {
|
||||
return []Correlation{}, ErrCorrelationNotFound
|
||||
}
|
||||
|
||||
return correlations, nil
|
||||
}
|
||||
|
||||
func (s CorrelationsService) deleteCorrelationsBySourceUID(ctx context.Context, cmd DeleteCorrelationsBySourceUIDCommand) error {
|
||||
return s.SQLStore.WithDbSession(ctx, func(session *sqlstore.DBSession) error {
|
||||
_, err := session.Delete(&Correlation{SourceUID: cmd.SourceUID})
|
||||
|
@ -94,6 +94,26 @@ type UpdateCorrelationCommand struct {
|
||||
Description *string `json:"description"`
|
||||
}
|
||||
|
||||
// GetCorrelationQuery is the query to retrieve a single correlation
|
||||
type GetCorrelationQuery struct {
|
||||
// UID of the correlation
|
||||
UID string `json:"-"`
|
||||
// UID of the source data source
|
||||
SourceUID string `json:"-"`
|
||||
OrgId int64 `json:"-"`
|
||||
}
|
||||
|
||||
// GetCorrelationsBySourceUIDQuery is the query to retrieve all correlations originating by the given Data Source
|
||||
type GetCorrelationsBySourceUIDQuery struct {
|
||||
SourceUID string `json:"-"`
|
||||
OrgId int64 `json:"-"`
|
||||
}
|
||||
|
||||
// GetCorrelationsQuery is the query to retrieve all correlations
|
||||
type GetCorrelationsQuery struct {
|
||||
OrgId int64 `json:"-"`
|
||||
}
|
||||
|
||||
type DeleteCorrelationsBySourceUIDCommand struct {
|
||||
SourceUID string
|
||||
}
|
||||
|
@ -15,7 +15,14 @@ func addCorrelationsMigrations(mg *Migrator) {
|
||||
{Name: "label", Type: DB_Text, Nullable: false},
|
||||
{Name: "description", Type: DB_Text, Nullable: false},
|
||||
},
|
||||
Indices: []*Index{
|
||||
{Cols: []string{"uid"}},
|
||||
{Cols: []string{"source_uid"}},
|
||||
},
|
||||
}
|
||||
|
||||
mg.AddMigration("create correlation table v1", NewAddTableMigration(correlationsV1))
|
||||
|
||||
mg.AddMigration("add index correlations.uid", NewAddIndexMigration(correlationsV1, correlationsV1.Indices[0]))
|
||||
mg.AddMigration("add index correlations.source_uid", NewAddIndexMigration(correlationsV1, correlationsV1.Indices[1]))
|
||||
}
|
||||
|
@ -43,6 +43,20 @@ type User struct {
|
||||
password string
|
||||
}
|
||||
|
||||
type GetParams struct {
|
||||
url string
|
||||
user User
|
||||
}
|
||||
|
||||
func (c TestContext) Get(params GetParams) *http.Response {
|
||||
c.t.Helper()
|
||||
|
||||
resp, err := http.Get(c.getURL(params.url, params.user))
|
||||
require.NoError(c.t, err)
|
||||
|
||||
return resp
|
||||
}
|
||||
|
||||
type PostParams struct {
|
||||
url string
|
||||
body string
|
||||
@ -127,7 +141,7 @@ func (c TestContext) createUser(cmd user.CreateUserCommand) {
|
||||
func (c TestContext) createDs(cmd *datasources.AddDataSourceCommand) {
|
||||
c.t.Helper()
|
||||
|
||||
err := c.env.SQLStore.AddDataSource(context.Background(), cmd)
|
||||
err := c.env.Server.HTTPServer.DataSourcesService.AddDataSource(context.Background(), cmd)
|
||||
require.NoError(c.t, err)
|
||||
}
|
||||
|
||||
|
315
pkg/tests/api/correlations/correlations_read_test.go
Normal file
315
pkg/tests/api/correlations/correlations_read_test.go
Normal file
@ -0,0 +1,315 @@
|
||||
package correlations
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"testing"
|
||||
|
||||
"github.com/grafana/grafana/pkg/models"
|
||||
"github.com/grafana/grafana/pkg/services/correlations"
|
||||
"github.com/grafana/grafana/pkg/services/datasources"
|
||||
"github.com/grafana/grafana/pkg/services/user"
|
||||
"github.com/stretchr/testify/require"
|
||||
)
|
||||
|
||||
func TestIntegrationReadCorrelation(t *testing.T) {
|
||||
if testing.Short() {
|
||||
t.Skip("skipping integration test")
|
||||
}
|
||||
ctx := NewTestEnv(t)
|
||||
|
||||
adminUser := User{
|
||||
username: "admin",
|
||||
password: "admin",
|
||||
}
|
||||
viewerUser := User{
|
||||
username: "viewer",
|
||||
password: "viewer",
|
||||
}
|
||||
|
||||
ctx.createUser(user.CreateUserCommand{
|
||||
DefaultOrgRole: string(models.ROLE_VIEWER),
|
||||
Password: viewerUser.password,
|
||||
Login: viewerUser.username,
|
||||
})
|
||||
ctx.createUser(user.CreateUserCommand{
|
||||
DefaultOrgRole: string(models.ROLE_ADMIN),
|
||||
Password: adminUser.password,
|
||||
Login: adminUser.username,
|
||||
})
|
||||
|
||||
t.Run("Get all correlations", func(t *testing.T) {
|
||||
// Running this here before creating a correlation in order to test this path.
|
||||
t.Run("If no correlation exists it should return 404", func(t *testing.T) {
|
||||
res := ctx.Get(GetParams{
|
||||
url: "/api/datasources/correlations",
|
||||
user: adminUser,
|
||||
})
|
||||
require.Equal(t, http.StatusNotFound, res.StatusCode)
|
||||
|
||||
responseBody, err := ioutil.ReadAll(res.Body)
|
||||
require.NoError(t, err)
|
||||
|
||||
var response errorResponseBody
|
||||
err = json.Unmarshal(responseBody, &response)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Equal(t, "No correlation found", response.Message)
|
||||
|
||||
require.NoError(t, res.Body.Close())
|
||||
})
|
||||
})
|
||||
|
||||
createDsCommand := &datasources.AddDataSourceCommand{
|
||||
Name: "with-correlations",
|
||||
Type: "loki",
|
||||
OrgId: 1,
|
||||
}
|
||||
ctx.createDs(createDsCommand)
|
||||
dsWithCorrelations := createDsCommand.Result
|
||||
correlation := ctx.createCorrelation(correlations.CreateCorrelationCommand{
|
||||
SourceUID: dsWithCorrelations.Uid,
|
||||
TargetUID: dsWithCorrelations.Uid,
|
||||
OrgId: dsWithCorrelations.OrgId,
|
||||
})
|
||||
|
||||
createDsCommand = &datasources.AddDataSourceCommand{
|
||||
Name: "without-correlations",
|
||||
Type: "loki",
|
||||
OrgId: 1,
|
||||
}
|
||||
ctx.createDs(createDsCommand)
|
||||
dsWithoutCorrelations := createDsCommand.Result
|
||||
|
||||
t.Run("Get all correlations", func(t *testing.T) {
|
||||
t.Run("Unauthenticated users shouldn't be able to read correlations", func(t *testing.T) {
|
||||
res := ctx.Get(GetParams{
|
||||
url: "/api/datasources/correlations",
|
||||
})
|
||||
require.Equal(t, http.StatusUnauthorized, res.StatusCode)
|
||||
|
||||
responseBody, err := ioutil.ReadAll(res.Body)
|
||||
require.NoError(t, err)
|
||||
|
||||
var response errorResponseBody
|
||||
err = json.Unmarshal(responseBody, &response)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Equal(t, "Unauthorized", response.Message)
|
||||
|
||||
require.NoError(t, res.Body.Close())
|
||||
})
|
||||
|
||||
t.Run("Authenticated users shouldn't get unauthorized or forbidden errors", func(t *testing.T) {
|
||||
res := ctx.Get(GetParams{
|
||||
url: "/api/datasources/correlations",
|
||||
user: viewerUser,
|
||||
})
|
||||
require.NotEqual(t, http.StatusUnauthorized, res.StatusCode)
|
||||
require.NotEqual(t, http.StatusForbidden, res.StatusCode)
|
||||
|
||||
require.NoError(t, res.Body.Close())
|
||||
})
|
||||
|
||||
t.Run("Should correctly return correlations", func(t *testing.T) {
|
||||
res := ctx.Get(GetParams{
|
||||
url: "/api/datasources/correlations",
|
||||
user: adminUser,
|
||||
})
|
||||
require.Equal(t, http.StatusOK, res.StatusCode)
|
||||
|
||||
responseBody, err := ioutil.ReadAll(res.Body)
|
||||
require.NoError(t, err)
|
||||
|
||||
var response []correlations.Correlation
|
||||
err = json.Unmarshal(responseBody, &response)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Len(t, response, 1)
|
||||
require.EqualValues(t, correlation, response[0])
|
||||
|
||||
require.NoError(t, res.Body.Close())
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("Get all correlations for a given data source", func(t *testing.T) {
|
||||
t.Run("Unauthenticated users shouldn't be able to read correlations", func(t *testing.T) {
|
||||
res := ctx.Get(GetParams{
|
||||
url: fmt.Sprintf("/api/datasources/uid/%s/correlations", "some-uid"),
|
||||
})
|
||||
require.Equal(t, http.StatusUnauthorized, res.StatusCode)
|
||||
|
||||
responseBody, err := ioutil.ReadAll(res.Body)
|
||||
require.NoError(t, err)
|
||||
|
||||
var response errorResponseBody
|
||||
err = json.Unmarshal(responseBody, &response)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Equal(t, "Unauthorized", response.Message)
|
||||
|
||||
require.NoError(t, res.Body.Close())
|
||||
})
|
||||
|
||||
t.Run("Authenticated users shouldn't get unauthorized or forbidden errors", func(t *testing.T) {
|
||||
res := ctx.Get(GetParams{
|
||||
url: fmt.Sprintf("/api/datasources/uid/%s/correlations", "some-uid"),
|
||||
user: viewerUser,
|
||||
})
|
||||
require.NotEqual(t, http.StatusUnauthorized, res.StatusCode)
|
||||
require.NotEqual(t, http.StatusForbidden, res.StatusCode)
|
||||
|
||||
require.NoError(t, res.Body.Close())
|
||||
})
|
||||
|
||||
t.Run("if datasource does not exist it should return 404", func(t *testing.T) {
|
||||
res := ctx.Get(GetParams{
|
||||
url: fmt.Sprintf("/api/datasources/uid/%s/correlations", "some-uid"),
|
||||
user: adminUser,
|
||||
})
|
||||
require.Equal(t, http.StatusNotFound, res.StatusCode)
|
||||
|
||||
responseBody, err := ioutil.ReadAll(res.Body)
|
||||
require.NoError(t, err)
|
||||
|
||||
var response errorResponseBody
|
||||
err = json.Unmarshal(responseBody, &response)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Equal(t, "Source data source not found", response.Message)
|
||||
|
||||
require.NoError(t, res.Body.Close())
|
||||
})
|
||||
|
||||
t.Run("If no correlation exists it should return 404", func(t *testing.T) {
|
||||
res := ctx.Get(GetParams{
|
||||
url: fmt.Sprintf("/api/datasources/uid/%s/correlations", dsWithoutCorrelations.Uid),
|
||||
user: adminUser,
|
||||
})
|
||||
require.Equal(t, http.StatusNotFound, res.StatusCode)
|
||||
|
||||
responseBody, err := ioutil.ReadAll(res.Body)
|
||||
require.NoError(t, err)
|
||||
|
||||
var response errorResponseBody
|
||||
err = json.Unmarshal(responseBody, &response)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Equal(t, "No correlation found", response.Message)
|
||||
|
||||
require.NoError(t, res.Body.Close())
|
||||
})
|
||||
|
||||
t.Run("Should correctly return correlations", func(t *testing.T) {
|
||||
res := ctx.Get(GetParams{
|
||||
url: fmt.Sprintf("/api/datasources/uid/%s/correlations", dsWithCorrelations.Uid),
|
||||
user: adminUser,
|
||||
})
|
||||
require.Equal(t, http.StatusOK, res.StatusCode)
|
||||
|
||||
responseBody, err := ioutil.ReadAll(res.Body)
|
||||
require.NoError(t, err)
|
||||
|
||||
var response []correlations.Correlation
|
||||
err = json.Unmarshal(responseBody, &response)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Len(t, response, 1)
|
||||
require.EqualValues(t, correlation, response[0])
|
||||
|
||||
require.NoError(t, res.Body.Close())
|
||||
})
|
||||
})
|
||||
|
||||
t.Run("Get a single correlation", func(t *testing.T) {
|
||||
t.Run("Unauthenticated users shouldn't be able to read correlations", func(t *testing.T) {
|
||||
res := ctx.Get(GetParams{
|
||||
url: fmt.Sprintf("/api/datasources/uid/%s/correlations/%s", "some-ds-uid", "some-correlation-uid"),
|
||||
})
|
||||
require.Equal(t, http.StatusUnauthorized, res.StatusCode)
|
||||
|
||||
responseBody, err := ioutil.ReadAll(res.Body)
|
||||
require.NoError(t, err)
|
||||
|
||||
var response errorResponseBody
|
||||
err = json.Unmarshal(responseBody, &response)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Equal(t, "Unauthorized", response.Message)
|
||||
|
||||
require.NoError(t, res.Body.Close())
|
||||
})
|
||||
|
||||
t.Run("Authenticated users shouldn't get unauthorized or forbidden errors", func(t *testing.T) {
|
||||
// FIXME: don't skip this test
|
||||
t.Skip("this test should pass but somehow testing with accesscontrol works different than live grafana")
|
||||
res := ctx.Get(GetParams{
|
||||
url: fmt.Sprintf("/api/datasources/uid/%s/correlations/%s", "some-ds-uid", "some-correlation-uid"),
|
||||
user: viewerUser,
|
||||
})
|
||||
require.NotEqual(t, http.StatusUnauthorized, res.StatusCode)
|
||||
require.NotEqual(t, http.StatusForbidden, res.StatusCode)
|
||||
|
||||
require.NoError(t, res.Body.Close())
|
||||
})
|
||||
|
||||
t.Run("if datasource does not exist it should return 404", func(t *testing.T) {
|
||||
res := ctx.Get(GetParams{
|
||||
url: fmt.Sprintf("/api/datasources/uid/%s/correlations/%s", "some-ds-uid", "some-correlation-uid"),
|
||||
user: adminUser,
|
||||
})
|
||||
require.Equal(t, http.StatusNotFound, res.StatusCode)
|
||||
|
||||
responseBody, err := ioutil.ReadAll(res.Body)
|
||||
require.NoError(t, err)
|
||||
|
||||
var response errorResponseBody
|
||||
err = json.Unmarshal(responseBody, &response)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Equal(t, "Source data source not found", response.Message)
|
||||
|
||||
require.NoError(t, res.Body.Close())
|
||||
})
|
||||
|
||||
t.Run("If no correlation exists it should return 404", func(t *testing.T) {
|
||||
res := ctx.Get(GetParams{
|
||||
url: fmt.Sprintf("/api/datasources/uid/%s/correlations/%s", dsWithoutCorrelations.Uid, "some-correlation-uid"),
|
||||
user: adminUser,
|
||||
})
|
||||
require.Equal(t, http.StatusNotFound, res.StatusCode)
|
||||
|
||||
responseBody, err := ioutil.ReadAll(res.Body)
|
||||
require.NoError(t, err)
|
||||
|
||||
var response errorResponseBody
|
||||
err = json.Unmarshal(responseBody, &response)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.Equal(t, "Correlation not found", response.Message)
|
||||
|
||||
require.NoError(t, res.Body.Close())
|
||||
})
|
||||
|
||||
t.Run("Should correctly return correlation", func(t *testing.T) {
|
||||
res := ctx.Get(GetParams{
|
||||
url: fmt.Sprintf("/api/datasources/uid/%s/correlations/%s", dsWithCorrelations.Uid, correlation.UID),
|
||||
user: adminUser,
|
||||
})
|
||||
require.Equal(t, http.StatusOK, res.StatusCode)
|
||||
|
||||
responseBody, err := ioutil.ReadAll(res.Body)
|
||||
require.NoError(t, err)
|
||||
|
||||
var response correlations.Correlation
|
||||
err = json.Unmarshal(responseBody, &response)
|
||||
require.NoError(t, err)
|
||||
|
||||
require.EqualValues(t, correlation, response)
|
||||
|
||||
require.NoError(t, res.Body.Close())
|
||||
})
|
||||
})
|
||||
}
|
@ -4020,6 +4020,27 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/datasources/correlations": {
|
||||
"get": {
|
||||
"tags": ["correlations"],
|
||||
"summary": "Gets all correlations.",
|
||||
"operationId": "getCorrelations",
|
||||
"responses": {
|
||||
"200": {
|
||||
"$ref": "#/responses/getCorrelationsResponse"
|
||||
},
|
||||
"401": {
|
||||
"$ref": "#/responses/unauthorisedError"
|
||||
},
|
||||
"404": {
|
||||
"$ref": "#/responses/notFoundError"
|
||||
},
|
||||
"500": {
|
||||
"$ref": "#/responses/internalServerError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/datasources/id/{name}": {
|
||||
"get": {
|
||||
"description": "If you are running Grafana Enterprise and have Fine-grained access control enabled\nyou need to have a permission with action: `datasources:read` and scopes: `datasources:*`, `datasources:name:*` and `datasources:name:test_datasource` (single data source).",
|
||||
@ -4402,6 +4423,33 @@
|
||||
}
|
||||
},
|
||||
"/datasources/uid/{sourceUID}/correlations": {
|
||||
"get": {
|
||||
"tags": ["correlations"],
|
||||
"summary": "Gets all correlations originating from the given data source.",
|
||||
"operationId": "getCorrelationsBySourceUID",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"name": "sourceUID",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"$ref": "#/responses/getCorrelationsBySourceUIDResponse"
|
||||
},
|
||||
"401": {
|
||||
"$ref": "#/responses/unauthorisedError"
|
||||
},
|
||||
"404": {
|
||||
"$ref": "#/responses/notFoundError"
|
||||
},
|
||||
"500": {
|
||||
"$ref": "#/responses/internalServerError"
|
||||
}
|
||||
}
|
||||
},
|
||||
"post": {
|
||||
"tags": [
|
||||
"correlations"
|
||||
@ -4447,6 +4495,39 @@
|
||||
}
|
||||
},
|
||||
"/datasources/uid/{sourceUID}/correlations/{correlationUID}": {
|
||||
"get": {
|
||||
"tags": ["correlations"],
|
||||
"summary": "Gets a correlation.",
|
||||
"operationId": "getCorrelation",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"name": "sourceUID",
|
||||
"in": "path",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"name": "correlationUID",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"$ref": "#/responses/getCorrelationResponse"
|
||||
},
|
||||
"401": {
|
||||
"$ref": "#/responses/unauthorisedError"
|
||||
},
|
||||
"404": {
|
||||
"$ref": "#/responses/notFoundError"
|
||||
},
|
||||
"500": {
|
||||
"$ref": "#/responses/internalServerError"
|
||||
}
|
||||
}
|
||||
},
|
||||
"patch": {
|
||||
"tags": [
|
||||
"correlations"
|
||||
@ -19174,6 +19255,30 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"getCorrelationResponse": {
|
||||
"description": "(empty)",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/Correlation"
|
||||
}
|
||||
},
|
||||
"getCorrelationsBySourceUIDResponse": {
|
||||
"description": "(empty)",
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/Correlation"
|
||||
}
|
||||
}
|
||||
},
|
||||
"getCorrelationsResponse": {
|
||||
"description": "(empty)",
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/Correlation"
|
||||
}
|
||||
}
|
||||
},
|
||||
"getCurrentOrgResponse": {
|
||||
"description": "(empty)",
|
||||
"schema": {
|
||||
|
@ -3373,6 +3373,27 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"/datasources/correlations": {
|
||||
"get": {
|
||||
"tags": ["correlations"],
|
||||
"summary": "Gets all correlations.",
|
||||
"operationId": "getCorrelations",
|
||||
"responses": {
|
||||
"200": {
|
||||
"$ref": "#/responses/getCorrelationsResponse"
|
||||
},
|
||||
"401": {
|
||||
"$ref": "#/responses/unauthorisedError"
|
||||
},
|
||||
"404": {
|
||||
"$ref": "#/responses/notFoundError"
|
||||
},
|
||||
"500": {
|
||||
"$ref": "#/responses/internalServerError"
|
||||
}
|
||||
}
|
||||
}
|
||||
},
|
||||
"/datasources/id/{name}": {
|
||||
"get": {
|
||||
"description": "If you are running Grafana Enterprise and have Fine-grained access control enabled\nyou need to have a permission with action: `datasources:read` and scopes: `datasources:*`, `datasources:name:*` and `datasources:name:test_datasource` (single data source).",
|
||||
@ -3755,6 +3776,33 @@
|
||||
}
|
||||
},
|
||||
"/datasources/uid/{sourceUID}/correlations": {
|
||||
"get": {
|
||||
"tags": ["correlations"],
|
||||
"summary": "Gets all correlations originating from the given data source.",
|
||||
"operationId": "getCorrelationsBySourceUID",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"name": "sourceUID",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"$ref": "#/responses/getCorrelationsBySourceUIDResponse"
|
||||
},
|
||||
"401": {
|
||||
"$ref": "#/responses/unauthorisedError"
|
||||
},
|
||||
"404": {
|
||||
"$ref": "#/responses/notFoundError"
|
||||
},
|
||||
"500": {
|
||||
"$ref": "#/responses/internalServerError"
|
||||
}
|
||||
}
|
||||
},
|
||||
"post": {
|
||||
"tags": [
|
||||
"correlations"
|
||||
@ -3800,6 +3848,39 @@
|
||||
}
|
||||
},
|
||||
"/datasources/uid/{sourceUID}/correlations/{correlationUID}": {
|
||||
"get": {
|
||||
"tags": ["correlations"],
|
||||
"summary": "Gets a correlation.",
|
||||
"operationId": "getCorrelation",
|
||||
"parameters": [
|
||||
{
|
||||
"type": "string",
|
||||
"name": "sourceUID",
|
||||
"in": "path",
|
||||
"required": true
|
||||
},
|
||||
{
|
||||
"type": "string",
|
||||
"name": "correlationUID",
|
||||
"in": "path",
|
||||
"required": true
|
||||
}
|
||||
],
|
||||
"responses": {
|
||||
"200": {
|
||||
"$ref": "#/responses/getCorrelationResponse"
|
||||
},
|
||||
"401": {
|
||||
"$ref": "#/responses/unauthorisedError"
|
||||
},
|
||||
"404": {
|
||||
"$ref": "#/responses/notFoundError"
|
||||
},
|
||||
"500": {
|
||||
"$ref": "#/responses/internalServerError"
|
||||
}
|
||||
}
|
||||
},
|
||||
"patch": {
|
||||
"tags": [
|
||||
"correlations"
|
||||
@ -15173,6 +15254,30 @@
|
||||
}
|
||||
}
|
||||
},
|
||||
"getCorrelationResponse": {
|
||||
"description": "",
|
||||
"schema": {
|
||||
"$ref": "#/definitions/Correlation"
|
||||
}
|
||||
},
|
||||
"getCorrelationsBySourceUIDResponse": {
|
||||
"description": "",
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/Correlation"
|
||||
}
|
||||
}
|
||||
},
|
||||
"getCorrelationsResponse": {
|
||||
"description": "",
|
||||
"schema": {
|
||||
"type": "array",
|
||||
"items": {
|
||||
"$ref": "#/definitions/Correlation"
|
||||
}
|
||||
}
|
||||
},
|
||||
"getCurrentOrgResponse": {
|
||||
"description": "",
|
||||
"schema": {
|
||||
|
Reference in New Issue
Block a user