1
// Copyright Istio Authors
3
// Licensed under the Apache License, Version 2.0 (the "License");
4
// you may not use this file except in compliance with the License.
5
// You may obtain a copy of the License at
7
// http://www.apache.org/licenses/LICENSE-2.0
9
// Unless required by applicable law or agreed to in writing, software
10
// distributed under the License is distributed on an "AS IS" BASIS,
11
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12
// See the License for the specific language governing permissions and
13
// limitations under the License.
21
"google.golang.org/protobuf/types/known/durationpb"
22
wrappers "google.golang.org/protobuf/types/known/wrapperspb"
23
metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
24
"k8s.io/apimachinery/pkg/util/strategicpatch"
25
yaml2 "sigs.k8s.io/yaml"
27
v1alpha13 "istio.io/api/mesh/v1alpha1"
28
"istio.io/api/networking/v1alpha3"
29
"istio.io/api/operator/v1alpha1"
30
v1alpha12 "istio.io/istio/operator/pkg/apis/istio/v1alpha1"
33
// Partially mirrored from istio/api and operator/pkg/api (for values).
34
// Struct tags are required to use k8s strategic merge library. It would be possible
35
// to add these to source protos but because the values field is defined as
36
// map[string]interface{} here (and similar for MeshConfig in v1alpha1.Values)
37
// that alone would not be sufficient.
38
// Only non-scalar types require tags, therefore most fields are omitted here.
39
type iopMergeStructType struct {
40
metav1.ObjectMeta `json:"metadata" patchStrategy:"merge"`
41
Spec istioOperatorSpec `json:"spec" patchStrategy:"merge"`
44
type istioOperatorSpec struct {
45
MeshConfig *meshConfig `json:"meshConfig" patchStrategy:"merge"`
46
Components *istioComponentSetSpec `json:"components" patchStrategy:"merge"`
47
Values *values `json:"values" patchStrategy:"merge"`
50
type istioComponentSetSpec struct {
51
Base *baseComponentSpec `json:"base" patchStrategy:"merge"`
52
Pilot *componentSpec `json:"pilot" patchStrategy:"merge"`
53
Cni *componentSpec `json:"cni" patchStrategy:"merge"`
54
Ztunel *componentSpec `json:"ztunnel" patchStrategy:"merge"`
55
IstiodRemote *componentSpec `json:"istiodRemote" patchStrategy:"merge"`
56
IngressGateways []*gatewaySpec `json:"ingressGateways" patchStrategy:"merge" patchMergeKey:"name"`
57
EgressGateways []*gatewaySpec `json:"egressGateways" patchStrategy:"merge" patchMergeKey:"name"`
60
type baseComponentSpec struct {
61
K8S *v1alpha1.KubernetesResourcesSpec `json:"k8s" patchStrategy:"merge"`
64
type componentSpec struct {
65
K8S *v1alpha1.KubernetesResourcesSpec `json:"k8s" patchStrategy:"merge"`
68
type gatewaySpec struct {
69
Label map[string]string `json:"label" patchStrategy:"merge"`
70
K8S *v1alpha1.KubernetesResourcesSpec `json:"k8s" patchStrategy:"merge"`
74
Cni *v1alpha12.CNIConfig `json:"cni" patchStrategy:"merge"`
75
Gateways *gatewaysConfig `json:"gateways" patchStrategy:"merge"`
76
Global *v1alpha12.GlobalConfig `json:"global" patchStrategy:"merge"`
77
Pilot *v1alpha12.PilotConfig `json:"pilot" patchStrategy:"merge"`
78
Telemetry *telemetryConfig `json:"telemetry" patchStrategy:"merge"`
79
SidecarInjectorWebhook *v1alpha12.SidecarInjectorConfig `json:"sidecarInjectorWebhook" patchStrategy:"merge"`
80
IstioCni *v1alpha12.CNIConfig `json:"istio_cni" patchStrategy:"merge"`
81
MeshConfig *meshConfig `json:"meshConfig" patchStrategy:"merge"`
82
Base *v1alpha12.BaseConfig `json:"base" patchStrategy:"merge"`
83
IstiodRemote *v1alpha12.IstiodRemoteConfig `json:"istiodRemote" patchStrategy:"merge"`
84
Ztunnel map[string]any `json:"ztunnel" patchStrategy:"merge"`
87
type gatewaysConfig struct {
88
IstioEgressgateway *egressGatewayConfig `json:"istio-egressgateway" patchStrategy:"merge"`
89
IstioIngressgateway *ingressGatewayConfig `json:"istio-ingressgateway" patchStrategy:"merge"`
92
// Configuration for an ingress gateway.
93
type ingressGatewayConfig struct {
94
Env map[string]any `json:"env" patchStrategy:"merge"`
95
Labels map[string]string `json:"labels" patchStrategy:"merge"`
96
CPU *v1alpha12.TargetUtilizationConfig `json:"cpu" patchStrategy:"replace"`
97
Memory *v1alpha12.TargetUtilizationConfig `json:"memory" patchStrategy:"replace"`
98
LoadBalancerSourceRanges []string `json:"loadBalancerSourceRanges" patchStrategy:"replace"`
99
NodeSelector map[string]any `json:"nodeSelector" patchStrategy:"merge"`
100
PodAntiAffinityLabelSelector []map[string]any `json:"podAntiAffinityLabelSelector" patchStrategy:"replace"`
101
PodAntiAffinityTermLabelSelector []map[string]any `json:"podAntiAffinityTermLabelSelector" patchStrategy:"replace"`
102
PodAnnotations map[string]any `json:"podAnnotations" patchStrategy:"merge"`
103
MeshExpansionPorts []*v1alpha12.PortsConfig `json:"meshExpansionPorts" patchStrategy:"merge" patchMergeKey:"name"`
104
Ports []*v1alpha12.PortsConfig `json:"ports" patchStrategy:"merge" patchMergeKey:"name"`
105
Resources *resources `json:"resources" patchStrategy:"merge"`
106
SecretVolumes []*v1alpha12.SecretVolume `json:"secretVolumes" patchStrategy:"merge" patchMergeKey:"name"`
107
ServiceAnnotations map[string]any `json:"serviceAnnotations" patchStrategy:"merge"`
108
Tolerations []map[string]any `json:"tolerations" patchStrategy:"replace"`
109
IngressPorts []map[string]any `json:"ingressPorts" patchStrategy:"replace"`
110
AdditionalContainers []map[string]any `json:"additionalContainers" patchStrategy:"replace"`
111
ConfigVolumes []map[string]any `json:"configVolumes" patchStrategy:"replace"`
112
Zvpn *v1alpha12.IngressGatewayZvpnConfig `json:"zvpn" patchStrategy:"merge"`
115
type resources struct {
116
Limits map[string]string `json:"limits" patchStrategy:"merge"`
117
Requests map[string]string `json:"requests" patchStrategy:"merge"`
120
type egressGatewayConfig struct {
121
Env map[string]any `json:"env" patchStrategy:"merge"`
122
Labels map[string]string `json:"labels" patchStrategy:"merge"`
123
NodeSelector map[string]any `json:"nodeSelector" patchStrategy:"merge"`
124
PodAntiAffinityLabelSelector []map[string]any `json:"podAntiAffinityLabelSelector" patchStrategy:"replace"`
125
PodAntiAffinityTermLabelSelector []map[string]any `json:"podAntiAffinityTermLabelSelector" patchStrategy:"replace"`
126
PodAnnotations map[string]any `json:"podAnnotations" patchStrategy:"merge"`
127
Ports []*v1alpha12.PortsConfig `json:"ports" patchStrategy:"merge" patchMergeKey:"name"`
128
Resources *resources `json:"resources" patchStrategy:"merge"`
129
SecretVolumes []*v1alpha12.SecretVolume `json:"secretVolumes" patchStrategy:"merge" patchMergeKey:"name"`
130
Tolerations []map[string]any `json:"tolerations" patchStrategy:"replace"`
131
ConfigVolumes []map[string]any `json:"configVolumes" patchStrategy:"replace"`
132
AdditionalContainers []map[string]any `json:"additionalContainers" patchStrategy:"replace"`
133
Zvpn *v1alpha12.ZeroVPNConfig `json:"zvpn" patchStrategy:"replace"`
136
type meshConfig struct {
137
ConnectTimeout *durationpb.Duration `json:"connectTimeout" patchStrategy:"replace"`
138
ProtocolDetectionTimeout *durationpb.Duration `json:"protocolDetectionTimeout" patchStrategy:"replace"`
139
RdsRefreshDelay *durationpb.Duration `json:"rdsRefreshDelay" patchStrategy:"replace"`
140
EnableAutoMtls *wrappers.BoolValue `json:"enableAutoMtls" patchStrategy:"replace"`
141
EnablePrometheusMerge *wrappers.BoolValue `json:"enablePrometheusMerge" patchStrategy:"replace"`
142
OutboundTrafficPolicy *v1alpha13.MeshConfig_OutboundTrafficPolicy `json:"outboundTrafficPolicy" patchStrategy:"merge"`
143
InboundTrafficPolicy *v1alpha13.MeshConfig_InboundTrafficPolicy `json:"inboundTrafficPolicy" patchStrategy:"merge"`
144
TCPKeepalive *v1alpha3.ConnectionPoolSettings_TCPSettings_TcpKeepalive `json:"tcpKeepalive" patchStrategy:"merge"`
145
DefaultConfig *proxyConfig `json:"defaultConfig" patchStrategy:"merge"`
146
ConfigSources []*v1alpha13.ConfigSource `json:"configSources" patchStrategy:"merge" patchMergeKey:"address"`
147
TrustDomainAliases []string `json:"trustDomainAliases" patchStrategy:"merge"`
148
DefaultServiceExportTo []string `json:"defaultServiceExportTo" patchStrategy:"merge"`
149
DefaultVirtualServiceExportTo []string `json:"defaultVirtualServiceExportTo" patchStrategy:"merge"`
150
DefaultDestinationRuleExportTo []string `json:"defaultDestinationRuleExportTo" patchStrategy:"merge"`
151
LocalityLbSetting *v1alpha3.LocalityLoadBalancerSetting `json:"localityLbSetting" patchStrategy:"merge"`
152
DNSRefreshRate *durationpb.Duration `json:"dnsRefreshRate" patchStrategy:"replace"`
153
Certificates []*v1alpha13.Certificate `json:"certificates" patchStrategy:"merge" patchMergeKey:"secretName"`
154
ServiceSettings []*meshConfigServiceSettings `json:"serviceSettings" patchStrategy:"replace"`
155
DefaultProviders *meshConfigDefaultProviders `json:"defaultProviders" patchStrategy:"merge"`
156
ExtensionProviders []*meshConfigExtensionProvider `json:"extensionProviders" patchStrategy:"merge" patchMergeKey:"name"`
160
meshConfigDefaultProviders struct {
161
AccessLogging []struct{} `json:"accessLogging"`
162
Tracing []struct{} `json:"tracing"`
163
Metrics []struct{} `json:"metrics"`
165
meshConfigExtensionProvider struct {
166
Name string `json:"string"`
167
EnvoyOtelAls struct{} `json:"envoyOtelAls"`
168
Prometheus struct{} `json:"prometheus"`
169
EnvoyFileAccessLog struct{} `json:"envoyFileAccessLog"`
170
Stackdriver struct{} `json:"stackdriver"`
171
EnvoyExtAuthzHTTP struct{} `json:"envoyExtAuthzHttp"`
172
EnvoyExtAuthzGrpc struct{} `json:"envoyExtAuthzGrpc"`
173
Zipkin struct{} `json:"zipkin"`
174
Lightstep struct{} `json:"lightstep"`
175
Datadog struct{} `json:"datadog"`
176
Opencensus struct{} `json:"opencensus"`
177
Skywalking struct{} `json:"skywalking"`
178
EnvoyHTTPAls struct{} `json:"envoyHttpAls"`
179
EnvoyTCPAls struct{} `json:"envoyTcpAls"`
180
OpenTelemetry struct{} `json:"opentelemetry"`
183
ServiceCluster *v1alpha13.ProxyConfig_ServiceCluster `json:"serviceCluster,omitempty"`
184
TracingServiceName *v1alpha13.ProxyConfig_TracingServiceName_ `json:"tracingServiceName,omitempty"`
188
type proxyConfig struct {
189
DrainDuration *durationpb.Duration `json:"drainDuration" patchStrategy:"replace"`
190
DiscoveryRefreshDelay *durationpb.Duration `json:"discoveryRefreshDelay" patchStrategy:"replace"`
191
TerminationDrainDuration *durationpb.Duration `json:"terminationDrainDuration" patchStrategy:"replace"`
192
Concurrency *wrappers.Int32Value `json:"concurrency" patchStrategy:"replace"`
193
ConfigSources []*v1alpha13.ConfigSource `json:"configSources" patchStrategy:"replace"`
194
ClusterName *clusterName `json:"clusterName" patchStrategy:"replace"`
195
TrustDomainAliases []string `json:"trustDomainAliases" patchStrategy:"replace"`
196
DefaultServiceExportTo []string `json:"defaultServiceExportTo" patchStrategy:"replace"`
197
DefaultVirtualServiceExportTo []string `json:"defaultVirtualServiceExportTo" patchStrategy:"replace"`
198
DefaultDestinationRuleExportTo []string `json:"defaultDestinationRuleExportTo" patchStrategy:"replace"`
199
LocalityLbSetting *v1alpha3.LocalityLoadBalancerSetting `json:"localityLbSetting" patchStrategy:"merge"`
200
DNSRefreshRate *durationpb.Duration `json:"dnsRefreshRate" patchStrategy:"replace"`
201
Certificates []*v1alpha13.Certificate `json:"certificates" patchStrategy:"replace"`
202
ServiceSettings []*v1alpha13.MeshConfig_ServiceSettings `json:"serviceSettings" patchStrategy:"replace"`
203
Tracing *tracing `json:"tracing" patchStrategy:"replace"`
204
Sds *v1alpha13.SDS `json:"sds" patchStrategy:"replace"`
205
EnvoyAccessLogService *v1alpha13.RemoteService `json:"envoyAccessLogService" patchStrategy:"merge" patchMergeKey:"address"`
206
EnvoyMetricsService *v1alpha13.RemoteService `json:"envoyMetricsService" patchStrategy:"merge" patchMergeKey:"address"`
207
ProxyMetadata map[string]string `json:"proxyMetadata" patchStrategy:"merge"`
208
ExtraStatTags []string `json:"extraStatTags" patchStrategy:"replace"`
209
GatewayTopology *v1alpha13.Topology `json:"gatewayTopology" patchStrategy:"replace"`
213
TlSSettings *v1alpha3.ClientTLSSettings `json:"tlsSettings" patchStrategy:"merge"`
216
type meshConfigServiceSettings struct {
217
Settings *v1alpha13.MeshConfig_ServiceSettings_Settings `json:"settings" patchStrategy:"merge"`
218
Hosts []string `json:"hosts" patchStrategy:"merge"`
221
type telemetryConfig struct {
222
V2 *telemetryV2Config `json:"v2" patchStrategy:"merge"`
225
type telemetryV2Config struct {
226
Prometheus *v1alpha12.TelemetryV2PrometheusConfig `json:"prometheus" patchStrategy:"merge"`
227
Stackdriver *v1alpha12.TelemetryV2StackDriverConfig `json:"stackdriver" patchStrategy:"merge"`
230
var iopMergeStruct iopMergeStructType
232
// OverlayIOP overlays over base using JSON strategic merge.
233
func OverlayIOP(base, overlay string) (string, error) {
234
if strings.TrimSpace(base) == "" {
237
if strings.TrimSpace(overlay) == "" {
240
bj, err := yaml2.YAMLToJSON([]byte(base))
242
return "", fmt.Errorf("yamlToJSON error in base: %s\n%s", err, bj)
244
oj, err := yaml2.YAMLToJSON([]byte(overlay))
246
return "", fmt.Errorf("yamlToJSON error in overlay: %s\n%s", err, oj)
255
merged, err := strategicpatch.StrategicMergePatch(bj, oj, &iopMergeStruct)
257
return "", fmt.Errorf("json merge error (%s) for base object: \n%s\n override object: \n%s", err, bj, oj)
260
my, err := yaml2.JSONToYAML(merged)
262
return "", fmt.Errorf("jsonToYAML error (%s) for merged object: \n%s", err, merged)
265
return string(my), nil