Merge pull request #3770 from yunkunrao/master

Remove metering ConfigMap dependency.
This commit is contained in:
KubeSphere CI Bot
2021-04-20 14:03:20 +08:00
committed by GitHub
22 changed files with 258 additions and 324 deletions

View File

@@ -220,14 +220,14 @@ func (s *APIServer) installKubeSphereAPIs() {
urlruntime.Must(configv1alpha2.AddToContainer(s.container, s.Config))
urlruntime.Must(resourcev1alpha3.AddToContainer(s.container, s.InformerFactory, s.RuntimeCache))
urlruntime.Must(monitoringv1alpha3.AddToContainer(s.container, s.KubernetesClient.Kubernetes(), s.MonitoringClient, s.MetricsClient, s.InformerFactory, s.KubernetesClient.KubeSphere()))
urlruntime.Must(meteringv1alpha1.AddToContainer(s.container, s.KubernetesClient.Kubernetes(), s.MonitoringClient, s.InformerFactory, s.KubernetesClient.KubeSphere(), s.RuntimeCache))
urlruntime.Must(meteringv1alpha1.AddToContainer(s.container, s.KubernetesClient.Kubernetes(), s.MonitoringClient, s.InformerFactory, s.KubernetesClient.KubeSphere(), s.RuntimeCache, s.Config.MeteringOptions))
urlruntime.Must(openpitrixv1.AddToContainer(s.container, s.InformerFactory, s.KubernetesClient.KubeSphere(), s.Config.OpenPitrixOptions))
urlruntime.Must(openpitrixv2alpha1.AddToContainer(s.container, s.InformerFactory, s.KubernetesClient.KubeSphere(), s.Config.OpenPitrixOptions))
urlruntime.Must(operationsv1alpha2.AddToContainer(s.container, s.KubernetesClient.Kubernetes()))
urlruntime.Must(resourcesv1alpha2.AddToContainer(s.container, s.KubernetesClient.Kubernetes(), s.InformerFactory,
s.KubernetesClient.Master()))
urlruntime.Must(tenantv1alpha2.AddToContainer(s.container, s.InformerFactory, s.KubernetesClient.Kubernetes(),
s.KubernetesClient.KubeSphere(), s.EventsClient, s.LoggingClient, s.AuditingClient, amOperator, rbacAuthorizer, s.MonitoringClient, s.RuntimeCache))
s.KubernetesClient.KubeSphere(), s.EventsClient, s.LoggingClient, s.AuditingClient, amOperator, rbacAuthorizer, s.MonitoringClient, s.RuntimeCache, s.Config.MeteringOptions))
urlruntime.Must(terminalv1alpha2.AddToContainer(s.container, s.KubernetesClient.Kubernetes(), s.KubernetesClient.Config()))
urlruntime.Must(clusterkapisv1alpha1.AddToContainer(s.container,
s.InformerFactory.KubernetesSharedInformerFactory(),

View File

@@ -290,8 +290,4 @@ func (conf *Config) stripEmptyOptions() {
if conf.KubeEdgeOptions != nil && conf.KubeEdgeOptions.Endpoint == "" {
conf.KubeEdgeOptions = nil
}
if conf.MeteringOptions != nil && !conf.MeteringOptions.Enable {
conf.MeteringOptions = nil
}
}

View File

@@ -176,7 +176,7 @@ func newTestConfig() (*Config, error) {
Endpoint: "http://edge-watcher.kubeedge.svc/api/",
},
MeteringOptions: &metering.Options{
Enable: false,
RetentionDay: "7d",
},
}
return conf, nil
@@ -193,13 +193,6 @@ func saveTestConfig(t *testing.T, conf *Config) {
}
}
func testMeteringConfig(t *testing.T, conf *Config) {
conf.ToMap()
if conf.MeteringOptions != nil {
t.Fatalf("setting metering options failed")
}
}
func cleanTestConfig(t *testing.T) {
file := fmt.Sprintf("%s.yaml", defaultConfigurationName)
if _, err := os.Stat(file); os.IsNotExist(err) {
@@ -229,7 +222,58 @@ func TestGet(t *testing.T) {
if diff := cmp.Diff(conf, conf2); diff != "" {
t.Fatal(diff)
}
testMeteringConfig(t, conf)
}
func TestStripEmptyOptions(t *testing.T) {
var config Config
config.RedisOptions = &cache.Options{Host: ""}
config.DevopsOptions = &jenkins.Options{Host: ""}
config.MonitoringOptions = &prometheus.Options{Endpoint: ""}
config.SonarQubeOptions = &sonarqube.Options{Host: ""}
config.LdapOptions = &ldap.Options{Host: ""}
config.NetworkOptions = &network.Options{
EnableNetworkPolicy: false,
WeaveScopeHost: "",
IPPoolType: networkv1alpha1.IPPoolTypeNone,
}
config.ServiceMeshOptions = &servicemesh.Options{
IstioPilotHost: "",
ServicemeshPrometheusHost: "",
JaegerQueryHost: "",
}
config.S3Options = &s3.Options{
Endpoint: "",
}
config.AlertingOptions = &alerting.Options{
Endpoint: "",
PrometheusEndpoint: "",
ThanosRulerEndpoint: "",
}
config.LoggingOptions = &logging.Options{Host: ""}
config.NotificationOptions = &notification.Options{Endpoint: ""}
config.MultiClusterOptions = &multicluster.Options{Enable: false}
config.EventsOptions = &events.Options{Host: ""}
config.AuditingOptions = &auditing.Options{Host: ""}
config.KubeEdgeOptions = &kubeedge.Options{Endpoint: ""}
config.stripEmptyOptions()
if config.RedisOptions != nil ||
config.DevopsOptions != nil ||
config.MonitoringOptions != nil ||
config.SonarQubeOptions != nil ||
config.LdapOptions != nil ||
config.NetworkOptions != nil ||
config.ServiceMeshOptions != nil ||
config.S3Options != nil ||
config.AlertingOptions != nil ||
config.LoggingOptions != nil ||
config.NotificationOptions != nil ||
config.MultiClusterOptions != nil ||
config.EventsOptions != nil ||
config.AuditingOptions != nil ||
config.KubeEdgeOptions != nil {
t.Fatal("config stripEmptyOptions failed")
}
}

View File

@@ -26,6 +26,7 @@ import (
"kubesphere.io/kubesphere/pkg/informers"
monitorhle "kubesphere.io/kubesphere/pkg/kapis/monitoring/v1alpha3"
resourcev1alpha3 "kubesphere.io/kubesphere/pkg/models/resources/v1alpha3/resource"
meteringclient "kubesphere.io/kubesphere/pkg/simple/client/metering"
"kubesphere.io/kubesphere/pkg/simple/client/monitoring"
)
@@ -42,6 +43,6 @@ type meterHandler interface {
HandlePVCMeterQuery(req *restful.Request, resp *restful.Response)
}
func newHandler(k kubernetes.Interface, m monitoring.Interface, f informers.InformerFactory, ksClient versioned.Interface, resourceGetter *resourcev1alpha3.ResourceGetter) meterHandler {
return monitorhle.NewHandler(k, m, nil, f, ksClient, resourceGetter)
func newHandler(k kubernetes.Interface, m monitoring.Interface, f informers.InformerFactory, ksClient versioned.Interface, resourceGetter *resourcev1alpha3.ResourceGetter, meteringOptions *meteringclient.Options) meterHandler {
return monitorhle.NewHandler(k, m, nil, f, ksClient, resourceGetter, meteringOptions)
}

View File

@@ -34,6 +34,7 @@ import (
monitoringv1alpha3 "kubesphere.io/kubesphere/pkg/kapis/monitoring/v1alpha3"
model "kubesphere.io/kubesphere/pkg/models/monitoring"
resourcev1alpha3 "kubesphere.io/kubesphere/pkg/models/resources/v1alpha3/resource"
meteringclient "kubesphere.io/kubesphere/pkg/simple/client/metering"
"kubesphere.io/kubesphere/pkg/simple/client/monitoring"
)
@@ -44,10 +45,10 @@ const (
var GroupVersion = schema.GroupVersion{Group: groupName, Version: "v1alpha1"}
func AddToContainer(c *restful.Container, k8sClient kubernetes.Interface, meteringClient monitoring.Interface, factory informers.InformerFactory, ksClient versioned.Interface, cache cache.Cache) error {
func AddToContainer(c *restful.Container, k8sClient kubernetes.Interface, meteringClient monitoring.Interface, factory informers.InformerFactory, ksClient versioned.Interface, cache cache.Cache, meteringOptions *meteringclient.Options) error {
ws := runtime.NewWebService(GroupVersion)
h := newHandler(k8sClient, meteringClient, factory, ksClient, resourcev1alpha3.NewResourceGetter(factory, cache))
h := newHandler(k8sClient, meteringClient, factory, ksClient, resourcev1alpha3.NewResourceGetter(factory, cache), meteringOptions)
ws.Route(ws.GET("/cluster").
To(h.HandleClusterMeterQuery).

View File

@@ -33,25 +33,31 @@ import (
"kubesphere.io/kubesphere/pkg/informers"
model "kubesphere.io/kubesphere/pkg/models/monitoring"
resourcev1alpha3 "kubesphere.io/kubesphere/pkg/models/resources/v1alpha3/resource"
meteringclient "kubesphere.io/kubesphere/pkg/simple/client/metering"
"kubesphere.io/kubesphere/pkg/simple/client/monitoring"
)
type handler struct {
k kubernetes.Interface
mo model.MonitoringOperator
opRelease openpitrix.ReleaseInterface
k kubernetes.Interface
mo model.MonitoringOperator
opRelease openpitrix.ReleaseInterface
meteringOptions *meteringclient.Options
}
func NewHandler(k kubernetes.Interface, monitoringClient monitoring.Interface, metricsClient monitoring.Interface, f informers.InformerFactory, ksClient versioned.Interface, resourceGetter *resourcev1alpha3.ResourceGetter) *handler {
func NewHandler(k kubernetes.Interface, monitoringClient monitoring.Interface, metricsClient monitoring.Interface, f informers.InformerFactory, ksClient versioned.Interface, resourceGetter *resourcev1alpha3.ResourceGetter, meteringOptions *meteringclient.Options) *handler {
var opRelease openpitrix.Interface
if ksClient != nil {
opRelease = openpitrix.NewOpenpitrixOperator(f, ksClient, nil)
}
if meteringOptions == nil || meteringOptions.RetentionDay == "" {
meteringOptions = &meteringclient.DefaultMeteringOption
}
return &handler{
k: k,
mo: model.NewMonitoringOperator(monitoringClient, metricsClient, k, f, resourceGetter),
opRelease: opRelease,
k: k,
mo: model.NewMonitoringOperator(monitoringClient, metricsClient, k, f, resourceGetter),
opRelease: opRelease,
meteringOptions: meteringOptions,
}
}

View File

@@ -331,7 +331,7 @@ func TestParseRequestParams(t *testing.T) {
fakeInformerFactory.KubeSphereSharedInformerFactory()
handler := NewHandler(client, nil, nil, fakeInformerFactory, ksClient, nil)
handler := NewHandler(client, nil, nil, fakeInformerFactory, ksClient, nil, nil)
result, err := handler.makeQueryOptions(tt.params, tt.lvl)
if err != nil {
@@ -419,3 +419,20 @@ func TestExportMetrics(t *testing.T) {
})
}
}
func TestGetMetricPosMap(t *testing.T) {
metrics := []monitoring.Metric{
{
MetricName: "a",
},
{
MetricName: "b",
},
}
metricMap := getMetricPosMap(metrics)
if metricMap["a"] != 0 ||
metricMap["b"] != 1 {
t.Fatal("getMetricPosMap failed")
}
}

View File

@@ -62,9 +62,9 @@ func (h handler) handleApplicationMetersQuery(meters []string, resp *restful.Res
}
if q.isRangeQuery() {
current_res, err = h.mo.GetNamedMetersOverTime(meters, q.start, q.end, q.step, opt)
current_res, err = h.mo.GetNamedMetersOverTime(meters, q.start, q.end, q.step, opt, h.meteringOptions.Billing.PriceInfo)
} else {
current_res, err = h.mo.GetNamedMeters(meters, q.time, opt)
current_res, err = h.mo.GetNamedMeters(meters, q.time, opt, h.meteringOptions.Billing.PriceInfo)
}
if err != nil {
api.HandleBadRequest(resp, nil, err)
@@ -119,9 +119,9 @@ func (h handler) handleServiceMetersQuery(meters []string, resp *restful.Respons
}
if q.isRangeQuery() {
current_res, err = h.mo.GetNamedMetersOverTime(meters, q.start, q.end, q.step, opt)
current_res, err = h.mo.GetNamedMetersOverTime(meters, q.start, q.end, q.step, opt, h.meteringOptions.Billing.PriceInfo)
} else {
current_res, err = h.mo.GetNamedMeters(meters, q.time, opt)
current_res, err = h.mo.GetNamedMeters(meters, q.time, opt, h.meteringOptions.Billing.PriceInfo)
}
if err != nil {
api.HandleBadRequest(resp, nil, err)
@@ -197,13 +197,13 @@ func (h handler) handleNamedMetersQuery(resp *restful.Response, q queryOptions)
}
if q.isRangeQuery() {
res, err = h.mo.GetNamedMetersOverTime(meters, q.start, q.end, q.step, q.option)
res, err = h.mo.GetNamedMetersOverTime(meters, q.start, q.end, q.step, q.option, h.meteringOptions.Billing.PriceInfo)
if err != nil {
api.HandleBadRequest(resp, nil, err)
return
}
} else {
res, err = h.mo.GetNamedMeters(meters, q.time, q.option)
res, err = h.mo.GetNamedMeters(meters, q.time, q.option, h.meteringOptions.Billing.PriceInfo)
if err != nil {
api.HandleBadRequest(resp, nil, err)
return
@@ -434,9 +434,9 @@ func (h handler) handleOpenpitrixMetersQuery(meters []string, resp *restful.Resp
}
if q.isRangeQuery() {
current_res, err = h.mo.GetNamedMetersOverTime(meters, q.start, q.end, q.step, opt)
current_res, err = h.mo.GetNamedMetersOverTime(meters, q.start, q.end, q.step, opt, h.meteringOptions.Billing.PriceInfo)
} else {
current_res, err = h.mo.GetNamedMeters(meters, q.time, opt)
current_res, err = h.mo.GetNamedMeters(meters, q.time, opt, h.meteringOptions.Billing.PriceInfo)
}
if err != nil {
api.HandleBadRequest(resp, nil, err)

View File

@@ -44,7 +44,7 @@ var GroupVersion = schema.GroupVersion{Group: groupName, Version: "v1alpha3"}
func AddToContainer(c *restful.Container, k8sClient kubernetes.Interface, monitoringClient monitoring.Interface, metricsClient monitoring.Interface, factory informers.InformerFactory, ksClient versioned.Interface) error {
ws := runtime.NewWebService(GroupVersion)
h := NewHandler(k8sClient, monitoringClient, metricsClient, factory, ksClient, nil)
h := NewHandler(k8sClient, monitoringClient, metricsClient, factory, ksClient, nil, nil)
ws.Route(ws.GET("/kubesphere").
To(h.handleKubeSphereMetricsQuery).

View File

@@ -46,20 +46,28 @@ import (
"kubesphere.io/kubesphere/pkg/simple/client/auditing"
"kubesphere.io/kubesphere/pkg/simple/client/events"
"kubesphere.io/kubesphere/pkg/simple/client/logging"
meteringclient "kubesphere.io/kubesphere/pkg/simple/client/metering"
monitoringclient "kubesphere.io/kubesphere/pkg/simple/client/monitoring"
)
type tenantHandler struct {
tenant tenant.Interface
tenant tenant.Interface
meteringOptions *meteringclient.Options
}
func newTenantHandler(factory informers.InformerFactory, k8sclient kubernetes.Interface, ksclient kubesphere.Interface,
evtsClient events.Client, loggingClient logging.Client, auditingclient auditing.Client,
am am.AccessManagementInterface, authorizer authorizer.Authorizer,
monitoringclient monitoringclient.Interface, resourceGetter *resourcev1alpha3.ResourceGetter) *tenantHandler {
monitoringclient monitoringclient.Interface, resourceGetter *resourcev1alpha3.ResourceGetter,
meteringOptions *meteringclient.Options) *tenantHandler {
if meteringOptions == nil || meteringOptions.RetentionDay == "" {
meteringOptions = &meteringclient.DefaultMeteringOption
}
return &tenantHandler{
tenant: tenant.New(factory, k8sclient, ksclient, evtsClient, loggingClient, auditingclient, am, authorizer, monitoringclient, resourceGetter),
tenant: tenant.New(factory, k8sclient, ksclient, evtsClient, loggingClient, auditingclient, am, authorizer, monitoringclient, resourceGetter),
meteringOptions: meteringOptions,
}
}

View File

@@ -14,7 +14,6 @@ import (
"kubesphere.io/kubesphere/pkg/apiserver/request"
monitoringv1alpha3 "kubesphere.io/kubesphere/pkg/kapis/monitoring/v1alpha3"
"kubesphere.io/kubesphere/pkg/models/metering"
"kubesphere.io/kubesphere/pkg/models/monitoring"
monitoringclient "kubesphere.io/kubesphere/pkg/simple/client/monitoring"
)
@@ -30,7 +29,7 @@ func (h *tenantHandler) QueryMetering(req *restful.Request, resp *restful.Respon
q := meteringv1alpha1.ParseQueryParameter(req)
res, err := h.tenant.Metering(u, q)
res, err := h.tenant.Metering(u, q, h.meteringOptions.Billing.PriceInfo)
if err != nil {
api.HandleBadRequest(resp, nil, err)
return
@@ -71,7 +70,7 @@ func (h *tenantHandler) QueryMeteringHierarchy(req *restful.Request, resp *restf
q := meteringv1alpha1.ParseQueryParameter(req)
q.Level = monitoringclient.LevelPod
resourceStats, err := h.tenant.MeteringHierarchy(u, q)
resourceStats, err := h.tenant.MeteringHierarchy(u, q, h.meteringOptions.Billing.PriceInfo)
if err != nil {
api.HandleBadRequest(resp, nil, err)
return
@@ -83,17 +82,9 @@ func (h *tenantHandler) QueryMeteringHierarchy(req *restful.Request, resp *restf
func (h *tenantHandler) HandlePriceInfoQuery(req *restful.Request, resp *restful.Response) {
var priceResponse metering.PriceResponse
priceResponse.Init()
meterConfig, err := monitoring.LoadYaml()
if err != nil {
klog.Warning(err)
resp.WriteAsJson(priceResponse)
return
}
priceInfo := meterConfig.GetPriceInfo()
priceResponse.RetentionDay = meterConfig.RetentionDay
priceInfo := h.meteringOptions.Billing.PriceInfo
priceResponse.RetentionDay = h.meteringOptions.RetentionDay
priceResponse.Currency = priceInfo.CurrencyUnit
priceResponse.CpuPerCorePerHour = priceInfo.CpuPerCorePerHour
priceResponse.MemPerGigabytesPerHour = priceInfo.MemPerGigabytesPerHour

View File

@@ -48,6 +48,7 @@ import (
"kubesphere.io/kubesphere/pkg/simple/client/auditing"
"kubesphere.io/kubesphere/pkg/simple/client/events"
"kubesphere.io/kubesphere/pkg/simple/client/logging"
meteringclient "kubesphere.io/kubesphere/pkg/simple/client/metering"
monitoringclient "kubesphere.io/kubesphere/pkg/simple/client/monitoring"
)
@@ -64,11 +65,11 @@ func Resource(resource string) schema.GroupResource {
func AddToContainer(c *restful.Container, factory informers.InformerFactory, k8sclient kubernetes.Interface,
ksclient kubesphere.Interface, evtsClient events.Client, loggingClient logging.Client,
auditingclient auditing.Client, am am.AccessManagementInterface, authorizer authorizer.Authorizer,
monitoringclient monitoringclient.Interface, cache cache.Cache) error {
monitoringclient monitoringclient.Interface, cache cache.Cache, meteringOptions *meteringclient.Options) error {
mimePatch := []string{restful.MIME_JSON, runtime.MimeMergePatchJson, runtime.MimeJsonPatchJson}
ws := runtime.NewWebService(GroupVersion)
handler := newTenantHandler(factory, k8sclient, ksclient, evtsClient, loggingClient, auditingclient, am, authorizer, monitoringclient, resourcev1alpha3.NewResourceGetter(factory, cache))
handler := newTenantHandler(factory, k8sclient, ksclient, evtsClient, loggingClient, auditingclient, am, authorizer, monitoringclient, resourcev1alpha3.NewResourceGetter(factory, cache), meteringOptions)
ws.Route(ws.GET("/clusters").
To(handler.ListClusters).

View File

@@ -1,12 +1,18 @@
package metering
type PriceInfo struct {
Currency string `json:"currency" description:"currency"`
CpuPerCorePerHour float64 `json:"cpu_per_core_per_hour,omitempty" description:"cpu price"`
MemPerGigabytesPerHour float64 `json:"mem_per_gigabytes_per_hour,omitempty" description:"mem price"`
// currency unit, currently support CNY and USD
Currency string `json:"currency" description:"currency"`
// cpu cost with above currency unit for per core per hour
CpuPerCorePerHour float64 `json:"cpu_per_core_per_hour,omitempty" description:"cpu price"`
// mem cost with above currency unit for per GB per hour
MemPerGigabytesPerHour float64 `json:"mem_per_gigabytes_per_hour,omitempty" description:"mem price"`
// ingress network traffic cost with above currency unit for per MB per hour
IngressNetworkTrafficPerMegabytesPerHour float64 `json:"ingress_network_traffic_per_megabytes_per_hour,omitempty" description:"ingress price"`
EgressNetworkTrafficPerMegabytesPerHour float64 `json:"egress_network_traffic_per_megabytes_per_hour,omitempty" description:"egress price"`
PvcPerGigabytesPerHour float64 `json:"pvc_per_gigabytes_per_hour,omitempty" description:"pvc price"`
// egress network traffice cost with above currency unit for per MB per hour
EgressNetworkTrafficPerMegabytesPerHour float64 `json:"egress_network_traffic_per_megabytes_per_hour,omitempty" description:"egress price"`
// pvc cost with above currency unit for per GB per hour
PvcPerGigabytesPerHour float64 `json:"pvc_per_gigabytes_per_hour,omitempty" description:"pvc price"`
}
type PriceResponse struct {
@@ -14,16 +20,6 @@ type PriceResponse struct {
PriceInfo `json:",inline"`
}
// currently init method fill illegal value to hint that metering config file was not mounted yet
func (p *PriceInfo) Init() {
p.Currency = ""
p.CpuPerCorePerHour = -1
p.MemPerGigabytesPerHour = -1
p.IngressNetworkTrafficPerMegabytesPerHour = -1
p.EgressNetworkTrafficPerMegabytesPerHour = -1
p.PvcPerGigabytesPerHour = -1
}
type PodStatistic struct {
CPUUsage float64 `json:"cpu_usage" description:"cpu_usage"`
MemoryUsageWoCache float64 `json:"memory_usage_wo_cache" description:"memory_usage_wo_cache"`

View File

@@ -41,6 +41,7 @@ import (
resourcev1alpha3 "kubesphere.io/kubesphere/pkg/models/resources/v1alpha3/resource"
"kubesphere.io/kubesphere/pkg/server/errors"
"kubesphere.io/kubesphere/pkg/server/params"
meteringclient "kubesphere.io/kubesphere/pkg/simple/client/metering"
"kubesphere.io/kubesphere/pkg/simple/client/monitoring"
)
@@ -57,8 +58,8 @@ type MonitoringOperator interface {
GetWorkspaceStats(workspace string) Metrics
// meter
GetNamedMetersOverTime(metrics []string, start, end time.Time, step time.Duration, opt monitoring.QueryOption) (Metrics, error)
GetNamedMeters(metrics []string, time time.Time, opt monitoring.QueryOption) (Metrics, error)
GetNamedMetersOverTime(metrics []string, start, end time.Time, step time.Duration, opt monitoring.QueryOption, priceInfo meteringclient.PriceInfo) (Metrics, error)
GetNamedMeters(metrics []string, time time.Time, opt monitoring.QueryOption, priceInfo meteringclient.PriceInfo) (Metrics, error)
GetAppWorkloads(ns string, apps []string) map[string][]string
GetSerivePodsMap(ns string, services []string) map[string][]string
}
@@ -421,7 +422,7 @@ func generateScalingFactorMap(step time.Duration) map[string]float64 {
return scalingMap
}
func (mo monitoringOperator) GetNamedMetersOverTime(meters []string, start, end time.Time, step time.Duration, opt monitoring.QueryOption) (metrics Metrics, err error) {
func (mo monitoringOperator) GetNamedMetersOverTime(meters []string, start, end time.Time, step time.Duration, opt monitoring.QueryOption, priceInfo meteringclient.PriceInfo) (metrics Metrics, err error) {
if step.Hours() < 1 {
klog.Warning("step should be longer than one hour")
@@ -458,13 +459,13 @@ func (mo monitoringOperator) GetNamedMetersOverTime(meters []string, start, end
sMap := generateScalingFactorMap(step)
for i, _ := range ress {
ress[i].MetricData = updateMetricStatData(ress[i], sMap)
ress[i].MetricData = updateMetricStatData(ress[i], sMap, priceInfo)
}
return Metrics{Results: ress}, nil
}
func (mo monitoringOperator) GetNamedMeters(meters []string, time time.Time, opt monitoring.QueryOption) (Metrics, error) {
func (mo monitoringOperator) GetNamedMeters(meters []string, time time.Time, opt monitoring.QueryOption, priceInfo meteringclient.PriceInfo) (Metrics, error) {
metersPerHour := mo.getNamedMetersWithHourInterval(meters, time, opt)
@@ -472,7 +473,7 @@ func (mo monitoringOperator) GetNamedMeters(meters []string, time time.Time, opt
res := metersPerHour.Results[metricIndex]
metersPerHour.Results[metricIndex].MetricData = updateMetricStatData(res, nil)
metersPerHour.Results[metricIndex].MetricData = updateMetricStatData(res, nil, priceInfo)
}
return metersPerHour, nil

View File

@@ -3,12 +3,10 @@ package monitoring
import (
"fmt"
"math/big"
"os"
"path/filepath"
"k8s.io/apimachinery/pkg/util/yaml"
"k8s.io/klog"
meteringclient "kubesphere.io/kubesphere/pkg/simple/client/metering"
"kubesphere.io/kubesphere/pkg/simple/client/monitoring"
)
@@ -76,56 +74,6 @@ var MeterResourceMap = map[string]int{
"meter_pod_pvc_bytes_total": METER_RESOURCE_TYPE_PVC,
}
type PriceInfo struct {
CpuPerCorePerHour float64 `json:"cpuPerCorePerHour" yaml:"cpuPerCorePerHour"`
MemPerGigabytesPerHour float64 `json:"memPerGigabytesPerHour" yaml:"memPerGigabytesPerHour"`
IngressNetworkTrafficPerMegabytesPerHour float64 `json:"ingressNetworkTrafficPerMegabytesPerHour" yaml:"ingressNetworkTrafficPerGiagabytesPerHour"`
EgressNetworkTrafficPerMegabytesPerHour float64 `json:"egressNetworkTrafficPerMegabytesPerHour" yaml:"egressNetworkTrafficPerGigabytesPerHour"`
PvcPerGigabytesPerHour float64 `json:"pvcPerGigabytesPerHour" yaml:"pvcPerGigabytesPerHour"`
CurrencyUnit string `json:"currencyUnit" yaml:"currencyUnit"`
}
type Billing struct {
PriceInfo PriceInfo `json:"priceInfo" yaml:"priceInfo"`
}
type MeterConfig struct {
RetentionDay string `json:"retentionDay" yaml:"retentionDay"`
Billing Billing `json:"billing" yaml:"billing"`
}
func (mc MeterConfig) GetPriceInfo() PriceInfo {
return mc.Billing.PriceInfo
}
func LoadYaml() (*MeterConfig, error) {
var meterConfig MeterConfig
var mf *os.File
var err error
if _, err := os.Stat(meteringConfigName); os.IsNotExist(err) {
mf, err = os.Open(filepath.Join(meteringConfigDir, meteringConfigName))
if err != nil {
klog.Error(err)
return nil, err
}
} else {
mf, err = os.Open(meteringConfigName)
if err != nil {
klog.Error(err)
return nil, err
}
}
if err = yaml.NewYAMLOrJSONDecoder(mf, 1024).Decode(&meterConfig); err != nil {
klog.Error(err)
return nil, err
}
return &meterConfig, nil
}
func getMaxPointValue(points []monitoring.Point) string {
var max *big.Float
for i, p := range points {
@@ -181,16 +129,6 @@ func getAvgPointValue(points []monitoring.Point) string {
return fmt.Sprintf(generateFloatFormat(meteringDefaultPrecision), sum.Quo(sum, length))
}
func getCurrencyUnit() string {
meterConfig, err := LoadYaml()
if err != nil {
klog.Error(err)
return ""
}
return meterConfig.GetPriceInfo().CurrencyUnit
}
func generateFloatFormat(precision int) string {
return "%." + fmt.Sprintf("%d", precision) + "f"
}
@@ -204,7 +142,7 @@ func getResourceUnit(meterName string) string {
}
}
func getFeeWithMeterName(meterName string, sum string) string {
func getFeeWithMeterName(meterName string, sum string, priceInfo meteringclient.PriceInfo) string {
s, ok := new(big.Float).SetString(sum)
if !ok {
@@ -212,13 +150,6 @@ func getFeeWithMeterName(meterName string, sum string) string {
return ""
}
meterConfig, err := LoadYaml()
if err != nil {
klog.Error(err)
return ""
}
priceInfo := meterConfig.GetPriceInfo()
if resourceType, ok := MeterResourceMap[meterName]; !ok {
klog.Errorf("invlaid meter %v", meterName)
return ""
@@ -267,7 +198,7 @@ func getFeeWithMeterName(meterName string, sum string) string {
}
}
func updateMetricStatData(metric monitoring.Metric, scalingMap map[string]float64) monitoring.MetricData {
func updateMetricStatData(metric monitoring.Metric, scalingMap map[string]float64, priceInfo meteringclient.PriceInfo) monitoring.MetricData {
metricName := metric.MetricName
metricData := metric.MetricData
for index, metricValue := range metricData.MetricValues {
@@ -293,14 +224,14 @@ func updateMetricStatData(metric monitoring.Metric, scalingMap map[string]float6
if metricData.MetricType == monitoring.MetricTypeMatrix {
sum := getSumPointValue(metricData.MetricValues[index].Series)
metricData.MetricValues[index].SumValue = sum
metricData.MetricValues[index].Fee = getFeeWithMeterName(metricName, sum)
metricData.MetricValues[index].Fee = getFeeWithMeterName(metricName, sum, priceInfo)
} else {
sum := getSumPointValue([]monitoring.Point{*metricValue.Sample})
metricData.MetricValues[index].SumValue = sum
metricData.MetricValues[index].Fee = getFeeWithMeterName(metricName, sum)
metricData.MetricValues[index].Fee = getFeeWithMeterName(metricName, sum, priceInfo)
}
metricData.MetricValues[index].CurrencyUnit = getCurrencyUnit()
metricData.MetricValues[index].CurrencyUnit = priceInfo.CurrencyUnit
metricData.MetricValues[index].ResourceUnit = getResourceUnit(metricName)
}

View File

@@ -2,13 +2,11 @@ package monitoring
import (
"fmt"
"io/ioutil"
"os"
"testing"
"github.com/google/go-cmp/cmp"
"gopkg.in/yaml.v2"
meteringclient "kubesphere.io/kubesphere/pkg/simple/client/metering"
"kubesphere.io/kubesphere/pkg/simple/client/monitoring"
)
@@ -164,67 +162,6 @@ func TestGetAvgPointValue(t *testing.T) {
}
}
func saveTestConfig(t *testing.T, conf *MeterConfig) {
content, err := yaml.Marshal(conf)
if err != nil {
t.Fatalf("error marshal config. %v", err)
}
err = ioutil.WriteFile(meteringConfigName, content, 0640)
if err != nil {
t.Fatalf("error write configuration file, %v", err)
}
}
func testInvalidConfig(t *testing.T) {
os.Mkdir(meteringConfigName, os.ModeDir)
defer os.RemoveAll(meteringConfigName)
_, err := LoadYaml()
if err == nil {
t.Error("LoadYaml should fail")
return
}
return
}
func cleanTestConfig(t *testing.T) {
if _, err := os.Stat(meteringConfigName); os.IsNotExist(err) {
t.Log("file not exists, skipping")
return
}
err := os.Remove(meteringConfigName)
if err != nil {
t.Fatalf("remove %s file failed", meteringConfigName)
}
}
func TestGetCurrencyUnit(t *testing.T) {
if getCurrencyUnit() != "" {
t.Fatal("currency unit should be empty")
}
saveTestConfig(t, &MeterConfig{
Billing: Billing{
PriceInfo: PriceInfo{
IngressNetworkTrafficPerMegabytesPerHour: 1,
EgressNetworkTrafficPerMegabytesPerHour: 2,
CpuPerCorePerHour: 3,
MemPerGigabytesPerHour: 4,
PvcPerGigabytesPerHour: 5,
CurrencyUnit: "CNY",
},
},
})
defer cleanTestConfig(t)
if getCurrencyUnit() != "CNY" {
t.Fatal("failed to get currency unit from config")
}
}
func TestGenerateFloatFormat(t *testing.T) {
format := generateFloatFormat(10)
if format != "%.10f" {
@@ -314,114 +251,49 @@ func TestSquashPoints(t *testing.T) {
}
}
func TestLoadYaml(t *testing.T) {
testInvalidConfig(t)
// LoadYaml file not exist
_, err := LoadYaml()
if err == nil {
t.Error("LoadYaml should return error.")
return
}
saveTestConfig(t, &MeterConfig{
Billing: Billing{
PriceInfo: PriceInfo{
IngressNetworkTrafficPerMegabytesPerHour: 1,
EgressNetworkTrafficPerMegabytesPerHour: 2,
CpuPerCorePerHour: 3,
MemPerGigabytesPerHour: 4,
PvcPerGigabytesPerHour: 5,
CurrencyUnit: "CNY",
},
},
})
_, err = LoadYaml()
if err != nil {
t.Error("LoadYaml failed")
return
}
cleanTestConfig(t)
}
func TestGetFeeWithMeterName(t *testing.T) {
saveTestConfig(t, &MeterConfig{
Billing: Billing{
PriceInfo: PriceInfo{
IngressNetworkTrafficPerMegabytesPerHour: 1,
EgressNetworkTrafficPerMegabytesPerHour: 2,
CpuPerCorePerHour: 3,
MemPerGigabytesPerHour: 4,
PvcPerGigabytesPerHour: 5,
CurrencyUnit: "CNY",
},
},
})
defer cleanTestConfig(t)
if getFeeWithMeterName("meter_cluster_cpu_usage", "1") != "3.000" {
priceInfo := meteringclient.PriceInfo{
IngressNetworkTrafficPerMegabytesPerHour: 1,
EgressNetworkTrafficPerMegabytesPerHour: 2,
CpuPerCorePerHour: 3,
MemPerGigabytesPerHour: 4,
PvcPerGigabytesPerHour: 5,
CurrencyUnit: "CNY",
}
if getFeeWithMeterName("meter_cluster_cpu_usage", "1", priceInfo) != "3.000" {
t.Error("failed to get fee with meter_cluster_cpu_usage")
return
}
if getFeeWithMeterName("meter_cluster_memory_usage", "0") != "0.000" {
if getFeeWithMeterName("meter_cluster_memory_usage", "0", priceInfo) != "0.000" {
t.Error("failed to get fee with meter_cluster_memory_usage")
return
}
if getFeeWithMeterName("meter_cluster_net_bytes_transmitted", "0") != "0.000" {
if getFeeWithMeterName("meter_cluster_net_bytes_transmitted", "0", priceInfo) != "0.000" {
t.Error("failed to get fee with meter_cluster_net_bytes_transmitted")
return
}
if getFeeWithMeterName("meter_cluster_net_bytes_received", "0") != "0.000" {
if getFeeWithMeterName("meter_cluster_net_bytes_received", "0", priceInfo) != "0.000" {
t.Error("failed to get fee with meter_cluster_net_bytes_received")
return
}
if getFeeWithMeterName("meter_cluster_pvc_bytes_total", "0") != "0.000" {
if getFeeWithMeterName("meter_cluster_pvc_bytes_total", "0", priceInfo) != "0.000" {
t.Error("failed to get fee with meter_cluster_pvc_bytes_total")
return
}
}
func TestGetPriceInfo(t *testing.T) {
meterConfig := MeterConfig{
Billing: Billing{
PriceInfo: PriceInfo{
CpuPerCorePerHour: 1,
MemPerGigabytesPerHour: 1,
IngressNetworkTrafficPerMegabytesPerHour: 1,
EgressNetworkTrafficPerMegabytesPerHour: 1,
PvcPerGigabytesPerHour: 1,
CurrencyUnit: "USD",
},
},
}
if meterConfig.GetPriceInfo().CurrencyUnit != meterConfig.Billing.PriceInfo.CurrencyUnit ||
meterConfig.GetPriceInfo().CpuPerCorePerHour != meterConfig.Billing.PriceInfo.CpuPerCorePerHour ||
meterConfig.GetPriceInfo().MemPerGigabytesPerHour != meterConfig.Billing.PriceInfo.MemPerGigabytesPerHour ||
meterConfig.GetPriceInfo().IngressNetworkTrafficPerMegabytesPerHour != meterConfig.Billing.PriceInfo.IngressNetworkTrafficPerMegabytesPerHour ||
meterConfig.GetPriceInfo().EgressNetworkTrafficPerMegabytesPerHour != meterConfig.Billing.PriceInfo.EgressNetworkTrafficPerMegabytesPerHour ||
meterConfig.GetPriceInfo().PvcPerGigabytesPerHour != meterConfig.Billing.PriceInfo.PvcPerGigabytesPerHour {
t.Error("failed to get price info")
}
}
func TestUpdateMetricStatData(t *testing.T) {
saveTestConfig(t, &MeterConfig{
Billing: Billing{
PriceInfo: PriceInfo{
IngressNetworkTrafficPerMegabytesPerHour: 1,
EgressNetworkTrafficPerMegabytesPerHour: 2,
CpuPerCorePerHour: 3,
MemPerGigabytesPerHour: 4,
PvcPerGigabytesPerHour: 5,
CurrencyUnit: "CNY",
},
},
})
defer cleanTestConfig(t)
priceInfo := meteringclient.PriceInfo{
IngressNetworkTrafficPerMegabytesPerHour: 1,
EgressNetworkTrafficPerMegabytesPerHour: 2,
CpuPerCorePerHour: 3,
MemPerGigabytesPerHour: 4,
PvcPerGigabytesPerHour: 5,
CurrencyUnit: "CNY",
}
tests := []struct {
metric monitoring.Metric
@@ -497,7 +369,7 @@ func TestUpdateMetricStatData(t *testing.T) {
}
for _, test := range tests {
got := updateMetricStatData(test.metric, test.scalingMap)
got := updateMetricStatData(test.metric, test.scalingMap, priceInfo)
if diff := cmp.Diff(got, test.expected); diff != "" {
t.Errorf("%T differ (-got, +want): %s", test.expected, diff)
return

View File

@@ -28,6 +28,7 @@ import (
monitoringmodel "kubesphere.io/kubesphere/pkg/models/monitoring"
"kubesphere.io/kubesphere/pkg/models/openpitrix"
"kubesphere.io/kubesphere/pkg/server/params"
meteringclient "kubesphere.io/kubesphere/pkg/simple/client/metering"
"kubesphere.io/kubesphere/pkg/simple/client/monitoring"
)
@@ -538,7 +539,7 @@ func (t *tenantOperator) makeQueryOptions(user user.Info, q meteringv1alpha1.Que
return qo, nil
}
func (t *tenantOperator) ProcessNamedMetersQuery(q QueryOptions) (metrics monitoringmodel.Metrics, err error) {
func (t *tenantOperator) ProcessNamedMetersQuery(q QueryOptions, priceInfo meteringclient.PriceInfo) (metrics monitoringmodel.Metrics, err error) {
var meters []string
for _, meter := range q.NamedMetrics {
if !strings.HasPrefix(meter, monitoringmodel.MetricMeterPrefix) {
@@ -559,20 +560,20 @@ func (t *tenantOperator) ProcessNamedMetersQuery(q QueryOptions) (metrics monito
_, ok := q.Option.(monitoring.ApplicationsOption)
if ok {
metrics, err = t.processApplicationMetersQuery(meters, q)
metrics, err = t.processApplicationMetersQuery(meters, q, priceInfo)
return
}
_, ok = q.Option.(monitoring.ServicesOption)
if ok {
metrics, err = t.processServiceMetersQuery(meters, q)
metrics, err = t.processServiceMetersQuery(meters, q, priceInfo)
return
}
if q.isRangeQuery() {
metrics, err = t.mo.GetNamedMetersOverTime(meters, q.Start, q.End, q.Step, q.Option)
metrics, err = t.mo.GetNamedMetersOverTime(meters, q.Start, q.End, q.Step, q.Option, priceInfo)
} else {
metrics, err = t.mo.GetNamedMeters(meters, q.Time, q.Option)
metrics, err = t.mo.GetNamedMeters(meters, q.Time, q.Option, priceInfo)
if q.shouldSort() {
metrics = *metrics.Sort(q.Target, q.Order, q.Identifier).Page(q.Page, q.Limit)
}
@@ -591,7 +592,7 @@ func getMetricPosMap(metrics []monitoring.Metric) map[string]int {
return metricMap
}
func (t *tenantOperator) processApplicationMetersQuery(meters []string, q QueryOptions) (res monitoringmodel.Metrics, err error) {
func (t *tenantOperator) processApplicationMetersQuery(meters []string, q QueryOptions, priceInfo meteringclient.PriceInfo) (res monitoringmodel.Metrics, err error) {
var metricMap = make(map[string]int)
var current_res monitoringmodel.Metrics
@@ -612,9 +613,9 @@ func (t *tenantOperator) processApplicationMetersQuery(meters []string, q QueryO
}
if q.isRangeQuery() {
current_res, err = t.mo.GetNamedMetersOverTime(meters, q.Start, q.End, q.Step, opt)
current_res, err = t.mo.GetNamedMetersOverTime(meters, q.Start, q.End, q.Step, opt, priceInfo)
} else {
current_res, err = t.mo.GetNamedMeters(meters, q.Time, opt)
current_res, err = t.mo.GetNamedMeters(meters, q.Time, opt, priceInfo)
}
if res.Results == nil {
@@ -639,7 +640,7 @@ func (t *tenantOperator) processApplicationMetersQuery(meters []string, q QueryO
return
}
func (t *tenantOperator) processServiceMetersQuery(meters []string, q QueryOptions) (res monitoringmodel.Metrics, err error) {
func (t *tenantOperator) processServiceMetersQuery(meters []string, q QueryOptions, priceInfo meteringclient.PriceInfo) (res monitoringmodel.Metrics, err error) {
var metricMap = make(map[string]int)
var current_res monitoringmodel.Metrics
@@ -659,9 +660,9 @@ func (t *tenantOperator) processServiceMetersQuery(meters []string, q QueryOptio
}
if q.isRangeQuery() {
current_res, err = t.mo.GetNamedMetersOverTime(meters, q.Start, q.End, q.Step, opt)
current_res, err = t.mo.GetNamedMetersOverTime(meters, q.Start, q.End, q.Step, opt, priceInfo)
} else {
current_res, err = t.mo.GetNamedMeters(meters, q.Time, opt)
current_res, err = t.mo.GetNamedMeters(meters, q.Time, opt, priceInfo)
}
if res.Results == nil {

View File

@@ -5,6 +5,8 @@ import (
"testing"
"time"
"kubesphere.io/kubesphere/pkg/constants"
"github.com/google/go-cmp/cmp"
"kubesphere.io/kubesphere/pkg/models/metering"
@@ -191,3 +193,32 @@ func TestTransformMetricData(t *testing.T) {
}
}
func TestGetAppNameFromLabels(t *testing.T) {
var tOperator tenantOperator
tests := []struct {
labels map[string]string
expectedValue string
}{
{
labels: make(map[string]string),
expectedValue: "",
},
{
labels: map[string]string{
constants.ApplicationName: "app1",
constants.ApplicationVersion: "v2",
},
expectedValue: "app1:v2",
},
}
for i, tt := range tests {
t.Run(fmt.Sprintf("%d", i), func(t *testing.T) {
if diff := cmp.Diff(tOperator.getAppNameFromLabels(tt.labels), tt.expectedValue); diff != "" {
t.Errorf("%T differ (-got, +want): %s", tt.expectedValue, diff)
}
})
}
}

View File

@@ -63,6 +63,7 @@ import (
auditingclient "kubesphere.io/kubesphere/pkg/simple/client/auditing"
eventsclient "kubesphere.io/kubesphere/pkg/simple/client/events"
loggingclient "kubesphere.io/kubesphere/pkg/simple/client/logging"
meteringclient "kubesphere.io/kubesphere/pkg/simple/client/metering"
monitoringclient "kubesphere.io/kubesphere/pkg/simple/client/monitoring"
"kubesphere.io/kubesphere/pkg/utils/stringutils"
)
@@ -90,8 +91,8 @@ type Interface interface {
PatchNamespace(workspace string, namespace *corev1.Namespace) (*corev1.Namespace, error)
PatchWorkspace(workspace string, data json.RawMessage) (*tenantv1alpha2.WorkspaceTemplate, error)
ListClusters(info user.Info) (*api.ListResult, error)
Metering(user user.Info, queryParam *meteringv1alpha1.Query) (monitoring.Metrics, error)
MeteringHierarchy(user user.Info, queryParam *meteringv1alpha1.Query) (metering.ResourceStatistic, error)
Metering(user user.Info, queryParam *meteringv1alpha1.Query, priceInfo meteringclient.PriceInfo) (monitoring.Metrics, error)
MeteringHierarchy(user user.Info, queryParam *meteringv1alpha1.Query, priceInfo meteringclient.PriceInfo) (metering.ResourceStatistic, error)
CreateWorkspaceResourceQuota(workspace string, resourceQuota *quotav1alpha2.ResourceQuota) (*quotav1alpha2.ResourceQuota, error)
DeleteWorkspaceResourceQuota(workspace string, resourceQuotaName string) error
UpdateWorkspaceResourceQuota(workspace string, resourceQuota *quotav1alpha2.ResourceQuota) (*quotav1alpha2.ResourceQuota, error)
@@ -991,7 +992,7 @@ func (t *tenantOperator) Auditing(user user.Info, queryParam *auditingv1alpha1.Q
})
}
func (t *tenantOperator) Metering(user user.Info, query *meteringv1alpha1.Query) (metrics monitoring.Metrics, err error) {
func (t *tenantOperator) Metering(user user.Info, query *meteringv1alpha1.Query, priceInfo meteringclient.PriceInfo) (metrics monitoring.Metrics, err error) {
var opt QueryOptions
@@ -999,13 +1000,13 @@ func (t *tenantOperator) Metering(user user.Info, query *meteringv1alpha1.Query)
if err != nil {
return
}
metrics, err = t.ProcessNamedMetersQuery(opt)
metrics, err = t.ProcessNamedMetersQuery(opt, priceInfo)
return
}
func (t *tenantOperator) MeteringHierarchy(user user.Info, queryParam *meteringv1alpha1.Query) (metering.ResourceStatistic, error) {
res, err := t.Metering(user, queryParam)
func (t *tenantOperator) MeteringHierarchy(user user.Info, queryParam *meteringv1alpha1.Query, priceInfo meteringclient.PriceInfo) (metering.ResourceStatistic, error) {
res, err := t.Metering(user, queryParam, priceInfo)
if err != nil {
return metering.ResourceStatistic{}, err
}

View File

@@ -1,7 +1,41 @@
package metering
type PriceInfo struct {
// currency unit, currently support CNY and USD
CpuPerCorePerHour float64 `json:"cpuPerCorePerHour" yaml:"cpuPerCorePerHour"`
// cpu cost with above currency unit for per core per hour
MemPerGigabytesPerHour float64 `json:"memPerGigabytesPerHour" yaml:"memPerGigabytesPerHour"`
// mem cost with above currency unit for per GB per hour
IngressNetworkTrafficPerMegabytesPerHour float64 `json:"ingressNetworkTrafficPerMegabytesPerHour" yaml:"ingressNetworkTrafficPerGiagabytesPerHour"`
// ingress network traffic cost with above currency unit for per MB per hour
EgressNetworkTrafficPerMegabytesPerHour float64 `json:"egressNetworkTrafficPerMegabytesPerHour" yaml:"egressNetworkTrafficPerGigabytesPerHour"`
// egress network traffice cost with above currency unit for per MB per hour
PvcPerGigabytesPerHour float64 `json:"pvcPerGigabytesPerHour" yaml:"pvcPerGigabytesPerHour"`
// pvc cost with above currency unit for per GB per hour
CurrencyUnit string `json:"currencyUnit" yaml:"currencyUnit"`
}
type Billing struct {
PriceInfo PriceInfo `json:"priceInfo" yaml:"priceInfo"`
}
type Options struct {
Enable bool `json:"enable" yaml:"enable"`
RetentionDay string `json:"retentionDay" yaml:"retentionDay"`
Billing Billing `json:"billing" yaml:"billing"`
}
var DefaultMeteringOption = Options{
RetentionDay: "7d",
Billing: Billing{
PriceInfo: PriceInfo{
CpuPerCorePerHour: 0,
MemPerGigabytesPerHour: 0,
IngressNetworkTrafficPerMegabytesPerHour: 0,
EgressNetworkTrafficPerMegabytesPerHour: 0,
PvcPerGigabytesPerHour: 0,
CurrencyUnit: "",
},
},
}
func NewMeteringOptions() *Options {

View File

@@ -16,7 +16,9 @@ limitations under the License.
package monitoring
import "time"
import (
"time"
)
type Interface interface {
GetMetric(expr string, time time.Time) Metric

View File

@@ -131,7 +131,7 @@ func generateSwaggerJson() []byte {
urlruntime.Must(operationsv1alpha2.AddToContainer(container, clientsets.Kubernetes()))
urlruntime.Must(resourcesv1alpha2.AddToContainer(container, clientsets.Kubernetes(), informerFactory, ""))
urlruntime.Must(resourcesv1alpha3.AddToContainer(container, informerFactory, nil))
urlruntime.Must(tenantv1alpha2.AddToContainer(container, informerFactory, nil, nil, nil, nil, nil, nil, nil, nil, nil))
urlruntime.Must(tenantv1alpha2.AddToContainer(container, informerFactory, nil, nil, nil, nil, nil, nil, nil, nil, nil, nil))
urlruntime.Must(terminalv1alpha2.AddToContainer(container, clientsets.Kubernetes(), nil))
urlruntime.Must(metricsv1alpha2.AddToContainer(container))
urlruntime.Must(networkv1alpha2.AddToContainer(container, ""))