fix(cloudmon): azure windows disk usage

This commit is contained in:
ioito
2022-09-14 19:40:25 +08:00
parent 6c7de082fd
commit 153d43348d
6 changed files with 220 additions and 2 deletions
+1
View File
@@ -221,6 +221,7 @@ func (self *SCollectByResourceIdDriver) CollectServerMetrics(ctx context.Context
RegionExtId: vm.RegionExtId,
StartTime: start,
EndTime: end,
OsType: vm.OsType,
}
opts.ResourceId = vm.ExternalId
+1
View File
@@ -358,6 +358,7 @@ type MetricListOptions struct {
StartTime time.Time
EndTime time.Time
OsType string
Interval int
// rds
Engine string
+30 -2
View File
@@ -64,8 +64,9 @@ const (
type TAzureResource string
var (
GraphResource = TAzureResource("graph")
DefaultResource = TAzureResource("default")
GraphResource = TAzureResource("graph")
DefaultResource = TAzureResource("default")
LoganalyticsResource = TAzureResource("loganalytics")
)
type azureAuthClient struct {
@@ -87,6 +88,8 @@ type SAzureClient struct {
subscriptions []SSubscription
debug bool
workspaces []SLoganalyticsWorkspace
}
type AzureClientConfig struct {
@@ -182,6 +185,13 @@ func (self *SAzureClient) getClient(resource TAzureResource) (*azureAuthClient,
case GraphResource:
ret.domain = env.GraphEndpoint
conf.Resource = env.GraphEndpoint
case LoganalyticsResource:
ret.domain = env.ResourceIdentifiers.OperationalInsights
conf.Resource = env.ResourceIdentifiers.OperationalInsights
if conf.Resource == "N/A" && self.envName == "AzureChinaCloud" {
ret.domain = "https://api.loganalytics.azure.cn"
conf.Resource = ret.domain
}
default:
ret.domain = env.ResourceManagerEndpoint
conf.Resource = env.ResourceManagerEndpoint
@@ -213,6 +223,10 @@ func (self *SAzureClient) getGraphClient() (*azureAuthClient, error) {
return self.getClient(GraphResource)
}
func (self *SAzureClient) getLoganalyticsClient() (*azureAuthClient, error) {
return self.getClient(LoganalyticsResource)
}
func (self *SAzureClient) jsonRequest(method, path string, body jsonutils.JSONObject, params url.Values, showErrorMsg bool) (jsonutils.JSONObject, error) {
cli, err := self.getDefaultClient()
if err != nil {
@@ -260,6 +274,18 @@ func (self *SAzureClient) jsonRequest(method, path string, body jsonutils.JSONOb
return resp, err
}
func (self *SAzureClient) ljsonRequest(method, path string, body jsonutils.JSONObject, params url.Values) (jsonutils.JSONObject, error) {
cli, err := self.getLoganalyticsClient()
if err != nil {
return nil, errors.Wrapf(err, "getLoganalyticsClient")
}
if params == nil {
params = url.Values{}
}
params.Set("api-version", "2021-12-01-preview")
return jsonRequest(cli.client, method, cli.domain, path, body, params, self.debug)
}
func (self *SAzureClient) gjsonRequest(method, path string, body jsonutils.JSONObject, params url.Values) (jsonutils.JSONObject, error) {
cli, err := self.getGraphClient()
if err != nil {
@@ -512,6 +538,8 @@ func (self *SAzureClient) _apiVersion(resource string, params url.Values) string
return "2020-06-01"
} else if utils.IsInStringArray("microsoft.containerservice", info) {
return "2021-05-01"
} else if utils.IsInStringArray("microsoft.operationalinsights", info) {
return "2021-12-01-preview"
}
return AZURE_API_VERSION
}
+92
View File
@@ -0,0 +1,92 @@
// Copyright 2019 Yunion
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package azure
import (
"fmt"
"net/url"
"time"
"yunion.io/x/onecloud/pkg/util/httputils"
)
type SLoganalyticsWorkspace struct {
Id string `json:"id"`
Location string `json:"location"`
Name string `json:"name"`
SLoganalyticsWorkspaceProperties SLoganalyticsWorkspaceProperties `json:"properties"`
Type string `json:"type"`
}
type SLoganalyticsWorkspaceProperties struct {
CreatedDate string `json:"createdDate"`
CustomerId string `json:"customerId"`
SLoganalyticsWorkspacePropertiesFeatures SLoganalyticsWorkspacePropertiesFeatures `json:"features"`
ModifiedDate string `json:"modifiedDate"`
ProvisioningState string `json:"provisioningState"`
PublicNetworkAccessForIngestion string `json:"publicNetworkAccessForIngestion"`
PublicNetworkAccessForQuery string `json:"publicNetworkAccessForQuery"`
RetentionInDays int `json:"retentionInDays"`
SLoganalyticsWorkspacePropertiesSku SLoganalyticsWorkspacePropertiesSku `json:"sku"`
Source string `json:"source"`
SLoganalyticsWorkspacePropertiesWorkspaceCapping SLoganalyticsWorkspacePropertiesWorkspaceCapping `json:"workspaceCapping"`
}
type SLoganalyticsWorkspacePropertiesWorkspaceCapping struct {
DailyQuotaGb int `json:"dailyQuotaGb"`
DataIngestionStatus string `json:"dataIngestionStatus"`
QuotaNextResetTime string `json:"quotaNextResetTime"`
}
type SLoganalyticsWorkspacePropertiesSku struct {
LastSkuUpdate string `json:"lastSkuUpdate"`
Name string `json:"name"`
}
type SLoganalyticsWorkspacePropertiesFeatures struct {
EnableLogAccessUsingOnlyResourcePermissions bool `json:"enableLogAccessUsingOnlyResourcePermissions"`
Legacy int `json:"legacy"`
SearchVersion int `json:"searchVersion"`
}
func (self *SAzureClient) GetLoganalyticsWorkspaces() ([]SLoganalyticsWorkspace, error) {
if len(self.workspaces) > 0 {
return self.workspaces, nil
}
self.workspaces = []SLoganalyticsWorkspace{}
return self.workspaces, self.list("Microsoft.OperationalInsights/workspaces", url.Values{}, &self.workspaces)
}
type WorkspaceData struct {
Name string
Columns []struct {
Name string
Type string
}
Rows [][]string
}
func (self *SAzureClient) GetInstanceDiskUsage(workspace string, instanceId string, start, end time.Time) ([]WorkspaceData, error) {
params := url.Values{}
params.Set("timespan", "P1D")
query := fmt.Sprintf(`Perf | where ObjectName == "LogicalDisk" or ObjectName == "Logical Disk" | where _ResourceId == "%s" | where InstanceName != "_Total" | where CounterName == "%% Free Space" | where TimeGenerated between(datetime("%s") .. datetime("%s")) | project TimeGenerated, InstanceName, CounterValue, Computer, _ResourceId`, instanceId, start.Format(time.RFC3339), end.Format(time.RFC3339))
params.Set("query", query)
resp, err := self.ljsonRequest(string(httputils.GET), fmt.Sprintf("v1/workspaces/%s/query", workspace), nil, params)
if err != nil {
return nil, err
}
ret := []WorkspaceData{}
return ret, resp.Unmarshal(&ret, "tables")
}
+44
View File
@@ -19,11 +19,13 @@ import (
"fmt"
"net/http"
"net/url"
"strconv"
"strings"
"time"
"yunion.io/x/log"
"yunion.io/x/pkg/errors"
"yunion.io/x/pkg/util/timeutils"
"yunion.io/x/pkg/utils"
api "yunion.io/x/onecloud/pkg/apis/compute"
@@ -234,6 +236,48 @@ func (self *SAzureClient) GetEcsMetrics(opts *cloudprovider.MetricListOptions) (
}
}
if len(opts.OsType) == 0 || strings.Contains(strings.ToLower(opts.OsType), "win") {
workspaces, err := self.GetLoganalyticsWorkspaces()
if err != nil {
return ret, nil
}
winmetric := cloudprovider.MetricValues{}
winmetric.MetricType = cloudprovider.VM_METRIC_TYPE_DISK_USAGE
winmetric.Values = []cloudprovider.MetricValue{}
for i := range workspaces {
data, err := self.GetInstanceDiskUsage(workspaces[i].SLoganalyticsWorkspaceProperties.CustomerId, opts.ResourceId, opts.StartTime, opts.EndTime)
if err != nil {
continue
}
for i := range data {
for j := range data[i].Rows {
if len(data[i].Rows[j]) == 5 {
date, device, free := data[i].Rows[j][0], data[i].Rows[j][1], data[i].Rows[j][2]
dataTime, err := timeutils.ParseTimeStr(date)
if err != nil {
continue
}
if dataTime.Second() > 15 {
continue
}
freeSize, err := strconv.ParseFloat(free, 64)
if err != nil {
continue
}
winmetric.Values = append(winmetric.Values, cloudprovider.MetricValue{
Timestamp: dataTime,
Value: 100 - freeSize,
Tags: map[string]string{cloudprovider.METRIC_TAG_DEVICE: device},
})
}
}
}
}
if len(winmetric.Values) > 0 {
ret = append(ret, winmetric)
}
}
return ret, nil
}
@@ -0,0 +1,52 @@
// Copyright 2019 Yunion
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package shell
import (
"time"
"yunion.io/x/onecloud/pkg/multicloud/azure"
"yunion.io/x/onecloud/pkg/util/shellutils"
)
func init() {
type LoganalyticsWorkspaceListOptions struct {
}
shellutils.R(&LoganalyticsWorkspaceListOptions{}, "loganalytics-workspace-list", "List loganalytics workspaces", func(cli *azure.SRegion, args *LoganalyticsWorkspaceListOptions) error {
workspaces, err := cli.GetClient().GetLoganalyticsWorkspaces()
if err != nil {
return err
}
printList(workspaces, len(workspaces), 0, 0, []string{})
return nil
})
type DiskUsageListOptions struct {
WORKSPACE_ID string
NAME string
START time.Time
END time.Time
}
shellutils.R(&DiskUsageListOptions{}, "disk-usage-list", "List disk usage", func(cli *azure.SRegion, args *DiskUsageListOptions) error {
usage, err := cli.GetClient().GetInstanceDiskUsage(args.WORKSPACE_ID, args.NAME, args.START, args.END)
if err != nil {
return err
}
printList(usage, len(usage), 0, 0, []string{})
return nil
})
}