diff --git a/pkg/apiserver/apiserver.go b/pkg/apiserver/apiserver.go index 529af7cbd..c26670a63 100644 --- a/pkg/apiserver/apiserver.go +++ b/pkg/apiserver/apiserver.go @@ -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(), diff --git a/pkg/apiserver/config/config.go b/pkg/apiserver/config/config.go index d8e26ce2e..a4080d5ee 100644 --- a/pkg/apiserver/config/config.go +++ b/pkg/apiserver/config/config.go @@ -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 - } } diff --git a/pkg/apiserver/config/config_test.go b/pkg/apiserver/config/config_test.go index 5330e3b2c..d0834cf28 100644 --- a/pkg/apiserver/config/config_test.go +++ b/pkg/apiserver/config/config_test.go @@ -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 = ¬ification.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") + } } diff --git a/pkg/kapis/metering/v1alpha1/handler.go b/pkg/kapis/metering/v1alpha1/handler.go index 544029e3f..8b24ff97d 100644 --- a/pkg/kapis/metering/v1alpha1/handler.go +++ b/pkg/kapis/metering/v1alpha1/handler.go @@ -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) } diff --git a/pkg/kapis/metering/v1alpha1/register.go b/pkg/kapis/metering/v1alpha1/register.go index 9b0433964..745f1d87e 100644 --- a/pkg/kapis/metering/v1alpha1/register.go +++ b/pkg/kapis/metering/v1alpha1/register.go @@ -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). diff --git a/pkg/kapis/monitoring/v1alpha3/handler.go b/pkg/kapis/monitoring/v1alpha3/handler.go index d8300a282..dc8bf30f1 100644 --- a/pkg/kapis/monitoring/v1alpha3/handler.go +++ b/pkg/kapis/monitoring/v1alpha3/handler.go @@ -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, } } diff --git a/pkg/kapis/monitoring/v1alpha3/helper_test.go b/pkg/kapis/monitoring/v1alpha3/helper_test.go index 9199b49bc..3d2ed7c4c 100644 --- a/pkg/kapis/monitoring/v1alpha3/helper_test.go +++ b/pkg/kapis/monitoring/v1alpha3/helper_test.go @@ -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") + } +} diff --git a/pkg/kapis/monitoring/v1alpha3/meter.go b/pkg/kapis/monitoring/v1alpha3/meter.go index 7f390a79a..8895ab628 100644 --- a/pkg/kapis/monitoring/v1alpha3/meter.go +++ b/pkg/kapis/monitoring/v1alpha3/meter.go @@ -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) diff --git a/pkg/kapis/monitoring/v1alpha3/register.go b/pkg/kapis/monitoring/v1alpha3/register.go index 73f5514f8..fca39f2e2 100644 --- a/pkg/kapis/monitoring/v1alpha3/register.go +++ b/pkg/kapis/monitoring/v1alpha3/register.go @@ -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). diff --git a/pkg/kapis/tenant/v1alpha2/handler.go b/pkg/kapis/tenant/v1alpha2/handler.go index 8c5b99774..9c132ebfb 100644 --- a/pkg/kapis/tenant/v1alpha2/handler.go +++ b/pkg/kapis/tenant/v1alpha2/handler.go @@ -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, } } diff --git a/pkg/kapis/tenant/v1alpha2/metering.go b/pkg/kapis/tenant/v1alpha2/metering.go index bca0b1b59..d507ac469 100644 --- a/pkg/kapis/tenant/v1alpha2/metering.go +++ b/pkg/kapis/tenant/v1alpha2/metering.go @@ -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 diff --git a/pkg/kapis/tenant/v1alpha2/register.go b/pkg/kapis/tenant/v1alpha2/register.go index 755dd5849..82697cae3 100644 --- a/pkg/kapis/tenant/v1alpha2/register.go +++ b/pkg/kapis/tenant/v1alpha2/register.go @@ -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). diff --git a/pkg/models/metering/type.go b/pkg/models/metering/type.go index 511274056..4c784af98 100644 --- a/pkg/models/metering/type.go +++ b/pkg/models/metering/type.go @@ -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"` diff --git a/pkg/models/monitoring/monitoring.go b/pkg/models/monitoring/monitoring.go index bd90b316f..9ea32b13c 100644 --- a/pkg/models/monitoring/monitoring.go +++ b/pkg/models/monitoring/monitoring.go @@ -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 diff --git a/pkg/models/monitoring/utils.go b/pkg/models/monitoring/utils.go index 450e600a8..5b369b0bd 100644 --- a/pkg/models/monitoring/utils.go +++ b/pkg/models/monitoring/utils.go @@ -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) } diff --git a/pkg/models/monitoring/utils_test.go b/pkg/models/monitoring/utils_test.go index ad794ee6a..52dcd9708 100644 --- a/pkg/models/monitoring/utils_test.go +++ b/pkg/models/monitoring/utils_test.go @@ -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 diff --git a/pkg/models/tenant/metering.go b/pkg/models/tenant/metering.go index 8f4aa1886..25f2ab4dd 100644 --- a/pkg/models/tenant/metering.go +++ b/pkg/models/tenant/metering.go @@ -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 { diff --git a/pkg/models/tenant/metering_test.go b/pkg/models/tenant/metering_test.go index 434377705..89252395d 100644 --- a/pkg/models/tenant/metering_test.go +++ b/pkg/models/tenant/metering_test.go @@ -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) + } + }) + } +} diff --git a/pkg/models/tenant/tenant.go b/pkg/models/tenant/tenant.go index f4e1a502a..1b4b6c19a 100644 --- a/pkg/models/tenant/tenant.go +++ b/pkg/models/tenant/tenant.go @@ -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 } diff --git a/pkg/simple/client/metering/options.go b/pkg/simple/client/metering/options.go index d95d9f619..323c3d438 100644 --- a/pkg/simple/client/metering/options.go +++ b/pkg/simple/client/metering/options.go @@ -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 { diff --git a/pkg/simple/client/monitoring/interface.go b/pkg/simple/client/monitoring/interface.go index 1e82eb221..687761bd3 100644 --- a/pkg/simple/client/monitoring/interface.go +++ b/pkg/simple/client/monitoring/interface.go @@ -16,7 +16,9 @@ limitations under the License. package monitoring -import "time" +import ( + "time" +) type Interface interface { GetMetric(expr string, time time.Time) Metric diff --git a/tools/cmd/doc-gen/main.go b/tools/cmd/doc-gen/main.go index 3d4f2234c..40c7ae70b 100644 --- a/tools/cmd/doc-gen/main.go +++ b/tools/cmd/doc-gen/main.go @@ -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, ""))