Skip to content

Commit b75b46d

Browse files
authored
Feat: Add support for start and stop command (#143)
* fixes #108 feat: Add support for start and stop command Signed-off-by: Harsh4902 <[email protected]> * fixes #108 feat:Add --driver flag to specify container engine for microcks instance Signed-off-by: Harsh4902 <[email protected]> --------- Signed-off-by: Harsh4902 <[email protected]>
1 parent c511571 commit b75b46d

6 files changed

Lines changed: 508 additions & 3 deletions

File tree

cmd/cmd.go

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ import (
2323
)
2424

2525
var rootCmd = &cobra.Command{
26-
Use: "microcks-cli",
26+
Use: "microcks",
2727
Short: "A CLI tool for Microcks",
2828
Long: `microcks-cli is a CLI for interacting with Microcks server APIs.
2929
It allows to launch tests or import API artifacts with minimal dependencies.`,
@@ -46,4 +46,6 @@ func init() {
4646
rootCmd.AddCommand(NewVersionCommand())
4747
rootCmd.AddCommand(NewTestCommand())
4848
rootCmd.AddCommand(NewImportURLCommand())
49+
rootCmd.AddCommand(NewStartCommand())
50+
rootCmd.AddCommand(NewStopCommand())
4951
}

cmd/start.go

Lines changed: 181 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,181 @@
1+
package cmd
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"io"
7+
"log"
8+
"os"
9+
"os/exec"
10+
"strings"
11+
12+
"github.com/docker/docker/api/types/container"
13+
"github.com/docker/docker/api/types/image"
14+
"github.com/docker/docker/client"
15+
"github.com/docker/go-connections/nat"
16+
"github.com/microcks/microcks-cli/pkg/config"
17+
"github.com/spf13/cobra"
18+
)
19+
20+
func NewStartCommand() *cobra.Command {
21+
var (
22+
hostIP string = "0.0.0.0"
23+
name string
24+
hostPort string
25+
imageName string
26+
autoRemove bool
27+
driver string
28+
)
29+
var startCmd = &cobra.Command{
30+
Use: "start",
31+
Short: "start microcks instance",
32+
Example: `# Start a Microcks instance
33+
microcks start
34+
35+
# Define your port (by default 8585)
36+
microcks start --port [Port you want]
37+
38+
# Define your driver (by default docker)
39+
microcks start --driver [driver you wnat either 'docker' or 'podman']
40+
41+
# Define name of your microcks container/instance
42+
microcks start --name [name of you container/instance]`,
43+
Run: func(cmd *cobra.Command, args []string) {
44+
cfg, err := config.EnsureConfig(config.ConfigPath)
45+
46+
if err != nil {
47+
log.Fatalf("Error loading config: %v", err)
48+
}
49+
50+
cfg.Instance.Driver = driver
51+
52+
cli, err := createClient(cfg.Instance.Driver)
53+
54+
if err != nil {
55+
fmt.Println(err)
56+
return
57+
}
58+
59+
defer cli.Close()
60+
61+
if cfg.Instance.Status == "Running" {
62+
fmt.Println("Microcks is already running.")
63+
return
64+
}
65+
66+
if cfg.Instance.Status == "Stopped" || cfg.Instance.Status == "Created" {
67+
if err := startContainer(cfg.Instance.ContainerID, cli); err != nil {
68+
fmt.Errorf("failed to start container: %v", err)
69+
}
70+
fmt.Println("Microcks started successfully...")
71+
return
72+
}
73+
74+
cfg.Instance.Name = name
75+
cfg.Instance.Image = imageName
76+
cfg.Instance.Port = hostPort
77+
cfg.Instance.AutoRemove = autoRemove
78+
79+
containerID, err := createContainer(cfg, hostIP, cli)
80+
81+
if err != nil {
82+
log.Fatalf("Failed to create a container: %v", err)
83+
return
84+
}
85+
cfg.Instance.ContainerID = containerID
86+
cfg.Instance.Status = "Created"
87+
88+
if err := startContainer(cfg.Instance.ContainerID, cli); err != nil {
89+
fmt.Errorf("failed to start container: %v", err)
90+
return
91+
}
92+
cfg.Instance.Status = "Running"
93+
err = config.SaveConfig(config.ConfigPath, cfg)
94+
95+
if err != nil {
96+
log.Fatalf("Failed to save config: %v", err)
97+
return
98+
}
99+
100+
fmt.Printf("Microcks started successfully...")
101+
},
102+
}
103+
startCmd.Flags().StringVar(&name, "name", "microcks", "name for you microcks instance")
104+
startCmd.Flags().StringVar(&hostPort, "port", "8585", "")
105+
startCmd.Flags().StringVar(&imageName, "image", "quay.io/microcks/microcks-uber:latest-native", "image which will be used to create a container")
106+
startCmd.Flags().BoolVar(&autoRemove, "rm", false, "mimic of '--rm' flag of dokcer to automatically remove the container when it exits")
107+
startCmd.Flags().StringVar(&driver, "driver", "docker", "use --driver to change driver from docker to podman")
108+
return startCmd
109+
}
110+
111+
func createClient(driver string) (*client.Client, error) {
112+
113+
if driver != "docker" {
114+
out, err := exec.Command("podman", "machine", "inspect", "--format", "{{.ConnectionInfo.PodmanSocket.Path}}").Output()
115+
if err != nil {
116+
fmt.Println(err)
117+
}
118+
119+
err = os.Setenv("DOCKER_HOST", "unix://"+strings.TrimSpace(string(out)))
120+
if err != nil {
121+
fmt.Println(err)
122+
}
123+
}
124+
125+
cli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())
126+
127+
if err != nil {
128+
return nil, err
129+
}
130+
131+
return cli, nil
132+
}
133+
134+
func createContainer(cfg *config.Config, hostIP string, cli *client.Client) (string, error) {
135+
ctx := context.Background()
136+
137+
// Define exposed port and bindings
138+
exposedPort, _ := nat.NewPort("tcp", "8080")
139+
portBindings := nat.PortMap{
140+
exposedPort: []nat.PortBinding{
141+
{
142+
HostIP: hostIP,
143+
HostPort: cfg.Instance.Port,
144+
},
145+
},
146+
}
147+
148+
out, err := cli.ImagePull(ctx, cfg.Instance.Image, image.PullOptions{})
149+
if err != nil {
150+
return "", err
151+
}
152+
defer out.Close()
153+
io.Copy(os.Stdout, out)
154+
155+
resp, err := cli.ContainerCreate(
156+
ctx,
157+
&container.Config{
158+
Image: cfg.Instance.Image,
159+
ExposedPorts: nat.PortSet{exposedPort: struct{}{}},
160+
},
161+
&container.HostConfig{
162+
PortBindings: portBindings,
163+
AutoRemove: cfg.Instance.AutoRemove,
164+
}, nil, nil, cfg.Instance.Name)
165+
166+
if err != nil {
167+
return "", err
168+
}
169+
170+
return resp.ID, nil
171+
}
172+
173+
func startContainer(cotainerID string, cli *client.Client) error {
174+
ctx := context.Background()
175+
176+
if err := cli.ContainerStart(ctx, cotainerID, container.StartOptions{}); err != nil {
177+
panic(err)
178+
}
179+
180+
return nil
181+
}

