mirror of
https://github.com/kubernetes-sigs/prometheus-adapter.git
synced 2026-04-06 09:47:54 +00:00
Continuing version updates.
This commit is contained in:
parent
cdd2e9be39
commit
f49892b097
4 changed files with 52 additions and 51 deletions
27
Gopkg.lock
generated
27
Gopkg.lock
generated
|
|
@ -66,6 +66,17 @@
|
||||||
revision = "346938d642f2ec3594ed81d874461961cd0faa76"
|
revision = "346938d642f2ec3594ed81d874461961cd0faa76"
|
||||||
version = "v1.1.0"
|
version = "v1.1.0"
|
||||||
|
|
||||||
|
[[projects]]
|
||||||
|
name = "github.com/directxman12/k8s-prometheus-adapter"
|
||||||
|
packages = [
|
||||||
|
"cmd/adapter/app",
|
||||||
|
"pkg/client",
|
||||||
|
"pkg/client/metrics",
|
||||||
|
"pkg/custom-provider"
|
||||||
|
]
|
||||||
|
revision = "8dd527d821f46b9e3961f3f7e5fdf5131d95681c"
|
||||||
|
version = "v0.2.0"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
name = "github.com/elazarl/go-bindata-assetfs"
|
name = "github.com/elazarl/go-bindata-assetfs"
|
||||||
packages = ["."]
|
packages = ["."]
|
||||||
|
|
@ -226,9 +237,10 @@
|
||||||
"pkg/cmd/server",
|
"pkg/cmd/server",
|
||||||
"pkg/dynamicmapper",
|
"pkg/dynamicmapper",
|
||||||
"pkg/provider",
|
"pkg/provider",
|
||||||
"pkg/registry/custom_metrics"
|
"pkg/registry/custom_metrics",
|
||||||
|
"pkg/registry/external_metrics"
|
||||||
]
|
]
|
||||||
revision = "fae01650d93f5de6151a024e36323344e14427aa"
|
revision = "e61f72fec56ab519d74ebd396cd3fcf31b084558"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
name = "github.com/mailru/easyjson"
|
name = "github.com/mailru/easyjson"
|
||||||
|
|
@ -712,18 +724,21 @@
|
||||||
revision = "868f2f29720b192240e18284659231b440f9cda5"
|
revision = "868f2f29720b192240e18284659231b440f9cda5"
|
||||||
|
|
||||||
[[projects]]
|
[[projects]]
|
||||||
|
branch = "master"
|
||||||
name = "k8s.io/metrics"
|
name = "k8s.io/metrics"
|
||||||
packages = [
|
packages = [
|
||||||
"pkg/apis/custom_metrics",
|
"pkg/apis/custom_metrics",
|
||||||
"pkg/apis/custom_metrics/install",
|
"pkg/apis/custom_metrics/install",
|
||||||
"pkg/apis/custom_metrics/v1beta1"
|
"pkg/apis/custom_metrics/v1beta1",
|
||||||
|
"pkg/apis/external_metrics",
|
||||||
|
"pkg/apis/external_metrics/install",
|
||||||
|
"pkg/apis/external_metrics/v1beta1"
|
||||||
]
|
]
|
||||||
revision = "4c7ac522b9daf7beeb53f6766722ba78b7e5712d"
|
revision = "baa04983db4e01d02a16d9c9fe32dd5b478b3248"
|
||||||
version = "kubernetes-1.9.0-alpha.1"
|
|
||||||
|
|
||||||
[solve-meta]
|
[solve-meta]
|
||||||
analyzer-name = "dep"
|
analyzer-name = "dep"
|
||||||
analyzer-version = 1
|
analyzer-version = 1
|
||||||
inputs-digest = "ee877002d2906b3baa3f7fb1a786646ecb3a6da62559ea479288058c11de2780"
|
inputs-digest = "ffa0ef091b3683f02efac4dc0a1a071ab5a0ff9741346b1532be064fb6c176c4"
|
||||||
solver-name = "gps-cdcl"
|
solver-name = "gps-cdcl"
|
||||||
solver-version = 1
|
solver-version = 1
|
||||||
|
|
|
||||||
25
Gopkg.toml
25
Gopkg.toml
|
|
@ -24,27 +24,10 @@
|
||||||
# go-tests = true
|
# go-tests = true
|
||||||
# unused-packages = true
|
# unused-packages = true
|
||||||
|
|
||||||
|
|
||||||
[[constraint]]
|
|
||||||
name = "github.com/stretchr/testify"
|
|
||||||
version = "1.1.4"
|
|
||||||
|
|
||||||
[[constraint]]
|
|
||||||
name = "k8s.io/apimachinery"
|
|
||||||
version = "kubernetes-1.9.0-alpha.1"
|
|
||||||
|
|
||||||
[[constraint]]
|
|
||||||
name = "k8s.io/apiserver"
|
|
||||||
version = "kubernetes-1.9.0-alpha.1"
|
|
||||||
|
|
||||||
[[constraint]]
|
|
||||||
name = "k8s.io/client-go"
|
|
||||||
version = "kubernetes-1.9.0-alpha.1"
|
|
||||||
|
|
||||||
[[constraint]]
|
|
||||||
name = "k8s.io/metrics"
|
|
||||||
version = "kubernetes-1.9.0-alpha.1"
|
|
||||||
|
|
||||||
[prune]
|
[prune]
|
||||||
go-tests = true
|
go-tests = true
|
||||||
unused-packages = true
|
unused-packages = true
|
||||||
|
|
||||||
|
[[constraint]]
|
||||||
|
name = "github.com/kubernetes-incubator/custom-metrics-apiserver"
|
||||||
|
revision = "e61f72fec56ab519d74ebd396cd3fcf31b084558"
|
||||||
|
|
|
||||||
|
|
@ -51,12 +51,12 @@ type SeriesRegistry interface {
|
||||||
// SetSeries replaces the known series in this registry
|
// SetSeries replaces the known series in this registry
|
||||||
SetSeries(series []prom.Series) error
|
SetSeries(series []prom.Series) error
|
||||||
// ListAllMetrics lists all metrics known to this registry
|
// ListAllMetrics lists all metrics known to this registry
|
||||||
ListAllMetrics() []provider.MetricInfo
|
ListAllMetrics() []provider.CustomMetricInfo
|
||||||
// SeriesForMetric looks up the minimum required series information to make a query for the given metric
|
// SeriesForMetric looks up the minimum required series information to make a query for the given metric
|
||||||
// against the given resource (namespace may be empty for non-namespaced resources)
|
// against the given resource (namespace may be empty for non-namespaced resources)
|
||||||
QueryForMetric(info provider.MetricInfo, namespace string, resourceNames ...string) (kind SeriesType, query prom.Selector, groupBy string, found bool)
|
QueryForMetric(info provider.CustomMetricInfo, namespace string, resourceNames ...string) (kind SeriesType, query prom.Selector, groupBy string, found bool)
|
||||||
// MatchValuesToNames matches result values to resource names for the given metric and value set
|
// MatchValuesToNames matches result values to resource names for the given metric and value set
|
||||||
MatchValuesToNames(metricInfo provider.MetricInfo, values pmodel.Vector) (matchedValues map[string]pmodel.SampleValue, found bool)
|
MatchValuesToNames(metricInfo provider.CustomMetricInfo, values pmodel.Vector) (matchedValues map[string]pmodel.SampleValue, found bool)
|
||||||
}
|
}
|
||||||
|
|
||||||
type seriesInfo struct {
|
type seriesInfo struct {
|
||||||
|
|
@ -73,9 +73,9 @@ type basicSeriesRegistry struct {
|
||||||
mu sync.RWMutex
|
mu sync.RWMutex
|
||||||
|
|
||||||
// info maps metric info to information about the corresponding series
|
// info maps metric info to information about the corresponding series
|
||||||
info map[provider.MetricInfo]seriesInfo
|
info map[provider.CustomMetricInfo]seriesInfo
|
||||||
// metrics is the list of all known metrics
|
// metrics is the list of all known metrics
|
||||||
metrics []provider.MetricInfo
|
metrics []provider.CustomMetricInfo
|
||||||
|
|
||||||
// namer is the metricNamer responsible for converting series to metric names and information
|
// namer is the metricNamer responsible for converting series to metric names and information
|
||||||
namer metricNamer
|
namer metricNamer
|
||||||
|
|
@ -91,7 +91,7 @@ func (r *basicSeriesRegistry) Selectors() []prom.Selector {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *basicSeriesRegistry) SetSeries(newSeries []prom.Series) error {
|
func (r *basicSeriesRegistry) SetSeries(newSeries []prom.Series) error {
|
||||||
newInfo := make(map[provider.MetricInfo]seriesInfo)
|
newInfo := make(map[provider.CustomMetricInfo]seriesInfo)
|
||||||
for _, series := range newSeries {
|
for _, series := range newSeries {
|
||||||
if strings.HasPrefix(series.Name, "container_") {
|
if strings.HasPrefix(series.Name, "container_") {
|
||||||
r.namer.processContainerSeries(series, newInfo)
|
r.namer.processContainerSeries(series, newInfo)
|
||||||
|
|
@ -109,7 +109,7 @@ func (r *basicSeriesRegistry) SetSeries(newSeries []prom.Series) error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
newMetrics := make([]provider.MetricInfo, 0, len(newInfo))
|
newMetrics := make([]provider.CustomMetricInfo, 0, len(newInfo))
|
||||||
for info := range newInfo {
|
for info := range newInfo {
|
||||||
newMetrics = append(newMetrics, info)
|
newMetrics = append(newMetrics, info)
|
||||||
}
|
}
|
||||||
|
|
@ -123,14 +123,14 @@ func (r *basicSeriesRegistry) SetSeries(newSeries []prom.Series) error {
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *basicSeriesRegistry) ListAllMetrics() []provider.MetricInfo {
|
func (r *basicSeriesRegistry) ListAllMetrics() []provider.CustomMetricInfo {
|
||||||
r.mu.RLock()
|
r.mu.RLock()
|
||||||
defer r.mu.RUnlock()
|
defer r.mu.RUnlock()
|
||||||
|
|
||||||
return r.metrics
|
return r.metrics
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *basicSeriesRegistry) QueryForMetric(metricInfo provider.MetricInfo, namespace string, resourceNames ...string) (kind SeriesType, query prom.Selector, groupBy string, found bool) {
|
func (r *basicSeriesRegistry) QueryForMetric(metricInfo provider.CustomMetricInfo, namespace string, resourceNames ...string) (kind SeriesType, query prom.Selector, groupBy string, found bool) {
|
||||||
r.mu.RLock()
|
r.mu.RLock()
|
||||||
defer r.mu.RUnlock()
|
defer r.mu.RUnlock()
|
||||||
|
|
||||||
|
|
@ -180,7 +180,7 @@ func (r *basicSeriesRegistry) QueryForMetric(metricInfo provider.MetricInfo, nam
|
||||||
return 0, "", "", false
|
return 0, "", "", false
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *basicSeriesRegistry) MatchValuesToNames(metricInfo provider.MetricInfo, values pmodel.Vector) (matchedValues map[string]pmodel.SampleValue, found bool) {
|
func (r *basicSeriesRegistry) MatchValuesToNames(metricInfo provider.CustomMetricInfo, values pmodel.Vector) (matchedValues map[string]pmodel.SampleValue, found bool) {
|
||||||
r.mu.RLock()
|
r.mu.RLock()
|
||||||
defer r.mu.RUnlock()
|
defer r.mu.RUnlock()
|
||||||
|
|
||||||
|
|
@ -234,7 +234,7 @@ type seriesSpec struct {
|
||||||
|
|
||||||
// processContainerSeries performs special work to extract metric definitions
|
// processContainerSeries performs special work to extract metric definitions
|
||||||
// from cAdvisor-sourced container metrics, which don't particularly follow any useful conventions consistently.
|
// from cAdvisor-sourced container metrics, which don't particularly follow any useful conventions consistently.
|
||||||
func (n *metricNamer) processContainerSeries(series prom.Series, infos map[provider.MetricInfo]seriesInfo) {
|
func (n *metricNamer) processContainerSeries(series prom.Series, infos map[provider.CustomMetricInfo]seriesInfo) {
|
||||||
|
|
||||||
originalName := series.Name
|
originalName := series.Name
|
||||||
|
|
||||||
|
|
@ -249,7 +249,7 @@ func (n *metricNamer) processContainerSeries(series prom.Series, infos map[provi
|
||||||
name, metricKind = n.metricNameFromSeries(series)
|
name, metricKind = n.metricNameFromSeries(series)
|
||||||
}
|
}
|
||||||
|
|
||||||
info := provider.MetricInfo{
|
info := provider.CustomMetricInfo{
|
||||||
GroupResource: schema.GroupResource{Resource: "pods"},
|
GroupResource: schema.GroupResource{Resource: "pods"},
|
||||||
Namespaced: true,
|
Namespaced: true,
|
||||||
Metric: name,
|
Metric: name,
|
||||||
|
|
@ -264,7 +264,7 @@ func (n *metricNamer) processContainerSeries(series prom.Series, infos map[provi
|
||||||
|
|
||||||
// processNamespacedSeries adds the metric info for the given generic namespaced series to
|
// processNamespacedSeries adds the metric info for the given generic namespaced series to
|
||||||
// the map of metric info.
|
// the map of metric info.
|
||||||
func (n *metricNamer) processNamespacedSeries(series prom.Series, infos map[provider.MetricInfo]seriesInfo) error {
|
func (n *metricNamer) processNamespacedSeries(series prom.Series, infos map[provider.CustomMetricInfo]seriesInfo) error {
|
||||||
// NB: all errors must occur *before* we save the series info
|
// NB: all errors must occur *before* we save the series info
|
||||||
name, metricKind := n.metricNameFromSeries(series)
|
name, metricKind := n.metricNameFromSeries(series)
|
||||||
resources, err := n.groupResourcesFromSeries(series)
|
resources, err := n.groupResourcesFromSeries(series)
|
||||||
|
|
@ -274,7 +274,7 @@ func (n *metricNamer) processNamespacedSeries(series prom.Series, infos map[prov
|
||||||
|
|
||||||
// we add one metric for each resource that this could describe
|
// we add one metric for each resource that this could describe
|
||||||
for _, resource := range resources {
|
for _, resource := range resources {
|
||||||
info := provider.MetricInfo{
|
info := provider.CustomMetricInfo{
|
||||||
GroupResource: resource,
|
GroupResource: resource,
|
||||||
Namespaced: true,
|
Namespaced: true,
|
||||||
Metric: name,
|
Metric: name,
|
||||||
|
|
@ -296,7 +296,7 @@ func (n *metricNamer) processNamespacedSeries(series prom.Series, infos map[prov
|
||||||
|
|
||||||
// processesRootScopedSeries adds the metric info for the given generic namespaced series to
|
// processesRootScopedSeries adds the metric info for the given generic namespaced series to
|
||||||
// the map of metric info.
|
// the map of metric info.
|
||||||
func (n *metricNamer) processRootScopedSeries(series prom.Series, infos map[provider.MetricInfo]seriesInfo) error {
|
func (n *metricNamer) processRootScopedSeries(series prom.Series, infos map[provider.CustomMetricInfo]seriesInfo) error {
|
||||||
// NB: all errors must occur *before* we save the series info
|
// NB: all errors must occur *before* we save the series info
|
||||||
name, metricKind := n.metricNameFromSeries(series)
|
name, metricKind := n.metricNameFromSeries(series)
|
||||||
resources, err := n.groupResourcesFromSeries(series)
|
resources, err := n.groupResourcesFromSeries(series)
|
||||||
|
|
@ -306,7 +306,7 @@ func (n *metricNamer) processRootScopedSeries(series prom.Series, infos map[prov
|
||||||
|
|
||||||
// we add one metric for each resource that this could describe
|
// we add one metric for each resource that this could describe
|
||||||
for _, resource := range resources {
|
for _, resource := range resources {
|
||||||
info := provider.MetricInfo{
|
info := provider.CustomMetricInfo{
|
||||||
GroupResource: resource,
|
GroupResource: resource,
|
||||||
Namespaced: false,
|
Namespaced: false,
|
||||||
Metric: name,
|
Metric: name,
|
||||||
|
|
|
||||||
|
|
@ -51,6 +51,9 @@ type prometheusProvider struct {
|
||||||
rateInterval time.Duration
|
rateInterval time.Duration
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type DoubleMetricProvider interface {
|
||||||
|
}
|
||||||
|
|
||||||
func NewPrometheusProvider(mapper apimeta.RESTMapper, kubeClient dynamic.ClientPool, promClient prom.Client, labelPrefix string, updateInterval time.Duration, rateInterval time.Duration, stopChan <-chan struct{}) provider.CustomMetricsProvider {
|
func NewPrometheusProvider(mapper apimeta.RESTMapper, kubeClient dynamic.ClientPool, promClient prom.Client, labelPrefix string, updateInterval time.Duration, rateInterval time.Duration, stopChan <-chan struct{}) provider.CustomMetricsProvider {
|
||||||
lister := &cachingMetricsLister{
|
lister := &cachingMetricsLister{
|
||||||
updateInterval: updateInterval,
|
updateInterval: updateInterval,
|
||||||
|
|
@ -98,7 +101,7 @@ func (p *prometheusProvider) metricFor(value pmodel.SampleValue, groupResource s
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *prometheusProvider) metricsFor(valueSet pmodel.Vector, info provider.MetricInfo, list runtime.Object) (*custom_metrics.MetricValueList, error) {
|
func (p *prometheusProvider) metricsFor(valueSet pmodel.Vector, info provider.CustomMetricInfo, list runtime.Object) (*custom_metrics.MetricValueList, error) {
|
||||||
if !apimeta.IsListType(list) {
|
if !apimeta.IsListType(list) {
|
||||||
return nil, apierr.NewInternalError(fmt.Errorf("result of label selector list operation was not a list"))
|
return nil, apierr.NewInternalError(fmt.Errorf("result of label selector list operation was not a list"))
|
||||||
}
|
}
|
||||||
|
|
@ -132,7 +135,7 @@ func (p *prometheusProvider) metricsFor(valueSet pmodel.Vector, info provider.Me
|
||||||
}, nil
|
}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *prometheusProvider) buildQuery(info provider.MetricInfo, namespace string, names ...string) (pmodel.Vector, error) {
|
func (p *prometheusProvider) buildQuery(info provider.CustomMetricInfo, namespace string, names ...string) (pmodel.Vector, error) {
|
||||||
kind, baseQuery, groupBy, found := p.QueryForMetric(info, namespace, names...)
|
kind, baseQuery, groupBy, found := p.QueryForMetric(info, namespace, names...)
|
||||||
if !found {
|
if !found {
|
||||||
return nil, provider.NewMetricNotFoundError(info.GroupResource, info.Metric)
|
return nil, provider.NewMetricNotFoundError(info.GroupResource, info.Metric)
|
||||||
|
|
@ -170,7 +173,7 @@ func (p *prometheusProvider) buildQuery(info provider.MetricInfo, namespace stri
|
||||||
return *queryResults.Vector, nil
|
return *queryResults.Vector, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *prometheusProvider) getSingle(info provider.MetricInfo, namespace, name string) (*custom_metrics.MetricValue, error) {
|
func (p *prometheusProvider) getSingle(info provider.CustomMetricInfo, namespace, name string) (*custom_metrics.MetricValue, error) {
|
||||||
queryResults, err := p.buildQuery(info, namespace, name)
|
queryResults, err := p.buildQuery(info, namespace, name)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
|
|
@ -198,7 +201,7 @@ func (p *prometheusProvider) getSingle(info provider.MetricInfo, namespace, name
|
||||||
return p.metricFor(resultValue, info.GroupResource, "", name, info.Metric)
|
return p.metricFor(resultValue, info.GroupResource, "", name, info.Metric)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *prometheusProvider) getMultiple(info provider.MetricInfo, namespace string, selector labels.Selector) (*custom_metrics.MetricValueList, error) {
|
func (p *prometheusProvider) getMultiple(info provider.CustomMetricInfo, namespace string, selector labels.Selector) (*custom_metrics.MetricValueList, error) {
|
||||||
// construct a client to list the names of objects matching the label selector
|
// construct a client to list the names of objects matching the label selector
|
||||||
client, err := p.kubeClient.ClientForGroupVersionResource(info.GroupResource.WithVersion(""))
|
client, err := p.kubeClient.ClientForGroupVersionResource(info.GroupResource.WithVersion(""))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
|
|
@ -244,7 +247,7 @@ func (p *prometheusProvider) getMultiple(info provider.MetricInfo, namespace str
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *prometheusProvider) GetRootScopedMetricByName(groupResource schema.GroupResource, name string, metricName string) (*custom_metrics.MetricValue, error) {
|
func (p *prometheusProvider) GetRootScopedMetricByName(groupResource schema.GroupResource, name string, metricName string) (*custom_metrics.MetricValue, error) {
|
||||||
info := provider.MetricInfo{
|
info := provider.CustomMetricInfo{
|
||||||
GroupResource: groupResource,
|
GroupResource: groupResource,
|
||||||
Metric: metricName,
|
Metric: metricName,
|
||||||
Namespaced: false,
|
Namespaced: false,
|
||||||
|
|
@ -254,7 +257,7 @@ func (p *prometheusProvider) GetRootScopedMetricByName(groupResource schema.Grou
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *prometheusProvider) GetRootScopedMetricBySelector(groupResource schema.GroupResource, selector labels.Selector, metricName string) (*custom_metrics.MetricValueList, error) {
|
func (p *prometheusProvider) GetRootScopedMetricBySelector(groupResource schema.GroupResource, selector labels.Selector, metricName string) (*custom_metrics.MetricValueList, error) {
|
||||||
info := provider.MetricInfo{
|
info := provider.CustomMetricInfo{
|
||||||
GroupResource: groupResource,
|
GroupResource: groupResource,
|
||||||
Metric: metricName,
|
Metric: metricName,
|
||||||
Namespaced: false,
|
Namespaced: false,
|
||||||
|
|
@ -263,7 +266,7 @@ func (p *prometheusProvider) GetRootScopedMetricBySelector(groupResource schema.
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *prometheusProvider) GetNamespacedMetricByName(groupResource schema.GroupResource, namespace string, name string, metricName string) (*custom_metrics.MetricValue, error) {
|
func (p *prometheusProvider) GetNamespacedMetricByName(groupResource schema.GroupResource, namespace string, name string, metricName string) (*custom_metrics.MetricValue, error) {
|
||||||
info := provider.MetricInfo{
|
info := provider.CustomMetricInfo{
|
||||||
GroupResource: groupResource,
|
GroupResource: groupResource,
|
||||||
Metric: metricName,
|
Metric: metricName,
|
||||||
Namespaced: true,
|
Namespaced: true,
|
||||||
|
|
@ -273,7 +276,7 @@ func (p *prometheusProvider) GetNamespacedMetricByName(groupResource schema.Grou
|
||||||
}
|
}
|
||||||
|
|
||||||
func (p *prometheusProvider) GetNamespacedMetricBySelector(groupResource schema.GroupResource, namespace string, selector labels.Selector, metricName string) (*custom_metrics.MetricValueList, error) {
|
func (p *prometheusProvider) GetNamespacedMetricBySelector(groupResource schema.GroupResource, namespace string, selector labels.Selector, metricName string) (*custom_metrics.MetricValueList, error) {
|
||||||
info := provider.MetricInfo{
|
info := provider.CustomMetricInfo{
|
||||||
GroupResource: groupResource,
|
GroupResource: groupResource,
|
||||||
Metric: metricName,
|
Metric: metricName,
|
||||||
Namespaced: true,
|
Namespaced: true,
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue