| /* |
| * 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) |
| } |