Skip to content

Commit

Permalink
Separate running state and maintenance mode.
Browse files Browse the repository at this point in the history
  • Loading branch information
nathan-osman committed Jul 30, 2022
1 parent 28668b2 commit 2321ca6
Show file tree
Hide file tree
Showing 7 changed files with 71 additions and 57 deletions.
46 changes: 25 additions & 21 deletions container/container.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,13 +38,14 @@ type Database struct {

// ContainerData provides a base type for container data.
type ContainerData struct {
ID string `json:"id"`
Name string `json:"name"`
Title string `json:"title"`
Domains []string `json:"domains"`
Insecure bool `json:"insecure"`
Disabled bool `json:"disabled"`
Uptime int64 `json:"uptime"`
ID string `json:"id"`
Name string `json:"name"`
Title string `json:"title"`
Domains []string `json:"domains"`
Insecure bool `json:"insecure"`
Running bool `json:"running"`
Maintenance bool `json:"maintenance"`
Uptime int64 `json:"uptime"`
}

// Container represents configuration for a Docker container with i5 metadata.
Expand All @@ -63,7 +64,7 @@ func getWithDefault(m map[string]string, key, def string) string {
}

// New creates a new Container instance from the provided labels.
func New(id, name string, labels map[string]string) (*Container, error) {
func New(id, name string, labels map[string]string, running bool) (*Container, error) {
var (
cfg = &proxy.Config{}
c = &Container{
Expand Down Expand Up @@ -122,23 +123,26 @@ func New(id, name string, labels map[string]string) (*Container, error) {
c.Title = title
}
c.Proxy = proxy.New(cfg)
c.Enable()
if running {
c.Started()
} else {
c.Stopped()
}
return c, nil
}

// Disable prevents clients from accessing the container and returns a static
// page with the specified message.
func (c *Container) Disable(message string) {
c.Disabled = true
// Started switches the handler to the proxy for the container.
func (c *Container) Started() {
c.Running = true
c.Uptime = time.Now().Unix()
c.Handler = c.Proxy
}

// Stopped switches the handler to the static "stopped" message.
func (c *Container) Stopped() {
c.Running = false
c.Uptime = 0
c.Handler = &disabledHandler{
Message: message,
Message: stoppedContainerMessage,
}
}

// Enable reverts the container to the proxy handler.
func (c *Container) Enable() {
c.Disabled = false
c.Uptime = time.Now().Unix()
c.Handler = c.Proxy
}
2 changes: 2 additions & 0 deletions container/handler.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,8 @@ import (
"github.com/nathan-osman/i5/util"
)

const stoppedContainerMessage = "The container serving this application is not currently running."

type disabledHandler struct {
Message string
}
Expand Down
30 changes: 13 additions & 17 deletions dockmon/dockmon.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,8 +23,6 @@ const (
// Die indicates that a container has been stopped.
Die = "die"

containerStoppedMessage = "The container serving this application is not currently running."

messageTypeContainer = "container"
)

Expand Down Expand Up @@ -66,16 +64,14 @@ func (d *Dockmon) newContainerFromClient(ctx context.Context, client *client.Cli
containerJSON.ID,
containerJSON.Name[1:],
containerJSON.Config.Labels,
containerJSON.State.Running,
)
if err != nil {
return nil, err
}
if t, err := time.Parse(time.RFC3339, containerJSON.State.StartedAt); err == nil && !t.IsZero() {
c.Uptime = t.Unix()
}
if !containerJSON.State.Running {
c.Disable(containerStoppedMessage)
}
c.Proxy.SetCallback(d.responseCallback)
return c, nil
}
Expand All @@ -100,21 +96,21 @@ func (d *Dockmon) add(ctx context.Context, id string) {
if con, err := d.newContainerFromClient(ctx, d.client, id); err == nil {
d.conMap.Insert(id, con)
d.sendEvent(Create, con)
if !con.Disabled {
if con.Running {
d.sendEvent(Start, con)
}
}
}

func (d *Dockmon) toggleState(id string, disable bool) {
func (d *Dockmon) toggleState(id string, running bool) {
if v, ok := d.conMap[id]; ok {
c := v.(*container.Container)
if disable {
c.Disable(containerStoppedMessage)
d.sendEvent(Die, c)
} else {
c.Enable()
if running {
c.Started()
d.sendEvent(Start, c)
} else {
c.Stopped()
d.sendEvent(Die, c)
}
}
}
Expand All @@ -136,7 +132,7 @@ func (d *Dockmon) sync(ctx context.Context) error {
for _, c := range containers {
newConMap.Insert(c.ID, &container.Container{
ContainerData: container.ContainerData{
Disabled: c.State != "running",
Running: c.State == "running",
},
})
}
Expand All @@ -148,8 +144,8 @@ func (d *Dockmon) sync(ctx context.Context) error {
oldV, ok := d.conMap[conID]
if ok {
c := oldV.(*container.Container)
if v.(*container.Container).Disabled != c.Disabled {
d.toggleState(conID, c.Disabled)
if v.(*container.Container).Running != c.Running {
d.toggleState(conID, c.Running)
}
} else {
d.add(ctx, conID)
Expand Down Expand Up @@ -182,9 +178,9 @@ func (d *Dockmon) loop(ctx context.Context) error {
d.sendEvent(Destroy, v.(*container.Container))
}
case Start:
d.toggleState(msg.ID, false)
case Die:
d.toggleState(msg.ID, true)
case Die:
d.toggleState(msg.ID, false)
}
case err := <-errChan:
return err
Expand Down
37 changes: 22 additions & 15 deletions ui/src/components/containerlist.js
Original file line number Diff line number Diff line change
Expand Up @@ -36,27 +36,34 @@ export default function ContainerList() {
title: "Status",
render: row => (
<div className={styles.status}>
{row.disabled ?
<span className={styles.stopped}>Stopped</span> :
<span className={styles.running}>Running</span>
{row.running ?
<span className={styles.running}>Running</span> :
<span className={styles.stopped}>Stopped</span>
}
</div>
)
},
{
title: "Tools",
right: true,
render: row => row.disabled ?
<Tool
src={startIcon}
url={`/api/containers/${row.id}/state`}
data={{ action: 'start' }}
/> :
<Tool
src={stopIcon}
url={`/api/containers/${row.id}/state`}
data={{ action: 'stop' }}
/>
render: row => (
<>
{
row.running ?
<Tool
src={stopIcon}
url={`/api/containers/${row.id}/state`}
data={{ action: 'stop' }}
title="Stop the container"
/> :
<Tool
src={startIcon}
url={`/api/containers/${row.id}/state`}
data={{ action: 'start' }}
title="Start the container"
/>
}
</>
)
}
]

Expand Down
9 changes: 7 additions & 2 deletions ui/src/components/tool.js
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import { usePopup } from '../lib/popup'
import styles from './tool.module.css'
import spinner from '../images/spinner.svg'

export default function Tool({ src, url, data }) {
export default function Tool({ src, url, data, ...props }) {

const api = useApi()
const popup = usePopup()
Expand All @@ -19,6 +19,11 @@ export default function Tool({ src, url, data }) {
}

return (
<img className={styles.tool} src={isLoading ? spinner : src} onClick={handleClick} />
<img
className={styles.tool}
src={isLoading ? spinner : src}
onClick={handleClick}
{...props}
/>
)
}
2 changes: 1 addition & 1 deletion ui/src/images/icons/start.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
2 changes: 1 addition & 1 deletion ui/src/images/icons/stop.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 2321ca6

Please sign in to comment.