Skip to content

Commit

Permalink
Manual Cherry-picks from 1.0.3 istio#8136 istio#9384 istio#9208 (isti…
Browse files Browse the repository at this point in the history
…o#9438)

* manual cherry-pick of istio#9208

* manual cherry-pick from istio#9384

* manual cherry-pick istio#8136

* fix linter errors
  • Loading branch information
mandarjog authored and istio-testing committed Oct 20, 2018
1 parent b193c4f commit 622467a
Show file tree
Hide file tree
Showing 17 changed files with 549 additions and 102 deletions.
1 change: 1 addition & 0 deletions Gopkg.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,16 @@ data:
fieldRef:
fieldPath: metadata.name
- name: ISTIO_META_INTERCEPTION_MODE
value: {{ "[[ annotation .ObjectMeta `sidecar.istio.io/interceptionMode` .ProxyConfig.InterceptionMode ]]" }}
value: {{ "[[ or (index .ObjectMeta.Annotations \"sidecar.istio.io/interceptionMode\") .ProxyConfig.InterceptionMode.String ]]" }}
{{ "[[ if .ObjectMeta.Annotations ]]" }}
- name: ISTIO_METAJSON_ANNOTATIONS
value: |
{{ "[[ toJSON .ObjectMeta.Annotations ]]" }}
{{ "[[ end ]]" }}
{{ "[[ range $k,$v := .ObjectMeta.Labels ]]" }}
- name: ISTIO_META_{{ "[[ $k ]]" }}
value: "{{ "[[ $v ]]" }}"
{{ "[[ end ]]" }}
imagePullPolicy: {{ .Values.global.imagePullPolicy }}
{{ "[[ if (ne (annotation .ObjectMeta `status.sidecar.istio.io/port` " }} {{ .Values.global.proxy.statusPort }} {{ ") \"0\") ]]" }}
readinessProbe:
Expand Down
17 changes: 16 additions & 1 deletion pilot/pkg/kube/inject/inject.go
Original file line number Diff line number Diff line change
Expand Up @@ -496,6 +496,7 @@ func injectionData(sidecarTemplate, version string, deploymentMetadata *metav1.O
"applicationPorts": applicationPorts,
"annotation": annotation,
"valueOrDefault": valueOrDefault,
"toJSON": toJSON,
}

