Skip to content

Commit d1f0cb7

Browse files
authored
Merge pull request #107 from thin-edge/feat-add-name-labels
feat(internal): improvements to internal cli tools
2 parents 58b86a3 + f9e5046 commit d1f0cb7

File tree

6 files changed

+114
-6
lines changed

6 files changed

+114
-6
lines changed

cli/tools/cmd.go

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ func NewToolsCommand(cmdCli cli.Cli) *cobra.Command {
1616
NewContainerCloneCommand(cmdCli),
1717
NewContainerLogsCommand(cmdCli),
1818
NewContainerRunInContextCommand(cmdCli),
19+
NewContainerRemoveCommand(cmdCli),
1920
)
2021
return cmd
2122
}

cli/tools/container_clone.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ type ContainerCloneCommand struct {
2222
CommandContext cli.Cli
2323

2424
// Options
25+
ForkName string
2526
ForceUpdate bool
2627
Fork bool
2728
WaitForExit bool
@@ -64,6 +65,7 @@ func NewContainerCloneCommand(ctx cli.Cli) *cobra.Command {
6465
cmd.Flags().BoolVar(&command.WaitForExit, "wait-for-exit", false, "Wait for the container to stop/exit before updating")
6566
cmd.Flags().BoolVar(&command.CheckForUpdate, "check", false, "Only check if an update is necessary, don't perform the update")
6667
cmd.Flags().StringVar(&command.Entrypoint, "entrypoint", "", "Change the container entrypoint when cloning the container")
68+
cmd.Flags().StringVar(&command.ForkName, "fork-name", "", "Container name to use for the fork")
6769
cmd.Flags().StringSliceVarP(&command.Labels, "label", "l", []string{}, "Set meta data on the new container")
6870
cmd.Flags().StringSliceVar(&command.ForkLabels, "fork-label", []string{}, "Set meta data on a the forked container")
6971

@@ -208,6 +210,9 @@ func (c *ContainerCloneCommand) RunE(cmd *cobra.Command, args []string) error {
208210
slog.Info("Forking container.", "command", strings.Join(forkCmd, " "))
209211

210212
cloneOptions := container.CloneOptions{
213+
// Fork container name. If blank then a random name will be used
214+
Name: c.ForkName,
215+
211216
Cmd: forkCmd,
212217

213218
// Use the new image, so that fixes can be delivered in the new image

cli/tools/container_remove.go

Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
/*
2+
Copyright © 2024 thin-edge.io <[email protected]>
3+
*/
4+
package tools
5+
6+
import (
7+
"context"
8+
"errors"
9+
"log/slog"
10+
11+
"github.com/spf13/cobra"
12+
"github.com/thin-edge/tedge-container-plugin/pkg/cli"
13+
"github.com/thin-edge/tedge-container-plugin/pkg/container"
14+
)
15+
16+
type ContainerRemoveCommand struct {
17+
*cobra.Command
18+
19+
CommandContext cli.Cli
20+
21+
// Options
22+
Tail string
23+
Since string
24+
Until string
25+
Timestamps bool
26+
Follow bool
27+
Details bool
28+
}
29+
30+
// NewContainerLogsCommand creates a new container remove command
31+
func NewContainerRemoveCommand(ctx cli.Cli) *cobra.Command {
32+
command := &ContainerLogsCommand{
33+
CommandContext: ctx,
34+
}
35+
cmd := &cobra.Command{
36+
Use: "container-remove [OPTIONS] CONTAINER...",
37+
Short: "Remove a container (stopping if necessary)",
38+
RunE: command.RunE,
39+
Args: cobra.ArbitraryArgs,
40+
SilenceUsage: true,
41+
}
42+
command.Command = cmd
43+
return cmd
44+
}
45+
46+
func (c *ContainerRemoveCommand) RunE(cmd *cobra.Command, args []string) error {
47+
slog.Debug("Executing", "cmd", cmd.CalledAs(), "args", args)
48+
49+
containerCli, err := container.NewContainerClient()
50+
if err != nil {
51+
return err
52+
}
53+
54+
ctx := context.Background()
55+
56+
errs := make([]error, 0)
57+
for _, name := range args {
58+
errs = append(errs, containerCli.StopRemoveContainer(ctx, name))
59+
}
60+
61+
return errors.Join(errs...)
62+
}

cli/tools/run_context.go

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import (
1515
"github.com/spf13/cobra"
1616
"github.com/thin-edge/tedge-container-plugin/pkg/cli"
1717
"github.com/thin-edge/tedge-container-plugin/pkg/container"
18+
"github.com/thin-edge/tedge-container-plugin/pkg/random"
1819
)
1920

2021
type ContainerRunInContextCommand struct {
@@ -29,6 +30,7 @@ type ContainerRunInContextCommand struct {
2930
AutoRemove bool
3031
Entrypoint string
3132
Labels []string
33+
NamePrefix string
3234
}
3335

3436
// NewRunRemoteAccessCommand creates a new c8y remote access command
@@ -46,6 +48,7 @@ func NewContainerRunInContextCommand(ctx cli.Cli) *cobra.Command {
4648
cmd.Flags().StringVar(&command.ContainerID, "container", "", "Container to clone. Either container id or name. By default the container id of the current container will be used")
4749
cmd.Flags().StringVar(&command.Image, "image", "", "Container image")
4850
cmd.Flags().StringVar(&command.Entrypoint, "entrypoint", "", "Overwrite the default ENTRYPOINT of the image")
51+
cmd.Flags().StringVar(&command.NamePrefix, "name-prefix", "", "Prefix to be added when generating the name. If left blank then the default will be used")
4952
cmd.Flags().StringSliceVarP(&command.Env, "env", "e", []string{}, "Set environment variables")
5053
cmd.Flags().BoolVar(&command.AutoRemove, "rm", false, "Auto remove the closed container on exit")
5154
cmd.Flags().StringSliceVarP(&command.Labels, "label", "l", []string{}, "Set meta data on a container")
@@ -155,7 +158,13 @@ func (c *ContainerRunInContextCommand) RunE(cmd *cobra.Command, args []string) e
155158
// Copy network config
156159
networkConfig := container.CloneNetworkConfig(currentContainer.NetworkSettings)
157160

158-
nextContainer, createErr := containerCli.Client.ContainerCreate(ctx, clonedConfig, hostConfig, networkConfig, nil, "")
161+
// container name
162+
containerName := "" // default. let docker create a random name
163+
if c.NamePrefix != "" {
164+
containerName = c.NamePrefix + "_" + random.String(8)
165+
}
166+
167+
nextContainer, createErr := containerCli.Client.ContainerCreate(ctx, clonedConfig, hostConfig, networkConfig, nil, containerName)
159168

160169
if createErr != nil {
161170
slog.Warn("Failed to create container.", "err", createErr)

pkg/container/container.go

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -960,6 +960,7 @@ func (c *ContainerClient) ContainerLogs(ctx context.Context, w io.Writer, contai
960960
}
961961

962962
type CloneOptions struct {
963+
Name string
963964
Image string
964965
HealthyAfter time.Duration
965966
StopAfter time.Duration
@@ -1195,11 +1196,11 @@ func (c *ContainerClient) Fork(ctx context.Context, currentContainer types.Conta
11951196
if cloneOptions.Image == "" {
11961197
cloneOptions.Image = currentContainer.Config.Image
11971198
}
1199+
1200+
cloneOptions.Labels["io.tedge.fork"] = "1"
1201+
cloneOptions.Labels["io.tedge.forked.name"] = currentContainer.Name
1202+
11981203
containerConfig := CloneContainerConfig(currentContainer.Config, cloneOptions)
1199-
labels := make(map[string]string)
1200-
labels["io.tedge.fork"] = "1"
1201-
labels["io.tedge.forked.name"] = currentContainer.Name
1202-
containerConfig.Labels = labels
12031204

12041205
hostConfig := CloneHostConfig(currentContainer.HostConfig, cloneOptions)
12051206

@@ -1213,7 +1214,13 @@ func (c *ContainerClient) Fork(ctx context.Context, currentContainer types.Conta
12131214
networkConfig := CloneNetworkConfig(currentContainer.NetworkSettings)
12141215
slog.Info("Forking container.", "new_image", containerConfig.Image, "from_id", currentContainer.ID)
12151216

1216-
resp, respErr := c.Client.ContainerCreate(ctx, containerConfig, hostConfig, networkConfig, nil, "")
1217+
if cloneOptions.Name != "" {
1218+
if err := c.StopRemoveContainer(ctx, cloneOptions.Name); err != nil {
1219+
return err
1220+
}
1221+
}
1222+
1223+
resp, respErr := c.Client.ContainerCreate(ctx, containerConfig, hostConfig, networkConfig, nil, cloneOptions.Name)
12171224
if respErr != nil {
12181225
return respErr
12191226
}

pkg/random/random.go

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
package random
2+
3+
import (
4+
"math/rand"
5+
"time"
6+
)
7+
8+
const charset = "abcdefghijklmnopqrstuvwxyz" +
9+
"ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789"
10+
11+
var seededRand *rand.Rand = rand.New(
12+
rand.NewSource(time.Now().UnixNano()))
13+
14+
func StringWithCharset(length int, charset string) string {
15+
b := make([]byte, length)
16+
for i := range b {
17+
b[i] = charset[seededRand.Intn(len(charset))]
18+
}
19+
return string(b)
20+
}
21+
22+
func String(length int) string {
23+
return StringWithCharset(length, charset)
24+
}

0 commit comments

Comments
 (0)