cmd/stop.go

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
package cmd
2+
3+
import (
4+
"context"
5+
"fmt"
6+
"log"
7+
8+
containertypes "github.com/docker/docker/api/types/container"
9+
"github.com/docker/docker/client"
10+
"github.com/microcks/microcks-cli/pkg/config"
11+
"github.com/spf13/cobra"
12+
)
13+
14+
func NewStopCommand() *cobra.Command {
15+
16+
var stopCmd = &cobra.Command{
17+
Use: "stop",
18+
Short: "stop microcks instance",
19+
Long: "stop microcks instance",
20+
Run: func(cmd *cobra.Command, args []string) {
21+
22+
cfg, err := config.LoadConfig(config.ConfigPath)
23+
if err != nil {
24+
log.Fatalf("Failed to load config: %v", err)
25+
}
26+
27+
cli, err := createClient(cfg.Instance.Driver)
28+
29+
if err != nil {
30+
fmt.Println(err)
31+
return
32+
}
33+
34+
stopContainer(cfg.Instance.ContainerID, cli)
35+
36+
cfg.Instance.Status = "Stopped"
37+
38+
if cfg.Instance.AutoRemove {
39+
cfg.Instance = struct {
40+
Name string "yaml:\"name\""
41+
Image string "yaml:\"image\""
42+
Status string "yaml:\"status\""
43+
Port string "yaml:\"port\""
44+
ContainerID string "yaml:\"containerID\""
45+
AutoRemove bool "yaml:\"autoRemove\""
46+
Driver string "yaml:\"driver\""
47+
}{}
48+
}
49+
50+
err = config.SaveConfig(config.ConfigPath, cfg)
51+
52+
if err != nil {
53+
log.Fatalf("Failed to save config: %v", err)
54+
}
55+
56+
fmt.Println("Microcks stopped successfully...")
57+
},
58+
}
59+
60+
return stopCmd
61+
}
62+
63+
func stopContainer(containerId string, cli *client.Client) {
64+
ctx := context.Background()
65+
66+
fmt.Print("Stopping container ", containerId, "... ")
67+
noWaitTimeout := 0 // to not wait for the container to exit gracefully
68+
if err := cli.ContainerStop(ctx, containerId, containertypes.StopOptions{Timeout: &noWaitTimeout}); err != nil {
69+
panic(err)
70+
}
71+
fmt.Println("Success")
72+
}

