From 750b5b464e63d0e64b3b177d56108c00bbf807e3 Mon Sep 17 00:00:00 2001 From: Nan Deng Date: Sat, 14 Jun 2014 15:31:18 -0700 Subject: [PATCH 1/7] storage --- storage/storage.go | 79 ++++++++++++++++++++++++++++++++++++++++ storage/storage_test.go | 81 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 160 insertions(+) create mode 100644 storage/storage.go create mode 100644 storage/storage_test.go diff --git a/storage/storage.go b/storage/storage.go new file mode 100644 index 00000000..253881ae --- /dev/null +++ b/storage/storage.go @@ -0,0 +1,79 @@ +// Copyright 2014 Google Inc. All Rights Reserved. +// +// 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 storage + +import ( + "fmt" + "sync" + + "github.com/google/cadvisor/info" +) + +type ContainerStatsWriter interface { + Write(ref info.ContainerReference, stats *info.ContainerStats) error +} + +// Database config which should contain all information used to connect to +// all/most databases +type Config struct { + Engine string `json:"engine,omitempty"` + Host string `json:"host,omitempty"` + Port int `json:"port,omitempty"` + Username string `json:"username,omitempty"` + Password string `json:"password,omitempty"` + Database string `json:"database,omitempty"` + Params map[string]string `json:"parameters,omitempty"` +} + +type ContainerStatsWriterFactory interface { + String() string + New(config *Config) (ContainerStatsWriter, error) +} + +type containerStatsWriterFactoryManager struct { + lock sync.RWMutex + factories map[string]ContainerStatsWriterFactory +} + +func (self *containerStatsWriterFactoryManager) Register(factory ContainerStatsWriterFactory) { + self.lock.Lock() + defer self.lock.Unlock() + + if self.factories == nil { + self.factories = make(map[string]ContainerStatsWriterFactory, 8) + } + + self.factories[factory.String()] = factory +} + +func (self *containerStatsWriterFactoryManager) New(config *Config) (ContainerStatsWriter, error) { + self.lock.RLock() + defer self.lock.RUnlock() + + if factory, ok := self.factories[config.Engine]; ok { + return factory.New(config) + } + return nil, fmt.Errorf("unknown database %v", config.Engine) +} + +var globalContainerStatsWriterFactoryManager containerStatsWriterFactoryManager + +func RegisterContainerStatsWriterFactory(factory ContainerStatsWriterFactory) { + globalContainerStatsWriterFactoryManager.Register(factory) +} + +func NewContainerStatsWriter(config *Config) (ContainerStatsWriter, error) { + return globalContainerStatsWriterFactoryManager.New(config) +} diff --git a/storage/storage_test.go b/storage/storage_test.go new file mode 100644 index 00000000..2c9ffa0b --- /dev/null +++ b/storage/storage_test.go @@ -0,0 +1,81 @@ +package storage + +import ( + "sync" + "testing" + + "github.com/google/cadvisor/info" + "github.com/stretchr/testify/mock" +) + +type mockContainerStatsWriter struct { + storageName string + mock.Mock +} + +func (self *mockContainerStatsWriter) Write( + ref info.ContainerReference, + stats *info.ContainerStats, +) error { + args := self.Called(ref, stats) + return args.Error(0) +} + +type mockContainerStatsWriterFactory struct { + name string +} + +func (self *mockContainerStatsWriterFactory) String() string { + return self.name +} + +func (self *mockContainerStatsWriterFactory) New( + config *Config, +) (ContainerStatsWriter, error) { + mockWriter := &mockContainerStatsWriter{ + storageName: self.name, + } + return mockWriter, nil +} + +func TestContainerStatsWriterFactoryManager(t *testing.T) { + factoryNames := []string{ + "abc", + "bcd", + } + + wg := sync.WaitGroup{} + + for _, name := range factoryNames { + wg.Add(1) + go func(n string) { + defer wg.Done() + factory := &mockContainerStatsWriterFactory{ + name: n, + } + RegisterContainerStatsWriterFactory(factory) + }(name) + } + wg.Wait() + for _, name := range factoryNames { + wg.Add(1) + config := &Config{ + Engine: name, + } + go func(n string) { + defer wg.Done() + writer, err := NewContainerStatsWriter(config) + if err != nil { + t.Error(err) + } + if mw, ok := writer.(*mockContainerStatsWriter); ok { + if mw.storageName != n { + t.Errorf("wrong writer. should be %v, got %v", n, mw.storageName) + } + } else { + t.Errorf("wrong writer: unknown type") + } + }(name) + } + wg.Wait() +} From 103e83fd862363726995c640b30879b2a7b3ad99 Mon Sep 17 00:00:00 2001 From: Nan Deng Date: Sat, 14 Jun 2014 16:29:29 -0700 Subject: [PATCH 2/7] stats processor --- .travis.yml | 1 + manager/statsproc.go | 61 ++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 62 insertions(+) create mode 100644 manager/statsproc.go diff --git a/.travis.yml b/.travis.yml index d3718380..43ef6320 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,6 +6,7 @@ before_script: - go get github.com/kr/pretty script: - go test -v -race github.com/google/cadvisor/container + - go test -v -race github.com/google/cadvisor/storage - go test -v github.com/google/cadvisor/info - go test -v github.com/google/cadvisor/client - go test -v github.com/google/cadvisor/sampling diff --git a/manager/statsproc.go b/manager/statsproc.go new file mode 100644 index 00000000..17f38ff3 --- /dev/null +++ b/manager/statsproc.go @@ -0,0 +1,61 @@ +// Copyright 2014 Google Inc. All Rights Reserved. +// +// 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 manager + +import ( + "log" + + "github.com/google/cadvisor/info" + "github.com/google/cadvisor/storage" +) + +type ContainerStats struct { + ContainerReference info.ContainerReference + Stats *info.ContainerStats + ResChan chan<- error +} + +type ContainerStatsProcessor interface { + StartStatsProcessors(numProcs int) (chan<- *ContainerStats, error) + StopAllProcessors() +} + +type containerStatsWriter struct { + config *storage.Config +} + +func (self *containerStatsWriter) StartStatsProcessors(numProcs int) (chan<- *ContainerStats, error) { + ch := make(chan *ContainerStats) + statsWriter, err := storage.NewContainerStatsWriter(self.config) + if err != nil { + return nil, err + } + for i := 0; i < numProcs; i++ { + go self.process(statsWriter, ch) + } + return ch, nil +} + +func (self *containerStatsWriter) process(statsWriter storage.ContainerStatsWriter, ch <-chan *ContainerStats) { + for stats := range ch { + err := statsWriter.Write(stats.ContainerReference, stats.Stats) + if err != nil { + log.Printf("unable to write stats: %v", err) + } + if stats.ResChan != nil { + stats.ResChan <- err + } + } +} From a8401c422e1c12b2aaf96f38eca065c9a9070a26 Mon Sep 17 00:00:00 2001 From: Nan Deng Date: Sat, 14 Jun 2014 17:22:06 -0700 Subject: [PATCH 3/7] stats writers --- cadvisor.go | 4 +++- manager/container.go | 19 +++++++++++++++---- manager/manager.go | 15 +++++++++++++-- manager/statsproc.go | 41 +++++++++++++++++++++++------------------ 4 files changed, 54 insertions(+), 25 deletions(-) diff --git a/cadvisor.go b/cadvisor.go index c145c74e..aabaa270 100644 --- a/cadvisor.go +++ b/cadvisor.go @@ -44,7 +44,9 @@ func main() { NumSamples: *argSampleSize, ResetPeriod: *argResetPeriod, }) - containerManager, err := manager.New() + + // TODO(monnand): Add stats writer for manager + containerManager, err := manager.New(nil) if err != nil { log.Fatalf("Failed to create a Container Manager: %s", err) } diff --git a/manager/container.go b/manager/container.go index 9431483c..ac7e03a2 100644 --- a/manager/container.go +++ b/manager/container.go @@ -43,9 +43,10 @@ type containerInfo struct { } type containerData struct { - handler container.ContainerHandler - info containerInfo - lock sync.Mutex + handler container.ContainerHandler + info containerInfo + statsChan chan<- *ContainerStats + lock sync.Mutex // Tells the container to stop. stop chan bool @@ -84,7 +85,7 @@ func (c *containerData) GetInfo() (*containerInfo, error) { return &ret, nil } -func NewContainerData(containerName string) (*containerData, error) { +func NewContainerData(containerName string, statsChan chan<- *ContainerStats) (*containerData, error) { cont := &containerData{} handler, err := container.NewContainerHandler(containerName) if err != nil { @@ -98,6 +99,7 @@ func NewContainerData(containerName string) (*containerData, error) { cont.info.Name = ref.Name cont.info.Aliases = ref.Aliases cont.info.Stats = list.New() + cont.statsChan = statsChan cont.stop = make(chan bool, 1) return cont, nil @@ -151,6 +153,15 @@ func (c *containerData) updateStats() error { if stats == nil { return nil } + if c.statsChan != nil { + ref, err := c.handler.ContainerReference() + if err == nil { + c.statsChan <- &ContainerStats{ + ContainerReference: ref, + Stats: stats, + } + } + } summary, err := c.handler.StatsSummary() if err != nil { return err diff --git a/manager/manager.go b/manager/manager.go index c223d5fd..c86bd830 100644 --- a/manager/manager.go +++ b/manager/manager.go @@ -22,6 +22,7 @@ import ( "github.com/google/cadvisor/container" "github.com/google/cadvisor/info" + "github.com/google/cadvisor/storage" ) type Manager interface { @@ -38,7 +39,7 @@ type Manager interface { GetVersionInfo() (*info.VersionInfo, error) } -func New() (Manager, error) { +func New(statsWriter storage.ContainerStatsWriter) (Manager, error) { newManager := &manager{} newManager.containers = make(map[string]*containerData) @@ -55,6 +56,15 @@ func New() (Manager, error) { } newManager.versionInfo = *versionInfo log.Printf("Version: %+v", newManager.versionInfo) + if statsWriter != nil { + // XXX(monnand): about numWorkers and queueLength, should we make it + // configurable? + ch, err := StartContainerStatsWriters(16, 64, statsWriter) + if err != nil { + return nil, err + } + newManager.statsChan = ch + } return newManager, nil } @@ -62,6 +72,7 @@ func New() (Manager, error) { type manager struct { containers map[string]*containerData containersLock sync.RWMutex + statsChan chan<- *ContainerStats machineInfo info.MachineInfo versionInfo info.VersionInfo } @@ -160,7 +171,7 @@ func (m *manager) GetVersionInfo() (*info.VersionInfo, error) { // Create a container. This expects to only be called from the global manager thread. func (m *manager) createContainer(containerName string) (*containerData, error) { - cont, err := NewContainerData(containerName) + cont, err := NewContainerData(containerName, m.statsChan) if err != nil { return nil, err } diff --git a/manager/statsproc.go b/manager/statsproc.go index 17f38ff3..6011f3ec 100644 --- a/manager/statsproc.go +++ b/manager/statsproc.go @@ -15,6 +15,7 @@ package manager import ( + "fmt" "log" "github.com/google/cadvisor/info" @@ -24,31 +25,35 @@ import ( type ContainerStats struct { ContainerReference info.ContainerReference Stats *info.ContainerStats - ResChan chan<- error + + // ResChan is nil if the sender wants to ignore the result + ResChan chan<- error } -type ContainerStatsProcessor interface { - StartStatsProcessors(numProcs int) (chan<- *ContainerStats, error) - StopAllProcessors() -} - -type containerStatsWriter struct { - config *storage.Config -} - -func (self *containerStatsWriter) StartStatsProcessors(numProcs int) (chan<- *ContainerStats, error) { - ch := make(chan *ContainerStats) - statsWriter, err := storage.NewContainerStatsWriter(self.config) - if err != nil { - return nil, err +// Create numWorkers goroutines to write container stats info into the +// specified storage. Returns a write-only channel for the caller to write +// container stats. Closing this channel will stop all workers. +func StartContainerStatsWriters( + numWorkers int, + queueLength int, + statsWriter storage.ContainerStatsWriter, +) (chan<- *ContainerStats, error) { + if statsWriter == nil { + return nil, fmt.Errorf("invalid stats writer") } - for i := 0; i < numProcs; i++ { - go self.process(statsWriter, ch) + var ch chan *ContainerStats + if queueLength > 0 { + ch = make(chan *ContainerStats, queueLength) + } else { + ch = make(chan *ContainerStats) + } + for i := 0; i < numWorkers; i++ { + go writeContainerStats(statsWriter, ch) } return ch, nil } -func (self *containerStatsWriter) process(statsWriter storage.ContainerStatsWriter, ch <-chan *ContainerStats) { +func writeContainerStats(statsWriter storage.ContainerStatsWriter, ch <-chan *ContainerStats) { for stats := range ch { err := statsWriter.Write(stats.ContainerReference, stats.Stats) if err != nil { From dc9f4422b49beddd8cfb26f8b9e2a1d9ae0b8d5a Mon Sep 17 00:00:00 2001 From: Nan Deng Date: Sat, 14 Jun 2014 22:27:26 -0700 Subject: [PATCH 4/7] rename --- manager/container.go | 26 ++++++++++++++------------ manager/manager.go | 16 ++++------------ manager/statsproc.go | 4 ++-- storage/storage.go | 20 ++++++++++---------- storage/storage_test.go | 22 +++++++++++----------- 5 files changed, 41 insertions(+), 47 deletions(-) diff --git a/manager/container.go b/manager/container.go index ac7e03a2..90d72647 100644 --- a/manager/container.go +++ b/manager/container.go @@ -25,6 +25,7 @@ import ( "github.com/google/cadvisor/container" "github.com/google/cadvisor/info" + "github.com/google/cadvisor/storage" ) var historyDuration = flag.Int("history_duration", 60, "number of seconds of container history to keep") @@ -43,10 +44,10 @@ type containerInfo struct { } type containerData struct { - handler container.ContainerHandler - info containerInfo - statsChan chan<- *ContainerStats - lock sync.Mutex + handler container.ContainerHandler + info containerInfo + storageDriver storage.StorageDriver + lock sync.Mutex // Tells the container to stop. stop chan bool @@ -85,7 +86,7 @@ func (c *containerData) GetInfo() (*containerInfo, error) { return &ret, nil } -func NewContainerData(containerName string, statsChan chan<- *ContainerStats) (*containerData, error) { +func NewContainerData(containerName string, driver storage.StorageDriver) (*containerData, error) { cont := &containerData{} handler, err := container.NewContainerHandler(containerName) if err != nil { @@ -99,7 +100,7 @@ func NewContainerData(containerName string, statsChan chan<- *ContainerStats) (* cont.info.Name = ref.Name cont.info.Aliases = ref.Aliases cont.info.Stats = list.New() - cont.statsChan = statsChan + cont.storageDriver = driver cont.stop = make(chan bool, 1) return cont, nil @@ -153,13 +154,14 @@ func (c *containerData) updateStats() error { if stats == nil { return nil } - if c.statsChan != nil { + if c.storageDriver != nil { ref, err := c.handler.ContainerReference() - if err == nil { - c.statsChan <- &ContainerStats{ - ContainerReference: ref, - Stats: stats, - } + if err != nil { + return err + } + err = c.storageDriver.WriteStats(ref, stats) + if err != nil { + return err } } summary, err := c.handler.StatsSummary() diff --git a/manager/manager.go b/manager/manager.go index c86bd830..de3ad29e 100644 --- a/manager/manager.go +++ b/manager/manager.go @@ -39,7 +39,7 @@ type Manager interface { GetVersionInfo() (*info.VersionInfo, error) } -func New(statsWriter storage.ContainerStatsWriter) (Manager, error) { +func New(driver storage.StorageDriver) (Manager, error) { newManager := &manager{} newManager.containers = make(map[string]*containerData) @@ -56,15 +56,7 @@ func New(statsWriter storage.ContainerStatsWriter) (Manager, error) { } newManager.versionInfo = *versionInfo log.Printf("Version: %+v", newManager.versionInfo) - if statsWriter != nil { - // XXX(monnand): about numWorkers and queueLength, should we make it - // configurable? - ch, err := StartContainerStatsWriters(16, 64, statsWriter) - if err != nil { - return nil, err - } - newManager.statsChan = ch - } + newManager.storageDriver = driver return newManager, nil } @@ -72,7 +64,7 @@ func New(statsWriter storage.ContainerStatsWriter) (Manager, error) { type manager struct { containers map[string]*containerData containersLock sync.RWMutex - statsChan chan<- *ContainerStats + storageDriver storage.StorageDriver machineInfo info.MachineInfo versionInfo info.VersionInfo } @@ -171,7 +163,7 @@ func (m *manager) GetVersionInfo() (*info.VersionInfo, error) { // Create a container. This expects to only be called from the global manager thread. func (m *manager) createContainer(containerName string) (*containerData, error) { - cont, err := NewContainerData(containerName, m.statsChan) + cont, err := NewContainerData(containerName, m.storageDriver) if err != nil { return nil, err } diff --git a/manager/statsproc.go b/manager/statsproc.go index 6011f3ec..b9fdb366 100644 --- a/manager/statsproc.go +++ b/manager/statsproc.go @@ -36,7 +36,7 @@ type ContainerStats struct { func StartContainerStatsWriters( numWorkers int, queueLength int, - statsWriter storage.ContainerStatsWriter, + statsWriter storage.StorageDriver, ) (chan<- *ContainerStats, error) { if statsWriter == nil { return nil, fmt.Errorf("invalid stats writer") @@ -53,7 +53,7 @@ func StartContainerStatsWriters( return ch, nil } -func writeContainerStats(statsWriter storage.ContainerStatsWriter, ch <-chan *ContainerStats) { +func writeContainerStats(statsWriter storage.StorageDriver, ch <-chan *ContainerStats) { for stats := range ch { err := statsWriter.Write(stats.ContainerReference, stats.Stats) if err != nil { diff --git a/storage/storage.go b/storage/storage.go index 253881ae..101a7b87 100644 --- a/storage/storage.go +++ b/storage/storage.go @@ -21,8 +21,8 @@ import ( "github.com/google/cadvisor/info" ) -type ContainerStatsWriter interface { - Write(ref info.ContainerReference, stats *info.ContainerStats) error +type StorageDriver interface { + WriteStats(ref info.ContainerReference, stats *info.ContainerStats) error } // Database config which should contain all information used to connect to @@ -37,28 +37,28 @@ type Config struct { Params map[string]string `json:"parameters,omitempty"` } -type ContainerStatsWriterFactory interface { +type StorageFactory interface { String() string - New(config *Config) (ContainerStatsWriter, error) + New(config *Config) (StorageDriver, error) } type containerStatsWriterFactoryManager struct { lock sync.RWMutex - factories map[string]ContainerStatsWriterFactory + factories map[string]StorageFactory } -func (self *containerStatsWriterFactoryManager) Register(factory ContainerStatsWriterFactory) { +func (self *containerStatsWriterFactoryManager) Register(factory StorageFactory) { self.lock.Lock() defer self.lock.Unlock() if self.factories == nil { - self.factories = make(map[string]ContainerStatsWriterFactory, 8) + self.factories = make(map[string]StorageFactory, 8) } self.factories[factory.String()] = factory } -func (self *containerStatsWriterFactoryManager) New(config *Config) (ContainerStatsWriter, error) { +func (self *containerStatsWriterFactoryManager) New(config *Config) (StorageDriver, error) { self.lock.RLock() defer self.lock.RUnlock() @@ -70,10 +70,10 @@ func (self *containerStatsWriterFactoryManager) New(config *Config) (ContainerSt var globalContainerStatsWriterFactoryManager containerStatsWriterFactoryManager -func RegisterContainerStatsWriterFactory(factory ContainerStatsWriterFactory) { +func RegisterStorage(factory StorageFactory) { globalContainerStatsWriterFactoryManager.Register(factory) } -func NewContainerStatsWriter(config *Config) (ContainerStatsWriter, error) { +func NewStorage(config *Config) (StorageDriver, error) { return globalContainerStatsWriterFactoryManager.New(config) } diff --git a/storage/storage_test.go b/storage/storage_test.go index 2c9ffa0b..d058fbe9 100644 --- a/storage/storage_test.go +++ b/storage/storage_test.go @@ -8,12 +8,12 @@ import ( "github.com/stretchr/testify/mock" ) -type mockContainerStatsWriter struct { +type mockStorageDriver struct { storageName string mock.Mock } -func (self *mockContainerStatsWriter) Write( +func (self *mockStorageDriver) WriteStats( ref info.ContainerReference, stats *info.ContainerStats, ) error { @@ -21,18 +21,18 @@ func (self *mockContainerStatsWriter) Write( return args.Error(0) } -type mockContainerStatsWriterFactory struct { +type mockStorageFactory struct { name string } -func (self *mockContainerStatsWriterFactory) String() string { +func (self *mockStorageFactory) String() string { return self.name } -func (self *mockContainerStatsWriterFactory) New( +func (self *mockStorageFactory) New( config *Config, -) (ContainerStatsWriter, error) { - mockWriter := &mockContainerStatsWriter{ +) (StorageDriver, error) { + mockWriter := &mockStorageDriver{ storageName: self.name, } return mockWriter, nil @@ -50,10 +50,10 @@ func TestContainerStatsWriterFactoryManager(t *testing.T) { wg.Add(1) go func(n string) { defer wg.Done() - factory := &mockContainerStatsWriterFactory{ + factory := &mockStorageFactory{ name: n, } - RegisterContainerStatsWriterFactory(factory) + RegisterStorage(factory) }(name) } wg.Wait() @@ -64,11 +64,11 @@ func TestContainerStatsWriterFactoryManager(t *testing.T) { } go func(n string) { defer wg.Done() - writer, err := NewContainerStatsWriter(config) + writer, err := NewStorage(config) if err != nil { t.Error(err) } - if mw, ok := writer.(*mockContainerStatsWriter); ok { + if mw, ok := writer.(*mockStorageDriver); ok { if mw.storageName != n { t.Errorf("wrong writer. should be %v, got %v", n, mw.storageName) } From 196b05f317b334eb67e8ff02bae958469d9e53b5 Mon Sep 17 00:00:00 2001 From: Nan Deng Date: Sat, 14 Jun 2014 22:27:45 -0700 Subject: [PATCH 5/7] remove statsproc --- manager/statsproc.go | 66 -------------------------------------------- 1 file changed, 66 deletions(-) delete mode 100644 manager/statsproc.go diff --git a/manager/statsproc.go b/manager/statsproc.go deleted file mode 100644 index b9fdb366..00000000 --- a/manager/statsproc.go +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright 2014 Google Inc. All Rights Reserved. -// -// 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 manager - -import ( - "fmt" - "log" - - "github.com/google/cadvisor/info" - "github.com/google/cadvisor/storage" -) - -type ContainerStats struct { - ContainerReference info.ContainerReference - Stats *info.ContainerStats - - // ResChan is nil if the sender wants to ignore the result - ResChan chan<- error -} - -// Create numWorkers goroutines to write container stats info into the -// specified storage. Returns a write-only channel for the caller to write -// container stats. Closing this channel will stop all workers. -func StartContainerStatsWriters( - numWorkers int, - queueLength int, - statsWriter storage.StorageDriver, -) (chan<- *ContainerStats, error) { - if statsWriter == nil { - return nil, fmt.Errorf("invalid stats writer") - } - var ch chan *ContainerStats - if queueLength > 0 { - ch = make(chan *ContainerStats, queueLength) - } else { - ch = make(chan *ContainerStats) - } - for i := 0; i < numWorkers; i++ { - go writeContainerStats(statsWriter, ch) - } - return ch, nil -} - -func writeContainerStats(statsWriter storage.StorageDriver, ch <-chan *ContainerStats) { - for stats := range ch { - err := statsWriter.Write(stats.ContainerReference, stats.Stats) - if err != nil { - log.Printf("unable to write stats: %v", err) - } - if stats.ResChan != nil { - stats.ResChan <- err - } - } -} From e593dd48233527d6c10d58fafb904bfc8162f177 Mon Sep 17 00:00:00 2001 From: Nan Deng Date: Mon, 16 Jun 2014 10:12:27 -0700 Subject: [PATCH 6/7] remove storage factory --- .travis.yml | 1 - storage/storage.go | 60 +----------------------------- storage/storage_test.go | 81 ----------------------------------------- 3 files changed, 1 insertion(+), 141 deletions(-) delete mode 100644 storage/storage_test.go diff --git a/.travis.yml b/.travis.yml index 43ef6320..d3718380 100644 --- a/.travis.yml +++ b/.travis.yml @@ -6,7 +6,6 @@ before_script: - go get github.com/kr/pretty script: - go test -v -race github.com/google/cadvisor/container - - go test -v -race github.com/google/cadvisor/storage - go test -v github.com/google/cadvisor/info - go test -v github.com/google/cadvisor/client - go test -v github.com/google/cadvisor/sampling diff --git a/storage/storage.go b/storage/storage.go index 101a7b87..8ebca965 100644 --- a/storage/storage.go +++ b/storage/storage.go @@ -14,66 +14,8 @@ package storage -import ( - "fmt" - "sync" - - "github.com/google/cadvisor/info" -) +import "github.com/google/cadvisor/info" type StorageDriver interface { WriteStats(ref info.ContainerReference, stats *info.ContainerStats) error } - -// Database config which should contain all information used to connect to -// all/most databases -type Config struct { - Engine string `json:"engine,omitempty"` - Host string `json:"host,omitempty"` - Port int `json:"port,omitempty"` - Username string `json:"username,omitempty"` - Password string `json:"password,omitempty"` - Database string `json:"database,omitempty"` - Params map[string]string `json:"parameters,omitempty"` -} - -type StorageFactory interface { - String() string - New(config *Config) (StorageDriver, error) -} - -type containerStatsWriterFactoryManager struct { - lock sync.RWMutex - factories map[string]StorageFactory -} - -func (self *containerStatsWriterFactoryManager) Register(factory StorageFactory) { - self.lock.Lock() - defer self.lock.Unlock() - - if self.factories == nil { - self.factories = make(map[string]StorageFactory, 8) - } - - self.factories[factory.String()] = factory -} - -func (self *containerStatsWriterFactoryManager) New(config *Config) (StorageDriver, error) { - self.lock.RLock() - defer self.lock.RUnlock() - - if factory, ok := self.factories[config.Engine]; ok { - return factory.New(config) - } - return nil, fmt.Errorf("unknown database %v", config.Engine) -} - -var globalContainerStatsWriterFactoryManager containerStatsWriterFactoryManager - -func RegisterStorage(factory StorageFactory) { - globalContainerStatsWriterFactoryManager.Register(factory) -} - -func NewStorage(config *Config) (StorageDriver, error) { - return globalContainerStatsWriterFactoryManager.New(config) -} diff --git a/storage/storage_test.go b/storage/storage_test.go deleted file mode 100644 index d058fbe9..00000000 --- a/storage/storage_test.go +++ /dev/null @@ -1,81 +0,0 @@ -package storage - -import ( - "sync" - "testing" - - "github.com/google/cadvisor/info" - "github.com/stretchr/testify/mock" -) - -type mockStorageDriver struct { - storageName string - mock.Mock -} - -func (self *mockStorageDriver) WriteStats( - ref info.ContainerReference, - stats *info.ContainerStats, -) error { - args := self.Called(ref, stats) - return args.Error(0) -} - -type mockStorageFactory struct { - name string -} - -func (self *mockStorageFactory) String() string { - return self.name -} - -func (self *mockStorageFactory) New( - config *Config, -) (StorageDriver, error) { - mockWriter := &mockStorageDriver{ - storageName: self.name, - } - return mockWriter, nil -} - -func TestContainerStatsWriterFactoryManager(t *testing.T) { - factoryNames := []string{ - "abc", - "bcd", - } - - wg := sync.WaitGroup{} - - for _, name := range factoryNames { - wg.Add(1) - go func(n string) { - defer wg.Done() - factory := &mockStorageFactory{ - name: n, - } - RegisterStorage(factory) - }(name) - } - wg.Wait() - for _, name := range factoryNames { - wg.Add(1) - config := &Config{ - Engine: name, - } - go func(n string) { - defer wg.Done() - writer, err := NewStorage(config) - if err != nil { - t.Error(err) - } - if mw, ok := writer.(*mockStorageDriver); ok { - if mw.storageName != n { - t.Errorf("wrong writer. should be %v, got %v", n, mw.storageName) - } - } else { - t.Errorf("wrong writer: unknown type") - } - }(name) - } - wg.Wait() -} From a6763f4525ef11c1a21fead17d45c00839951d35 Mon Sep 17 00:00:00 2001 From: Nan Deng Date: Mon, 16 Jun 2014 14:55:39 -0700 Subject: [PATCH 7/7] gofmt -r "WriteStats->AddStats" --- manager/container.go | 2 +- storage/storage.go | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/manager/container.go b/manager/container.go index 90d72647..a4a21ac1 100644 --- a/manager/container.go +++ b/manager/container.go @@ -159,7 +159,7 @@ func (c *containerData) updateStats() error { if err != nil { return err } - err = c.storageDriver.WriteStats(ref, stats) + err = c.storageDriver.AddStats(ref, stats) if err != nil { return err } diff --git a/storage/storage.go b/storage/storage.go index 8ebca965..f9990831 100644 --- a/storage/storage.go +++ b/storage/storage.go @@ -17,5 +17,5 @@ package storage import "github.com/google/cadvisor/info" type StorageDriver interface { - WriteStats(ref info.ContainerReference, stats *info.ContainerStats) error + AddStats(ref info.ContainerReference, stats *info.ContainerStats) error }