130 lines
4.4 KiB
Go
130 lines
4.4 KiB
Go
package oci
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"time"
|
|
|
|
"github.com/oracle/oci-go-sdk/v65/common"
|
|
"github.com/oracle/oci-go-sdk/v65/monitoring"
|
|
)
|
|
|
|
// trafficNamespace 是 VNIC 流量指标所在的 Monitoring 命名空间;
|
|
// 指标由 OCI 自动上报,原始点 1 分钟一个,这里按天聚合。
|
|
const (
|
|
trafficNamespace = "oci_vcn"
|
|
trafficResolution = "1440m"
|
|
metricVnicInbound = "VnicFromNetworkBytes" // 实例收到的字节
|
|
metricVnicOutbund = "VnicToNetworkBytes" // 实例发出的字节
|
|
)
|
|
|
|
// TrafficQuery 是一次实例流量统计的条件。
|
|
type TrafficQuery struct {
|
|
Region string
|
|
InstanceID string
|
|
StartTime time.Time
|
|
EndTime time.Time
|
|
}
|
|
|
|
// TrafficPoint 是一个聚合窗口(天)的流量字节数。
|
|
type TrafficPoint struct {
|
|
Timestamp time.Time `json:"timestamp"`
|
|
Bytes float64 `json:"bytes"`
|
|
}
|
|
|
|
// VnicTraffic 是单块 VNIC 的进出流量。
|
|
type VnicTraffic struct {
|
|
VnicID string `json:"vnicId"`
|
|
InboundBytes float64 `json:"inboundBytes"`
|
|
OutboundBytes float64 `json:"outboundBytes"`
|
|
Inbound []TrafficPoint `json:"inbound"`
|
|
Outbound []TrafficPoint `json:"outbound"`
|
|
}
|
|
|
|
// InstanceTraffic 是实例全部 VNIC 的流量汇总。
|
|
type InstanceTraffic struct {
|
|
InstanceID string `json:"instanceId"`
|
|
InboundBytes float64 `json:"inboundBytes"`
|
|
OutboundBytes float64 `json:"outboundBytes"`
|
|
Vnics []VnicTraffic `json:"vnics"`
|
|
}
|
|
|
|
func (c *RealClient) monitoringClient(cred Credentials, region string) (monitoring.MonitoringClient, error) {
|
|
mc, err := monitoring.NewMonitoringClientWithConfigurationProvider(provider(cred))
|
|
if err != nil {
|
|
return mc, fmt.Errorf("new monitoring client: %w", err)
|
|
}
|
|
applyProxy(&mc.BaseClient, cred)
|
|
if region != "" {
|
|
mc.SetRegion(normalizeRegion(region))
|
|
}
|
|
return mc, nil
|
|
}
|
|
|
|
// SummarizeInstanceTraffic 实现 Client:逐 VNIC 查询进出流量并汇总。
|
|
func (c *RealClient) SummarizeInstanceTraffic(ctx context.Context, cred Credentials, q TrafficQuery) (InstanceTraffic, error) {
|
|
mc, err := c.monitoringClient(cred, q.Region)
|
|
if err != nil {
|
|
return InstanceTraffic{}, err
|
|
}
|
|
// VNIC 指标上报在实例所在 compartment,查询须用同一 compartment 才有数据
|
|
vnics, compartmentID, err := c.instanceVnics(ctx, cred, q.Region, q.InstanceID)
|
|
if err != nil {
|
|
return InstanceTraffic{}, err
|
|
}
|
|
result := InstanceTraffic{InstanceID: q.InstanceID, Vnics: make([]VnicTraffic, 0, len(vnics))}
|
|
for _, vnic := range vnics {
|
|
vt := VnicTraffic{VnicID: deref(vnic.Id)}
|
|
if vt.Inbound, err = summarizeVnicMetric(ctx, mc, compartmentID, vt.VnicID, metricVnicInbound, q); err != nil {
|
|
return InstanceTraffic{}, err
|
|
}
|
|
if vt.Outbound, err = summarizeVnicMetric(ctx, mc, compartmentID, vt.VnicID, metricVnicOutbund, q); err != nil {
|
|
return InstanceTraffic{}, err
|
|
}
|
|
vt.Inbound, vt.Outbound = orEmpty(vt.Inbound), orEmpty(vt.Outbound)
|
|
vt.InboundBytes, vt.OutboundBytes = sumTraffic(vt.Inbound), sumTraffic(vt.Outbound)
|
|
result.InboundBytes += vt.InboundBytes
|
|
result.OutboundBytes += vt.OutboundBytes
|
|
result.Vnics = append(result.Vnics, vt)
|
|
}
|
|
return result, nil
|
|
}
|
|
|
|
// summarizeVnicMetric 按天聚合查询单块 VNIC 的一个流量指标;
|
|
// compartmentID 须是实例所在 compartment,指标数据挂在该 compartment 下。
|
|
func summarizeVnicMetric(ctx context.Context, mc monitoring.MonitoringClient, compartmentID, vnicID, metric string, q TrafficQuery) ([]TrafficPoint, error) {
|
|
query := fmt.Sprintf("%s[%s]{resourceId = %q}.sum()", metric, trafficResolution, vnicID)
|
|
resolution := trafficResolution
|
|
resp, err := mc.SummarizeMetricsData(ctx, monitoring.SummarizeMetricsDataRequest{
|
|
CompartmentId: &compartmentID,
|
|
SummarizeMetricsDataDetails: monitoring.SummarizeMetricsDataDetails{
|
|
Namespace: common.String(trafficNamespace),
|
|
Query: &query,
|
|
StartTime: &common.SDKTime{Time: q.StartTime},
|
|
EndTime: &common.SDKTime{Time: q.EndTime},
|
|
Resolution: &resolution,
|
|
},
|
|
})
|
|
if err != nil {
|
|
return nil, fmt.Errorf("summarize %s of vnic %s: %w", metric, vnicID, err)
|
|
}
|
|
var points []TrafficPoint
|
|
for _, item := range resp.Items {
|
|
for _, dp := range item.AggregatedDatapoints {
|
|
if dp.Timestamp == nil || dp.Value == nil {
|
|
continue
|
|
}
|
|
points = append(points, TrafficPoint{Timestamp: dp.Timestamp.Time, Bytes: *dp.Value})
|
|
}
|
|
}
|
|
return orEmpty(points), nil
|
|
}
|
|
|
|
func sumTraffic(points []TrafficPoint) float64 {
|
|
var total float64
|
|
for _, p := range points {
|
|
total += p.Bytes
|
|
}
|
|
return total
|
|
}
|