blob: 5acd9f718d4b81303666037f751ad544a34795c4 [file] [log] [blame]
/*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You under the Apache License, Version 2.0
* (the "License"); you may not use this file except in compliance with
* the License. You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package xds
import (
"strconv"
)
import (
"google.golang.org/protobuf/types/known/structpb"
)
import (
mesh_proto "github.com/apache/dubbo-kubernetes/api/mesh/v1alpha1"
"github.com/apache/dubbo-kubernetes/pkg/core"
core_mesh "github.com/apache/dubbo-kubernetes/pkg/core/resources/apis/mesh"
"github.com/apache/dubbo-kubernetes/pkg/core/resources/model"
"github.com/apache/dubbo-kubernetes/pkg/core/resources/model/rest"
)
var metadataLog = core.Log.WithName("xds-server").WithName("metadata-tracker")
const (
// Supported Envoy node metadata fields.
FieldDataplaneAdminPort = "dataplane.admin.port"
FieldDataplaneAdminAddress = "dataplane.admin.address"
FieldDataplaneDNSPort = "dataplane.dns.port"
FieldDataplaneDNSEmptyPort = "dataplane.dns.empty.port"
FieldDataplaneDataplaneResource = "dataplane.resource"
FieldDynamicMetadata = "dynamicMetadata"
FieldDataplaneProxyType = "dataplane.proxyType"
FieldPrefixDependenciesVersion = "version.dependencies"
FieldVersion = "version"
FieldFeatures = "features"
FieldWorkdir = "workdir"
FieldAccessLogSocketPath = "accessLogSocketPath"
FieldMetricsSocketPath = "metricsSocketPath"
FieldMetricsCertPath = "metricsCertPath"
FieldMetricsKeyPath = "metricsKeyPath"
)
// DataplaneMetadata represents environment-specific part of a dataplane configuration.
//
// This information might change from one dataplane run to another,
// and therefore it cannot be a part of Dataplane resource.
//
// On start-up, a dataplane captures its effective configuration (that might come
// from a file, environment variables and command line options) and includes it
// into request for a bootstrap config.
// Control Plane can use this information to fill in node metadata in the bootstrap
// config.
// Envoy will include node metadata from the bootstrap config
// at least into the very first discovery request on every xDS stream.
// This way, xDS server will be able to use Envoy node metadata
// to generate xDS resources that depend on environment-specific configuration.
type DataplaneMetadata struct {
Resource model.Resource
AdminPort uint32
AdminAddress string
DNSPort uint32
EmptyDNSPort uint32
DynamicMetadata map[string]string
ProxyType mesh_proto.ProxyType
Features Features
WorkDir string
AccessLogSocketPath string
MetricsSocketPath string
MetricsCertPath string
MetricsKeyPath string
}
// GetDataplaneResource returns the underlying DataplaneResource, if present.
// If the resource is of a different type, it returns nil.
func (m *DataplaneMetadata) GetDataplaneResource() *core_mesh.DataplaneResource {
if m != nil {
if d, ok := m.Resource.(*core_mesh.DataplaneResource); ok {
return d
}
}
return nil
}
// GetZoneIngressResource returns the underlying ZoneIngressResource, if present.
// If the resource is of a different type, it returns nil.
func (m *DataplaneMetadata) GetZoneIngressResource() *core_mesh.ZoneIngressResource {
if m != nil {
if z, ok := m.Resource.(*core_mesh.ZoneIngressResource); ok {
return z
}
}
return nil
}
func (m *DataplaneMetadata) GetProxyType() mesh_proto.ProxyType {
if m == nil || m.ProxyType == "" {
return mesh_proto.DataplaneProxyType
}
return m.ProxyType
}
func (m *DataplaneMetadata) GetAdminPort() uint32 {
if m == nil {
return 0
}
return m.AdminPort
}
func (m *DataplaneMetadata) GetAdminAddress() string {
if m == nil {
return ""
}
return m.AdminAddress
}
func (m *DataplaneMetadata) GetDNSPort() uint32 {
if m == nil {
return 0
}
return m.DNSPort
}
func (m *DataplaneMetadata) GetEmptyDNSPort() uint32 {
if m == nil {
return 0
}
return m.EmptyDNSPort
}
func (m *DataplaneMetadata) GetDynamicMetadata(key string) string {
if m == nil || m.DynamicMetadata == nil {
return ""
}
return m.DynamicMetadata[key]
}
func DataplaneMetadataFromXdsMetadata(xdsMetadata *structpb.Struct, tmpDir string, dpKey model.ResourceKey) *DataplaneMetadata {
// Be extra careful here about nil checks since xdsMetadata is a "user" input.
// Even if we know that something should not be nil since we are generating metadata,
// the DiscoveryRequest can still be crafted manually to crash the CP.
metadata := DataplaneMetadata{}
if xdsMetadata == nil {
return &metadata
}
if field := xdsMetadata.Fields[FieldDataplaneProxyType]; field != nil {
metadata.ProxyType = mesh_proto.ProxyType(field.GetStringValue())
}
metadata.AdminPort = uint32Metadata(xdsMetadata, FieldDataplaneAdminPort)
metadata.AdminAddress = xdsMetadata.Fields[FieldDataplaneAdminAddress].GetStringValue()
metadata.DNSPort = uint32Metadata(xdsMetadata, FieldDataplaneDNSPort)
metadata.EmptyDNSPort = uint32Metadata(xdsMetadata, FieldDataplaneDNSEmptyPort)
if value := xdsMetadata.Fields[FieldDataplaneDataplaneResource]; value != nil {
res, err := rest.YAML.UnmarshalCore([]byte(value.GetStringValue()))
if err != nil {
metadataLog.Error(err, "invalid value in dataplane metadata", "field", FieldDataplaneDataplaneResource, "value", value)
} else {
switch r := res.(type) {
case *core_mesh.DataplaneResource,
*core_mesh.ZoneIngressResource:
metadata.Resource = r
default:
metadataLog.Error(err, "invalid dataplane resource type",
"resource", r.Descriptor().Name,
"field", FieldDataplaneDataplaneResource,
"value", value)
}
}
}
if xdsMetadata.Fields[FieldAccessLogSocketPath] != nil {
metadata.AccessLogSocketPath = xdsMetadata.Fields[FieldAccessLogSocketPath].GetStringValue()
metadata.MetricsSocketPath = xdsMetadata.Fields[FieldMetricsSocketPath].GetStringValue()
}
metadata.WorkDir = xdsMetadata.Fields[FieldWorkdir].GetStringValue()
if xdsMetadata.Fields[FieldMetricsCertPath] != nil {
metadata.MetricsCertPath = xdsMetadata.Fields[FieldMetricsCertPath].GetStringValue()
}
if xdsMetadata.Fields[FieldMetricsKeyPath] != nil {
metadata.MetricsKeyPath = xdsMetadata.Fields[FieldMetricsKeyPath].GetStringValue()
}
if listValue := xdsMetadata.Fields[FieldFeatures]; listValue != nil {
metadata.Features = Features{}
for _, feature := range listValue.GetListValue().GetValues() {
metadata.Features[feature.GetStringValue()] = true
}
}
return &metadata
}
func uint32Metadata(xdsMetadata *structpb.Struct, field string) uint32 {
value := xdsMetadata.Fields[field]
if value == nil {
return 0
}
port, err := strconv.ParseInt(value.GetStringValue(), 10, 32)
if err != nil {
metadataLog.Error(err, "invalid value in dataplane metadata", "field", field, "value", value)
return 0
}
return uint32(port)
}