go.mod

Lines changed: 37 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,40 @@
11
module github.com/microcks/microcks-cli
22

3-
go 1.12
3+
go 1.23.0
44

5-
require github.com/spf13/cobra v1.9.1
5+
toolchain go1.24.1
6+
7+
require (
8+
github.com/docker/docker v28.0.4+incompatible
9+
github.com/docker/go-connections v0.5.0
10+
github.com/spf13/cobra v1.9.1
11+
gopkg.in/yaml.v2 v2.4.0
12+
)
13+
14+
require (
15+
github.com/Microsoft/go-winio v0.4.14 // indirect
16+
github.com/containerd/log v0.1.0 // indirect
17+
github.com/distribution/reference v0.6.0 // indirect
18+
github.com/docker/go-units v0.5.0 // indirect
19+
github.com/felixge/httpsnoop v1.0.4 // indirect
20+
github.com/go-logr/logr v1.4.2 // indirect
21+
github.com/go-logr/stdr v1.2.2 // indirect
22+
github.com/gogo/protobuf v1.3.2 // indirect
23+
github.com/inconshreveable/mousetrap v1.1.0 // indirect
24+
github.com/moby/docker-image-spec v1.3.1 // indirect
25+
github.com/moby/term v0.5.2 // indirect
26+
github.com/morikuni/aec v1.0.0 // indirect
27+
github.com/opencontainers/go-digest v1.0.0 // indirect
28+
github.com/opencontainers/image-spec v1.1.1 // indirect
29+
github.com/pkg/errors v0.9.1 // indirect
30+
github.com/spf13/pflag v1.0.6 // indirect
31+
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
32+
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0 // indirect
33+
go.opentelemetry.io/otel v1.35.0 // indirect
34+
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.35.0 // indirect
35+
go.opentelemetry.io/otel/metric v1.35.0 // indirect
36+
go.opentelemetry.io/otel/trace v1.35.0 // indirect
37+
golang.org/x/sys v0.30.0 // indirect
38+
golang.org/x/time v0.11.0 // indirect
39+
gotest.tools/v3 v3.5.2 // indirect
40+
)

0 commit comments

Comments
 (0)