diff --git a/README.md b/README.md index 016989c..1a17b7a 100644 --- a/README.md +++ b/README.md @@ -324,8 +324,6 @@ GET /api/sessions/:id/logs Returns session tracing logs. -Note: endpoint is currently not implemented in the codebase (returns HTTP 501). - Example curl (get session logs): ```sh @@ -338,9 +336,7 @@ curl -X GET http://localhost:8080/api/sessions//logs POST /api/sessions/:id/logs ``` -Uploads session tracing logs. - -Intended usage: upload tracing artifacts for the given session. The current handlers are not implemented in the codebase (returns HTTP 501). When implemented, this endpoint is expected to accept file uploads (multipart/form-data) containing the logs/artifacts for the session. +Uploads session tracing logs. This endpoint is expected to be used by the FileMD service to accept file uploads (multipart/form-data) containing the logs/artifacts for the session. Example curl (upload session logs): @@ -353,11 +349,17 @@ curl -X POST http://localhost:8080/api/sessions//logs \ * Docker * Go 1.25 +* build-essential * libzmq3-dev * libczmq-dev * libsodium-dev * pkg-config +``` sh +sudo apt update +sudo apt install build-essential libzmq3-dev libczmq-dev libsodium-dev pkg-config -y +``` + ## Build & Run ```sh diff --git a/cmd/filemd.go b/cmd/filemd.go index e6ab0c6..f54fb16 100644 --- a/cmd/filemd.go +++ b/cmd/filemd.go @@ -3,6 +3,7 @@ package cmd import ( "context" "fmt" + "time" "github.com/amirhnajafiz/bedrock-api/internal/components/filemd" "github.com/amirhnajafiz/bedrock-api/internal/components/logs" @@ -47,17 +48,19 @@ func StartFileMD(ctx context.Context, cfg *configs.FileMDConfig) error { uploader := filemd.NewHTTPUploader(apiBaseURL) + pollInterval, _ := time.ParseDuration(cfg.PollInterval) + daemon := &filemd.Daemon{ Scanner: scanner, Uploader: uploader, VolumePath: cfg.VolumePath, - PollInterval: cfg.PollInterval, + PollInterval: pollInterval, Logger: logr.Named("filemd"), } logr.Info("starting filemd", zap.String("volume_path", cfg.VolumePath), - zap.Duration("poll_interval", cfg.PollInterval), + zap.Duration("poll_interval", pollInterval), zap.String("api_base_url", apiBaseURL), ) diff --git a/go.mod b/go.mod index 7c756ef..ca15b1d 100644 --- a/go.mod +++ b/go.mod @@ -42,6 +42,7 @@ require ( github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect github.com/go-viper/mapstructure/v2 v2.4.0 // indirect + github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 // indirect github.com/inconshreveable/mousetrap v1.1.0 // indirect github.com/knadh/koanf/maps v0.1.2 // indirect github.com/leodido/go-urn v1.4.0 // indirect diff --git a/go.sum b/go.sum index 1ab12b7..41a78cc 100644 --- a/go.sum +++ b/go.sum @@ -54,6 +54,8 @@ github.com/go-viper/mapstructure/v2 v2.4.0 h1:EBsztssimR/CONLSZZ04E8qAkxNYq4Qp9L github.com/go-viper/mapstructure/v2 v2.4.0/go.mod h1:oJDH3BJKyqBA2TXFhDsKDGDTlndYOZ6rGS0BRZIxGhM= github.com/google/go-cmp v0.7.0 h1:wk8382ETsv4JYUZwIsn6YpYiWiBsYLSJiTsyBybVuN8= github.com/google/go-cmp v0.7.0/go.mod h1:pXiqmnSA92OHEEa9HXL2W4E7lf9JzCmGVUdgjX3N/iU= +github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510 h1:El6M4kTTCOh6aBiKaUGG7oYTSPP8MxqL4YI3kZKwcP4= +github.com/google/shlex v0.0.0-20191202100458-e7afc7fbc510/go.mod h1:pupxD2MaaD3pAXIBCelhxNneeOaAeabZDe5s4K6zSpQ= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/grpc-ecosystem/grpc-gateway/v2 v2.28.0 h1:HWRh5R2+9EifMyIHV7ZV+MIZqgz+PMpZ14Jynv3O2Zs= diff --git a/internal/components/containers/docker/docker.go b/internal/components/containers/docker/docker.go index 3ac6134..8f83a3e 100644 --- a/internal/components/containers/docker/docker.go +++ b/internal/components/containers/docker/docker.go @@ -87,10 +87,20 @@ func (m *DockerContainerManager) Create(ctx context.Context, cfg *models.Contain // set up volume mounts var mounts []mount.Mount for hostPath, containerPath := range cfg.Volumes { + readOnly := false + + if trimmed, ok := strings.CutSuffix(containerPath, ":ro"); ok { + readOnly = true + containerPath = trimmed + } else if trimmed, ok := strings.CutSuffix(containerPath, ":rw"); ok { + containerPath = trimmed + } + mounts = append(mounts, mount.Mount{ - Type: mount.TypeBind, - Source: hostPath, - Target: containerPath, + Type: mount.TypeBind, + Source: hostPath, + Target: containerPath, + ReadOnly: readOnly, }) } diff --git a/internal/configs/configs.go b/internal/configs/configs.go index e6fe49e..ddb8f26 100644 --- a/internal/configs/configs.go +++ b/internal/configs/configs.go @@ -41,12 +41,12 @@ type DockerdConfig struct { // FileMDConfig represents the configuration for the File Management Daemon. type FileMDConfig struct { - LogLevel string `koanf:"log_level" validate:"oneof=debug info warn error"` - APIHTTPHost string `koanf:"api_http_host" validate:"ip"` - APIHTTPPort int `koanf:"api_http_port" validate:"min=1,max=65535"` - DataDir string `koanf:"data_dir"` - VolumePath string `koanf:"volume_path"` - PollInterval time.Duration `koanf:"poll_interval" validate:"duration"` + LogLevel string `koanf:"log_level" validate:"oneof=debug info warn error"` + APIHTTPHost string `koanf:"api_http_host" validate:"ip"` + APIHTTPPort int `koanf:"api_http_port" validate:"min=1,max=65535"` + DataDir string `koanf:"data_dir"` + VolumePath string `koanf:"volume_path"` + PollInterval string `koanf:"poll_interval" validate:"duration"` } // Config represents the configuration for the application. diff --git a/internal/configs/default.go b/internal/configs/default.go index 321a2ef..7e078e6 100644 --- a/internal/configs/default.go +++ b/internal/configs/default.go @@ -1,7 +1,5 @@ package configs -import "time" - // Default returns the default configuration for the application. func Default() *Config { return &Config{ @@ -22,7 +20,7 @@ func DefaultAPIConfig() *APIConfig { FullStackMode: false, DockerDHealthCheckInterval: "1m", SessionStatusCheckInterval: "30s", - BedrockTracerImage: "ghcr.io/amirhnajafiz/bedrock-tracer:v0.0.6-beta", + BedrockTracerImage: "ghcr.io/amirhnajafiz/bedrock-tracer:v0.0.7-beta", } } @@ -34,7 +32,7 @@ func DefaultDockerdConfig() *DockerdConfig { APISocketPort: 8081, APITimeout: "5s", PullInterval: "10s", - BedrockTracerImage: "ghcr.io/amirhnajafiz/bedrock-tracer:v0.0.6-beta", + BedrockTracerImage: "ghcr.io/amirhnajafiz/bedrock-tracer:v0.0.7-beta", DataDir: "/tmp/bedrock-logs", ContainerRuntimeInterface: "simulator", } @@ -47,6 +45,6 @@ func DefaultFileMDConfig() *FileMDConfig { APIHTTPPort: 8081, DataDir: "/tmp/bedrock-logs", VolumePath: "/var/lib/bedrock/volumes", - PollInterval: 10 * time.Second, + PollInterval: "10s", } } diff --git a/internal/ports/daemon/handlers.go b/internal/ports/daemon/handlers.go index 8253fa4..ebeca84 100644 --- a/internal/ports/daemon/handlers.go +++ b/internal/ports/daemon/handlers.go @@ -4,10 +4,10 @@ import ( "context" "encoding/json" "fmt" - "strings" "github.com/amirhnajafiz/bedrock-api/pkg/enums" "github.com/amirhnajafiz/bedrock-api/pkg/models" + "github.com/google/shlex" "go.uber.org/zap" ) @@ -168,6 +168,11 @@ func (d Daemon) startContainersForSession(sessionId string, sessionSpec models.S target := fmt.Sprintf("bedrock-target-%s", sessionId) tracer := fmt.Sprintf("bedrock-tracer-%s", sessionId) + cmd, err := shlex.Split(sessionSpec.Command) + if err != nil { + return fmt.Errorf("invalid command: %w", err) + } + // create the output directory for the tracer if err := createTracerOutputDir(d.datadir, sessionId); err != nil { return fmt.Errorf("failed to create tracer output directory: %w", err) @@ -206,7 +211,7 @@ func (d Daemon) startContainersForSession(sessionId string, sessionSpec models.S &models.ContainerConfig{ Name: target, Image: sessionSpec.Image, - Cmd: strings.Split(sessionSpec.Command, " "), + Cmd: cmd, Labels: map[string]string{ daemonContainerKey: daemonContainerVal, daemonContainerType: daemonContainerTypeTarget,