var tmpl bytes.Buffer
Expand Down Expand Up @@ -655,7 +656,7 @@ func intoObject(sidecarTemplate string, meshconfig *meshconfig.MeshConfig, in ru
// affect the network provider within the cluster causing
// additional pod failures.
if podSpec.HostNetwork {
fmt.Fprintf(os.Stderr, "Skipping injection because %q has host networking enabled\n", metadata.Name)
fmt.Fprintf(os.Stderr, "Skipping injection because %q has host networking enabled\n", metadata.Name) //nolint: errcheck
return out, nil
}

Expand Down Expand Up @@ -725,6 +726,20 @@ func includeInboundPorts(containers []corev1.Container) string {
return getContainerPorts(containers, func(corev1.Container) bool { return true })
}

func toJSON(m map[string]string) string {
if m == nil {
return "{}"
}

ba, err := json.Marshal(m)
if err != nil {
log.Warnf("Unable to marshal %v", m)
return "{}"
}

return string(ba)
}

func annotation(meta metav1.ObjectMeta, name string, defaultValue interface{}) string {
value, ok := meta.Annotations[name]
if !ok {
Expand Down
26 changes: 23 additions & 3 deletions pilot/pkg/kube/inject/webhook_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -743,7 +743,7 @@ func TestHelmInject(t *testing.T) {
// Generate the patch. At runtime, the webhook would actually generate the patch against the
// pod configuration. But since our input files are deployments, rather than actual pod instances,
// we have to apply the patch to the template portion of the deployment only.
templateJSON := toJSON(inputDeployment.Spec.Template, t)
templateJSON := convertToJSON(inputDeployment.Spec.Template, t)
got := webhook.inject(&v1beta1.AdmissionReview{
Request: &v1beta1.AdmissionRequest{
Object: runtime.RawExtension{
Expand Down Expand Up @@ -886,7 +886,7 @@ func splitYamlBytes(yaml []byte, t *testing.T) [][]byte {

func writeYamlsToGoldenFile(yamls [][]byte, goldenFile string, t *testing.T) {
content := make([]byte, 0)
for _, part := range(yamls) {
for _, part := range yamls {
content = append(content, part...)
content = append(content, []byte(yamlSeparator)...)
content = append(content, '\n')
Expand Down Expand Up @@ -939,7 +939,7 @@ func getInjectableYamlDocs(yamlDoc string, t *testing.T) [][]byte {
}
}

func toJSON(i interface{}, t *testing.T) []byte {
func convertToJSON(i interface{}, t *testing.T) []byte {
t.Helper()
outputJSON, err := json.Marshal(i)
if err != nil {
Expand Down Expand Up @@ -1020,11 +1020,31 @@ func compareDeployments(got, want *extv1beta1.Deployment, name string, t *testin
gotIstioProxy.Image = wantIstioProxy.Image
gotIstioProxy.TerminationMessagePath = wantIstioProxy.TerminationMessagePath
gotIstioProxy.TerminationMessagePolicy = wantIstioProxy.TerminationMessagePolicy

// collect automatically injected pod labels so that they can
// be adjusted later.
envNames := map[string]bool{}
for k := range got.Spec.Template.ObjectMeta.Labels {
envNames["ISTIO_META_"+k] = true
}

envVars := make([]corev1.EnvVar, 0)
for _, env := range gotIstioProxy.Env {
if env.ValueFrom != nil {
env.ValueFrom.FieldRef.APIVersion = ""
}
// check if metajson is encoded correctly
if strings.HasPrefix(env.Name, "ISTIO_METAJSON_") {
var mm map[string]string
if err := json.Unmarshal([]byte(env.Value), &mm); err != nil {
t.Fatalf("unable to unmarshal %s: %v", env.Value, err)
}
continue
}
// adjust for injected var names.
if _, found := envNames[env.Name]; found {
continue
}
envVars = append(envVars, env)
}
gotIstioProxy.Env = envVars
Expand Down
2 changes: 1 addition & 1 deletion pilot/pkg/proxy/envoy/proxy.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,7 +90,7 @@ func (e *envoy) Run(config interface{}, epoch int, abort <-chan error) error {
// there is a custom configuration. Don't write our own config - but keep watching the certs.
fname = e.config.CustomConfigFile
} else {
out, err := bootstrap.WriteBootstrap(&e.config, e.node, epoch, e.pilotSAN, e.opts)
out, err := bootstrap.WriteBootstrap(&e.config, e.node, epoch, e.pilotSAN, e.opts, os.Environ())
if err != nil {
log.Errora("Failed to generate bootstrap config", err)
os.Exit(1) // Prevent infinite loop attempting to write the file, let k8s/systemd report
Expand Down
2 changes: 1 addition & 1 deletion pilot/pkg/proxy/envoy/v2/ads.go
Original file line number Diff line number Diff line change
Expand Up @@ -375,7 +375,7 @@ func (s *DiscoveryServer) StreamAggregatedResources(stream ads.AggregatedDiscove
// poor new pilot and overwhelm it.
// TODO: instead of readiness probe, let endpoints connect and wait here for
// config to become stable. Will better spread the load.
s.rateLimiter.Wait(context.TODO())
s.initRateLimiter.Wait(context.TODO())

// first call - lazy loading, in tests. This should not happen if readiness
// check works, since it assumes ClearCache is called (and as such PushContext
Expand Down
1 change: 0 additions & 1 deletion pilot/pkg/proxy/envoy/v2/debug.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,6 @@ import (
"sync"

"github.com/gogo/protobuf/jsonpb"

authn "istio.io/api/authentication/v1alpha1"
networking "istio.io/api/networking/v1alpha3"
"istio.io/istio/pilot/pkg/model"
Expand Down
10 changes: 9 additions & 1 deletion pilot/pkg/proxy/envoy/v2/discovery.go
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,14 @@ type DiscoveryServer struct {
// ConfigController provides readiness info (if initial sync is complete)
ConfigController model.ConfigStoreCache

rateLimiter *rate.Limiter
// rate limiter for sending updates during full ads push.
rateLimiter *rate.Limiter

// rate limiter for sending config to new connections.
// We want to have a larger limit for new connections because until configuration is sent the proxies
// will not be ready.
initRateLimiter *rate.Limiter

concurrentPushLimit chan struct{}

// DebugConfigs controls saving snapshots of configs for /debug/adsz.
Expand Down Expand Up @@ -266,6 +273,7 @@ func NewDiscoveryServer(env *model.Environment, generator core.ConfigGenerator,

adsLog.Infof("Starting ADS server with rateLimiter=%d burst=%d", pushThrottle, pushBurst)
out.rateLimiter = rate.NewLimiter(rate.Limit(pushThrottle), pushBurst)
out.initRateLimiter = rate.NewLimiter(rate.Limit(pushThrottle*2), pushBurst*2)

return out
}
Expand Down
70 changes: 57 additions & 13 deletions pkg/bootstrap/bootstrap_config.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
package bootstrap

import (
"encoding/json"
"fmt"
"io"
"io/ioutil"
Expand All @@ -29,13 +30,22 @@ import (
"github.com/gogo/protobuf/types"

meshconfig "istio.io/api/mesh/v1alpha1"
"istio.io/istio/pkg/log"
)

// Generate the envoy v2 bootstrap configuration, using template.
const (
// EpochFileTemplate is a template for the root config JSON
EpochFileTemplate = "envoy-rev%d.json"
DefaultCfgDir = "/var/lib/istio/envoy/envoy_bootstrap_tmpl.json"
// MaxClusterNameLength is the maximum cluster name length
MaxClusterNameLength = 189 // TODO: use MeshConfig.StatNameLength instead

// IstioMetaPrefix is used to pass env vars as node metadata.
IstioMetaPrefix = "ISTIO_META_"

// IstioMetaJSONPrefix is used to pass annotations and similar environment info.
IstioMetaJSONPrefix = "ISTIO_METAJSON_"
)

var (
Expand Down Expand Up @@ -124,9 +134,49 @@ func StoreHostPort(host, port, field string, opts map[string]interface{}) {
opts[field] = fmt.Sprintf("{\"address\": \"%s\", \"port_value\": %s}", host, port)
}

type setMetaFunc func(m map[string]string, key string, val string)

func extractMetadata(envs []string, prefix string, set setMetaFunc, meta map[string]string) {
metaPrefixLen := len(prefix)
for _, env := range envs {
if strings.HasPrefix(env, prefix) {
v := env[metaPrefixLen:]
parts := strings.SplitN(v, "=", 2)
if len(parts) != 2 {
continue
}
metaKey, metaVal := parts[0], parts[1]

set(meta, metaKey, metaVal)
}
}
}

// getNodeMetaData function uses an environment variable contract
// ISTIO_METAJSON_* env variables contain json_string in the value.
// The name of variable is ignored.
// ISTIO_META_* env variables are passed thru
func getNodeMetaData(envs []string) map[string]string {
meta := map[string]string{}

extractMetadata(envs, IstioMetaPrefix, func(m map[string]string, key string, val string) {
m[key] = val
}, meta)

extractMetadata(envs, IstioMetaJSONPrefix, func(m map[string]string, key string, val string) {
err := json.Unmarshal([]byte(val), &m)
if err != nil {
log.Warnf("Env variable %s [%s] failed json unmarshal: %v", key, val, err)
}
}, meta)
meta["istio"] = "sidecar"
return meta
}

// WriteBootstrap generates an envoy config based on config and epoch, and returns the filename.
// TODO: in v2 some of the LDS ports (port, http_port) should be configured in the bootstrap.
func WriteBootstrap(config *meshconfig.ProxyConfig, node string, epoch int, pilotSAN []string, opts map[string]interface{}) (string, error) {
func WriteBootstrap(config *meshconfig.ProxyConfig, node string, epoch int, pilotSAN []string,
opts map[string]interface{}, localEnv []string) (string, error) {
if opts == nil {
opts = map[string]interface{}{}
}
Expand Down Expand Up @@ -167,23 +217,17 @@ func WriteBootstrap(config *meshconfig.ProxyConfig, node string, epoch int, pilo
opts["pilot_SAN"] = pilotSAN

// Simplify the template
opts["connect_timeout"] = fmt.Sprintf("{\"seconds\": %d, \"nanos\": %d}", config.ConnectTimeout.Seconds, config.ConnectTimeout.Nanos)

opts["connect_timeout"] = (&types.Duration{Seconds: config.ConnectTimeout.Seconds, Nanos: config.ConnectTimeout.Nanos}).String()
opts["cluster"] = config.ServiceCluster
opts["nodeID"] = node

// Support passing extra info from node environment as metadata
meta := map[string]string{}
for _, env := range os.Environ() {
if strings.HasPrefix(env, "ISTIO_META_") {
v := env[len("ISTIO_META_"):]
parts := strings.SplitN(v, "=", 2)
if len(parts) == 2 {
meta[parts[0]] = parts[1]
}
}
meta := getNodeMetaData(localEnv)
ba, err := json.Marshal(meta)
if err != nil {
return "", err
}
opts["meta"] = meta
opts["meta_json_str"] = string(ba)

// TODO: allow reading a file with additional metadata (for example if created with
// 'envref'. This will allow Istio to generate the right config even if the pod info
Expand Down
Loading

0 comments on commit 622467a

Please sign in to comment.