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: 2 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ Spin applications have the ability to export metrics and trace data. This plugin

This plugin relies on third-party software to work properly. Please be sure you have the following installed before continuing:

- Latest version of [Docker](https://www.docker.com/products/docker-desktop)
- Latest version of [Docker](https://www.docker.com/products/docker-desktop) or [Podman](https://podman.io/docs)

# Installation

Expand Down Expand Up @@ -49,7 +49,7 @@ The `otel` plugin currently supports two different observability stacks:

- Default: Multi-container observability stack based on Prometheus, Loki, Grafana and Jaeger
- Aspire: Single-container observability stack using .NET Aspire Dashboard

# Usage

Once the plugin is installed, you can try the below commands:
Expand Down
23 changes: 12 additions & 11 deletions cmd/cleanup.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,12 +26,12 @@ func init() {
cleanUpCmd.Flags().BoolVarP(&removeContainers, "remove", "r", false, "If specified, OTel containers will be removed")
}

func getIDs(dockerOutput []byte) []string {
func getIDs(runtimeOutput []byte) []string {
var result []string
outputArray := strings.Split(string(dockerOutput), "\n")
outputArray := strings.Split(string(runtimeOutput), "\n")

// skip the first line of the output, because it is the table header row
// docker ps does not support hiding column headers
// {{runtime}} ps does not support hiding column headers
for _, entry := range outputArray[1:] {
fields := strings.Fields(entry)
if len(fields) > 0 {
Expand All @@ -43,21 +43,22 @@ func getIDs(dockerOutput []byte) []string {
}

func cleanUp() error {
if err := checkDocker(); err != nil {
runtime, err := detectContainerRuntime()
if err != nil {
return err
}

fmt.Println("Stopping Spin OpenTelemetry Docker containers...")
getContainers := exec.Command("docker", "ps", fmt.Sprintf("--filter=name=%s*", otelConfigDirName), "--format=table")
dockerPsOutput, err := getContainers.CombinedOutput()
fmt.Println("Stopping Spin OpenTelemetry containers...")
getContainers := exec.Command(runtime, "ps", fmt.Sprintf("--filter=name=%s*", otelConfigDirName))
processOutput, err := getContainers.CombinedOutput()
if err != nil {
fmt.Println(string(dockerPsOutput))
fmt.Println(string(processOutput))
return err
}

containerIDs := getIDs(dockerPsOutput)
containerIDs := getIDs(processOutput)

// The `docker stop` command will throw an error if there are no containers to stop
// The `{{runtime}} stop` command will throw an error if there are no containers to stop
if len(containerIDs) == 0 {
fmt.Println("No Spin OpenTelemetry resources found. Nothing to clean up.")
return nil
Expand All @@ -67,7 +68,7 @@ func cleanUp() error {
if removeContainers {
cleanupArgs = []string{"rm", "-f"}
}
stopContainers := exec.Command("docker", append(cleanupArgs, containerIDs...)...)
stopContainers := exec.Command(runtime, append(cleanupArgs, containerIDs...)...)
stopContainersOutput, err := stopContainers.CombinedOutput()
if err != nil {
fmt.Println(string(stopContainersOutput))
Expand Down
49 changes: 41 additions & 8 deletions cmd/root.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ import (
"os"
"os/exec"
"path"
"strings"

open "github.com/fermyon/otel-plugin/cmd/open"
"github.com/spf13/cobra"
Expand Down Expand Up @@ -35,19 +36,51 @@ func setOtelConfigPath() error {
return nil
}

// checkDocker checks whether Docker is installed and the Docker daemon is running
func checkDocker() error {
cmd := exec.Command("docker", "--version")
if err := cmd.Run(); err != nil {
return fmt.Errorf("Docker appears not to be installed, so please visit their install page and try again once installed: https://www.docker.com/products/docker-desktop")
// detectContainerRuntime checks for a supported container runtime.
//
// Returns the detected runtime name.
func detectContainerRuntime() (string, error) {
// Default Docker, fallback Podman
runtimesToCheck := []string{"docker", "podman"}
runtime := ""
for _, rt := range runtimesToCheck {
cmd := exec.Command(rt, "--version")
if err := cmd.Run(); err != nil {
continue
}
runtime = rt
break
}

if runtime == "" {
return "", fmt.Errorf("Unable to detect container runtime.\nPlease ensure at least one of the following is installed and in the PATH: %s\n", strings.Join(runtimesToCheck, ", "))
}

if runtime == "podman" {
// Podman doesn't auto-install a compose provider
composeProvidersToCheck := []string{"podman-compose", "docker-compose"}
composeProvider := ""
for _, rt := range composeProvidersToCheck {
cmd := exec.Command(rt, "--version")
if err := cmd.Run(); err != nil {
continue
}

composeProvider = rt
break
}

if composeProvider == "" {
return "", fmt.Errorf("Unable to detect compose provider.\n Please ensure at least one of the following is installed and in the PATH: %s\n", strings.Join(composeProvidersToCheck, ", "))
}
}

cmd = exec.Command("docker", "info")
cmd := exec.Command(runtime, "info")
if err := cmd.Run(); err != nil {
return fmt.Errorf("The Docker daemon appears not to be running. The command to start Docker depends on your operating system. For instructions, check the correct page under https://docs.docker.com/engine/install")
return "", fmt.Errorf("The daemon/virtual machine for %[1]s appears not to be running. Please check the documentation for %[1]s for more information.", runtime)
}

return nil
return runtime, nil
}

func Execute() {
Expand Down
9 changes: 6 additions & 3 deletions cmd/setup.go
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ var (
aspire = false
setUpCmd = &cobra.Command{
Use: "setup",
Short: "Run OpenTelemetry dependencies in Docker.",
Short: "Run OpenTelemetry dependencies as containers",
Long: "Required OpenTelemetry dependencies will be started as containers using a supported container runtime (docker, podman)",
RunE: func(cmd *cobra.Command, args []string) error {
s := stack.GetStackByFlags(aspire)
if err := setUp(s); err != nil {
Expand All @@ -30,16 +31,18 @@ func init() {
}

func setUp(s stack.Stack) error {
if err := checkDocker(); err != nil {
runtime, err := detectContainerRuntime()
if err != nil {
return err
}

composeFileName := s.GetComposeFileName()
composeFilePath := path.Join(otelConfigPath, composeFileName)
if _, err := os.Stat(composeFilePath); os.IsNotExist(err) {
return fmt.Errorf("The \"otel-config\" directory is missing the \"%s\" file, so please consider removing and re-installing the otel plugin", composeFileName)
}

cmd := exec.Command("docker", "compose", "-f", composeFilePath, "up", "-d")
cmd := exec.Command(runtime, "compose", "-f", composeFilePath, "up", "-d")

fmt.Println("Pulling and running Spin OpenTelemetry resources...")

Expand Down
4 changes: 0 additions & 4 deletions cmd/up.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,10 +22,6 @@ var upCmd = &cobra.Command{
}

func up(args []string) error {
if err := checkDocker(); err != nil {
return err
}

pathToSpin := os.Getenv("SPIN_BIN_PATH")
if pathToSpin == "" {
return fmt.Errorf("Please ensure that you are running \"spin otel up\", rather than calling the OpenTelemetry plugin binary directly")
Expand Down