mirror of https://github.com/grafana/grafana
[release-11.6.1] Prometheus: Add support for cloud partners Prometheus data sources (#103941)
Prometheus: Add support for cloud partners Prometheus data sources (#103482)
* wip
* Add prom flavor support for data source variables and export/import dashboards (#103321)
* add dashboard and data source var selection
* use match plugin id instead
* use updated matchpluginid
* formatting
* cleanup
* regex anchor
* update error msg
* Alerting: Clean up prometheus-flavored types and functions (#103703)
* clean up types and utility functions for dealing with
prometheus-flavored data sources
* Refactor alerting datasource types to use constants as source of truth
* Alerting: Clean up prometheus-flavored types and functions on the bac… (#103716)
Alerting: Clean up prometheus-flavored types and functions on the backend
* add matchPluginId tests
* Update matchPluginId func to bidirectional (#103746)
* update matchpluginid func to bidirectional
* lint
* formatting
* use actual isSupportedExternalRulesSourceType in test
* add tests in datasource_srv
* betterer
* remove type assertion
* remove unnecessary case
* use satisifies to not have to convert tuple to an array of string
* add prometheus_flavor test
---------
Co-authored-by: Andrew Hackmann <5140848+bossinc@users.noreply.github.com>
Co-authored-by: Gilles De Mey <gilles.de.mey@gmail.com>
Co-authored-by: Alexander Akhmetov <me@alx.cx>
(cherry picked from commit fd6fd91115
)
pull/104086/head
parent
56d976552e
commit
760b9176fc
@ -0,0 +1,64 @@ |
||||
import { PluginMeta, PluginType } from '../types/plugin'; |
||||
|
||||
import { matchPluginId } from './matchPluginId'; |
||||
|
||||
const createPluginMeta = (id: string, aliasIDs?: string[]): PluginMeta => ({ |
||||
id, |
||||
name: 'Test Plugin', |
||||
type: PluginType.datasource, |
||||
module: 'test', |
||||
baseUrl: 'test', |
||||
info: { |
||||
author: { name: 'Test' }, |
||||
description: 'Test', |
||||
links: [], |
||||
logos: { small: '', large: '' }, |
||||
screenshots: [], |
||||
updated: '', |
||||
version: '', |
||||
}, |
||||
aliasIDs, |
||||
}); |
||||
|
||||
describe('matchPluginId', () => { |
||||
it('should match exact plugin ID', () => { |
||||
const pluginMeta = createPluginMeta('test-plugin'); |
||||
expect(matchPluginId('test-plugin', pluginMeta)).toBe(true); |
||||
}); |
||||
|
||||
it('should not match different plugin ID', () => { |
||||
const pluginMeta = createPluginMeta('test-plugin'); |
||||
expect(matchPluginId('different-plugin', pluginMeta)).toBe(false); |
||||
}); |
||||
|
||||
it('should match Amazon Prometheus flavor when idToMatch is prometheus', () => { |
||||
const pluginMeta = createPluginMeta('grafana-amazonprometheus-datasource'); |
||||
expect(matchPluginId('prometheus', pluginMeta)).toBe(true); |
||||
}); |
||||
|
||||
it('should match Azure Prometheus flavor when idToMatch is prometheus', () => { |
||||
const pluginMeta = createPluginMeta('grafana-azureprometheus-datasource'); |
||||
expect(matchPluginId('prometheus', pluginMeta)).toBe(true); |
||||
}); |
||||
|
||||
it('should not match non-prometheus flavor when idToMatch is prometheus', () => { |
||||
const pluginMeta = createPluginMeta('test-plugin'); |
||||
expect(matchPluginId('prometheus', pluginMeta)).toBe(false); |
||||
}); |
||||
|
||||
it('should match alias IDs', () => { |
||||
const pluginMeta = createPluginMeta('test-plugin', ['alias1', 'alias2']); |
||||
expect(matchPluginId('alias1', pluginMeta)).toBe(true); |
||||
expect(matchPluginId('alias2', pluginMeta)).toBe(true); |
||||
}); |
||||
|
||||
it('should not match non-existent alias ID', () => { |
||||
const pluginMeta = createPluginMeta('test-plugin', ['alias1', 'alias2']); |
||||
expect(matchPluginId('alias3', pluginMeta)).toBe(false); |
||||
}); |
||||
|
||||
it('should handle undefined aliasIDs', () => { |
||||
const pluginMeta = createPluginMeta('test-plugin'); |
||||
expect(matchPluginId('alias1', pluginMeta)).toBe(false); |
||||
}); |
||||
}); |
@ -0,0 +1,98 @@ |
||||
package api |
||||
|
||||
import ( |
||||
"errors" |
||||
"net/http" |
||||
"testing" |
||||
|
||||
"github.com/stretchr/testify/require" |
||||
|
||||
"github.com/grafana/grafana/pkg/infra/log" |
||||
contextmodel "github.com/grafana/grafana/pkg/services/contexthandler/model" |
||||
"github.com/grafana/grafana/pkg/services/datasourceproxy" |
||||
"github.com/grafana/grafana/pkg/services/datasources" |
||||
"github.com/grafana/grafana/pkg/web" |
||||
) |
||||
|
||||
func TestLotexProm_GetEndpoints(t *testing.T) { |
||||
tc := []struct { |
||||
name string |
||||
namedParams map[string]string |
||||
datasourceCache datasources.CacheService |
||||
expectedRoutes *promEndpoints |
||||
err error |
||||
}{ |
||||
{ |
||||
name: "with an empty datasource UID", |
||||
namedParams: map[string]string{":DatasourceUID": ""}, |
||||
err: errors.New("datasource UID is invalid"), |
||||
}, |
||||
{ |
||||
name: "with an error while trying to fetch the datasource", |
||||
namedParams: map[string]string{":DatasourceUID": "d164"}, |
||||
datasourceCache: fakeCacheService{err: datasources.ErrDataSourceNotFound}, |
||||
err: errors.New("data source not found"), |
||||
}, |
||||
{ |
||||
name: "with an empty datasource URL", |
||||
namedParams: map[string]string{":DatasourceUID": "d164"}, |
||||
datasourceCache: fakeCacheService{datasource: &datasources.DataSource{}}, |
||||
err: errors.New("URL for this data source is empty"), |
||||
}, |
||||
{ |
||||
name: "with an unsupported datasource type", |
||||
namedParams: map[string]string{":DatasourceUID": "d164"}, |
||||
datasourceCache: fakeCacheService{datasource: &datasources.DataSource{URL: "http://loki.com", Type: "unsupported-type"}}, |
||||
err: errors.New("unexpected datasource type 'unsupported-type', expected loki, prometheus, amazon prometheus, azure prometheus"), |
||||
}, |
||||
{ |
||||
name: "with a Loki datasource", |
||||
namedParams: map[string]string{":DatasourceUID": "d164"}, |
||||
datasourceCache: fakeCacheService{datasource: &datasources.DataSource{URL: "http://loki.com", Type: datasources.DS_LOKI}}, |
||||
expectedRoutes: &lokiEndpoints, |
||||
err: nil, |
||||
}, |
||||
{ |
||||
name: "with a Prometheus datasource", |
||||
namedParams: map[string]string{":DatasourceUID": "d164"}, |
||||
datasourceCache: fakeCacheService{datasource: &datasources.DataSource{URL: "http://prom.com", Type: datasources.DS_PROMETHEUS}}, |
||||
expectedRoutes: &prometheusEndpoints, |
||||
err: nil, |
||||
}, |
||||
{ |
||||
name: "with an Amazon Prometheus datasource", |
||||
namedParams: map[string]string{":DatasourceUID": "d164"}, |
||||
datasourceCache: fakeCacheService{datasource: &datasources.DataSource{URL: "http://amp.com", Type: datasources.DS_AMAZON_PROMETHEUS}}, |
||||
expectedRoutes: &prometheusEndpoints, |
||||
err: nil, |
||||
}, |
||||
{ |
||||
name: "with an Azure Prometheus datasource", |
||||
namedParams: map[string]string{":DatasourceUID": "d164"}, |
||||
datasourceCache: fakeCacheService{datasource: &datasources.DataSource{URL: "http://azp.com", Type: datasources.DS_AZURE_PROMETHEUS}}, |
||||
expectedRoutes: &prometheusEndpoints, |
||||
err: nil, |
||||
}, |
||||
} |
||||
|
||||
for _, tt := range tc { |
||||
t.Run(tt.name, func(t *testing.T) { |
||||
proxy := &AlertingProxy{DataProxy: &datasourceproxy.DataSourceProxyService{DataSourceCache: tt.datasourceCache}} |
||||
prom := &LotexProm{AlertingProxy: proxy, log: log.NewNopLogger()} |
||||
|
||||
// Setup request context.
|
||||
httpReq, err := http.NewRequest(http.MethodGet, "http://grafanacloud.com", nil) |
||||
require.NoError(t, err) |
||||
ctx := &contextmodel.ReqContext{Context: &web.Context{Req: web.SetURLParams(httpReq, tt.namedParams)}} |
||||
|
||||
endpoints, err := prom.getEndpoints(ctx) |
||||
|
||||
if tt.err != nil { |
||||
require.Error(t, err) |
||||
} else { |
||||
require.NoError(t, err) |
||||
require.Equal(t, tt.expectedRoutes, endpoints) |
||||
} |
||||
}) |
||||
} |
||||
} |
Loading…
Reference in new issue