forked from istio/istio
/
context.go
402 lines (331 loc) · 12.3 KB
/
context.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
// Copyright 2017 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 model
import (
"fmt"
"net"
"strconv"
"strings"
"time"
"github.com/gogo/protobuf/types"
multierror "github.com/hashicorp/go-multierror"
meshconfig "istio.io/api/mesh/v1alpha1"
)
// Environment provides an aggregate environmental API for Pilot
type Environment struct {
// Discovery interface for listing services and instances.
ServiceDiscovery
// Accounts interface for listing service accounts
// Deprecated - use PushContext.ServiceAccounts
ServiceAccounts
// Config interface for listing routing rules
IstioConfigStore
// Mesh is the mesh config (to be merged into the config store)
Mesh *meshconfig.MeshConfig
// Mixer subject alternate name for mutual TLS
MixerSAN []string
// PushContext holds informations during push generation. It is reset on config change, at the beginning
// of the pushAll. It will hold all errors and stats and possibly caches needed during the entire cache computation.
// DO NOT USE EXCEPT FOR TESTS AND HANDLING OF NEW CONNECTIONS.
// ALL USE DURING A PUSH SHOULD USE THE ONE CREATED AT THE
// START OF THE PUSH, THE GLOBAL ONE MAY CHANGE AND REFLECT A DIFFERENT
// CONFIG AND PUSH
// Deprecated - a local config for ads will be used instead
PushContext *PushContext
// MeshNetworks (loaded from a config map) provides information about the
// set of networks inside a mesh and how to route to endpoints in each
// network. Each network provides information about the endpoints in a
// routable L3 network. A single routable L3 network can have one or more
// service registries.
MeshNetworks *meshconfig.MeshNetworks
}
// Proxy defines the proxy attributes used by xDS identification
type Proxy struct {
// ClusterID specifies the cluster where the proxy resides
ClusterID string
// Type specifies the node type
Type NodeType
// IPAddress is the IP address of the proxy used to identify it and its
// co-located service instances. Example: "10.60.1.6"
IPAddress string
// ID is the unique platform-specific sidecar proxy ID
ID string
// Domain defines the DNS domain suffix for short hostnames (e.g.
// "default.svc.cluster.local")
Domain string
// ConfigNamespace defines the namespace where this proxy resides
// for the purposes of network scoping.
// NOTE: DO NOT USE THIS FIELD TO CONSTRUCT DNS NAMES
ConfigNamespace string
// Metadata key-value pairs extending the Node identifier
Metadata map[string]string
}
// NodeType decides the responsibility of the proxy serves in the mesh
type NodeType string
const (
// Sidecar type is used for sidecar proxies in the application containers
Sidecar NodeType = "sidecar"
// Ingress type is used for cluster ingress proxies
Ingress NodeType = "ingress"
// Router type is used for standalone proxies acting as L7/L4 routers
Router NodeType = "router"
)
// IsApplicationNodeType verifies that the NodeType is one of the declared constants in the model
func IsApplicationNodeType(nType NodeType) bool {
switch nType {
case Sidecar, Ingress, Router:
return true
default:
return false
}
}
// ServiceNode encodes the proxy node attributes into a URI-acceptable string
func (node *Proxy) ServiceNode() string {
return strings.Join([]string{
string(node.Type), node.IPAddress, node.ID, node.Domain,
}, serviceNodeSeparator)
}
// GetProxyVersion returns the proxy version string identifier, and whether it is present.
func (node *Proxy) GetProxyVersion() (string, bool) {
version, found := node.Metadata["ISTIO_PROXY_VERSION"]
return version, found
}
// RouterMode decides the behavior of Istio Gateway (normal or sni-dnat)
type RouterMode string
const (
// StandardRouter is the normal gateway mode
StandardRouter RouterMode = "standard"
// SniDnatRouter is used for bridging two networks
SniDnatRouter RouterMode = "sni-dnat"
)
// GetRouterMode returns the operating mode associated with the router.
// Assumes that the proxy is of type Router
func (node *Proxy) GetRouterMode() RouterMode {
if modestr, found := node.Metadata["ROUTER_MODE"]; found {
switch RouterMode(modestr) {
case SniDnatRouter:
return SniDnatRouter
}
}
return StandardRouter
}
// UnnamedNetwork is the default network that proxies in the mesh
// get when they don't request a specific network view.
const UnnamedNetwork = ""
// GetNetworkView returns the networks that the proxy requested.
// When sending EDS/CDS-with-dns-endpoints, Pilot will only send
// endpoints corresponding to the networks that the proxy wants to see.
// If not set, we assume that the proxy wants to see endpoints from the default
// unnamed network.
func GetNetworkView(node *Proxy) map[string]bool {
if node == nil {
return map[string]bool{UnnamedNetwork: true}
}
nmap := make(map[string]bool)
if networks, found := node.Metadata["REQUESTED_NETWORK_VIEW"]; found {
for _, n := range strings.Split(networks, ",") {
nmap[n] = true
}
} else {
// Proxy sees endpoints from the default unnamed network only
nmap[UnnamedNetwork] = true
}
return nmap
}
// ParseMetadata parses the opaque Metadata from an Envoy Node into string key-value pairs.
// Any non-string values are ignored.
func ParseMetadata(metadata *types.Struct) map[string]string {
if metadata == nil {
return nil
}
fields := metadata.GetFields()
res := make(map[string]string, len(fields))
for k, v := range fields {
if s, ok := v.GetKind().(*types.Value_StringValue); ok {
res[k] = s.StringValue
}
}
if len(res) == 0 {
res = nil
}
return res
}
// ParseServiceNode is the inverse of service node function
func ParseServiceNode(s string) (Proxy, error) {
parts := strings.Split(s, serviceNodeSeparator)
out := Proxy{}
if len(parts) != 4 {
return out, fmt.Errorf("missing parts in the service node %q", s)
}
out.Type = NodeType(parts[0])
switch out.Type {
case Sidecar, Ingress, Router:
default:
return out, fmt.Errorf("invalid node type (valid types: ingress, sidecar, router in the service node %q", s)
}
out.IPAddress = parts[1]
// Does query from ingress or router have to carry valid IP address?
if net.ParseIP(out.IPAddress) == nil && out.Type == Sidecar {
return out, fmt.Errorf("invalid IP address %q in the service node %q", out.IPAddress, s)
}
out.ID = parts[2]
out.Domain = parts[3]
return out, nil
}
// GetProxyConfigNamespace extracts the namespace associated with the proxy
// from the proxy metadata or the proxy ID
func GetProxyConfigNamespace(proxy *Proxy) string {
if proxy == nil {
return ""
}
// First look for ISTIO_META_CONFIG_NAMESPACE
if configNamespace, found := proxy.Metadata["CONFIG_NAMESPACE"]; found {
return configNamespace
}
// If its not present, fallback to parsing the namespace from the proxyID
// NOTE: This is a hack for Kubernetes only where we assume that the
// proxy ID is of the form name.namespace. Other platforms should
// set ISTIO_META_CONFIG_NAMESPACE in the sidecar bootstrap config.
parts := strings.Split(proxy.ID, ".")
if len(parts) != 2 {
return ""
}
return parts[1]
}
const (
serviceNodeSeparator = "~"
// IngressCertsPath is the path location for ingress certificates
IngressCertsPath = "/etc/istio/ingress-certs/"
// AuthCertsPath is the path location for mTLS certificates
AuthCertsPath = "/etc/certs/"
// CertChainFilename is mTLS chain file
CertChainFilename = "cert-chain.pem"
// KeyFilename is mTLS private key
KeyFilename = "key.pem"
// RootCertFilename is mTLS root cert
RootCertFilename = "root-cert.pem"
// IngressCertFilename is the ingress cert file name
IngressCertFilename = "tls.crt"
// IngressKeyFilename is the ingress private key file name
IngressKeyFilename = "tls.key"
// ConfigPathDir config directory for storing envoy json config files.
ConfigPathDir = "/etc/istio/proxy"
// BinaryPathFilename envoy binary location
BinaryPathFilename = "/usr/local/bin/envoy"
// ServiceClusterName service cluster name used in xDS calls
ServiceClusterName = "istio-proxy"
// DiscoveryPlainAddress discovery IP address:port with plain text
DiscoveryPlainAddress = "istio-pilot:15007"
// IstioIngressGatewayName is the internal gateway name assigned to ingress
IstioIngressGatewayName = "istio-autogenerated-k8s-ingress"
// IstioIngressNamespace is the namespace where Istio ingress controller is deployed
IstioIngressNamespace = "istio-system"
)
// IstioIngressWorkloadLabels is the label assigned to Istio ingress pods
var IstioIngressWorkloadLabels = map[string]string{"istio": "ingress"}
// DefaultProxyConfig for individual proxies
func DefaultProxyConfig() meshconfig.ProxyConfig {
return meshconfig.ProxyConfig{
ConfigPath: ConfigPathDir,
BinaryPath: BinaryPathFilename,
ServiceCluster: ServiceClusterName,
DrainDuration: types.DurationProto(2 * time.Second),
ParentShutdownDuration: types.DurationProto(3 * time.Second),
DiscoveryAddress: DiscoveryPlainAddress,
ConnectTimeout: types.DurationProto(1 * time.Second),
StatsdUdpAddress: "",
ProxyAdminPort: 15000,
ControlPlaneAuthPolicy: meshconfig.AuthenticationPolicy_NONE,
CustomConfigFile: "",
Concurrency: 0,
StatNameLength: 189,
Tracing: nil,
}
}
// DefaultMeshConfig configuration
func DefaultMeshConfig() meshconfig.MeshConfig {
config := DefaultProxyConfig()
return meshconfig.MeshConfig{
MixerCheckServer: "",
MixerReportServer: "",
DisablePolicyChecks: false,
PolicyCheckFailOpen: false,
ProxyListenPort: 15001,
ConnectTimeout: types.DurationProto(1 * time.Second),
IngressClass: "istio",
IngressControllerMode: meshconfig.MeshConfig_STRICT,
EnableTracing: true,
AccessLogFile: "/dev/stdout",
AccessLogEncoding: meshconfig.MeshConfig_TEXT,
DefaultConfig: &config,
SdsUdsPath: "",
EnableSdsTokenMount: false,
TrustDomain: "",
}
}
// ApplyMeshConfigDefaults returns a new MeshConfig decoded from the
// input YAML with defaults applied to omitted configuration values.
func ApplyMeshConfigDefaults(yaml string) (*meshconfig.MeshConfig, error) {
out := DefaultMeshConfig()
if err := ApplyYAML(yaml, &out, false); err != nil {
return nil, multierror.Prefix(err, "failed to convert to proto.")
}
// Reset the default ProxyConfig as jsonpb.UnmarshalString doesn't
// handled nested decode properly for our use case.
prevDefaultConfig := out.DefaultConfig
defaultProxyConfig := DefaultProxyConfig()
out.DefaultConfig = &defaultProxyConfig
// Re-apply defaults to ProxyConfig if they were defined in the
// original input MeshConfig.ProxyConfig.
if prevDefaultConfig != nil {
origProxyConfigYAML, err := ToYAML(prevDefaultConfig)
if err != nil {
return nil, multierror.Prefix(err, "failed to re-encode default proxy config")
}
if err := ApplyYAML(origProxyConfigYAML, out.DefaultConfig, false); err != nil {
return nil, multierror.Prefix(err, "failed to convert to proto.")
}
}
if err := ValidateMeshConfig(&out); err != nil {
return nil, err
}
return &out, nil
}
// EmptyMeshNetworks configuration with no networks
func EmptyMeshNetworks() meshconfig.MeshNetworks {
return meshconfig.MeshNetworks{
Networks: map[string]*meshconfig.Network{},
}
}
// LoadMeshNetworksConfig returns a new MeshNetworks decoded from the
// input YAML.
func LoadMeshNetworksConfig(yaml string) (*meshconfig.MeshNetworks, error) {
out := EmptyMeshNetworks()
if err := ApplyYAML(yaml, &out, false); err != nil {
return nil, multierror.Prefix(err, "failed to convert to proto.")
}
// TODO validate the loaded MeshNetworks
// if err := ValidateMeshNetworks(&out); err != nil {
// return nil, err
// }
return &out, nil
}
// ParsePort extracts port number from a valid proxy address
func ParsePort(addr string) int {
port, err := strconv.Atoi(addr[strings.Index(addr, ":")+1:])
if err != nil {
log.Warna(err)
}
return port
}