diff --git a/container/docker/factory.go b/container/docker/factory.go index ec5c26e0..b8cd4ad2 100644 --- a/container/docker/factory.go +++ b/container/docker/factory.go @@ -149,6 +149,10 @@ func (self *dockerFactory) CanHandleAndAccept(name string) (bool, bool, error) { return true, canAccept, nil } +func (self *dockerFactory) DebugInfo() map[string][]string { + return map[string][]string{} +} + func parseDockerVersion(full_version_string string) ([]int, error) { version_regexp_string := "(\\d+)\\.(\\d+)\\.(\\d+)" version_re := regexp.MustCompile(version_regexp_string) diff --git a/container/factory.go b/container/factory.go index 04a26b17..d5ab8290 100644 --- a/container/factory.go +++ b/container/factory.go @@ -30,6 +30,9 @@ type ContainerHandlerFactory interface { // Name of the factory. String() string + + // Returns debugging information. Map of lines per category. + DebugInfo() map[string][]string } // TODO(vmarmol): Consider not making this global. @@ -90,3 +93,17 @@ func ClearContainerHandlerFactories() { factories = make([]ContainerHandlerFactory, 0, 4) } + +func DebugInfo() map[string][]string { + factoriesLock.RLock() + defer factoriesLock.RUnlock() + + // Get debug information for all factories. + out := make(map[string][]string) + for _, factory := range factories { + for k, v := range factory.DebugInfo() { + out[k] = v + } + } + return out +} diff --git a/container/factory_test.go b/container/factory_test.go index 535fcb07..991c365a 100644 --- a/container/factory_test.go +++ b/container/factory_test.go @@ -31,6 +31,10 @@ func (self *mockContainerHandlerFactory) String() string { return self.Name } +func (self *mockContainerHandlerFactory) DebugInfo() map[string][]string { + return map[string][]string{} +} + func (self *mockContainerHandlerFactory) CanHandleAndAccept(name string) (bool, bool, error) { return self.CanHandleValue, self.CanAcceptValue, nil } diff --git a/container/raw/factory.go b/container/raw/factory.go index 27020eeb..be1c799b 100644 --- a/container/raw/factory.go +++ b/container/raw/factory.go @@ -36,6 +36,9 @@ type rawFactory struct { // Information about mounted filesystems. fsInfo fs.FsInfo + + // Watcher for inotify events. + watcher *InotifyWatcher } func (self *rawFactory) String() string { @@ -43,7 +46,7 @@ func (self *rawFactory) String() string { } func (self *rawFactory) NewContainerHandler(name string) (container.ContainerHandler, error) { - return newRawContainerHandler(name, self.cgroupSubsystems, self.machineInfoFactory, self.fsInfo) + return newRawContainerHandler(name, self.cgroupSubsystems, self.machineInfoFactory, self.fsInfo, self.watcher) } // The raw factory can handle any container. If --docker_only is set to false, non-docker containers are ignored. @@ -52,6 +55,23 @@ func (self *rawFactory) CanHandleAndAccept(name string) (bool, bool, error) { return true, accept, nil } +func (self *rawFactory) DebugInfo() map[string][]string { + out := make(map[string][]string) + + // Get information about inotify watches. + watches := self.watcher.GetWatches() + lines := make([]string, 0, len(watches)) + for containerName, cgroupWatches := range watches { + lines = append(lines, fmt.Sprintf("%s:", containerName)) + for _, cg := range cgroupWatches { + lines = append(lines, fmt.Sprintf("\t%s", cg)) + } + } + out["Inotify watches"] = lines + + return out +} + func Register(machineInfoFactory info.MachineInfoFactory, fsInfo fs.FsInfo) error { cgroupSubsystems, err := libcontainer.GetCgroupSubsystems() if err != nil { @@ -61,11 +81,17 @@ func Register(machineInfoFactory info.MachineInfoFactory, fsInfo fs.FsInfo) erro return fmt.Errorf("failed to find supported cgroup mounts for the raw factory") } + watcher, err := NewInotifyWatcher() + if err != nil { + return err + } + glog.Infof("Registering Raw factory") factory := &rawFactory{ machineInfoFactory: machineInfoFactory, fsInfo: fsInfo, cgroupSubsystems: &cgroupSubsystems, + watcher: watcher, } container.RegisterContainerHandlerFactory(factory) return nil diff --git a/container/raw/handler.go b/container/raw/handler.go index d3c1029c..160477f6 100644 --- a/container/raw/handler.go +++ b/container/raw/handler.go @@ -62,7 +62,7 @@ type rawContainerHandler struct { externalMounts []mount } -func newRawContainerHandler(name string, cgroupSubsystems *libcontainer.CgroupSubsystems, machineInfoFactory info.MachineInfoFactory, fsInfo fs.FsInfo) (container.ContainerHandler, error) { +func newRawContainerHandler(name string, cgroupSubsystems *libcontainer.CgroupSubsystems, machineInfoFactory info.MachineInfoFactory, fsInfo fs.FsInfo, watcher *InotifyWatcher) (container.ContainerHandler, error) { // Create the cgroup paths. cgroupPaths := make(map[string]string, len(cgroupSubsystems.MountPoints)) for key, val := range cgroupSubsystems.MountPoints { @@ -106,6 +106,7 @@ func newRawContainerHandler(name string, cgroupSubsystems *libcontainer.CgroupSu fsInfo: fsInfo, hasNetwork: hasNetwork, externalMounts: externalMounts, + watcher: watcher, }, nil } @@ -501,15 +502,6 @@ func (self *rawContainerHandler) processEvent(event *inotify.Event, events chan } func (self *rawContainerHandler) WatchSubcontainers(events chan container.SubcontainerEvent) error { - // Lazily initialize the watcher so we don't use it when not asked to. - if self.watcher == nil { - w, err := NewInotifyWatcher() - if err != nil { - return err - } - self.watcher = w - } - // Watch this container (all its cgroups) and all subdirectories. for _, cgroupPath := range self.cgroupPaths { _, err := self.watchDirectory(cgroupPath, self.name) @@ -533,7 +525,6 @@ func (self *rawContainerHandler) WatchSubcontainers(events chan container.Subcon err := self.watcher.Close() if err == nil { self.stopWatcher <- err - self.watcher = nil return } } @@ -544,10 +535,6 @@ func (self *rawContainerHandler) WatchSubcontainers(events chan container.Subcon } func (self *rawContainerHandler) StopWatchingSubcontainers() error { - if self.watcher == nil { - return fmt.Errorf("can't stop watch that has not started for container %q", self.name) - } - // Rendezvous with the watcher thread. self.stopWatcher <- nil return <-self.stopWatcher diff --git a/manager/manager.go b/manager/manager.go index 6b9e3715..d06f8e80 100644 --- a/manager/manager.go +++ b/manager/manager.go @@ -107,6 +107,9 @@ type Manager interface { // Get details about interesting docker images. DockerImages() ([]DockerImage, error) + + // Returns debugging information. Map of lines per category. + DebugInfo() map[string][]string } // New takes a memory storage and returns a new manager. @@ -1131,3 +1134,7 @@ func (m *manager) DockerInfo() (DockerStatus, error) { } return out, nil } + +func (m *manager) DebugInfo() map[string][]string { + return container.DebugInfo() +} diff --git a/validate/validate.go b/validate/validate.go index 5534d0de..264b3444 100644 --- a/validate/validate.go +++ b/validate/validate.go @@ -313,6 +313,13 @@ func HandleRequest(w http.ResponseWriter, containerManager manager.Manager) erro ioSchedulerValidation, desc := validateIoScheduler(containerManager) out += fmt.Sprintf(OutputFormat, "Block device setup", ioSchedulerValidation, desc) + + // Output debug info. + debugInfo := containerManager.DebugInfo() + for category, lines := range debugInfo { + out += fmt.Sprintf(OutputFormat, category, "", strings.Join(lines, "\n\t")) + } + _, err = w.Write([]byte(out)) return err }