Merge pull request #670 from rjnagal/docker

Add --docker_only flag to enable tracking for only docker containers & root.
This commit is contained in:
Victor Marmol 2015-04-30 17:27:50 -07:00
commit 95f1ee9c40
7 changed files with 95 additions and 21 deletions

View File

@ -134,17 +134,19 @@ func FullContainerName(dockerId string) string {
}
// Docker handles all containers under /docker
func (self *dockerFactory) CanHandle(name string) (bool, error) {
func (self *dockerFactory) CanHandleAndAccept(name string) (bool, bool, error) {
// docker factory accepts all containers it can handle.
canAccept := true
// Check if the container is known to docker and it is active.
id := ContainerNameToDockerId(name)
// We assume that if Inspect fails then the container is not known to docker.
ctnr, err := self.client.InspectContainer(id)
if err != nil || !ctnr.State.Running {
return false, fmt.Errorf("error inspecting container: %v", err)
return false, canAccept, fmt.Errorf("error inspecting container: %v", err)
}
return true, nil
return true, canAccept, nil
}
func parseDockerVersion(full_version_string string) ([]int, error) {

View File

@ -22,11 +22,11 @@ import (
)
type ContainerHandlerFactory interface {
// Create a new ContainerHandler using this factory. CanHandle() must have returned true.
NewContainerHandler(name string) (ContainerHandler, error)
// Create a new ContainerHandler using this factory. CanHandleAndAccept() must have returned true.
NewContainerHandler(name string) (c ContainerHandler, err error)
// Returns whether this factory can handle the specified container.
CanHandle(name string) (bool, error)
// Returns whether this factory can handle and accept the specified container.
CanHandleAndAccept(name string) (handle bool, accept bool, err error)
// Name of the factory.
String() string
@ -57,25 +57,30 @@ func HasFactories() bool {
}
// Create a new ContainerHandler for the specified container.
func NewContainerHandler(name string) (ContainerHandler, error) {
func NewContainerHandler(name string) (ContainerHandler, bool, error) {
factoriesLock.RLock()
defer factoriesLock.RUnlock()
// Create the ContainerHandler with the first factory that supports it.
for _, factory := range factories {
canHandle, err := factory.CanHandle(name)
canHandle, canAccept, err := factory.CanHandleAndAccept(name)
if err != nil {
glog.V(4).Infof("Error trying to work out if we can hande %s: %v", name, err)
glog.V(4).Infof("Error trying to work out if we can handle %s: %v", name, err)
}
if canHandle {
if !canAccept {
glog.V(3).Infof("Factory %q can handle container %q, but ignoring.", factory, name)
return nil, false, nil
}
glog.V(3).Infof("Using factory %q for container %q", factory, name)
return factory.NewContainerHandler(name)
handle, err := factory.NewContainerHandler(name)
return handle, canAccept, err
} else {
glog.V(4).Infof("Factory %q was unable to handle container %q", factory, name)
}
}
return nil, fmt.Errorf("no known factory can handle creation of container")
return nil, false, fmt.Errorf("no known factory can handle creation of container")
}
// Clear the known factories.

View File

@ -24,14 +24,15 @@ type mockContainerHandlerFactory struct {
mock.Mock
Name string
CanHandleValue bool
CanAcceptValue bool
}
func (self *mockContainerHandlerFactory) String() string {
return self.Name
}
func (self *mockContainerHandlerFactory) CanHandle(name string) (bool, error) {
return self.CanHandleValue, nil
func (self *mockContainerHandlerFactory) CanHandleAndAccept(name string) (bool, bool, error) {
return self.CanHandleValue, self.CanAcceptValue, nil
}
func (self *mockContainerHandlerFactory) NewContainerHandler(name string) (ContainerHandler, error) {
@ -50,6 +51,7 @@ func TestNewContainerHandler_FirstMatches(t *testing.T) {
allwaysYes := &mockContainerHandlerFactory{
Name: "yes",
CanHandleValue: true,
CanAcceptValue: true,
}
RegisterContainerHandlerFactory(allwaysYes)
@ -60,7 +62,7 @@ func TestNewContainerHandler_FirstMatches(t *testing.T) {
}
allwaysYes.On("NewContainerHandler", testContainerName).Return(mockContainer, nil)
cont, err := NewContainerHandler(testContainerName)
cont, _, err := NewContainerHandler(testContainerName)
if err != nil {
t.Error(err)
}
@ -76,11 +78,13 @@ func TestNewContainerHandler_SecondMatches(t *testing.T) {
allwaysNo := &mockContainerHandlerFactory{
Name: "no",
CanHandleValue: false,
CanAcceptValue: true,
}
RegisterContainerHandlerFactory(allwaysNo)
allwaysYes := &mockContainerHandlerFactory{
Name: "yes",
CanHandleValue: true,
CanAcceptValue: true,
}
RegisterContainerHandlerFactory(allwaysYes)
@ -91,7 +95,7 @@ func TestNewContainerHandler_SecondMatches(t *testing.T) {
}
allwaysYes.On("NewContainerHandler", testContainerName).Return(mockContainer, nil)
cont, err := NewContainerHandler(testContainerName)
cont, _, err := NewContainerHandler(testContainerName)
if err != nil {
t.Error(err)
}
@ -107,16 +111,44 @@ func TestNewContainerHandler_NoneMatch(t *testing.T) {
allwaysNo1 := &mockContainerHandlerFactory{
Name: "no",
CanHandleValue: false,
CanAcceptValue: true,
}
RegisterContainerHandlerFactory(allwaysNo1)
allwaysNo2 := &mockContainerHandlerFactory{
Name: "no",
CanHandleValue: false,
CanAcceptValue: true,
}
RegisterContainerHandlerFactory(allwaysNo2)
_, err := NewContainerHandler(testContainerName)
_, _, err := NewContainerHandler(testContainerName)
if err == nil {
t.Error("Expected NewContainerHandler to fail")
}
}
func TestNewContainerHandler_Accept(t *testing.T) {
ClearContainerHandlerFactories()
// Register handler that can handle the container, but can't accept it.
cannotHandle := &mockContainerHandlerFactory{
Name: "no",
CanHandleValue: false,
CanAcceptValue: true,
}
RegisterContainerHandlerFactory(cannotHandle)
cannotAccept := &mockContainerHandlerFactory{
Name: "no",
CanHandleValue: true,
CanAcceptValue: false,
}
RegisterContainerHandlerFactory(cannotAccept)
_, accept, err := NewContainerHandler(testContainerName)
if err != nil {
t.Error("Expected NewContainerHandler to succeed")
}
if accept == true {
t.Error("Expected NewContainerHandler to ignore the container.")
}
}

View File

@ -15,6 +15,7 @@
package raw
import (
"flag"
"fmt"
"github.com/golang/glog"
@ -24,6 +25,8 @@ import (
info "github.com/google/cadvisor/info/v1"
)
var dockerOnly = flag.Bool("docker_only", false, "Only report docker containers in addition to root stats")
type rawFactory struct {
// Factory for machine information.
machineInfoFactory info.MachineInfoFactory
@ -43,9 +46,10 @@ func (self *rawFactory) NewContainerHandler(name string) (container.ContainerHan
return newRawContainerHandler(name, self.cgroupSubsystems, self.machineInfoFactory, self.fsInfo)
}
// The raw factory can handle any container.
func (self *rawFactory) CanHandle(name string) (bool, error) {
return true, nil
// The raw factory can handle any container. If --docker_only is set to false, non-docker containers are ignored.
func (self *rawFactory) CanHandleAndAccept(name string) (bool, bool, error) {
accept := name == "/" || !*dockerOnly
return true, accept, nil
}
func Register(machineInfoFactory info.MachineInfoFactory, fsInfo fs.FsInfo) error {

View File

@ -73,6 +73,9 @@ type Manager interface {
// Get info for all requested containers based on the request options.
GetRequestedContainersInfo(containerName string, options v2.RequestOptions) (map[string]*info.ContainerInfo, error)
// Returns true if the named container exists.
Exists(containerName string) bool
// Get information about the machine.
GetMachineInfo() (*info.MachineInfo, error)
@ -619,12 +622,32 @@ func (m *manager) GetVersionInfo() (*info.VersionInfo, error) {
return &m.versionInfo, nil
}
func (m *manager) Exists(containerName string) bool {
m.containersLock.Lock()
defer m.containersLock.Unlock()
namespacedName := namespacedContainerName{
Name: containerName,
}
_, ok := m.containers[namespacedName]
if ok {
return true
}
return false
}
// Create a container.
func (m *manager) createContainer(containerName string) error {
handler, err := container.NewContainerHandler(containerName)
handler, accept, err := container.NewContainerHandler(containerName)
if err != nil {
return err
}
if !accept {
// ignoring this container.
glog.V(4).Infof("ignoring container %q", containerName)
return nil
}
logUsage := *logCadvisorUsage && containerName == m.cadvisorContainer
cont, err := newContainerData(containerName, m.memoryStorage, handler, m.loadReader, logUsage)
if err != nil {

View File

@ -70,6 +70,11 @@ func (c *ManagerMock) GetRequestedContainersInfo(containerName string, options v
return args.Get(0).(map[string]*info.ContainerInfo), args.Error(1)
}
func (c *ManagerMock) Exists(name string) bool {
args := c.Called(name)
return args.Get(0).(bool)
}
func (c *ManagerMock) WatchForEvents(queryuest *events.Request, passedChannel chan *info.Event) error {
args := c.Called(queryuest, passedChannel)
return args.Error(0)

View File

@ -216,6 +216,9 @@ func serveContainersPage(m manager.Manager, w http.ResponseWriter, u *url.URL) e
// Build the links for the subcontainers.
subcontainerLinks := make([]link, 0, len(cont.Subcontainers))
for _, sub := range cont.Subcontainers {
if !m.Exists(sub.Name) {
continue
}
subcontainerLinks = append(subcontainerLinks, link{
Text: getContainerDisplayName(sub),
Link: path.Join(ContainersPage, sub.Name),