mirror of
https://github.com/psviderski/uncloud.git
synced 2026-08-26 11:03:34 +00:00
feat(pre-deploy): list hook containers in 'uc ps' and 'uc inspect'
This commit is contained in:
+38
-8
@@ -10,11 +10,11 @@ import (
|
||||
"charm.land/lipgloss/v2"
|
||||
"github.com/docker/docker/api/types/container"
|
||||
"github.com/docker/go-units"
|
||||
"github.com/psviderski/uncloud/internal/cli/tui"
|
||||
"github.com/spf13/cobra"
|
||||
|
||||
"github.com/psviderski/uncloud/internal/cli"
|
||||
"github.com/psviderski/uncloud/internal/cli/tui"
|
||||
"github.com/psviderski/uncloud/pkg/api"
|
||||
"github.com/psviderski/uncloud/pkg/client"
|
||||
"github.com/spf13/cobra"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -66,12 +66,13 @@ type containerInfo struct {
|
||||
serviceName string
|
||||
machineName string
|
||||
id string
|
||||
name string
|
||||
image string
|
||||
status string
|
||||
highlight containerHighlight
|
||||
created time.Time
|
||||
ip string
|
||||
// Hook type (e.g., "pre-deploy"), empty for regular containers.
|
||||
hook string
|
||||
}
|
||||
|
||||
func runPs(ctx context.Context, uncli *cli.CLI, opts psOptions) error {
|
||||
@@ -132,7 +133,21 @@ func runPs(ctx context.Context, uncli *cli.CLI, opts psOptions) error {
|
||||
|
||||
func printContainers(containers []containerInfo) error {
|
||||
t := tui.NewTable()
|
||||
t.Headers("SERVICE", "CONTAINER ID", "CONTAINER NAME", "IMAGE", "CREATED", "STATUS", "IP ADDRESS", "MACHINE")
|
||||
|
||||
// Show HOOK column only when hook containers are present.
|
||||
hasHooks := false
|
||||
for _, ctr := range containers {
|
||||
if ctr.hook != "" {
|
||||
hasHooks = true
|
||||
break
|
||||
}
|
||||
}
|
||||
|
||||
if hasHooks {
|
||||
t.Headers("SERVICE", "CONTAINER ID", "IMAGE", "CREATED", "STATUS", "HOOK", "IP ADDRESS", "MACHINE")
|
||||
} else {
|
||||
t.Headers("SERVICE", "CONTAINER ID", "IMAGE", "CREATED", "STATUS", "IP ADDRESS", "MACHINE")
|
||||
}
|
||||
|
||||
for _, ctr := range containers {
|
||||
id := ctr.id
|
||||
@@ -154,10 +169,21 @@ func printContainers(containers []containerInfo) error {
|
||||
statusStyle = lipgloss.NewStyle() // Default
|
||||
}
|
||||
|
||||
if hasHooks {
|
||||
t.Row(
|
||||
ctr.serviceName,
|
||||
id,
|
||||
tui.FormatImage(ctr.image, tui.NoStyle),
|
||||
created,
|
||||
statusStyle.Render(ctr.status),
|
||||
ctr.hook,
|
||||
ctr.ip,
|
||||
ctr.machineName,
|
||||
)
|
||||
} else {
|
||||
t.Row(
|
||||
ctr.serviceName,
|
||||
id,
|
||||
ctr.name,
|
||||
tui.FormatImage(ctr.image, tui.NoStyle),
|
||||
created,
|
||||
statusStyle.Render(ctr.status),
|
||||
@@ -165,6 +191,7 @@ func printContainers(containers []containerInfo) error {
|
||||
ctr.machineName,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Println(t)
|
||||
return nil
|
||||
@@ -220,7 +247,7 @@ func collectContainers(ctx context.Context, cli *client.Client) ([]containerInfo
|
||||
continue
|
||||
}
|
||||
|
||||
for _, ctr := range msc.Containers {
|
||||
for _, ctr := range append(msc.Containers, msc.HookContainers...) {
|
||||
if ctr.Container.State == nil || ctr.Container.Config == nil {
|
||||
continue
|
||||
}
|
||||
@@ -242,6 +269,9 @@ func collectContainers(ctx context.Context, cli *client.Client) ([]containerInfo
|
||||
highlight = highlightSuccess
|
||||
} else if ctr.Container.State.Status == "running" {
|
||||
highlight = highlightNormal
|
||||
} else if ctr.IsHook() && ctr.Container.State.Status == "exited" && ctr.Container.State.ExitCode == 0 {
|
||||
// Hook containers (e.g., pre-deploy) are expected to exit successfully.
|
||||
highlight = highlightNormal
|
||||
} else { // Other non-critical but noteworthy states
|
||||
highlight = highlightWarning
|
||||
}
|
||||
@@ -259,12 +289,12 @@ func collectContainers(ctx context.Context, cli *client.Client) ([]containerInfo
|
||||
serviceName: ctr.ServiceName(),
|
||||
machineName: machineName,
|
||||
id: ctr.Container.ID,
|
||||
name: ctr.Container.Name,
|
||||
image: ctr.Container.Config.Image,
|
||||
status: status,
|
||||
highlight: highlight,
|
||||
created: created,
|
||||
ip: ipStr,
|
||||
hook: ctr.Config.Labels[api.LabelHook],
|
||||
}
|
||||
containers = append(containers, info)
|
||||
}
|
||||
|
||||
@@ -111,7 +111,6 @@ func TestCollectContainers_NilMetadata(t *testing.T) {
|
||||
if len(containers) > 0 {
|
||||
c := containers[0]
|
||||
assert.Equal(t, "container1", c.id)
|
||||
assert.Equal(t, "test-container", c.name)
|
||||
assert.Equal(t, "machine-1", c.machineName, "Should fall back to the single machine name when metadata is nil")
|
||||
}
|
||||
}
|
||||
|
||||
@@ -60,23 +60,33 @@ func inspect(ctx context.Context, uncli *cli.CLI, opts inspectOptions) error {
|
||||
fmt.Printf("Mode: %s\n", svc.Mode)
|
||||
fmt.Println()
|
||||
|
||||
// Combine regular and hook containers.
|
||||
allContainers := append(svc.Containers, svc.HookContainers...)
|
||||
|
||||
// Parse created times for sorting and display.
|
||||
createdTimes := make(map[string]time.Time, len(svc.Containers))
|
||||
for _, ctr := range svc.Containers {
|
||||
createdTimes := make(map[string]time.Time, len(allContainers))
|
||||
for _, ctr := range allContainers {
|
||||
createdTimes[ctr.Container.ID], _ = time.Parse(time.RFC3339Nano, ctr.Container.Created)
|
||||
}
|
||||
|
||||
// Sort containers by created time (newest first).
|
||||
slices.SortFunc(svc.Containers, func(a, b api.MachineServiceContainer) int {
|
||||
slices.SortFunc(allContainers, func(a, b api.MachineServiceContainer) int {
|
||||
return createdTimes[b.Container.ID].Compare(createdTimes[a.Container.ID])
|
||||
})
|
||||
|
||||
// Print the list of containers in a table format.
|
||||
// Show HOOK column only when hook containers are present.
|
||||
hasHooks := len(svc.HookContainers) > 0
|
||||
|
||||
t := tui.NewTable()
|
||||
if hasHooks {
|
||||
t.Headers("CONTAINER ID", "IMAGE", "CREATED", "STATUS", "HOOK", "IP ADDRESS", "MACHINE")
|
||||
} else {
|
||||
t.Headers("CONTAINER ID", "IMAGE", "CREATED", "STATUS", "IP ADDRESS", "MACHINE")
|
||||
}
|
||||
|
||||
now := time.Now().UTC()
|
||||
for _, ctr := range svc.Containers {
|
||||
for _, ctr := range allContainers {
|
||||
created := units.HumanDuration(now.Sub(createdTimes[ctr.Container.ID])) + " ago"
|
||||
|
||||
machine := machinesNamesByID[ctr.MachineID]
|
||||
@@ -95,6 +105,17 @@ func inspect(ctx context.Context, uncli *cli.CLI, opts inspectOptions) error {
|
||||
ipStr = ip.String()
|
||||
}
|
||||
|
||||
if hasHooks {
|
||||
t.Row(
|
||||
stringid.TruncateID(ctr.Container.ID),
|
||||
tui.FormatImage(ctr.Container.Config.Image, tui.NoStyle),
|
||||
created,
|
||||
state,
|
||||
ctr.Container.Config.Labels[api.LabelHook],
|
||||
ipStr,
|
||||
machine,
|
||||
)
|
||||
} else {
|
||||
t.Row(
|
||||
stringid.TruncateID(ctr.Container.ID),
|
||||
tui.FormatImage(ctr.Container.Config.Image, tui.NoStyle),
|
||||
@@ -104,6 +125,7 @@ func inspect(ctx context.Context, uncli *cli.CLI, opts inspectOptions) error {
|
||||
machine,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
fmt.Println(t)
|
||||
return nil
|
||||
|
||||
Reference in New Issue
Block a user