diff --git a/Gopkg.lock b/Gopkg.lock index f6da0727..7f964899 100644 --- a/Gopkg.lock +++ b/Gopkg.lock @@ -927,7 +927,7 @@ [[projects]] branch = "master" - digest = "1:5dddb45857ff59292216934b6f39415befab65246afac26ba14976e3ec11a343" + digest = "1:4ede44d732fec3c64776a5ec3897efc2b5fbd42dd014f9bde56e69f3bece21e1" name = "knative.dev/pkg" packages = [ "apis", @@ -946,7 +946,7 @@ "metrics/metricskey", ] pruneopts = "T" - revision = "9f6e5334c25aeebd862b19cb6715f9fe5aa56467" + revision = "366ab85660d4e1c260795bd23c2aa09a4721c282" [[projects]] branch = "master" @@ -957,7 +957,7 @@ "tools/dep-collector", ] pruneopts = "UT" - revision = "d2746f8b9470e8c8452a997e95190aba5320678a" + revision = "d7182fdc8d03f19b78b96e4aa3e94d831facf4d0" [solve-meta] analyzer-name = "dep" diff --git a/vendor/knative.dev/pkg/Gopkg.lock b/vendor/knative.dev/pkg/Gopkg.lock index b37b2eb4..6659710e 100644 --- a/vendor/knative.dev/pkg/Gopkg.lock +++ b/vendor/knative.dev/pkg/Gopkg.lock @@ -1217,14 +1217,14 @@ [[projects]] branch = "master" - digest = "1:305af75fc194c059ae710a75276ca8f1870c959214b18ed33f7ef8671995947f" + digest = "1:a68a49f889453ee0abab8d32ceaa19c12a1e86c7919e9cecb3d5ceac6aac199c" name = "knative.dev/test-infra" packages = [ "scripts", "tools/dep-collector", ] pruneopts = "UT" - revision = "f3fe0bcc30693df8e3c9616358b16045efb9ed10" + revision = "d2746f8b9470e8c8452a997e95190aba5320678a" [[projects]] digest = "1:8730e0150dfb2b7e173890c8b9868e7a273082ef8e39f4940e3506a481cf895c" diff --git a/vendor/knative.dev/pkg/apis/url.go b/vendor/knative.dev/pkg/apis/url.go index 0ff8ea05..181685cd 100644 --- a/vendor/knative.dev/pkg/apis/url.go +++ b/vendor/knative.dev/pkg/apis/url.go @@ -57,11 +57,14 @@ func (u *URL) UnmarshalJSON(b []byte) error { if err := json.Unmarshal(b, &ref); err != nil { return err } - r, err := ParseURL(ref) - if err != nil { + if r, err := ParseURL(ref); err != nil { return err + } else if r != nil { + *u = *r + } else { + *u = URL{} } - *u = *r + return nil } diff --git a/vendor/knative.dev/pkg/configmap/informed_watcher.go b/vendor/knative.dev/pkg/configmap/informed_watcher.go index 5903d59d..ed247ae1 100644 --- a/vendor/knative.dev/pkg/configmap/informed_watcher.go +++ b/vendor/knative.dev/pkg/configmap/informed_watcher.go @@ -79,7 +79,7 @@ var _ Watcher = (*InformedWatcher)(nil) var _ DefaultingWatcher = (*InformedWatcher)(nil) // WatchWithDefault implements DefaultingWatcher. -func (i *InformedWatcher) WatchWithDefault(cm corev1.ConfigMap, o Observer) { +func (i *InformedWatcher) WatchWithDefault(cm corev1.ConfigMap, o ...Observer) { i.defaults[cm.Name] = &cm i.m.Lock() @@ -94,7 +94,7 @@ func (i *InformedWatcher) WatchWithDefault(cm corev1.ConfigMap, o Observer) { panic("cannot WatchWithDefault after the InformedWatcher has started") } - i.Watch(cm.Name, o) + i.Watch(cm.Name, o...) } // Start implements Watcher. diff --git a/vendor/knative.dev/pkg/configmap/manual_watcher.go b/vendor/knative.dev/pkg/configmap/manual_watcher.go index ad243de5..dc801e77 100644 --- a/vendor/knative.dev/pkg/configmap/manual_watcher.go +++ b/vendor/knative.dev/pkg/configmap/manual_watcher.go @@ -35,14 +35,14 @@ type ManualWatcher struct { var _ Watcher = (*ManualWatcher)(nil) // Watch implements Watcher -func (w *ManualWatcher) Watch(name string, o Observer) { +func (w *ManualWatcher) Watch(name string, o ...Observer) { w.m.Lock() defer w.m.Unlock() if w.observers == nil { - w.observers = make(map[string][]Observer, 1) + w.observers = make(map[string][]Observer, len(o)) } - w.observers[name] = append(w.observers[name], o) + w.observers[name] = append(w.observers[name], o...) } func (w *ManualWatcher) Start(<-chan struct{}) error { diff --git a/vendor/knative.dev/pkg/configmap/static_watcher.go b/vendor/knative.dev/pkg/configmap/static_watcher.go index 96a01140..43ff9de3 100644 --- a/vendor/knative.dev/pkg/configmap/static_watcher.go +++ b/vendor/knative.dev/pkg/configmap/static_watcher.go @@ -48,10 +48,12 @@ type StaticWatcher struct { var _ Watcher = (*StaticWatcher)(nil) // Watch implements Watcher -func (di *StaticWatcher) Watch(name string, o Observer) { +func (di *StaticWatcher) Watch(name string, o ...Observer) { cm, ok := di.cfgs[name] if ok { - o(cm) + for _, observer := range o { + observer(cm) + } } else { panic(fmt.Sprintf("Tried to watch unknown config with name %q", name)) } diff --git a/vendor/knative.dev/pkg/configmap/watcher.go b/vendor/knative.dev/pkg/configmap/watcher.go index 71a18f49..ff703dbc 100644 --- a/vendor/knative.dev/pkg/configmap/watcher.go +++ b/vendor/knative.dev/pkg/configmap/watcher.go @@ -28,8 +28,8 @@ type Observer func(*corev1.ConfigMap) // Watcher defines the interface that a configmap implementation must implement. type Watcher interface { - // Watch is called to register a callback to be notified when a named ConfigMap changes. - Watch(string, Observer) + // Watch is called to register callbacks to be notified when a named ConfigMap changes. + Watch(string, ...Observer) // Start is called to initiate the watches and provide a channel to signal when we should // stop watching. When Start returns, all registered Observers will be called with the @@ -42,8 +42,8 @@ type Watcher interface { type DefaultingWatcher interface { Watcher - // WatchWithDefault is called to register a callback to be notified when a named ConfigMap + // WatchWithDefault is called to register callbacks to be notified when a named ConfigMap // changes. The provided default value is always observed before any real ConfigMap with that // name is. If the real ConfigMap with that name is deleted, then the default value is observed. - WatchWithDefault(cm corev1.ConfigMap, o Observer) + WatchWithDefault(cm corev1.ConfigMap, o ...Observer) } diff --git a/vendor/knative.dev/pkg/injection/sharedmain/main.go b/vendor/knative.dev/pkg/injection/sharedmain/main.go index 47f32d44..e8e56048 100644 --- a/vendor/knative.dev/pkg/injection/sharedmain/main.go +++ b/vendor/knative.dev/pkg/injection/sharedmain/main.go @@ -21,10 +21,12 @@ import ( "flag" "fmt" "log" + "net/http" "os" "os/user" "path/filepath" + "golang.org/x/sync/errgroup" metav1 "k8s.io/apimachinery/pkg/apis/meta/v1" "k8s.io/client-go/rest" "k8s.io/client-go/tools/clientcmd" @@ -36,6 +38,7 @@ import ( "knative.dev/pkg/injection/clients/kubeclient" "knative.dev/pkg/logging" "knative.dev/pkg/metrics" + "knative.dev/pkg/profiling" "knative.dev/pkg/signals" "knative.dev/pkg/system" ) @@ -76,6 +79,7 @@ func GetLoggingConfig(ctx context.Context) (*logging.Config, error) { if err != nil { return nil, err } + return logging.NewConfigFromConfigMap(loggingConfigMap) } @@ -128,10 +132,16 @@ func MainWithConfig(ctx context.Context, component string, cfg *rest.Config, cto controllers = append(controllers, cf(ctx, cmw)) } + profilingHandler := profiling.NewHandler(logger, false) + // Watch the logging config map and dynamically update logging levels. cmw.Watch(logging.ConfigMapName(), logging.UpdateLevelFromConfigMap(logger, atomicLevel, component)) - // Watch the observability config map and dynamically update metrics exporter. - cmw.Watch(metrics.ConfigMapName(), metrics.UpdateExporterFromConfigMap(component, logger)) + + // Watch the observability config map + cmw.Watch(metrics.ConfigMapName(), + metrics.UpdateExporterFromConfigMap(component, logger), + profilingHandler.UpdateFromConfigMap) + if err := cmw.Start(ctx.Done()); err != nil { logger.Fatalw("failed to start configuration manager", zap.Error(err)) } @@ -144,7 +154,22 @@ func MainWithConfig(ctx context.Context, component string, cfg *rest.Config, cto // Start all of the controllers. logger.Info("Starting controllers...") - controller.StartAll(ctx.Done(), controllers...) + go controller.StartAll(ctx.Done(), controllers...) + + profilingServer := profiling.NewServer(profilingHandler) + + eg, egCtx := errgroup.WithContext(ctx) + eg.Go(profilingServer.ListenAndServe) + + // This will block until either a signal arrives or one of the grouped functions + // returns an error. + <-egCtx.Done() + + profilingServer.Shutdown(context.Background()) + // Don't forward ErrServerClosed as that indicates we're already shutting down. + if err := eg.Wait(); err != nil && err != http.ErrServerClosed { + logger.Errorw("Error while running server", zap.Error(err)) + } } func flush(logger *zap.SugaredLogger) { diff --git a/vendor/knative.dev/pkg/profiling/server.go b/vendor/knative.dev/pkg/profiling/server.go new file mode 100644 index 00000000..1fa3cb46 --- /dev/null +++ b/vendor/knative.dev/pkg/profiling/server.go @@ -0,0 +1,114 @@ +/* +Copyright 2019 The Knative 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 profiling + +import ( + "net/http" + "net/http/pprof" + "strconv" + "sync" + + perrors "github.com/pkg/errors" + "go.uber.org/zap" + corev1 "k8s.io/api/core/v1" +) + +const ( + // profilingPort is the port where we expose profiling information if profiling is enabled + profilingPort = ":8008" + + // profilingKey is the name of the key in config-observability config map that indicates whether profiling + // is enabled of disabled + profilingKey = "profiling.enable" +) + +// Handler holds the main HTTP handler and a flag indicating +// whether the handler is active +type Handler struct { + enabled bool + enabledMux sync.Mutex + handler http.Handler + log *zap.SugaredLogger +} + +// NewHandler create a new ProfilingHandler which serves runtime profiling data +// according to the given context path +func NewHandler(logger *zap.SugaredLogger, enableProfiling bool) *Handler { + const pprofPrefix = "/debug/pprof/" + + mux := http.NewServeMux() + mux.HandleFunc(pprofPrefix, pprof.Index) + mux.HandleFunc(pprofPrefix+"cmdline", pprof.Cmdline) + mux.HandleFunc(pprofPrefix+"profile", pprof.Profile) + mux.HandleFunc(pprofPrefix+"symbol", pprof.Symbol) + mux.HandleFunc(pprofPrefix+"trace", pprof.Trace) + + logger.Infof("Profiling enabled: %t", enableProfiling) + + return &Handler{ + enabled: enableProfiling, + handler: mux, + log: logger, + } +} + +func (h *Handler) ServeHTTP(w http.ResponseWriter, r *http.Request) { + h.enabledMux.Lock() + defer h.enabledMux.Unlock() + if h.enabled { + h.handler.ServeHTTP(w, r) + } else { + http.NotFoundHandler().ServeHTTP(w, r) + } +} + +func readProfilingFlag(configMap *corev1.ConfigMap) (bool, error) { + profiling, ok := configMap.Data[profilingKey] + if !ok { + return false, nil + } + enabled, err := strconv.ParseBool(profiling) + if err != nil { + return false, perrors.Wrapf(err, "failed to parse the profiling flag") + } + return enabled, nil +} + +// UpdateFromConfigMap modifies the Enabled flag in the Handler +// according to the value in the given ConfigMap +func (h *Handler) UpdateFromConfigMap(configMap *corev1.ConfigMap) { + enabled, err := readProfilingFlag(configMap) + if err != nil { + h.log.Errorw("Failed to update the profiling flag", zap.Error(err)) + return + } + h.enabledMux.Lock() + defer h.enabledMux.Unlock() + if h.enabled != enabled { + h.enabled = enabled + h.log.Infof("Profiling enabled: %t", h.enabled) + } +} + +// NewServer creates a new http server that exposes profiling data using the +// HTTP handler that is passed as an argument +func NewServer(handler http.Handler) *http.Server { + return &http.Server{ + Addr: profilingPort, + Handler: handler, + } +} diff --git a/vendor/knative.dev/pkg/test/mako/README.md b/vendor/knative.dev/pkg/test/mako/README.md index 1bc749fe..dbb48b56 100644 --- a/vendor/knative.dev/pkg/test/mako/README.md +++ b/vendor/knative.dev/pkg/test/mako/README.md @@ -1,7 +1,8 @@ # Mako -[Mako](https://github.com/google/mako) is an open source project for performance testing in Knative. -It offers capacities like data storage, charting, statistical aggregation and automated regression analysis. +[Mako](https://github.com/google/mako) is an open source project for performance +testing in Knative. It offers capacities like data storage, charting, +statistical aggregation and automated regression analysis. -This folder contains common code that can be used by all Knative projects, with which we can follow the -same process to set up Mako and collaborate. +This folder contains common code that can be used by all Knative projects, with +which we can follow the same process to set up Mako and collaborate.