blob: 8bf553fb6025d962ef596dcd3a995ed3faa36a3e [file] [log] [blame]
// Copyright Istio Authors
//
// Licensed 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 util
import (
"fmt"
"strings"
)
import (
"google.golang.org/protobuf/types/known/durationpb"
wrappers "google.golang.org/protobuf/types/known/wrapperspb"
v1alpha13 "istio.io/api/mesh/v1alpha1"
"istio.io/api/networking/v1alpha3"
"istio.io/api/operator/v1alpha1"
v11 "k8s.io/apimachinery/pkg/apis/meta/v1"
"k8s.io/apimachinery/pkg/util/strategicpatch"
yaml2 "sigs.k8s.io/yaml"
)
import (
v1alpha12 "github.com/apache/dubbo-go-pixiu/operator/pkg/apis/istio/v1alpha1"
)
// Partially mirrored from istio/api and operator/pkg/api (for values).
// Struct tags are required to use k8s strategic merge library. It would be possible
// to add these to source protos but because the values field is defined as
// map[string]interface{} here (and similar for MeshConfig in v1alpha1.Values)
// that alone would not be sufficient.
// Only non-scalar types require tags, therefore most fields are omitted here.
type iopMergeStructType struct {
v11.ObjectMeta `json:"metadata" patchStrategy:"merge"`
Spec istioOperatorSpec `json:"spec" patchStrategy:"merge"`
}
type istioOperatorSpec struct {
MeshConfig *meshConfig `json:"meshConfig" patchStrategy:"merge"`
Components *istioComponentSetSpec `json:"components" patchStrategy:"merge"`
Values *values `json:"values" patchStrategy:"merge"`
}
type istioComponentSetSpec struct {
Base *baseComponentSpec `json:"base" patchStrategy:"merge"`
Pilot *componentSpec `json:"pilot" patchStrategy:"merge"`
Cni *componentSpec `json:"cni" patchStrategy:"merge"`
IstiodRemote *componentSpec `json:"istiodRemote" patchStrategy:"merge"`
IngressGateways []*gatewaySpec `json:"ingressGateways" patchStrategy:"merge" patchMergeKey:"name"`
EgressGateways []*gatewaySpec `json:"egressGateways" patchStrategy:"merge" patchMergeKey:"name"`
}
type baseComponentSpec struct {
K8S *v1alpha1.KubernetesResourcesSpec `json:"k8s" patchStrategy:"merge"`
}
type componentSpec struct {
K8S *v1alpha1.KubernetesResourcesSpec `json:"k8s" patchStrategy:"merge"`
}
type gatewaySpec struct {
Label map[string]string `json:"label" patchStrategy:"merge"`
K8S *v1alpha1.KubernetesResourcesSpec `json:"k8s" patchStrategy:"merge"`
}
type values struct {
Cni *v1alpha12.CNIConfig `json:"cni" patchStrategy:"merge"`
Gateways *gatewaysConfig `json:"gateways" patchStrategy:"merge"`
Global *v1alpha12.GlobalConfig `json:"global" patchStrategy:"merge"`
Pilot *v1alpha12.PilotConfig `json:"pilot" patchStrategy:"merge"`
Telemetry *telemetryConfig `json:"telemetry" patchStrategy:"merge"`
SidecarInjectorWebhook *v1alpha12.SidecarInjectorConfig `json:"sidecarInjectorWebhook" patchStrategy:"merge"`
IstioCni *v1alpha12.CNIConfig `json:"istio_cni" patchStrategy:"merge"`
MeshConfig *meshConfig `json:"meshConfig" patchStrategy:"merge"`
Base *v1alpha12.BaseConfig `json:"base" patchStrategy:"merge"`
IstiodRemote *v1alpha12.IstiodRemoteConfig `json:"istiodRemote" patchStrategy:"merge"`
}
type gatewaysConfig struct {
IstioEgressgateway *egressGatewayConfig `json:"istio-egressgateway" patchStrategy:"merge"`
IstioIngressgateway *ingressGatewayConfig `json:"istio-ingressgateway" patchStrategy:"merge"`
}
// Configuration for an ingress gateway.
type ingressGatewayConfig struct {
Env map[string]interface{} `json:"env" patchStrategy:"merge"`
Labels map[string]string `json:"labels" patchStrategy:"merge"`
CPU *v1alpha12.CPUTargetUtilizationConfig `json:"cpu" patchStrategy:"replace"`
LoadBalancerSourceRanges []string `json:"loadBalancerSourceRanges" patchStrategy:"replace"`
NodeSelector map[string]interface{} `json:"nodeSelector" patchStrategy:"merge"`
PodAntiAffinityLabelSelector []map[string]interface{} `json:"podAntiAffinityLabelSelector" patchStrategy:"replace"`
PodAntiAffinityTermLabelSelector []map[string]interface{} `json:"podAntiAffinityTermLabelSelector" patchStrategy:"replace"`
PodAnnotations map[string]interface{} `json:"podAnnotations" patchStrategy:"merge"`
MeshExpansionPorts []*v1alpha12.PortsConfig `json:"meshExpansionPorts" patchStrategy:"merge" patchMergeKey:"name"`
Ports []*v1alpha12.PortsConfig `json:"ports" patchStrategy:"merge" patchMergeKey:"name"`
Resources *resources `json:"resources" patchStrategy:"merge"`
SecretVolumes []*v1alpha12.SecretVolume `json:"secretVolumes" patchStrategy:"merge" patchMergeKey:"name"`
ServiceAnnotations map[string]interface{} `json:"serviceAnnotations" patchStrategy:"merge"`
Tolerations []map[string]interface{} `json:"tolerations" patchStrategy:"replace"`
IngressPorts []map[string]interface{} `json:"ingressPorts" patchStrategy:"replace"`
AdditionalContainers []map[string]interface{} `json:"additionalContainers" patchStrategy:"replace"`
ConfigVolumes []map[string]interface{} `json:"configVolumes" patchStrategy:"replace"`
Zvpn *v1alpha12.IngressGatewayZvpnConfig `json:"zvpn" patchStrategy:"merge"`
}
type resources struct {
Limits map[string]string `json:"limits" patchStrategy:"merge"`
Requests map[string]string `json:"requests" patchStrategy:"merge"`
}
type egressGatewayConfig struct {
Env map[string]interface{} `json:"env" patchStrategy:"merge"`
Labels map[string]string `json:"labels" patchStrategy:"merge"`
NodeSelector map[string]interface{} `json:"nodeSelector" patchStrategy:"merge"`
PodAntiAffinityLabelSelector []map[string]interface{} `json:"podAntiAffinityLabelSelector" patchStrategy:"replace"`
PodAntiAffinityTermLabelSelector []map[string]interface{} `json:"podAntiAffinityTermLabelSelector" patchStrategy:"replace"`
PodAnnotations map[string]interface{} `json:"podAnnotations" patchStrategy:"merge"`
Ports []*v1alpha12.PortsConfig `json:"ports" patchStrategy:"merge" patchMergeKey:"name"`
Resources *resources `json:"resources" patchStrategy:"merge"`
SecretVolumes []*v1alpha12.SecretVolume `json:"secretVolumes" patchStrategy:"merge" patchMergeKey:"name"`
Tolerations []map[string]interface{} `json:"tolerations" patchStrategy:"replace"`
ConfigVolumes []map[string]interface{} `json:"configVolumes" patchStrategy:"replace"`
AdditionalContainers []map[string]interface{} `json:"additionalContainers" patchStrategy:"replace"`
Zvpn *v1alpha12.ZeroVPNConfig `json:"zvpn" patchStrategy:"replace"`
}
type meshConfig struct {
ConnectTimeout *durationpb.Duration `json:"connectTimeout" patchStrategy:"replace"`
ProtocolDetectionTimeout *durationpb.Duration `json:"protocolDetectionTimeout" patchStrategy:"replace"`
RdsRefreshDelay *durationpb.Duration `json:"rdsRefreshDelay" patchStrategy:"replace"`
EnableAutoMtls *wrappers.BoolValue `json:"enableAutoMtls" patchStrategy:"replace"`
EnablePrometheusMerge *wrappers.BoolValue `json:"enablePrometheusMerge" patchStrategy:"replace"`
OutboundTrafficPolicy *v1alpha13.MeshConfig_OutboundTrafficPolicy `json:"outboundTrafficPolicy" patchStrategy:"merge"`
TCPKeepalive *v1alpha3.ConnectionPoolSettings_TCPSettings_TcpKeepalive `json:"tcpKeepalive" patchStrategy:"merge"`
DefaultConfig *proxyConfig `json:"defaultConfig" patchStrategy:"merge"`
ConfigSources []*v1alpha13.ConfigSource `json:"configSources" patchStrategy:"merge" patchMergeKey:"address"`
TrustDomainAliases []string `json:"trustDomainAliases" patchStrategy:"merge"`
DefaultServiceExportTo []string `json:"defaultServiceExportTo" patchStrategy:"merge"`
DefaultVirtualServiceExportTo []string `json:"defaultVirtualServiceExportTo" patchStrategy:"merge"`
DefaultDestinationRuleExportTo []string `json:"defaultDestinationRuleExportTo" patchStrategy:"merge"`
LocalityLbSetting *v1alpha3.LocalityLoadBalancerSetting `json:"localityLbSetting" patchStrategy:"merge"`
DNSRefreshRate *durationpb.Duration `json:"dnsRefreshRate" patchStrategy:"replace"`
Certificates []*v1alpha13.Certificate `json:"certificates" patchStrategy:"merge" patchMergeKey:"secretName"`
ThriftConfig *meshConfigThriftConfig `json:"thriftConfig" patchStrategy:"merge"`
ServiceSettings []*meshConfigServiceSettings `json:"serviceSettings" patchStrategy:"replace"`
DefaultProviders *meshConfigDefaultProviders `json:"defaultProviders" patchStrategy:"merge"`
ExtensionProviders []*meshConfigExtensionProvider `json:"extensionProviders" patchStrategy:"merge" patchMergeKey:"name"`
}
type (
meshConfigDefaultProviders struct {
AccessLogging []struct{} `json:"accessLogging"`
Tracing []struct{} `json:"tracing"`
Metrics []struct{} `json:"metrics"`
}
meshConfigExtensionProvider struct {
Name string `json:"string"`
EnvoyOtelAls struct{} `json:"envoyOtelAls"`
Prometheus struct{} `json:"prometheus"`
EnvoyFileAccessLog struct{} `json:"envoyFileAccessLog"`
Stackdriver struct{} `json:"stackdriver"`
EnvoyExtAuthzHTTP struct{} `json:"envoyExtAuthzHttp"`
EnvoyExtAuthzGrpc struct{} `json:"envoyExtAuthzGrpc"`
Zipkin struct{} `json:"zipkin"`
Lightstep struct{} `json:"lightstep"`
Datadog struct{} `json:"datadog"`
Opencensus struct{} `json:"opencensus"`
Skywalking struct{} `json:"skywalking"`
EnvoyHTTPAls struct{} `json:"envoyHttpAls"`
EnvoyTCPAls struct{} `json:"envoyTcpAls"`
}
clusterName struct {
ServiceCluster *v1alpha13.ProxyConfig_ServiceCluster `json:"serviceCluster,omitempty"`
TracingServiceName *v1alpha13.ProxyConfig_TracingServiceName_ `json:"tracingServiceName,omitempty"`
}
)
type meshConfigThriftConfig struct {
RateLimitTimeout *durationpb.Duration `json:"rateLimitTimeout" patchStrategy:"replace"`
}
type proxyConfig struct {
DrainDuration *durationpb.Duration `json:"drainDuration" patchStrategy:"replace"`
ParentShutdownDuration *durationpb.Duration `json:"parentShutdownDuration" patchStrategy:"replace"`
DiscoveryRefreshDelay *durationpb.Duration `json:"discoveryRefreshDelay" patchStrategy:"replace"`
TerminationDrainDuration *durationpb.Duration `json:"terminationDrainDuration" patchStrategy:"replace"`
Concurrency *wrappers.Int32Value `json:"concurrency" patchStrategy:"replace"`
ConfigSources []*v1alpha13.ConfigSource `json:"configSources" patchStrategy:"replace"`
ClusterName *clusterName `json:"clusterName" patchStrategy:"replace"`
TrustDomainAliases []string `json:"trustDomainAliases" patchStrategy:"replace"`
DefaultServiceExportTo []string `json:"defaultServiceExportTo" patchStrategy:"replace"`
DefaultVirtualServiceExportTo []string `json:"defaultVirtualServiceExportTo" patchStrategy:"replace"`
DefaultDestinationRuleExportTo []string `json:"defaultDestinationRuleExportTo" patchStrategy:"replace"`
LocalityLbSetting *v1alpha3.LocalityLoadBalancerSetting `json:"localityLbSetting" patchStrategy:"merge"`
DNSRefreshRate *durationpb.Duration `json:"dnsRefreshRate" patchStrategy:"replace"`
Certificates []*v1alpha13.Certificate `json:"certificates" patchStrategy:"replace"`
ThriftConfig *v1alpha13.MeshConfig_ThriftConfig `json:"thriftConfig" patchStrategy:"merge"`
ServiceSettings []*v1alpha13.MeshConfig_ServiceSettings `json:"serviceSettings" patchStrategy:"replace"`
Tracing *tracing `json:"tracing" patchStrategy:"replace"`
Sds *v1alpha13.SDS `json:"sds" patchStrategy:"replace"`
EnvoyAccessLogService *v1alpha13.RemoteService `json:"envoyAccessLogService" patchStrategy:"merge" patchMergeKey:"address"`
EnvoyMetricsService *v1alpha13.RemoteService `json:"envoyMetricsService" patchStrategy:"merge" patchMergeKey:"address"`
ProxyMetadata map[string]string `json:"proxyMetadata" patchStrategy:"merge"`
ExtraStatTags []string `json:"extraStatTags" patchStrategy:"replace"`
GatewayTopology *v1alpha13.Topology `json:"gatewayTopology" patchStrategy:"replace"`
}
type tracing struct {
TlSSettings *v1alpha3.ClientTLSSettings `json:"tlsSettings" patchStrategy:"merge"`
}
type meshConfigServiceSettings struct {
Settings *v1alpha13.MeshConfig_ServiceSettings_Settings `json:"settings" patchStrategy:"merge"`
Hosts []string `json:"hosts" patchStrategy:"merge"`
}
type telemetryConfig struct {
V2 *telemetryV2Config `json:"v2" patchStrategy:"merge"`
}
type telemetryV2Config struct {
MetadataExchange *v1alpha12.TelemetryV2MetadataExchangeConfig `json:"metadataExchange" patchStrategy:"merge"`
Prometheus *v1alpha12.TelemetryV2PrometheusConfig `json:"prometheus" patchStrategy:"merge"`
Stackdriver *v1alpha12.TelemetryV2StackDriverConfig `json:"stackdriver" patchStrategy:"merge"`
AccessLogPolicy *v1alpha12.TelemetryV2AccessLogPolicyFilterConfig `json:"accessLogPolicy" patchStrategy:"merge"`
}
var iopMergeStruct iopMergeStructType
// OverlayIOP overlays over base using JSON strategic merge.
func OverlayIOP(base, overlay string) (string, error) {
if strings.TrimSpace(base) == "" {
return overlay, nil
}
if strings.TrimSpace(overlay) == "" {
return base, nil
}
bj, err := yaml2.YAMLToJSON([]byte(base))
if err != nil {
return "", fmt.Errorf("yamlToJSON error in base: %s\n%s", err, bj)
}
oj, err := yaml2.YAMLToJSON([]byte(overlay))
if err != nil {
return "", fmt.Errorf("yamlToJSON error in overlay: %s\n%s", err, oj)
}
if base == "" {
bj = []byte("{}")
}
if overlay == "" {
oj = []byte("{}")
}
merged, err := strategicpatch.StrategicMergePatch(bj, oj, &iopMergeStruct)
if err != nil {
return "", fmt.Errorf("json merge error (%s) for base object: \n%s\n override object: \n%s", err, bj, oj)
}
my, err := yaml2.JSONToYAML(merged)
if err != nil {
return "", fmt.Errorf("jsonToYAML error (%s) for merged object: \n%s", err, merged)
}
return string(my), nil
}