AzureMonitor: Add data links to deep link to Azure Portal Azure Resource Graph (#35591)

* Add deep link in ARG

* add soverigh clouds

* add query to Azure portal link

* move deep link to backend

* cloud specific to ARG

* Add unit test

* fix lint

* fix escape issue

* use constant & fix test

* fix constant & use pathEscape

* use cmp.Equal for test
This commit is contained in:
shuotli
2021-08-13 08:21:24 -07:00
committed by GitHub
parent 6a77cd43ae
commit 6ecf401cd1
2 changed files with 85 additions and 5 deletions

View File

@@ -179,15 +179,38 @@ func (e *AzureResourceGraphDatasource) executeQuery(ctx context.Context, query *
if err != nil { if err != nil {
return dataResponseErrorWithExecuted(err) return dataResponseErrorWithExecuted(err)
} }
if frame.Meta == nil {
frame.Meta = &data.FrameMeta{}
}
frame.Meta.ExecutedQueryString = req.URL.RawQuery
dataResponse.Frames = data.Frames{frame} azurePortalUrl, err := getAzurePortalUrl(dsInfo.Cloud)
if err != nil {
return dataResponseErrorWithExecuted(err)
}
url := azurePortalUrl + "/#blade/HubsExtension/ArgQueryBlade/query/" + url.PathEscape(query.InterpolatedQuery)
frameWithLink := addConfigData(*frame, url)
if frameWithLink.Meta == nil {
frameWithLink.Meta = &data.FrameMeta{}
}
frameWithLink.Meta.ExecutedQueryString = req.URL.RawQuery
dataResponse.Frames = data.Frames{&frameWithLink}
return dataResponse return dataResponse
} }
func addConfigData(frame data.Frame, dl string) data.Frame {
for i := range frame.Fields {
if frame.Fields[i].Config == nil {
frame.Fields[i].Config = &data.FieldConfig{}
}
deepLink := data.DataLink{
Title: "View in Azure Portal",
TargetBlank: true,
URL: dl,
}
frame.Fields[i].Config.Links = append(frame.Fields[i].Config.Links, deepLink)
}
return frame
}
func (e *AzureResourceGraphDatasource) createRequest(ctx context.Context, dsInfo datasourceInfo, reqBody []byte, url string) (*http.Request, error) { func (e *AzureResourceGraphDatasource) createRequest(ctx context.Context, dsInfo datasourceInfo, reqBody []byte, url string) (*http.Request, error) {
req, err := http.NewRequest(http.MethodPost, url, bytes.NewBuffer(reqBody)) req, err := http.NewRequest(http.MethodPost, url, bytes.NewBuffer(reqBody))
if err != nil { if err != nil {
@@ -228,3 +251,18 @@ func (e *AzureResourceGraphDatasource) unmarshalResponse(res *http.Response) (Az
return data, nil return data, nil
} }
func getAzurePortalUrl(azureCloud string) (string, error) {
switch azureCloud {
case setting.AzurePublic:
return "https://portal.azure.com", nil
case setting.AzureChina:
return "https://portal.azure.cn", nil
case setting.AzureUSGovernment:
return "https://portal.azure.us", nil
case setting.AzureGermany:
return "https://portal.microsoftazure.de", nil
default:
return "", fmt.Errorf("the cloud is not supported")
}
}

View File

@@ -10,8 +10,11 @@ import (
"github.com/google/go-cmp/cmp" "github.com/google/go-cmp/cmp"
"github.com/google/go-cmp/cmp/cmpopts" "github.com/google/go-cmp/cmp/cmpopts"
"github.com/grafana/grafana-plugin-sdk-go/backend" "github.com/grafana/grafana-plugin-sdk-go/backend"
"github.com/grafana/grafana-plugin-sdk-go/data"
"github.com/grafana/grafana/pkg/components/simplejson" "github.com/grafana/grafana/pkg/components/simplejson"
"github.com/grafana/grafana/pkg/plugins" "github.com/grafana/grafana/pkg/plugins"
"github.com/grafana/grafana/pkg/setting"
"github.com/stretchr/testify/assert"
"github.com/stretchr/testify/require" "github.com/stretchr/testify/require"
) )
@@ -110,3 +113,42 @@ func TestAzureResourceGraphCreateRequest(t *testing.T) {
}) })
} }
} }
func TestAddConfigData(t *testing.T) {
field := data.Field{}
dataLink := data.DataLink{Title: "View in Azure Portal", TargetBlank: true, URL: "http://ds"}
frame := data.Frame{
Fields: []*data.Field{&field},
}
frameWithLink := addConfigData(frame, "http://ds")
expectedFrameWithLink := data.Frame{
Fields: []*data.Field{
{
Config: &data.FieldConfig{
Links: []data.DataLink{dataLink},
},
},
},
}
if !cmp.Equal(frameWithLink, expectedFrameWithLink, data.FrameTestCompareOptions()...) {
t.Errorf("unexpepcted frame: %v", cmp.Diff(frameWithLink, expectedFrameWithLink, data.FrameTestCompareOptions()...))
}
}
func TestGetAzurePortalUrl(t *testing.T) {
clouds := []string{setting.AzurePublic, setting.AzureChina, setting.AzureUSGovernment, setting.AzureGermany}
expectedAzurePortalUrl := map[string]interface{}{
setting.AzurePublic: "https://portal.azure.com",
setting.AzureChina: "https://portal.azure.cn",
setting.AzureUSGovernment: "https://portal.azure.us",
setting.AzureGermany: "https://portal.microsoftazure.de",
}
for _, cloud := range clouds {
azurePortalUrl, err := getAzurePortalUrl(cloud)
if err != nil {
t.Errorf("The cloud not supported")
}
assert.Equal(t, expectedAzurePortalUrl[cloud], azurePortalUrl)
}
}