Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion cmd/cmd.go
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ import (
)

var rootCmd = &cobra.Command{
Use: "microcks-cli",
Use: "microcks",
Short: "A CLI tool for Microcks",
Long: `microcks-cli is a CLI for interacting with Microcks server APIs.
It allows to launch tests or import API artifacts with minimal dependencies.`,
Expand All @@ -46,4 +46,6 @@ func init() {
rootCmd.AddCommand(NewVersionCommand())
rootCmd.AddCommand(NewTestCommand())
rootCmd.AddCommand(NewImportURLCommand())
rootCmd.AddCommand(NewStartCommand())
rootCmd.AddCommand(NewStopCommand())
}
181 changes: 181 additions & 0 deletions cmd/start.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,181 @@
package cmd

import (
"context"
"fmt"
"io"
"log"
"os"
"os/exec"
"strings"

"github.com/docker/docker/api/types/container"
"github.com/docker/docker/api/types/image"
"github.com/docker/docker/client"
"github.com/docker/go-connections/nat"
"github.com/microcks/microcks-cli/pkg/config"
"github.com/spf13/cobra"
)

func NewStartCommand() *cobra.Command {
var (
hostIP string = "0.0.0.0"
name string
hostPort string
imageName string
autoRemove bool
driver string
)
var startCmd = &cobra.Command{
Use: "start",
Short: "start microcks instance",
Example: `# Start a Microcks instance
microcks start

# Define your port (by default 8585)
microcks start --port [Port you want]

# Define your driver (by default docker)
microcks start --driver [driver you wnat either 'docker' or 'podman']

# Define name of your microcks container/instance
microcks start --name [name of you container/instance]`,
Run: func(cmd *cobra.Command, args []string) {
cfg, err := config.EnsureConfig(config.ConfigPath)

if err != nil {
log.Fatalf("Error loading config: %v", err)
}

cfg.Instance.Driver = driver

cli, err := createClient(cfg.Instance.Driver)

if err != nil {
fmt.Println(err)
return
}

defer cli.Close()

if cfg.Instance.Status == "Running" {
fmt.Println("Microcks is already running.")
return
}

if cfg.Instance.Status == "Stopped" || cfg.Instance.Status == "Created" {
if err := startContainer(cfg.Instance.ContainerID, cli); err != nil {
fmt.Errorf("failed to start container: %v", err)
}
fmt.Println("Microcks started successfully...")
return
}

cfg.Instance.Name = name
cfg.Instance.Image = imageName
cfg.Instance.Port = hostPort
cfg.Instance.AutoRemove = autoRemove

containerID, err := createContainer(cfg, hostIP, cli)

if err != nil {
log.Fatalf("Failed to create a container: %v", err)
return
}
cfg.Instance.ContainerID = containerID
cfg.Instance.Status = "Created"

if err := startContainer(cfg.Instance.ContainerID, cli); err != nil {
fmt.Errorf("failed to start container: %v", err)
return
}
cfg.Instance.Status = "Running"
err = config.SaveConfig(config.ConfigPath, cfg)

if err != nil {
log.Fatalf("Failed to save config: %v", err)
return
}

fmt.Printf("Microcks started successfully...")
},
}
startCmd.Flags().StringVar(&name, "name", "microcks", "name for you microcks instance")
startCmd.Flags().StringVar(&hostPort, "port", "8585", "")
startCmd.Flags().StringVar(&imageName, "image", "quay.io/microcks/microcks-uber:latest-native", "image which will be used to create a container")
startCmd.Flags().BoolVar(&autoRemove, "rm", false, "mimic of '--rm' flag of dokcer to automatically remove the container when it exits")
startCmd.Flags().StringVar(&driver, "driver", "docker", "use --driver to change driver from docker to podman")
return startCmd
}

func createClient(driver string) (*client.Client, error) {

if driver != "docker" {
out, err := exec.Command("podman", "machine", "inspect", "--format", "{{.ConnectionInfo.PodmanSocket.Path}}").Output()
if err != nil {
fmt.Println(err)
}

err = os.Setenv("DOCKER_HOST", "unix://"+strings.TrimSpace(string(out)))
if err != nil {
fmt.Println(err)
}
}

cli, err := client.NewClientWithOpts(client.FromEnv, client.WithAPIVersionNegotiation())

if err != nil {
return nil, err
}

return cli, nil
}

func createContainer(cfg *config.Config, hostIP string, cli *client.Client) (string, error) {
ctx := context.Background()

// Define exposed port and bindings
exposedPort, _ := nat.NewPort("tcp", "8080")
portBindings := nat.PortMap{
exposedPort: []nat.PortBinding{
{
HostIP: hostIP,
HostPort: cfg.Instance.Port,
},
},
}

out, err := cli.ImagePull(ctx, cfg.Instance.Image, image.PullOptions{})
if err != nil {
return "", err
}
defer out.Close()
io.Copy(os.Stdout, out)

resp, err := cli.ContainerCreate(
ctx,
&container.Config{
Image: cfg.Instance.Image,
ExposedPorts: nat.PortSet{exposedPort: struct{}{}},
},
&container.HostConfig{
PortBindings: portBindings,
AutoRemove: cfg.Instance.AutoRemove,
}, nil, nil, cfg.Instance.Name)

if err != nil {
return "", err
}

return resp.ID, nil
}

func startContainer(cotainerID string, cli *client.Client) error {
ctx := context.Background()

if err := cli.ContainerStart(ctx, cotainerID, container.StartOptions{}); err != nil {
panic(err)
}

return nil
}
72 changes: 72 additions & 0 deletions cmd/stop.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
package cmd

import (
"context"
"fmt"
"log"

containertypes "github.com/docker/docker/api/types/container"
"github.com/docker/docker/client"
"github.com/microcks/microcks-cli/pkg/config"
"github.com/spf13/cobra"
)

func NewStopCommand() *cobra.Command {

var stopCmd = &cobra.Command{
Use: "stop",
Short: "stop microcks instance",
Long: "stop microcks instance",
Run: func(cmd *cobra.Command, args []string) {

cfg, err := config.LoadConfig(config.ConfigPath)
if err != nil {
log.Fatalf("Failed to load config: %v", err)
}

cli, err := createClient(cfg.Instance.Driver)

if err != nil {
fmt.Println(err)
return
}

stopContainer(cfg.Instance.ContainerID, cli)

cfg.Instance.Status = "Stopped"

if cfg.Instance.AutoRemove {
cfg.Instance = struct {
Name string "yaml:\"name\""
Image string "yaml:\"image\""
Status string "yaml:\"status\""
Port string "yaml:\"port\""
ContainerID string "yaml:\"containerID\""
AutoRemove bool "yaml:\"autoRemove\""
Driver string "yaml:\"driver\""
}{}
}

err = config.SaveConfig(config.ConfigPath, cfg)

if err != nil {
log.Fatalf("Failed to save config: %v", err)
}

fmt.Println("Microcks stopped successfully...")
},
}

return stopCmd
}

func stopContainer(containerId string, cli *client.Client) {
ctx := context.Background()

fmt.Print("Stopping container ", containerId, "... ")
noWaitTimeout := 0 // to not wait for the container to exit gracefully
if err := cli.ContainerStop(ctx, containerId, containertypes.StopOptions{Timeout: &noWaitTimeout}); err != nil {
panic(err)
}
fmt.Println("Success")
}
39 changes: 37 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
@@ -1,5 +1,40 @@
module github.com/microcks/microcks-cli

go 1.12
go 1.23.0

require github.com/spf13/cobra v1.9.1
toolchain go1.24.1

require (
github.com/docker/docker v28.0.4+incompatible
github.com/docker/go-connections v0.5.0
github.com/spf13/cobra v1.9.1
gopkg.in/yaml.v2 v2.4.0
)

require (
github.com/Microsoft/go-winio v0.4.14 // indirect
github.com/containerd/log v0.1.0 // indirect
github.com/distribution/reference v0.6.0 // indirect
github.com/docker/go-units v0.5.0 // indirect
github.com/felixge/httpsnoop v1.0.4 // indirect
github.com/go-logr/logr v1.4.2 // indirect
github.com/go-logr/stdr v1.2.2 // indirect
github.com/gogo/protobuf v1.3.2 // indirect
github.com/inconshreveable/mousetrap v1.1.0 // indirect
github.com/moby/docker-image-spec v1.3.1 // indirect
github.com/moby/term v0.5.2 // indirect
github.com/morikuni/aec v1.0.0 // indirect
github.com/opencontainers/go-digest v1.0.0 // indirect
github.com/opencontainers/image-spec v1.1.1 // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/spf13/pflag v1.0.6 // indirect
go.opentelemetry.io/auto/sdk v1.1.0 // indirect
go.opentelemetry.io/contrib/instrumentation/net/http/otelhttp v0.60.0 // indirect
go.opentelemetry.io/otel v1.35.0 // indirect
go.opentelemetry.io/otel/exporters/otlp/otlptrace/otlptracehttp v1.35.0 // indirect
go.opentelemetry.io/otel/metric v1.35.0 // indirect
go.opentelemetry.io/otel/trace v1.35.0 // indirect
golang.org/x/sys v0.30.0 // indirect
golang.org/x/time v0.11.0 // indirect
gotest.tools/v3 v3.5.2 // indirect
)
Loading
Loading