The following pull request was submitted through Github. It can be accessed and reviewed at: https://github.com/lxc/lxd/pull/4770
This e-mail was sent by the LXC bot, direct replies will not reach the author unless they happen to be subscribed to this list. === Description (from pull-request) ===
From 2dc38fae2e4ec597c8562e14a31b2b04f5b12154 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgra...@ubuntu.com> Date: Tue, 10 Jul 2018 10:34:50 -0400 Subject: [PATCH 1/2] lxd/storage: Fix double quoting MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Stéphane Graber <stgra...@ubuntu.com> --- lxd/storage_ceph.go | 2 +- lxd/storage_lvm.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/lxd/storage_ceph.go b/lxd/storage_ceph.go index e5dfdd15f..fda817a01 100644 --- a/lxd/storage_ceph.go +++ b/lxd/storage_ceph.go @@ -2420,7 +2420,7 @@ func (s *storageCeph) StorageEntitySetQuota(volumeType int, size int64, data int ctName := c.Name() if c.IsRunning() { msg := fmt.Sprintf(`Cannot resize RBD storage volume `+ - `for container \"%s\" when it is running`, + `for container "%s" when it is running`, ctName) logger.Errorf(msg) return fmt.Errorf(msg) diff --git a/lxd/storage_lvm.go b/lxd/storage_lvm.go index 18ea22f44..6d6f51180 100644 --- a/lxd/storage_lvm.go +++ b/lxd/storage_lvm.go @@ -2152,7 +2152,7 @@ func (s *storageLvm) StorageEntitySetQuota(volumeType int, size int64, data inte ctName := c.Name() if c.IsRunning() { msg := fmt.Sprintf(`Cannot resize LVM storage volume `+ - `for container \"%s\" when it is running`, + `for container "%s" when it is running`, ctName) logger.Errorf(msg) return fmt.Errorf(msg) From 943bde0e3750f80ec79fa4434c9eb4d68d9e8fd6 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?St=C3=A9phane=20Graber?= <stgra...@ubuntu.com> Date: Tue, 10 Jul 2018 12:45:11 -0400 Subject: [PATCH 2/2] lxd: Add built-in pprof server MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This commit adds a new core.debug_address option (node specific) which controls a built-in HTTP server to be used with the "pprof" tool or directly from a web browser (/debug/pprof is the main endpoint). This is a much more flexible option that can be live-enabled by our users when running into a problem and replaces the old cpu-profile, memory-profile and print-goroutines command line options. Signed-off-by: Stéphane Graber <stgra...@ubuntu.com> --- doc/api-extensions.md | 6 +++ doc/server.md | 3 +- lxd/api_1.0.go | 14 ++++-- lxd/daemon.go | 8 ++- lxd/debug/cpu.go | 30 ------------ lxd/debug/cpu_test.go | 33 ------------- lxd/debug/goroutines.go | 34 ------------- lxd/debug/memory.go | 58 ---------------------- lxd/debug/memory_test.go | 54 -------------------- lxd/debug/start.go | 56 --------------------- lxd/endpoints/endpoints.go | 18 +++++++ lxd/endpoints/pprof.go | 109 +++++++++++++++++++++++++++++++++++++++++ lxd/main_daemon.go | 23 +-------- lxd/node/config.go | 30 +++++++++++- scripts/bash/lxd-client | 2 +- shared/version/api.go | 1 + test/main.sh | 2 - test/suites/profiling.sh | 44 ----------------- test/suites/static_analysis.sh | 1 - 19 files changed, 183 insertions(+), 343 deletions(-) delete mode 100644 lxd/debug/cpu.go delete mode 100644 lxd/debug/cpu_test.go delete mode 100644 lxd/debug/goroutines.go delete mode 100644 lxd/debug/memory.go delete mode 100644 lxd/debug/memory_test.go delete mode 100644 lxd/debug/start.go create mode 100644 lxd/endpoints/pprof.go delete mode 100644 test/suites/profiling.sh diff --git a/doc/api-extensions.md b/doc/api-extensions.md index a16527207..4ee151e48 100644 --- a/doc/api-extensions.md +++ b/doc/api-extensions.md @@ -540,3 +540,9 @@ sockets. ## container\_protection\_delete Enables setting the `security.protection.delete` field which prevents containers from being deleted if set to true. Snapshots are not affected by this setting. + +## pprof\_http +This adds a new core.debug\_address config option to start a debugging HTTP server. + +That server currently includes a pprof API and replaces the old +cpu-profile, memory-profile and print-goroutines debug options. diff --git a/doc/server.md b/doc/server.md index a24668b58..d71ceccaf 100644 --- a/doc/server.md +++ b/doc/server.md @@ -11,7 +11,8 @@ currently supported: Key | Type | Default | API extension | Description :-- | :--- | :------ | :------------ | :---------- cluster.offline\_threshold | integer | 20 | clustering | Number of seconds after which an unresponsive node is considered offline -core.https\_address | string | - | - | Address to bind for the remote API +core.debug\_address | string | - | pprof\_http | Address to bind the pprof debug server to (HTTP) +core.https\_address | string | - | - | Address to bind for the remote API (HTTPs) core.https\_allowed\_credentials| boolean | - | - | Whether to set Access-Control-Allow-Credentials http header value to "true" core.https\_allowed\_headers | string | - | - | Access-Control-Allow-Headers http header value core.https\_allowed\_methods | string | - | - | Access-Control-Allow-Methods http header value diff --git a/lxd/api_1.0.go b/lxd/api_1.0.go index 2fc1b6751..ca0f06247 100644 --- a/lxd/api_1.0.go +++ b/lxd/api_1.0.go @@ -273,8 +273,7 @@ func api10Patch(d *Daemon, r *http.Request) Response { } func doApi10Update(d *Daemon, req api.ServerPut, patch bool) Response { - // The HTTPS address and maas machine are the only config keys that we - // want to save in the node-level database, so handle it here. + // First deal with config specific to the local daemon nodeValues := map[string]interface{}{} for key := range node.ConfigSchema { @@ -291,7 +290,7 @@ func doApi10Update(d *Daemon, req api.ServerPut, patch bool) Response { var err error newNodeConfig, err = node.ConfigLoad(tx) if err != nil { - return errors.Wrap(err, "failed to load node config") + return errors.Wrap(err, "Failed to load node config") } if patch { nodeChanged, err = newNodeConfig.Patch(nodeValues) @@ -309,13 +308,14 @@ func doApi10Update(d *Daemon, req api.ServerPut, patch bool) Response { } } + // Then deal with cluster wide configuration var clusterChanged map[string]string var newClusterConfig *cluster.Config err = d.cluster.Transaction(func(tx *db.ClusterTx) error { var err error newClusterConfig, err = cluster.ConfigLoad(tx) if err != nil { - return errors.Wrap(err, "failed to load cluster config") + return errors.Wrap(err, "Failed to load cluster config") } if patch { clusterChanged, err = newClusterConfig.Patch(req.Config) @@ -333,6 +333,7 @@ func doApi10Update(d *Daemon, req api.ServerPut, patch bool) Response { } } + // Notify the other nodes about changes notifier, err := cluster.NewNotifier(d.State(), d.endpoints.NetworkCert(), cluster.NotifyAlive) if err != nil { return SmartError(err) @@ -401,6 +402,11 @@ func doApi10UpdateTriggers(d *Daemon, nodeChanged, clusterChanged map[string]str if err != nil { return err } + case "core.debug_address": + err := d.endpoints.PprofUpdateAddress(value) + if err != nil { + return err + } } } if maasChanged { diff --git a/lxd/daemon.go b/lxd/daemon.go index 7344f8d5b..31c7bd0d1 100644 --- a/lxd/daemon.go +++ b/lxd/daemon.go @@ -441,7 +441,12 @@ func (d *Daemon) init() error { address, err := node.HTTPSAddress(d.db) if err != nil { - return errors.Wrap(err, "failed to fetch node address") + return errors.Wrap(err, "Failed to fetch node address") + } + + debugAddress, err := node.DebugAddress(d.db) + if err != nil { + return errors.Wrap(err, "Failed to fetch debug address") } /* Setup the web server */ @@ -453,6 +458,7 @@ func (d *Daemon) init() error { DevLxdServer: DevLxdServer(d), LocalUnixSocketGroup: d.config.Group, NetworkAddress: address, + DebugAddress: debugAddress, } d.endpoints, err = endpoints.Up(config) if err != nil { diff --git a/lxd/debug/cpu.go b/lxd/debug/cpu.go deleted file mode 100644 index 9d76d2d2f..000000000 --- a/lxd/debug/cpu.go +++ /dev/null @@ -1,30 +0,0 @@ -package debug - -import ( - "fmt" - "os" - "runtime/pprof" - - "golang.org/x/net/context" -) - -// CPU starts the Go CPU profiler, dumping to the given file. -func CPU(filename string) Activity { - return func() (activityFunc, error) { - if filename == "" { - return nil, nil - } - - file, err := os.Create(filename) - if err != nil { - return nil, fmt.Errorf("Error opening cpu profile file: %v", err) - } - - pprof.StartCPUProfile(file) - f := func(ctx context.Context) { - <-ctx.Done() - pprof.StopCPUProfile() - } - return f, nil - } -} diff --git a/lxd/debug/cpu_test.go b/lxd/debug/cpu_test.go deleted file mode 100644 index 2a4d4290b..000000000 --- a/lxd/debug/cpu_test.go +++ /dev/null @@ -1,33 +0,0 @@ -package debug_test - -import ( - "io/ioutil" - "os" - "testing" - - "github.com/lxc/lxd/lxd/debug" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -func TestCPU(t *testing.T) { - // Create a temporary file. - file, err := ioutil.TempFile("", "lxd-util-") - assert.NoError(t, err) - file.Close() - defer os.Remove(file.Name()) - - stop, err := debug.Start(debug.CPU(file.Name())) - require.NoError(t, err) - stop() - - // The CPU profiling data actually exists on disk. - _, err = os.Stat(file.Name()) - assert.NoError(t, err) -} - -func TestCPU_CannotCreateFile(t *testing.T) { - stop, err := debug.Start(debug.CPU("/a/path/that/does/not/exists")) - assert.Contains(t, err.Error(), "Error opening cpu profile file") - stop() -} diff --git a/lxd/debug/goroutines.go b/lxd/debug/goroutines.go deleted file mode 100644 index fd8919fb1..000000000 --- a/lxd/debug/goroutines.go +++ /dev/null @@ -1,34 +0,0 @@ -package debug - -import ( - "time" - - "github.com/lxc/lxd/lxd/task" - "github.com/lxc/lxd/shared/logger" - "golang.org/x/net/context" -) - -// Goroutines starts a task to print the goroutines stack at the given interval. -func Goroutines(seconds int) Activity { - return func() (activityFunc, error) { - if seconds <= 0 { - return nil, nil - } - - schedule := task.Every(time.Duration(seconds) * time.Second) - - f := func(ctx context.Context) { - stop, _ := task.Start(goroutinesTaskFunc, schedule) - <-ctx.Done() - - // Stop the task, giving it some little time to finish - // if it's in the middle of a print. - stop(100 * time.Millisecond) - } - return f, nil - } -} - -func goroutinesTaskFunc(context.Context) { - logger.Debugf(logger.GetStack()) -} diff --git a/lxd/debug/memory.go b/lxd/debug/memory.go deleted file mode 100644 index 6926cc515..000000000 --- a/lxd/debug/memory.go +++ /dev/null @@ -1,58 +0,0 @@ -package debug - -import ( - "os" - "os/signal" - "runtime/pprof" - "syscall" - - "github.com/lxc/lxd/shared/logger" - "golang.org/x/net/context" -) - -// Memory is a debug activity that perpetually watches for SIGUSR1 signals and -// dumps the memory to the given file whenever the signal is received. -// -// If the given filename is the empty string, no profiler is started. -func Memory(filename string) Activity { - return func() (activityFunc, error) { - if filename == "" { - return nil, nil - } - - signals := make(chan os.Signal, 1) - signal.Notify(signals, syscall.SIGUSR1) - - f := func(ctx context.Context) { - memoryWatcher(ctx, signals, filename) - signal.Stop(signals) - } - - return f, nil - } -} - -// Watch for SIGUSR1 and trigger memoryDump(). -func memoryWatcher(ctx context.Context, signals <-chan os.Signal, filename string) { - for { - select { - case sig := <-signals: - logger.Debugf("Received '%s signal', dumping memory", sig) - memoryDump(filename) - case <-ctx.Done(): - logger.Debugf("Shutdown memory profiler") - return - } - } -} - -// Dump the current memory info to the given file. -func memoryDump(filename string) { - f, err := os.Create(filename) - if err != nil { - logger.Debugf("Error opening memory profile file '%s': %s", filename, err) - return - } - pprof.WriteHeapProfile(f) - f.Close() -} diff --git a/lxd/debug/memory_test.go b/lxd/debug/memory_test.go deleted file mode 100644 index 9a8f89f7e..000000000 --- a/lxd/debug/memory_test.go +++ /dev/null @@ -1,54 +0,0 @@ -package debug_test - -import ( - "io/ioutil" - "os" - "syscall" - "testing" - "time" - - log "github.com/lxc/lxd/shared/log15" - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" - - "github.com/lxc/lxd/lxd/debug" - "github.com/lxc/lxd/shared/logging" -) - -func TestMemory(t *testing.T) { - // Create a logger that will block when emitting records. - records := make(chan *log.Record) - logger := log.New() - logger.SetHandler(log.ChannelHandler(records)) - defer logging.SetLogger(logger)() - - // Create a temporary file. - file, err := ioutil.TempFile("", "lxd-util-") - assert.NoError(t, err) - file.Close() - defer os.Remove(file.Name()) - - // Spawn the profiler and check that it dumps the memmory to the given - // file and stops when we close the shutdown channel. - stop, err := debug.Start(debug.Memory(file.Name())) - require.NoError(t, err) - syscall.Kill(os.Getpid(), syscall.SIGUSR1) - record := logging.WaitRecord(records, time.Second) - require.NotNil(t, record) - assert.Equal(t, "Received 'user defined signal 1 signal', dumping memory", record.Msg) - - go stop() - record = logging.WaitRecord(records, time.Second) - require.NotNil(t, record) - assert.Equal(t, "Shutdown memory profiler", record.Msg) - - // The memory dump actually exists on disk. - _, err = os.Stat(file.Name()) - assert.NoError(t, err) -} - -func TestMemory_EmptyFilename(t *testing.T) { - stop, err := debug.Start(debug.Memory("")) - require.NoError(t, err) - stop() -} diff --git a/lxd/debug/start.go b/lxd/debug/start.go deleted file mode 100644 index d908f4c6a..000000000 --- a/lxd/debug/start.go +++ /dev/null @@ -1,56 +0,0 @@ -package debug - -import ( - "sync" - - "golang.org/x/net/context" -) - -// Start the given LXD daemon debug activities. -// -// Return a function that can be used to stop all debug activities that were -// started, along with an error if any activity could not be started. -func Start(activities ...Activity) (func(), error) { - // First create the debug activities functions that will be run in - // individual goroutines. If any error happens here we bail out before - // actually spawning any activity. - functions := make([]activityFunc, len(activities)) - for i, activity := range activities { - f, err := activity() - if err != nil { - return func() {}, err - } - functions[i] = f - } - - // Now spawn the debug activities. - ctx, cancel := context.WithCancel(context.Background()) - wg := sync.WaitGroup{} - for i := range functions { - f := functions[i] - if f == nil { - // There's actually nothing to execute. - continue - } - wg.Add(1) - go func() { - f(ctx) - wg.Done() - }() - } - - stop := func() { - cancel() - wg.Wait() - } - return stop, nil -} - -// Activity creates a specific debug activity function, returning an error if it -// can't be created for some reason. -type Activity func() (activityFunc, error) - -// A function that executes a specific debug activity. -// -// It must terminate gracefully whenever the given context is done. -type activityFunc func(context.Context) diff --git a/lxd/endpoints/endpoints.go b/lxd/endpoints/endpoints.go index 4b4192670..ea9bc0f6a 100644 --- a/lxd/endpoints/endpoints.go +++ b/lxd/endpoints/endpoints.go @@ -46,6 +46,11 @@ type Config struct { // // It can be updated after the endpoints are up using UpdateNetworkAddress(). NetworkAddress string + + // DebugSetAddress sets the address for the pprof endpoint. + // + // It can be updated after the endpoints are up using UpdateDebugAddress(). + DebugAddress string } // Up brings up all applicable LXD endpoints and starts accepting HTTP @@ -140,6 +145,7 @@ func (e *Endpoints) up(config *Config) error { devlxd: config.DevLxdServer, local: config.RestServer, network: config.RestServer, + pprof: pprofCreateServer(), } e.cert = config.Cert @@ -177,6 +183,16 @@ func (e *Endpoints) up(config *Config) error { e.listeners[network] = networkCreateListener(config.NetworkAddress, e.cert) } + if config.DebugAddress != "" { + e.listeners[pprof], err = pprofCreateListener(config.DebugAddress) + if err != nil { + return err + } + + logger.Infof("Starting pprof handler:") + e.serveHTTP(pprof) + } + logger.Infof("Starting /dev/lxd handler:") e.serveHTTP(devlxd) @@ -283,6 +299,7 @@ const ( local kind = iota devlxd network + pprof ) // Human-readable descriptions of the various kinds of endpoints. @@ -290,4 +307,5 @@ var descriptions = map[kind]string{ local: "Unix socket", devlxd: "devlxd socket", network: "TCP socket", + pprof: "pprof socket", } diff --git a/lxd/endpoints/pprof.go b/lxd/endpoints/pprof.go new file mode 100644 index 000000000..e9a3181f1 --- /dev/null +++ b/lxd/endpoints/pprof.go @@ -0,0 +1,109 @@ +package endpoints + +import ( + "fmt" + "net" + "net/http" + "time" + + "github.com/lxc/lxd/lxd/util" + "github.com/lxc/lxd/shared/logger" + + _ "net/http/pprof" // pprof magic +) + +func pprofCreateServer() *http.Server { + // Undo the magic that importing pprof does + pprofMux := http.DefaultServeMux + http.DefaultServeMux = http.NewServeMux() + + // Setup an http server + srv := &http.Server{ + Handler: pprofMux, + } + + return srv +} + +func pprofCreateListener(address string) (net.Listener, error) { + return net.Listen("tcp", address) +} + +// PprofAddress returns the network addresss of the pprof endpoint, or an empty string if there's no pprof endpoint +func (e *Endpoints) PprofAddress() string { + e.mu.RLock() + defer e.mu.RUnlock() + + listener := e.listeners[pprof] + if listener == nil { + return "" + } + + return listener.Addr().String() +} + +// PprofUpdateAddress updates the address for the pprof endpoint, shutting it down and restarting it. +func (e *Endpoints) PprofUpdateAddress(address string) error { + if address != "" { + address = util.CanonicalNetworkAddress(address) + } + + oldAddress := e.NetworkAddress() + if address == oldAddress { + return nil + } + + logger.Infof("Update pprof address") + + e.mu.Lock() + defer e.mu.Unlock() + + // Close the previous socket + e.closeListener(pprof) + + // If turning off listening, we're done + if address == "" { + return nil + } + + // Attempt to setup the new listening socket + getListener := func(address string) (*net.Listener, error) { + var err error + var listener net.Listener + + for i := 0; i < 10; i++ { // Ten retries over a second seems reasonable. + listener, err = net.Listen("tcp", address) + if err == nil { + break + } + + time.Sleep(100 * time.Millisecond) + } + + if err != nil { + return nil, fmt.Errorf("Cannot listen on http socket: %v", err) + } + + return &listener, nil + } + + // If setting a new address, setup the listener + if address != "" { + listener, err := getListener(address) + if err != nil { + // Attempt to revert to the previous address + listener, err1 := getListener(oldAddress) + if err1 == nil { + e.listeners[pprof] = *listener + e.serveHTTP(pprof) + } + + return err + } + + e.listeners[pprof] = *listener + e.serveHTTP(pprof) + } + + return nil +} diff --git a/lxd/main_daemon.go b/lxd/main_daemon.go index 2a5d324ed..d6b3b1c9f 100644 --- a/lxd/main_daemon.go +++ b/lxd/main_daemon.go @@ -9,7 +9,6 @@ import ( "github.com/spf13/cobra" - dbg "github.com/lxc/lxd/lxd/debug" "github.com/lxc/lxd/lxd/sys" "github.com/lxc/lxd/shared/logger" ) @@ -19,11 +18,6 @@ type cmdDaemon struct { // Common options flagGroup string - - // Debug options - flagCPUProfile string - flagMemoryProfile string - flagPrintGoroutines int } func (c *cmdDaemon) Command() *cobra.Command { @@ -41,9 +35,6 @@ func (c *cmdDaemon) Command() *cobra.Command { ` cmd.RunE = c.Run cmd.Flags().StringVar(&c.flagGroup, "group", "", "The group of users that will be allowed to talk to LXD"+"``") - cmd.Flags().StringVar(&c.flagCPUProfile, "cpu-profile", "", "Enable CPU profiling, writing into the specified file"+"``") - cmd.Flags().StringVar(&c.flagMemoryProfile, "memory-profile", "", "Enable memory profiling, writing into the specified file"+"``") - cmd.Flags().IntVar(&c.flagPrintGoroutines, "print-goroutines", 0, "How often to print all the goroutines"+"``") return cmd } @@ -54,18 +45,6 @@ func (c *cmdDaemon) Run(cmd *cobra.Command, args []string) error { return fmt.Errorf("This must be run as root") } - // Start debug activities as per command line flags, if any. - stop, err := dbg.Start( - dbg.CPU(c.flagCPUProfile), - dbg.Memory(c.flagMemoryProfile), - dbg.Goroutines(c.flagPrintGoroutines), - ) - if err != nil { - return err - } - - defer stop() - neededPrograms := []string{"setfacl", "rsync", "tar", "unsquashfs", "xz"} for _, p := range neededPrograms { _, err := exec.LookPath(p) @@ -79,7 +58,7 @@ func (c *cmdDaemon) Run(cmd *cobra.Command, args []string) error { conf.Trace = c.global.flagLogTrace d := NewDaemon(conf, sys.DefaultOS()) - err = d.Init() + err := d.Init() if err != nil { return err } diff --git a/lxd/node/config.go b/lxd/node/config.go index 087da756c..186c8056a 100644 --- a/lxd/node/config.go +++ b/lxd/node/config.go @@ -37,6 +37,11 @@ func (c *Config) HTTPSAddress() string { return c.m.GetString("core.https_address") } +// DebugAddress returns the address and port to setup the pprof listener on +func (c *Config) DebugAddress() string { + return c.m.GetString("core.debug_address") +} + // MAASMachine returns the MAAS machine this instance is associated with, if // any. func (c *Config) MAASMachine() string { @@ -60,6 +65,7 @@ func (c *Config) Patch(patch map[string]interface{}) (map[string]string, error) for name, value := range patch { values[name] = value } + return c.update(values) } @@ -75,9 +81,26 @@ func HTTPSAddress(node *db.Node) (string, error) { if err != nil { return "", err } + return config.HTTPSAddress(), nil } +// DebugAddress is a convenience for loading the node configuration and +// returning the value of core.debug_address. +func DebugAddress(node *db.Node) (string, error) { + var config *Config + err := node.Transaction(func(tx *db.NodeTx) error { + var err error + config, err = ConfigLoad(tx) + return err + }) + if err != nil { + return "", err + } + + return config.DebugAddress(), nil +} + func (c *Config) update(values map[string]interface{}) (map[string]string, error) { changed, err := c.m.Change(values) if err != nil { @@ -94,9 +117,12 @@ func (c *Config) update(values map[string]interface{}) (map[string]string, error // ConfigSchema defines available server configuration keys. var ConfigSchema = config.Schema{ - // Network address for this LXD server. + // Network address for this LXD server "core.https_address": {}, - // MAAS machine this LXD instance is associated with. + // Network address for the debug server + "core.debug_address": {}, + + // MAAS machine this LXD instance is associated with "maas.machine": {}, } diff --git a/scripts/bash/lxd-client b/scripts/bash/lxd-client index 54d8d7eb8..ceed02fa2 100644 --- a/scripts/bash/lxd-client +++ b/scripts/bash/lxd-client @@ -68,7 +68,7 @@ _have lxc && { core.https_allowed_headers core.https_allowed_methods \ core.https_allowed_origin core.macaroon.endpoint core.proxy_https \ core.proxy_http core.proxy_ignore_hosts core.trust_password \ - cluster.offline_threshold \ + core.debug_address cluster.offline_threshold \ images.auto_update_cached images.auto_update_interval \ images.compression_algorithm images.remote_cache_expiry \ maas.api.url maas.api.key maas.machine" diff --git a/shared/version/api.go b/shared/version/api.go index 3a673206f..2b83d1291 100644 --- a/shared/version/api.go +++ b/shared/version/api.go @@ -113,6 +113,7 @@ var APIExtensions = []string{ "network_state", "proxy_unix_dac_properties", "container_protection_delete", + "pprof_http", } // APIExtensionsCount returns the number of available API extensions. diff --git a/test/main.sh b/test/main.sh index 34ac7ee58..352141169 100755 --- a/test/main.sh +++ b/test/main.sh @@ -188,8 +188,6 @@ run_test test_devlxd "/dev/lxd" run_test test_fuidshift "fuidshift" run_test test_migration "migration" run_test test_fdleak "fd leak" -run_test test_cpu_profiling "CPU profiling" -run_test test_mem_profiling "memory profiling" run_test test_storage "storage" run_test test_init_auto "lxd init auto" run_test test_init_interactive "lxd init interactive" diff --git a/test/suites/profiling.sh b/test/suites/profiling.sh deleted file mode 100644 index 006d1badc..000000000 --- a/test/suites/profiling.sh +++ /dev/null @@ -1,44 +0,0 @@ -test_cpu_profiling() { - LXD3_DIR=$(mktemp -d -p "${TEST_DIR}" XXX) - chmod +x "${LXD3_DIR}" - spawn_lxd "${LXD3_DIR}" false --cpu-profile "${LXD3_DIR}/cpu.out" - lxdpid=$(cat "${LXD3_DIR}/lxd.pid") - kill -TERM "${lxdpid}" - wait "${lxdpid}" - #|| true - export PPROF_TMPDIR="${TEST_DIR}/pprof" - echo top5 | go tool pprof "$(which lxd)" "${LXD3_DIR}/cpu.out" - echo "" - - # Cleanup following manual kill - rm -f "${LXD3_DIR}/unix.socket" - find "${LXD3_DIR}" -name shmounts -exec "umount" "-l" "{}" \; >/dev/null 2>&1 || true - - kill_lxd "${LXD3_DIR}" -} - -test_mem_profiling() { - LXD4_DIR=$(mktemp -d -p "${TEST_DIR}" XXX) - chmod +x "${LXD4_DIR}" - spawn_lxd "${LXD4_DIR}" false --memory-profile "${LXD4_DIR}/mem" - lxdpid=$(cat "${LXD4_DIR}/lxd.pid") - - if [ -e "${LXD4_DIR}/mem" ]; then - false - fi - - kill -USR1 "${lxdpid}" - - timeout=50 - while [ "${timeout}" != "0" ]; do - [ -e "${LXD4_DIR}/mem" ] && break - sleep 0.1 - timeout=$((timeout-1)) - done - - export PPROF_TMPDIR="${TEST_DIR}/pprof" - echo top5 | go tool pprof "$(which lxd)" "${LXD4_DIR}/mem" - echo "" - - kill_lxd "${LXD4_DIR}" -} diff --git a/test/suites/static_analysis.sh b/test/suites/static_analysis.sh index 2aa61bf96..8ef94b506 100644 --- a/test/suites/static_analysis.sh +++ b/test/suites/static_analysis.sh @@ -72,7 +72,6 @@ test_static_analysis() { golint -set_exit_status lxd/db/node golint -set_exit_status lxd/db/query golint -set_exit_status lxd/db/schema - golint -set_exit_status lxd/debug golint -set_exit_status lxd/endpoints golint -set_exit_status lxd/maas #golint -set_exit_status lxd/migration
_______________________________________________ lxc-devel mailing list lxc-devel@lists.linuxcontainers.org http://lists.linuxcontainers.org/listinfo/lxc-devel