diff --git a/pkg/apis/cloudevent/doc.go b/pkg/apis/cloudevent/doc.go index 55353b4c9d..e2c6ab1419 100644 --- a/pkg/apis/cloudevent/doc.go +++ b/pkg/apis/cloudevent/doc.go @@ -1 +1,15 @@ +// 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 cloudevent // import "yunion.io/x/onecloud/pkg/apis/cloudevent" diff --git a/pkg/apis/compute/guests.go b/pkg/apis/compute/guests.go index c655827e03..ab8baa5721 100644 --- a/pkg/apis/compute/guests.go +++ b/pkg/apis/compute/guests.go @@ -1,3 +1,17 @@ +// 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 compute import ( diff --git a/pkg/cloudevent/models/doc.go b/pkg/cloudevent/models/doc.go index 3f5a8f7a44..5aec6ac0c3 100644 --- a/pkg/cloudevent/models/doc.go +++ b/pkg/cloudevent/models/doc.go @@ -1 +1,15 @@ +// 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 models // import "yunion.io/x/onecloud/pkg/cloudevent/models" diff --git a/pkg/cloudevent/options/doc.go b/pkg/cloudevent/options/doc.go index c3aebfcb46..8e3bd136e6 100644 --- a/pkg/cloudevent/options/doc.go +++ b/pkg/cloudevent/options/doc.go @@ -1 +1,15 @@ +// 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 options // import "yunion.io/x/onecloud/pkg/cloudevent/options" diff --git a/pkg/cloudevent/service/doc.go b/pkg/cloudevent/service/doc.go index afa75a4c8f..9088427832 100644 --- a/pkg/cloudevent/service/doc.go +++ b/pkg/cloudevent/service/doc.go @@ -1 +1,15 @@ +// 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 service // import "yunion.io/x/onecloud/pkg/cloudevent/service" diff --git a/pkg/cloudevent/tasks/doc.go b/pkg/cloudevent/tasks/doc.go index fb076b68cc..90e9ab9120 100644 --- a/pkg/cloudevent/tasks/doc.go +++ b/pkg/cloudevent/tasks/doc.go @@ -1 +1,15 @@ +// 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 tasks // import "yunion.io/x/onecloud/pkg/cloudevent/tasks" diff --git a/pkg/hostman/guestman/qemu-arm.go b/pkg/hostman/guestman/qemu-arm.go index 9bce85c346..631af614f1 100644 --- a/pkg/hostman/guestman/qemu-arm.go +++ b/pkg/hostman/guestman/qemu-arm.go @@ -1,3 +1,17 @@ +// 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 guestman import ( diff --git a/pkg/httperrors/consts.go b/pkg/httperrors/consts.go index 8356f4a623..3c05cb01cb 100644 --- a/pkg/httperrors/consts.go +++ b/pkg/httperrors/consts.go @@ -76,6 +76,8 @@ const ( ErrInvalidProvider = errors.Error("InvalidProvider") ErrNoBalancePermission = errors.Error("NoBalancePermission") + + ErrTooLarge = errors.Error("TooLargeEntity") ) var ( @@ -141,6 +143,8 @@ var ( ErrTimeout: 504, ErrProtectedResource: 403, ErrNoProject: 403, + + ErrTooLarge: 413, } ) diff --git a/pkg/httperrors/errors.go b/pkg/httperrors/errors.go index 7ead5ce6b6..1602b2c8ab 100644 --- a/pkg/httperrors/errors.go +++ b/pkg/httperrors/errors.go @@ -199,3 +199,7 @@ func NewClientError(msg string, params ...interface{}) *httputils.JSONClientErro func NewUnclassifiedError(msg string, params ...interface{}) *httputils.JSONClientError { return httputils.NewJsonClientError(httpErrorCode[errors.ErrUnclassified], string(errors.ErrUnclassified), msg, params) } + +func NewTooLargeEntityError(msg string, params ...interface{}) *httputils.JSONClientError { + return httputils.NewJsonClientError(httpErrorCode[ErrTooLarge], string(ErrTooLarge), msg, params) +} diff --git a/pkg/multicloud/aliyun/monitor.go b/pkg/multicloud/aliyun/monitor.go new file mode 100644 index 0000000000..67780e30b0 --- /dev/null +++ b/pkg/multicloud/aliyun/monitor.go @@ -0,0 +1,189 @@ +// 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 aliyun + +import ( + "strconv" + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/pkg/errors" +) + +const ( + ALIYUN_API_VERSION_METRICS = "2019-01-01" +) + +func (r *SRegion) metricsRequest(action string, params map[string]string) (jsonutils.JSONObject, error) { + client, err := r.getSdkClient() + if err != nil { + return nil, errors.Wrap(err, "r.getSdkClient") + } + return jsonRequest(client, "metrics.aliyuncs.com", ALIYUN_API_VERSION_METRICS, action, params, r.client.Debug) +} + +type SResourceLabel struct { + Name string `json:"name"` + Value string `json:"value"` +} + +type SResource struct { + Description string `json:"Description"` + Labels string `json:"Labels"` + Namespace string `json:"Namespace"` +} + +func (r *SRegion) DescribeProjectMeta(limit, offset int) (int, []SResource, error) { + params := make(map[string]string) + if limit <= 0 { + limit = 30 + } + params["PageSize"] = strconv.FormatInt(int64(limit), 10) + if offset > 0 { + pageNum := (offset / limit) + 1 + params["PageNumber"] = strconv.FormatInt(int64(pageNum), 10) + } + body, err := r.metricsRequest("DescribeProjectMeta", params) + if err != nil { + return 0, nil, errors.Wrap(err, "r.metricsRequest DescribeProjectMeta") + } + total, _ := body.Int("Total") + res := make([]SResource, 0) + err = body.Unmarshal(&res, "Resources", "Resource") + if err != nil { + return 0, nil, errors.Wrap(err, "body.Unmarshal Resources Resource") + } + return int(total), res, nil +} + +func (r *SRegion) FetchNamespaces() ([]SResource, error) { + resources := make([]SResource, 0) + total := -1 + for total < 0 || len(resources) < total { + ntotal, res, err := r.DescribeProjectMeta(1000, len(resources)) + if err != nil { + return nil, errors.Wrap(err, "r.DescribeProjectMeta") + } + if len(res) == 0 { + break + } + resources = append(resources, res...) + total = ntotal + } + return resources, nil +} + +type SMetricMeta struct { + Description string `json:"Description"` + MetricName string `json:"MetricName"` + Statistics string `json:"Statistics"` + Labels string `json:"Labels"` + Dimensions string `json:"Dimensions"` + Namespace string `json:"Namespace"` + Periods string `json:"Periods"` + Unit string `json:"Unit"` +} + +func (r *SRegion) DescribeMetricMetaList(ns string, limit, offset int) (int, []SMetricMeta, error) { + params := make(map[string]string) + if limit <= 0 { + limit = 30 + } + params["Namespace"] = ns + params["PageSize"] = strconv.FormatInt(int64(limit), 10) + if offset > 0 { + pageNum := (offset / limit) + 1 + params["PageNumber"] = strconv.FormatInt(int64(pageNum), 10) + } + body, err := r.metricsRequest("DescribeMetricMetaList", params) + if err != nil { + return 0, nil, errors.Wrap(err, "r.metricsRequest DescribeMetricMetaList") + } + total, _ := body.Int("TotalCount") + res := make([]SMetricMeta, 0) + err = body.Unmarshal(&res, "Resources", "Resource") + if err != nil { + return 0, nil, errors.Wrap(err, "body.Unmarshal Resources Resource") + } + return int(total), res, nil +} + +func (r *SRegion) FetchMetrics(ns string) ([]SMetricMeta, error) { + metrics := make([]SMetricMeta, 0) + total := -1 + for total < 0 || len(metrics) < total { + ntotal, res, err := r.DescribeMetricMetaList(ns, 1000, len(metrics)) + if err != nil { + return nil, errors.Wrap(err, "r.DescribeMetricMetaList") + } + if len(res) == 0 { + break + } + metrics = append(metrics, res...) + total = ntotal + } + return metrics, nil +} + +func (r *SRegion) DescribeMetricList(name string, ns string, since time.Time, until time.Time, nextToken string) ([]jsonutils.JSONObject, string, error) { + params := make(map[string]string) + params["MetricName"] = name + params["Namespace"] = ns + params["Length"] = "2000" + if len(nextToken) > 0 { + params["NextToken"] = nextToken + } + if !since.IsZero() { + params["StartTime"] = strconv.FormatInt(since.UnixNano()/1000, 10) + } + if !until.IsZero() { + params["EndTime"] = strconv.FormatInt(until.UnixNano()/1000, 10) + } + body, err := r.metricsRequest("DescribeMetricList", params) + if err != nil { + return nil, "", errors.Wrap(err, "region.MetricRequest") + } + nToken, _ := body.GetString("NextToken") + dataStr, _ := body.GetString("Datapoints") + if len(dataStr) == 0 { + return nil, "", nil + } + dataJson, err := jsonutils.ParseString(dataStr) + if err != nil { + return nil, "", errors.Wrap(err, "jsonutils.ParseString") + } + dataArray, err := dataJson.GetArray() + if err != nil { + return nil, "", errors.Wrap(err, "dataJson.GetArray") + } + return dataArray, nToken, nil +} + +func (r *SRegion) FetchMetricData(name string, ns string, since time.Time, until time.Time) ([]jsonutils.JSONObject, error) { + data := make([]jsonutils.JSONObject, 0) + nextToken := "" + for { + datArray, next, err := r.DescribeMetricList(name, ns, since, until, nextToken) + if err != nil { + return nil, errors.Wrap(err, "r.DescribeMetricList") + } + data = append(data, datArray...) + if len(next) == 0 { + break + } + nextToken = next + } + return data, nil +} diff --git a/pkg/multicloud/aliyun/shell/monitor.go b/pkg/multicloud/aliyun/shell/monitor.go new file mode 100644 index 0000000000..a88242394f --- /dev/null +++ b/pkg/multicloud/aliyun/shell/monitor.go @@ -0,0 +1,85 @@ +// 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/pkg/util/timeutils" + + "yunion.io/x/onecloud/pkg/mcclient/modulebase" + "yunion.io/x/onecloud/pkg/multicloud/aliyun" + "yunion.io/x/onecloud/pkg/util/printutils" + "yunion.io/x/onecloud/pkg/util/shellutils" +) + +func init() { + type NamespaceListOptions struct { + } + shellutils.R(&NamespaceListOptions{}, "namespace-list", "List monbitor metric namespaces", func(cli *aliyun.SRegion, args *NamespaceListOptions) error { + nslist, err := cli.FetchNamespaces() + if err != nil { + return err + } + printList(nslist, 0, 0, 0, nil) + return nil + }) + + type MetricListOptions struct { + NAMESPACE string `help:"namespace"` + } + shellutils.R(&MetricListOptions{}, "metrics-list", "List metrics in a namespace", func(cli *aliyun.SRegion, args *MetricListOptions) error { + metrics, err := cli.FetchMetrics(args.NAMESPACE) + if err != nil { + return err + } + printList(metrics, 0, 0, 0, nil) + return nil + }) + + type DescribeMetricListOptions struct { + METRIC string `help:"metric name"` + NAMESPACE string `help:"name space"` + Since string `help:"since, 2019-11-29T11:22:00Z"` + Until string `help:"since, 2019-11-30T11:22:00Z"` + } + shellutils.R(&DescribeMetricListOptions{}, "metric-data-list", "DescribeMetricList", func(cli *aliyun.SRegion, args *DescribeMetricListOptions) error { + var since time.Time + var err error + if len(args.Since) > 0 { + since, err = timeutils.ParseTimeStr(args.Since) + if err != nil { + return err + } + } + var until time.Time + if len(args.Until) > 0 { + until, err = timeutils.ParseTimeStr(args.Until) + if err != nil { + return err + } + } + data, err := cli.FetchMetricData(args.METRIC, args.NAMESPACE, since, until) + if err != nil { + return err + } + result := &modulebase.ListResult{ + Data: data, + Total: len(data), + } + printutils.PrintJSONList(result, nil) + return nil + }) +} diff --git a/pkg/multicloud/huawei/client/client.go b/pkg/multicloud/huawei/client/client.go index a2b9ea6a52..e5a5d9c3de 100644 --- a/pkg/multicloud/huawei/client/client.go +++ b/pkg/multicloud/huawei/client/client.go @@ -78,6 +78,7 @@ type Client struct { DBInstanceFlavor *modules.SDBInstanceFlavorManager DBInstanceJob *modules.SDBInstanceJobManager Traces *modules.STraceManager + CloudEye *modules.SCloudEyeManager } func (self *Client) Init() error { @@ -160,6 +161,7 @@ func (self *Client) initManagers() { self.DBInstanceFlavor = modules.NewDBInstanceFlavorManager(self.regionId, self.projectId, self.signer, self.debug) self.DBInstanceJob = modules.NewDBInstanceJobManager(self.regionId, self.projectId, self.signer, self.debug) self.Traces = modules.NewTraceManager(self.regionId, self.projectId, self.signer, self.debug) + self.CloudEye = modules.NewCloudEyeManager(self.regionId, self.projectId, self.signer, self.debug) } self.init = true diff --git a/pkg/multicloud/huawei/client/modules/manager_resource.go b/pkg/multicloud/huawei/client/modules/manager_resource.go index dc335631c6..e2bc622b91 100644 --- a/pkg/multicloud/huawei/client/modules/manager_resource.go +++ b/pkg/multicloud/huawei/client/modules/manager_resource.go @@ -34,7 +34,7 @@ const ( ServiceNameECS ServiceNameType = "ecs" // 弹性云服务 ServiceNameCCE ServiceNameType = "cce" // 云容器服务 ServiceNameAS ServiceNameType = "as" // 弹性伸缩服务 - ServiceNameIAM ServiceNameType = "iam" // 统一身份认证服务 + ServiceNameIAM ServiceNameType = "iam" // 统一身份认证服务 ServiceNameIMS ServiceNameType = "ims" // 镜像服务 ServiceNameCSBS ServiceNameType = "csbs" // 云服务器备份服务 ServiceNameCCI ServiceNameType = "cci" // 云容器实例 CCI @@ -48,7 +48,8 @@ const ( ServiceNameNAT ServiceNameType = "nat" // Nat网关 NAT ServiceNameDCS ServiceNameType = "dcs" // 分布式缓存服务 ServiceNameRDS ServiceNameType = "rds" // 关系型数据库 RDS - ServiceNameCTS ServiceNameType = "cts" //云审计服务 + ServiceNameCTS ServiceNameType = "cts" // 云审计服务 + ServiceNameCES ServiceNameType = "ces" // 监控服务 CloudEye ) type SManagerContext struct { diff --git a/pkg/multicloud/huawei/client/modules/mod_ces.go b/pkg/multicloud/huawei/client/modules/mod_ces.go new file mode 100644 index 0000000000..a821693de8 --- /dev/null +++ b/pkg/multicloud/huawei/client/modules/mod_ces.go @@ -0,0 +1,153 @@ +// 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 modules + +import ( + "time" + + "yunion.io/x/jsonutils" + "yunion.io/x/log" + "yunion.io/x/pkg/errors" + + "yunion.io/x/onecloud/pkg/httperrors" + "yunion.io/x/onecloud/pkg/multicloud/huawei/client/auth" + "yunion.io/x/onecloud/pkg/multicloud/huawei/client/requests" +) + +type SCloudEyeManager struct { + SResourceManager +} + +func NewCloudEyeManager(regionId string, projectId string, signer auth.Signer, debug bool) *SCloudEyeManager { + return &SCloudEyeManager{SResourceManager: SResourceManager{ + SBaseManager: NewBaseManager(signer, debug), + ServiceName: ServiceNameCES, + Region: regionId, + ProjectId: projectId, + version: "V1.0", + Keyword: "", + KeywordPlural: "metrics", + ResourceKeyword: "metrics", + }} +} + +type SMetricDimension struct { + Name string `json:"name"` + Value string `json:"value"` +} + +type SDatapoint struct { + Timestamp int64 `json:"timestamp"` + Max float64 `json:"max,omitzero"` + Min float64 `json:"min,omitzero"` + Average float64 `json:"average,omitzero"` + Sum float64 `json:"sum,omitzero"` + Variance float64 `json:"variance,omitzero"` +} + +type SMetricData struct { + SMetricMeta + + Datapoints []SDatapoint +} + +type SMetricMeta struct { + SMetric + + Unit string `json:"unit"` +} + +type SMetric struct { + MetricName string `json:"metric_name"` + Namespace string `json:"namespace"` + + Dimensions []SMetricDimension `json:"dimensions"` +} + +func (ces *SCloudEyeManager) ListMetrics() ([]SMetricMeta, error) { + metrics := make([]SMetricMeta, 0) + next := "" + for { + marker, data, err := ces.listMetricsInternal(next) + if err != nil { + return nil, errors.Wrap(err, "ces.listMetricsInternal") + } + if len(data) == 0 { + break + } + metrics = append(metrics, data...) + next = marker + } + return metrics, nil +} + +func (ces *SCloudEyeManager) listMetricsInternal(start string) (string, []SMetricMeta, error) { + request := requests.NewResourceRequest("GET", string(ces.ServiceName), ces.version, ces.Region, ces.ProjectId, ces.ResourceKeyword) + request.AddQueryParam("limit", "1000") + if len(start) > 0 { + request.AddQueryParam("start", start) + } + _, resp, err := ces.jsonRequest(request) + if err != nil { + return "", nil, errors.Wrap(err, "ces.jsonRequest") + } + marker, _ := resp.GetString("meta_data", "marker") + metrics := make([]SMetricMeta, 0) + err = resp.Unmarshal(&metrics, "metrics") + if err != nil { + return "", nil, errors.Wrap(err, "resp.Unmarshal metrics") + } + return marker, metrics, nil +} + +type SBatchQueryMetricDataInput struct { + Metrics []SMetric `json:"metrics"` + + From int64 `json:"from"` + To int64 `json:"to"` + Period string `json:"period"` + Filter string `json:"filter"` +} + +func (ces *SCloudEyeManager) GetMetricsData(metrics []SMetricMeta, since time.Time, until time.Time) ([]SMetricData, error) { + if len(metrics) > 10 { + return nil, errors.Wrap(httperrors.ErrTooLarge, "request more than 10 metrics") + } + metricReq := make([]SMetric, len(metrics)) + for i := range metrics { + metricReq[i] = metrics[i].SMetric + } + request := requests.NewResourceRequest("POST", string(ces.ServiceName), ces.version, ces.Region, ces.ProjectId, "batch-query-metric-data") + input := SBatchQueryMetricDataInput{ + Metrics: metricReq, + From: since.UnixNano() / 1000, + To: until.UnixNano() / 1000, + Period: "1", + Filter: "average", + } + body := jsonutils.Marshal(&input).String() + request.SetContent([]byte(body)) + _, resp, err := ces.jsonRequest(request) + if err != nil { + return nil, errors.Wrap(err, "ces.jsonRequest") + } + log.Debugf("%s", resp) + result := make([]SMetricData, 0) + err = resp.Unmarshal(&result, "metrics") + if err != nil { + return nil, errors.Wrap(err, "resp.Unmarshal") + } + return result, nil +} diff --git a/pkg/multicloud/huawei/monitor.go b/pkg/multicloud/huawei/monitor.go new file mode 100644 index 0000000000..a14e60d31c --- /dev/null +++ b/pkg/multicloud/huawei/monitor.go @@ -0,0 +1,29 @@ +// 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 huawei + +import ( + "time" + + "yunion.io/x/onecloud/pkg/multicloud/huawei/client/modules" +) + +func (r *SRegion) GetMetrics() ([]modules.SMetricMeta, error) { + return r.ecsClient.CloudEye.ListMetrics() +} + +func (r *SRegion) GetMetricsData(metrics []modules.SMetricMeta, since time.Time, until time.Time) ([]modules.SMetricData, error) { + return r.ecsClient.CloudEye.GetMetricsData(metrics, since, until) +} diff --git a/pkg/multicloud/huawei/shell/monitor.go b/pkg/multicloud/huawei/shell/monitor.go new file mode 100644 index 0000000000..99c87d704f --- /dev/null +++ b/pkg/multicloud/huawei/shell/monitor.go @@ -0,0 +1,62 @@ +// 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 ( + "yunion.io/x/pkg/util/timeutils" + + "yunion.io/x/onecloud/pkg/multicloud/huawei" + "yunion.io/x/onecloud/pkg/util/shellutils" +) + +func init() { + type MetricListOptions struct { + } + shellutils.R(&MetricListOptions{}, "metrics-list", "List metrics", func(cli *huawei.SRegion, args *MetricListOptions) error { + metrics, err := cli.GetMetrics() + if err != nil { + return err + } + printList(metrics, 0, 0, 0, nil) + return nil + }) + + type MetricDataOptions struct { + START int `help:"Start metrics"` + Count int `help:"Metric count" default:"1"` + SINCE string `help:"since"` + UNTIL string `help:"until"` + } + shellutils.R(&MetricDataOptions{}, "metrics-data-list", "List metrics", func(cli *huawei.SRegion, args *MetricDataOptions) error { + metrics, err := cli.GetMetrics() + if err != nil { + return err + } + since, err := timeutils.ParseTimeStr(args.SINCE) + if err != nil { + return err + } + until, err := timeutils.ParseTimeStr(args.UNTIL) + if err != nil { + return err + } + data, err := cli.GetMetricsData(metrics[args.START:args.START+args.Count], since, until) + if err != nil { + return err + } + printList(data, 0, 0, 0, nil) + return nil + }) +} diff --git a/pkg/util/httputils/error.go b/pkg/util/httputils/error.go index 1f5e2a7f1f..98a7271f7c 100644 --- a/pkg/util/httputils/error.go +++ b/pkg/util/httputils/error.go @@ -1,3 +1,17 @@ +// 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 httputils import (