From 436266b1a44f1a444dfdf6c9b0133ca8b57c3d27 Mon Sep 17 00:00:00 2001 From: Peter Reisinger Date: Mon, 20 Nov 2017 11:09:36 +0000 Subject: [PATCH] added container menu closes #28 --- connector/docker.go | 5 +++- connector/manager/docker.go | 44 ++++++++++++++++++++++++++++++++ connector/manager/main.go | 7 ++++++ connector/manager/mock.go | 19 ++++++++++++++ connector/mock.go | 4 ++- container/main.go | 33 +++++++++++++++++++++++- grid.go | 4 +++ menus.go | 50 +++++++++++++++++++++++++++++++++++++ 8 files changed, 163 insertions(+), 3 deletions(-) create mode 100644 connector/manager/docker.go create mode 100644 connector/manager/main.go create mode 100644 connector/manager/mock.go diff --git a/connector/docker.go b/connector/docker.go index ee1e060..399f0e9 100644 --- a/connector/docker.go +++ b/connector/docker.go @@ -8,6 +8,7 @@ import ( "github.com/bcicen/ctop/connector/collector" "github.com/bcicen/ctop/container" api "github.com/fsouza/go-dockerclient" + "github.com/bcicen/ctop/connector/manager" ) type Docker struct { @@ -132,8 +133,10 @@ func (cm *Docker) MustGet(id string) *container.Container { if !ok { // create collector collector := collector.NewDocker(cm.client, id) + // create manager + manager := manager.NewDocker(cm.client, id) // create container - c = container.New(id, collector) + c = container.New(id, collector, manager) cm.lock.Lock() cm.containers[id] = c cm.lock.Unlock() diff --git a/connector/manager/docker.go b/connector/manager/docker.go new file mode 100644 index 0000000..c2943ad --- /dev/null +++ b/connector/manager/docker.go @@ -0,0 +1,44 @@ +package manager + +import ( + api "github.com/fsouza/go-dockerclient" + "fmt" +) + +type Docker struct { + id string + client *api.Client +} + +func NewDocker(client *api.Client, id string) *Docker { + return &Docker{ + id: id, + client: client, + } +} + +func (dc *Docker) Start() error { + c, err := dc.client.InspectContainer(dc.id) + if err != nil { + return fmt.Errorf("cannot inspect container: %v", err) + } + + if err := dc.client.StartContainer(c.ID, c.HostConfig); err != nil { + return fmt.Errorf("cannot start container: %v", err) + } + return nil +} + +func (dc *Docker) Stop() error { + if err := dc.client.StopContainer(dc.id, 3); err != nil { + return fmt.Errorf("cannot stop container: %v", err) + } + return nil +} + +func (dc *Docker) Remove() error { + if err := dc.client.RemoveContainer(api.RemoveContainerOptions{ID: dc.id}); err != nil { + return fmt.Errorf("cannot remove container: %v", err) + } + return nil +} diff --git a/connector/manager/main.go b/connector/manager/main.go new file mode 100644 index 0000000..31a2060 --- /dev/null +++ b/connector/manager/main.go @@ -0,0 +1,7 @@ +package manager + +type Manager interface { + Start() error + Stop() error + Remove() error +} diff --git a/connector/manager/mock.go b/connector/manager/mock.go new file mode 100644 index 0000000..bd7b182 --- /dev/null +++ b/connector/manager/mock.go @@ -0,0 +1,19 @@ +package manager + +type Mock struct {} + +func NewMock() *Mock { + return &Mock{} +} + +func (m *Mock) Start() error { + return nil +} + +func (m *Mock) Stop() error { + return nil +} + +func (m *Mock) Remove() error { + return nil +} diff --git a/connector/mock.go b/connector/mock.go index daecc3e..131ce71 100644 --- a/connector/mock.go +++ b/connector/mock.go @@ -11,6 +11,7 @@ import ( "github.com/bcicen/ctop/container" "github.com/jgautheron/codename-generator" "github.com/nu7hatch/gouuid" + "github.com/bcicen/ctop/connector/manager" ) type Mock struct { @@ -40,7 +41,8 @@ func (cs *Mock) Init() { func (cs *Mock) makeContainer(aggression int64) { collector := collector.NewMock(aggression) - c := container.New(makeID(), collector) + manager := manager.NewMock() + c := container.New(makeID(), collector, manager) c.SetMeta("name", makeName()) c.SetState(makeState()) cs.containers = append(cs.containers, c) diff --git a/container/main.go b/container/main.go index 3b93ab7..ad02013 100644 --- a/container/main.go +++ b/container/main.go @@ -6,6 +6,7 @@ import ( "github.com/bcicen/ctop/cwidgets/compact" "github.com/bcicen/ctop/logging" "github.com/bcicen/ctop/models" + "github.com/bcicen/ctop/connector/manager" ) var ( @@ -21,9 +22,10 @@ type Container struct { Display bool // display this container in compact view updater cwidgets.WidgetUpdater collector collector.Collector + manager manager.Manager } -func New(id string, collector collector.Collector) *Container { +func New(id string, collector collector.Collector, manager manager.Manager) *Container { widgets := compact.NewCompact(id) return &Container{ Metrics: models.NewMetrics(), @@ -32,6 +34,7 @@ func New(id string, collector collector.Collector) *Container { Widgets: widgets, updater: widgets, collector: collector, + manager: manager, } } @@ -85,3 +88,31 @@ func (c *Container) Read(stream chan models.Metrics) { }() log.Infof("reader started for container: %s", c.Id) } + +func (c *Container) Start() { + if c.Meta["state"] != "running" { + if err := c.manager.Start(); err != nil { + log.Warningf("container %s: %v", c.Id, err) + return + } + c.SetState("running") + } +} + +func (c *Container) Stop() { + if c.Meta["state"] == "running" { + if err := c.manager.Stop(); err != nil { + log.Warningf("container %s: %v", c.Id, err) + return + } + c.SetState("exited") + } +} + +func (c *Container) Remove() { + if c.Meta["state"] == "exited" { + if err := c.manager.Remove(); err != nil { + log.Warningf("container %s: %v", c.Id, err) + } + } +} diff --git a/grid.go b/grid.go index 6553506..7266e94 100644 --- a/grid.go +++ b/grid.go @@ -93,6 +93,10 @@ func Display() bool { ui.StopLoop() }) + ui.Handle("/sys/kbd/m", func(ui.Event) { + menu = ContainerMenu + ui.StopLoop() + }) ui.Handle("/sys/kbd/", func(ui.Event) { single = true ui.StopLoop() diff --git a/menus.go b/menus.go index 3edfc1b..88bda21 100644 --- a/menus.go +++ b/menus.go @@ -94,3 +94,53 @@ func SortMenu() { ui.Render(m) ui.Loop() } + +func ContainerMenu() { + + c := cursor.Selected() + if c == nil { + return + } + + ui.DefaultEvtStream.ResetHandlers() + defer ui.DefaultEvtStream.ResetHandlers() + + m := menu.NewMenu() + m.Selectable = true + + m.BorderLabel = "Menu" + var items []menu.Item + if c.Meta["state"] == "running" { + items = append(items, menu.Item{Val: "stop", Label: "stop"}) + } + if c.Meta["state"] == "exited" { + items = append(items, menu.Item{Val: "start", Label: "start"}) + items = append(items, menu.Item{Val: "remove", Label: "remove"}) + } + items = append(items, menu.Item{Val: "cancel", Label: "cancel"}) + + m.AddItems(items...) + ui.Render(m) + + HandleKeys("up", m.Up) + HandleKeys("down", m.Down) + ui.Handle("/sys/kbd/", func(ui.Event) { + switch m.SelectedItem().Val { + case "start": + c.Start() + ui.StopLoop() + case "stop": + c.Stop() + ui.StopLoop() + case "remove": + c.Remove() + ui.StopLoop() + case "cancel": + ui.StopLoop() + } + }) + ui.Handle("/sys/kbd/", func(ui.Event) { + ui.StopLoop() + }) + ui.Loop() +}