diff --git a/cmd/exec/exec.go b/cmd/exec/exec.go index 7200a18..aebc134 100644 --- a/cmd/exec/exec.go +++ b/cmd/exec/exec.go @@ -2,6 +2,8 @@ package exec import ( "fmt" + "github.com/puppetlabs/prm/pkg/backend" + "github.com/puppetlabs/prm/pkg/backend/docker" "os" "os/user" "path/filepath" @@ -92,10 +94,10 @@ func preExecute(cmd *cobra.Command, args []string) error { } switch prmApi.RunningConfig.Backend { - case prm.DOCKER: - prmApi.Backend = &prm.Docker{AFS: prmApi.AFS, IOFS: prmApi.IOFS, AlwaysBuild: alwaysBuild, ContextTimeout: prmApi.RunningConfig.Timeout} + case backend.DOCKER: + prmApi.Backend = &docker.Docker{AFS: prmApi.AFS, IOFS: prmApi.IOFS, AlwaysBuild: alwaysBuild, ContextTimeout: prmApi.RunningConfig.Timeout} default: - prmApi.Backend = &prm.Docker{AFS: prmApi.AFS, IOFS: prmApi.IOFS, AlwaysBuild: alwaysBuild, ContextTimeout: prmApi.RunningConfig.Timeout} + prmApi.Backend = &docker.Docker{AFS: prmApi.AFS, IOFS: prmApi.IOFS, AlwaysBuild: alwaysBuild, ContextTimeout: prmApi.RunningConfig.Timeout} } if prmApi.CodeDir == "" { diff --git a/cmd/set/backend.go b/cmd/set/backend.go index 8dfb481..ecfb93e 100644 --- a/cmd/set/backend.go +++ b/cmd/set/backend.go @@ -2,13 +2,14 @@ package set import ( "fmt" + "github.com/puppetlabs/prm/pkg/backend" "strings" "github.com/puppetlabs/prm/pkg/prm" "github.com/spf13/cobra" ) -var SelectedBackend prm.BackendType +var SelectedBackend backend.BackendType func (sc *SetCommand) createSetBackendCommand() *cobra.Command { tmp := &cobra.Command{ @@ -17,7 +18,7 @@ func (sc *SetCommand) createSetBackendCommand() *cobra.Command { Long: `Sets the backend exec environment to the specified type`, PreRunE: sc.setBackendPreRunE, RunE: sc.setBackendType, - ValidArgs: []string{string(prm.DOCKER)}, + ValidArgs: []string{string(backend.DOCKER)}, } return tmp @@ -25,18 +26,18 @@ func (sc *SetCommand) createSetBackendCommand() *cobra.Command { func (sc *SetCommand) setBackendPreRunE(cmd *cobra.Command, args []string) (err error) { if len(args) > 1 { - return fmt.Errorf("too many args, please specify ONE of the following backend types after 'set backend':\n- %s", prm.DOCKER) + return fmt.Errorf("too many args, please specify ONE of the following backend types after 'set backend':\n- %s", backend.DOCKER) } if len(args) < 1 { - return fmt.Errorf("please specify specify one of the following backend types after 'set backend':\n- %s", prm.DOCKER) + return fmt.Errorf("please specify specify one of the following backend types after 'set backend':\n- %s", backend.DOCKER) } switch strings.ToLower(args[0]) { - case string(prm.DOCKER): - SelectedBackend = prm.DOCKER + case string(backend.DOCKER): + SelectedBackend = backend.DOCKER default: - return fmt.Errorf("'%s' is not a valid backend type, please specify one of the following backend types:\n- %s", args[0], prm.DOCKER) + return fmt.Errorf("'%s' is not a valid backend type, please specify one of the following backend types:\n- %s", args[0], backend.DOCKER) } return nil diff --git a/cmd/set/set_test.go b/cmd/set/set_test.go index 9f9d354..2fff2f3 100644 --- a/cmd/set/set_test.go +++ b/cmd/set/set_test.go @@ -3,12 +3,12 @@ package set_test import ( "bytes" "fmt" + "github.com/puppetlabs/prm/pkg/backend" "io/ioutil" "testing" "github.com/puppetlabs/prm/cmd/set" "github.com/puppetlabs/prm/internal/pkg/mock" - "github.com/puppetlabs/prm/pkg/prm" "github.com/stretchr/testify/assert" ) @@ -17,7 +17,7 @@ type test struct { args []string expectedOutput string expectedPuppetVer string - expectedBackedType prm.BackendType + expectedBackedType backend.BackendType expectError bool } @@ -78,29 +78,29 @@ func Test_SetBackendCommand(t *testing.T) { { name: "Should handle valid backend selection (docker)", args: []string{"backend", "docker"}, - expectedBackedType: prm.DOCKER, + expectedBackedType: backend.DOCKER, }, { name: "Should handle valid backend selection (dOcKeR)", args: []string{"backend", "dOcKeR"}, - expectedBackedType: prm.DOCKER, + expectedBackedType: backend.DOCKER, }, { name: "Should error when too many args supplied to 'backend' sub cmd", args: []string{"backend", "foo", "bar"}, - expectedOutput: fmt.Sprintf("Error: too many args, please specify ONE of the following backend types after 'set backend':\n- %s", prm.DOCKER), + expectedOutput: fmt.Sprintf("Error: too many args, please specify ONE of the following backend types after 'set backend':\n- %s", backend.DOCKER), expectError: true, }, { name: "Should error when no arg supplied to 'badckend' sub cmd", args: []string{"backend"}, - expectedOutput: fmt.Sprintf("please specify specify one of the following backend types after 'set backend':\n- %s", prm.DOCKER), + expectedOutput: fmt.Sprintf("please specify specify one of the following backend types after 'set backend':\n- %s", backend.DOCKER), expectError: true, }, { name: "Should error when invalid backend type supplied to 'badckend' sub cmd", args: []string{"backend", "foo"}, - expectedOutput: fmt.Sprintf("Error: 'foo' is not a valid backend type, please specify one of the following backend types:\n- %s", prm.DOCKER), + expectedOutput: fmt.Sprintf("Error: 'foo' is not a valid backend type, please specify one of the following backend types:\n- %s", backend.DOCKER), expectError: true, }, } diff --git a/cmd/status/status.go b/cmd/status/status.go index da2d62e..4b70416 100644 --- a/cmd/status/status.go +++ b/cmd/status/status.go @@ -2,6 +2,7 @@ package status import ( "fmt" + "github.com/puppetlabs/prm/pkg/backend/docker" "github.com/puppetlabs/prm/pkg/prm" "github.com/spf13/cobra" @@ -36,7 +37,7 @@ func CreateStatusCommand(parent *prm.Prm) *cobra.Command { func preExecute(cmd *cobra.Command, args []string) error { switch prmApi.RunningConfig.Backend { default: - prmApi.Backend = &prm.Docker{AFS: prmApi.AFS, IOFS: prmApi.IOFS, ContextTimeout: prmApi.RunningConfig.Timeout} + prmApi.Backend = &docker.Docker{AFS: prmApi.AFS, IOFS: prmApi.IOFS, ContextTimeout: prmApi.RunningConfig.Timeout} } return nil } diff --git a/cmd/validate/validate.go b/cmd/validate/validate.go index 81433d4..fc2d449 100644 --- a/cmd/validate/validate.go +++ b/cmd/validate/validate.go @@ -2,6 +2,8 @@ package validate import ( "fmt" + "github.com/puppetlabs/prm/pkg/backend" + "github.com/puppetlabs/prm/pkg/backend/docker" "os" "os/user" "path" @@ -127,10 +129,10 @@ func preExecute(cmd *cobra.Command, args []string) error { } switch prmApi.RunningConfig.Backend { - case prm.DOCKER: - prmApi.Backend = &prm.Docker{AFS: prmApi.AFS, IOFS: prmApi.IOFS, AlwaysBuild: alwaysBuild, ContextTimeout: prmApi.RunningConfig.Timeout} + case backend.DOCKER: + prmApi.Backend = &docker.Docker{AFS: prmApi.AFS, IOFS: prmApi.IOFS, AlwaysBuild: alwaysBuild, ContextTimeout: prmApi.RunningConfig.Timeout} default: - prmApi.Backend = &prm.Docker{AFS: prmApi.AFS, IOFS: prmApi.IOFS, AlwaysBuild: alwaysBuild, ContextTimeout: prmApi.RunningConfig.Timeout} + prmApi.Backend = &docker.Docker{AFS: prmApi.AFS, IOFS: prmApi.IOFS, AlwaysBuild: alwaysBuild, ContextTimeout: prmApi.RunningConfig.Timeout} } if !listTools { @@ -233,16 +235,16 @@ func execute(cmd *cobra.Command, args []string) error { additionalToolArgs, _ = shlex.Split(toolArgs) } - toolInfo := prm.ToolInfo{ + toolInfo := backend.ToolInfo{ Tool: cachedTool, Args: additionalToolArgs, } - settings := prm.OutputSettings{ + settings := backend.OutputSettings{ ResultsView: resultsView, OutputDir: path.Join(prmApi.CodeDir, ".prm-validate"), } - err := prmApi.Validate([]prm.ToolInfo{toolInfo}, 1, settings) + err := prmApi.Validate([]backend.ToolInfo{toolInfo}, 1, settings) if err != nil { return err } @@ -264,14 +266,14 @@ func execute(cmd *cobra.Command, args []string) error { } // Gather a list of tools - var toolList []prm.ToolInfo + var toolList []backend.ToolInfo for _, tool := range toolGroup.Tools { cachedTool, ok := prmApi.IsToolAvailable(tool.Name) if !ok { return fmt.Errorf("Tool %s not found in cache", tool) } - info := prm.ToolInfo{Tool: cachedTool, Args: tool.Args} + info := backend.ToolInfo{Tool: cachedTool, Args: tool.Args} toolList = append(toolList, info) } @@ -281,7 +283,7 @@ func execute(cmd *cobra.Command, args []string) error { if isSerial || workerCount < 1 { workerCount = 1 } - err = prmApi.Validate(toolList, workerCount, prm.OutputSettings{ResultsView: resultsView, OutputDir: outputDir}) + err = prmApi.Validate(toolList, workerCount, backend.OutputSettings{ResultsView: resultsView, OutputDir: outputDir}) if err != nil { return err } diff --git a/internal/pkg/mock/backend.go b/internal/pkg/mock/backend.go index f01d30f..c7cbffe 100644 --- a/internal/pkg/mock/backend.go +++ b/internal/pkg/mock/backend.go @@ -2,6 +2,8 @@ package mock import ( "errors" + "github.com/puppetlabs/prm/pkg/backend" + "github.com/puppetlabs/prm/pkg/backend/docker" "github.com/puppetlabs/prm/pkg/prm" ) @@ -14,8 +16,8 @@ type MockBackend struct { ValidateReturn string } -func (m *MockBackend) Status() prm.BackendStatus { - return prm.BackendStatus{IsAvailable: m.StatusIsAvailable, StatusMsg: m.StatusMessageString} +func (m *MockBackend) Status() backend.BackendStatus { + return backend.BackendStatus{IsAvailable: m.StatusIsAvailable, StatusMsg: m.StatusMessageString} } func (m *MockBackend) GetTool(tool *prm.Tool, prmConfig prm.Config) error { @@ -27,7 +29,7 @@ func (m *MockBackend) GetTool(tool *prm.Tool, prmConfig prm.Config) error { } // Implement when needed -func (m *MockBackend) Validate(toolInfo prm.ToolInfo, prmConfig prm.Config, paths prm.DirectoryPaths) (prm.ValidateExitCode, string, error) { +func (m *MockBackend) Validate(toolInfo backend.ToolInfo, prmConfig prm.Config, paths backend.DirectoryPaths) (prm.ValidateExitCode, string, error) { switch m.ValidateReturn { case "PASS": return prm.VALIDATION_PASS, "", nil @@ -40,7 +42,7 @@ func (m *MockBackend) Validate(toolInfo prm.ToolInfo, prmConfig prm.Config, path } } -func (m *MockBackend) Exec(tool *prm.Tool, args []string, prmConfig prm.Config, paths prm.DirectoryPaths) (prm.ToolExitCode, error) { +func (m *MockBackend) Exec(tool *prm.Tool, args []string, prmConfig prm.Config, paths backend.DirectoryPaths) (prm.ToolExitCode, error) { switch m.ExecReturn { case "SUCCESS": return prm.SUCCESS, nil @@ -51,6 +53,6 @@ func (m *MockBackend) Exec(tool *prm.Tool, args []string, prmConfig prm.Config, case "TOOL_NOT_FOUND": return prm.TOOL_NOT_FOUND, nil default: - return prm.FAILURE, prm.ErrDockerNotRunning + return prm.FAILURE, docker.ErrDockerNotRunning } } diff --git a/pkg/prm/backend.go b/pkg/backend/backend.go similarity index 67% rename from pkg/prm/backend.go rename to pkg/backend/backend.go index bf8a535..94fa8e3 100644 --- a/pkg/prm/backend.go +++ b/pkg/backend/backend.go @@ -1,5 +1,7 @@ //nolint:structcheck,unused -package prm +package backend + +import "github.com/puppetlabs/prm/pkg/prm" type BackendType string @@ -8,9 +10,9 @@ const ( ) type BackendI interface { - GetTool(tool *Tool, prmConfig Config) error - Validate(toolInfo ToolInfo, prmConfig Config, paths DirectoryPaths) (ValidateExitCode, string, error) - Exec(tool *Tool, args []string, prmConfig Config, paths DirectoryPaths) (ToolExitCode, error) + GetTool(tool *prm.Tool, prmConfig prm.Config) error + Validate(toolInfo ToolInfo, prmConfig prm.Config, paths DirectoryPaths) (ValidateExitCode, string, error) + Exec(tool *prm.Tool, args []string, prmConfig prm.Config, paths DirectoryPaths) (prm.ToolExitCode, error) Status() BackendStatus } @@ -33,7 +35,7 @@ type OutputSettings struct { } type ToolInfo struct { - Tool *Tool + Tool *prm.Tool Args []string } diff --git a/pkg/prm/docker.go b/pkg/backend/docker/docker.go similarity index 93% rename from pkg/prm/docker.go rename to pkg/backend/docker/docker.go index df34532..7313c38 100644 --- a/pkg/prm/docker.go +++ b/pkg/backend/docker/docker.go @@ -1,4 +1,4 @@ -package prm +package docker import ( "bufio" @@ -6,6 +6,8 @@ import ( "context" "encoding/json" "fmt" + "github.com/puppetlabs/prm/pkg/backend" + "github.com/puppetlabs/prm/pkg/prm" "io" "os" "path/filepath" @@ -29,8 +31,8 @@ import ( type Docker struct { // We need to be able to mock the docker client in testing - Client DockerClientI - Context context.Context + Client DockerClientI + Context context.Context ContextCancel func() ContextTimeout time.Duration AFS *afero.Afero @@ -56,7 +58,7 @@ type DockerClientI interface { ContainerStop(ctx context.Context, containerID string, timeout *time.Duration) error } -func (d *Docker) GetTool(tool *Tool, prmConfig Config) error { +func (d *Docker) GetTool(tool *prm.Tool, prmConfig prm.Config) error { // initialise the docker client err := d.initClient() @@ -171,7 +173,7 @@ func (d *Docker) GetTool(tool *Tool, prmConfig Config) error { return nil } -func (d *Docker) createDockerfile(tool *Tool, prmConfig Config) string { +func (d *Docker) createDockerfile(tool *prm.Tool, prmConfig prm.Config) string { // create a dockerfile from the Tool and prmConfig dockerfile := strings.Builder{} dockerfile.WriteString(fmt.Sprintf("FROM puppet/puppet-agent:%s\n", prmConfig.PuppetVersion.String())) @@ -243,13 +245,13 @@ func (d *Docker) createDockerfile(tool *Tool, prmConfig Config) string { } // Creates a unique name for the image based on the tool and the PRM configuration -func (d *Docker) ImageName(tool *Tool, prmConfig Config) string { +func (d *Docker) ImageName(tool *prm.Tool, prmConfig prm.Config) string { // build up a name based on the tool and puppet version imageName := fmt.Sprintf("pdk:puppet-%s_%s-%s_%s", prmConfig.PuppetVersion.String(), tool.Cfg.Plugin.Author, tool.Cfg.Plugin.Id, tool.Cfg.Plugin.Version) return imageName } -func getOutputAsStrings(containerOutput *ContainerOutput, reader io.ReadCloser) error { +func getOutputAsStrings(containerOutput *backend.ContainerOutput, reader io.ReadCloser) error { stdoutBuf := new(bytes.Buffer) stderrBuf := new(bytes.Buffer) @@ -273,7 +275,7 @@ func (d *Docker) setTimeoutContext() (context.Context, context.CancelFunc) { return ctx, cancel } -func (d *Docker) Validate(toolInfo ToolInfo, prmConfig Config, paths DirectoryPaths) (ValidateExitCode, string, error) { +func (d *Docker) Validate(toolInfo backend.ToolInfo, prmConfig prm.Config, paths backend.DirectoryPaths) (ValidateExitCode, string, error) { // is Docker up and running? status := d.Status() if !status.IsAvailable { @@ -354,7 +356,7 @@ func (d *Docker) Validate(toolInfo ToolInfo, prmConfig Config, paths DirectoryPa }() // parse out the containers logs while we wait for the container to finish - containerOutput := ContainerOutput{} + containerOutput := backend.ContainerOutput{} for { out, err := d.Client.ContainerLogs(timeoutCtx, resp.ID, types.ContainerLogsOptions{ShowStdout: true, ShowStderr: true, Tail: "all", Follow: true}) if err != nil { @@ -384,12 +386,12 @@ func (d *Docker) Validate(toolInfo ToolInfo, prmConfig Config, paths DirectoryPa } } -func (d *Docker) Exec(tool *Tool, args []string, prmConfig Config, paths DirectoryPaths) (ToolExitCode, error) { +func (d *Docker) Exec(tool *prm.Tool, args []string, prmConfig prm.Config, paths backend.DirectoryPaths) (prm.ToolExitCode, error) { // is Docker up and running? status := d.Status() if !status.IsAvailable { log.Error().Msgf("Docker is not available") - return FAILURE, fmt.Errorf("%s", status.StatusMsg) + return prm.FAILURE, fmt.Errorf("%s", status.StatusMsg) } // clean up paths @@ -430,7 +432,7 @@ func (d *Docker) Exec(tool *Tool, args []string, prmConfig Config, paths Directo }, nil, nil, "") if err != nil { - return FAILURE, err + return prm.FAILURE, err } // the autoremove functionality is too aggressive // it fires before we can get at the logs @@ -451,7 +453,7 @@ func (d *Docker) Exec(tool *Tool, args []string, prmConfig Config, paths Directo }() if err := d.Client.ContainerStart(timeoutCtx, resp.ID, types.ContainerStartOptions{}); err != nil { - return FAILURE, err + return prm.FAILURE, err } isError := make(chan error) @@ -470,20 +472,20 @@ func (d *Docker) Exec(tool *Tool, args []string, prmConfig Config, paths Directo for { out, err := d.Client.ContainerLogs(timeoutCtx, resp.ID, types.ContainerLogsOptions{ShowStdout: true, ShowStderr: true, Tail: "all", Follow: true}) if err != nil { - return FAILURE, err + return prm.FAILURE, err } _, err = stdcopy.StdCopy(os.Stdout, os.Stderr, out) if err != nil { - return FAILURE, err + return prm.FAILURE, err } select { case err := <-isError: - return FAILURE, err + return prm.FAILURE, err case exitValues := <-toolExit: if exitValues.StatusCode == int64(tool.Cfg.Common.SuccessExitCode) { - return SUCCESS, nil + return prm.SUCCESS, nil } else { // If we have more details on why the tool failed, use that info if exitValues.Error != nil { @@ -492,7 +494,7 @@ func (d *Docker) Exec(tool *Tool, args []string, prmConfig Config, paths Directo // otherwise, just log the exit code err = fmt.Errorf("Tool exited with code: %d", exitValues.StatusCode) } - return TOOL_ERROR, err + return prm.TOOL_ERROR, err } } @@ -519,10 +521,10 @@ func (d *Docker) initClient() (err error) { // Check to see if the Docker runtime is available: // if so, return true and info about Docker on this node; // if not, return false and the error message -func (d *Docker) Status() BackendStatus { +func (d *Docker) Status() backend.BackendStatus { err := d.initClient() if err != nil { - return BackendStatus{ + return backend.BackendStatus{ IsAvailable: false, StatusMsg: fmt.Sprintf("unable to initialize the docker client: %s", err.Error()), } @@ -541,13 +543,13 @@ func (d *Docker) Status() BackendStatus { if strings.Contains(message, daemonNotRunning) { message = daemonNotRunning } - return BackendStatus{ + return backend.BackendStatus{ IsAvailable: false, StatusMsg: message, } } status := fmt.Sprintf("\tPlatform: %s\n\tVersion: %s\n\tAPI Version: %s", dockerInfo.Platform.Name, dockerInfo.Version, dockerInfo.APIVersion) - return BackendStatus{ + return backend.BackendStatus{ IsAvailable: true, StatusMsg: status, } diff --git a/pkg/prm/docker_test.go b/pkg/backend/docker/docker_test.go similarity index 93% rename from pkg/prm/docker_test.go rename to pkg/backend/docker/docker_test.go index 8795d49..b7ea2d2 100644 --- a/pkg/prm/docker_test.go +++ b/pkg/backend/docker/docker_test.go @@ -1,7 +1,9 @@ -package prm_test +package docker_test import ( "context" + "github.com/puppetlabs/prm/pkg/backend" + "github.com/puppetlabs/prm/pkg/backend/docker" "reflect" "testing" "time" @@ -20,14 +22,14 @@ func TestDocker_Status(t *testing.T) { tests := []struct { name string mockClient mock.DockerClient - want prm.BackendStatus + want backend.BackendStatus }{ { name: "When connection unavailable", mockClient: mock.DockerClient{ ErrorString: "error during connect: This error may indicate that the docker daemon is not running.: Get \"http://%2F%2F.%2Fpipe%2Fdocker_engine/v1.41/version\": open //./pipe/docker_engine: The system cannot find the file specified.", }, - want: prm.BackendStatus{ + want: backend.BackendStatus{ IsAvailable: false, StatusMsg: "error during connect: This error may indicate that the docker daemon is not running.", }, @@ -37,7 +39,7 @@ func TestDocker_Status(t *testing.T) { mockClient: mock.DockerClient{ ErrorString: "Something has gone terribly wrong!", }, - want: prm.BackendStatus{ + want: backend.BackendStatus{ IsAvailable: false, StatusMsg: "Something has gone terribly wrong!", }, @@ -49,7 +51,7 @@ func TestDocker_Status(t *testing.T) { Version: "1.2.3", ApiVersion: "3.2.1", }, - want: prm.BackendStatus{ + want: backend.BackendStatus{ IsAvailable: true, StatusMsg: "\tPlatform: Docker\n\tVersion: 1.2.3\n\tAPI Version: 3.2.1", }, @@ -60,7 +62,7 @@ func TestDocker_Status(t *testing.T) { // Uncomment to run unmocked // cli, _ := dockerClient.NewClientWithOpts(dockerClient.FromEnv) // d := &Docker{Client: cli} - d := &prm.Docker{Client: &tt.mockClient} + d := &docker.Docker{Client: &tt.mockClient} if got := d.Status(); !reflect.DeepEqual(got, tt.want) { t.Errorf("Docker.Status() = %v, want %v", got, tt.want) } @@ -127,7 +129,7 @@ func TestDocker_GetTool(t *testing.T) { fs := afero.NewMemMapFs() afs := &afero.Afero{Fs: fs} - d := &prm.Docker{Client: &tt.mockClient, AFS: afs, AlwaysBuild: tt.alwaysBuild} + d := &docker.Docker{Client: &tt.mockClient, AFS: afs, AlwaysBuild: tt.alwaysBuild} err := d.GetTool(&tt.tool, tt.config) if err != nil { assert.Contains(t, err.Error(), tt.errorMsg) @@ -148,8 +150,8 @@ func TestDocker_Validate(t *testing.T) { AlwaysBuild bool } type args struct { - paths prm.DirectoryPaths - author string + paths backend.DirectoryPaths + author string version string id string puppetVersion string @@ -252,7 +254,7 @@ func TestDocker_Validate(t *testing.T) { afs := &afero.Afero{Fs: fs} iofs := &afero.IOFS{Fs: fs} - d := &prm.Docker{ + d := &docker.Docker{ Client: tt.fields.Client, Context: tt.fields.Context, ContextCancel: tt.fields.ContextCancel, @@ -291,7 +293,7 @@ func TestDocker_Validate(t *testing.T) { } } -func CreateToolInfo(id, author, version string, args []string) prm.ToolInfo { +func CreateToolInfo(id, author, version string, args []string) backend.ToolInfo { tool := &prm.Tool{ Cfg: prm.ToolConfig{ Plugin: &prm.PluginConfig{ @@ -304,7 +306,7 @@ func CreateToolInfo(id, author, version string, args []string) prm.ToolInfo { }, } - return prm.ToolInfo{ + return backend.ToolInfo{ Tool: tool, Args: args, } diff --git a/pkg/prm/exec.go b/pkg/backend/docker/exec.go similarity index 77% rename from pkg/prm/exec.go rename to pkg/backend/docker/exec.go index fb46952..e2b1640 100644 --- a/pkg/prm/exec.go +++ b/pkg/backend/docker/exec.go @@ -1,7 +1,9 @@ //nolint:structcheck,unused -package prm +package docker import ( + "github.com/puppetlabs/prm/pkg/backend" + "github.com/puppetlabs/prm/pkg/prm" "github.com/rs/zerolog/log" ) @@ -14,7 +16,7 @@ const ( ) // Executes a tool with the given arguments, against the codeDir. -func (p *Prm) Exec(tool *Tool, args []string) error { +func (p *prm.Prm) Exec(tool *prm.Tool, args []string) error { if status := p.Backend.Status(); !status.IsAvailable { return ErrDockerNotRunning } @@ -27,22 +29,22 @@ func (p *Prm) Exec(tool *Tool, args []string) error { } // the tool is available so execute against it - exit, err := p.Backend.Exec(tool, args, p.RunningConfig, DirectoryPaths{codeDir: p.CodeDir, cacheDir: p.CacheDir}) + exit, err := p.Backend.Exec(tool, args, p.RunningConfig, backend.DirectoryPaths{codeDir: p.CodeDir, cacheDir: p.CacheDir}) if err != nil { log.Error().Msgf("Error executing tool %s/%s: %s", tool.Cfg.Plugin.Author, tool.Cfg.Plugin.Id, err.Error()) return err } switch exit { - case SUCCESS: + case prm.SUCCESS: log.Info().Msgf("Tool %s/%s executed successfully", tool.Cfg.Plugin.Author, tool.Cfg.Plugin.Id) - case FAILURE: + case prm.FAILURE: log.Error().Msgf("Tool %s/%s failed to execute", tool.Cfg.Plugin.Author, tool.Cfg.Plugin.Id) return err - case TOOL_ERROR: + case prm.TOOL_ERROR: log.Error().Msgf("Tool %s/%s encountered an error", tool.Cfg.Plugin.Author, tool.Cfg.Plugin.Id) return err - case TOOL_NOT_FOUND: + case prm.TOOL_NOT_FOUND: log.Error().Msgf("Tool %s/%s not found", tool.Cfg.Plugin.Author, tool.Cfg.Plugin.Id) return err default: diff --git a/pkg/prm/exec_test.go b/pkg/backend/docker/exec_test.go similarity index 92% rename from pkg/prm/exec_test.go rename to pkg/backend/docker/exec_test.go index 278f15a..f01092c 100644 --- a/pkg/prm/exec_test.go +++ b/pkg/backend/docker/exec_test.go @@ -1,6 +1,7 @@ -package prm_test +package docker_test import ( + "github.com/puppetlabs/prm/pkg/backend" "testing" "github.com/Masterminds/semver" @@ -27,7 +28,7 @@ func TestPrm_Exec(t *testing.T) { p: &prm.Prm{ RunningConfig: prm.Config{ PuppetVersion: semver.MustParse("7.15.0"), - Backend: prm.DOCKER, + Backend: backend.DOCKER, }, Backend: &mock.MockBackend{ ToolAvalible: false, @@ -41,7 +42,7 @@ func TestPrm_Exec(t *testing.T) { p: &prm.Prm{ RunningConfig: prm.Config{ PuppetVersion: semver.MustParse("7.15.0"), - Backend: prm.DOCKER, + Backend: backend.DOCKER, }, Backend: &mock.MockBackend{ ToolAvalible: true, @@ -60,7 +61,7 @@ func TestPrm_Exec(t *testing.T) { p: &prm.Prm{ RunningConfig: prm.Config{ PuppetVersion: semver.MustParse("7.15.0"), - Backend: prm.DOCKER, + Backend: backend.DOCKER, }, Backend: &mock.MockBackend{ ToolAvalible: true, @@ -79,7 +80,7 @@ func TestPrm_Exec(t *testing.T) { p: &prm.Prm{ RunningConfig: prm.Config{ PuppetVersion: semver.MustParse("7.15.0"), - Backend: prm.DOCKER, + Backend: backend.DOCKER, }, Backend: &mock.MockBackend{ ToolAvalible: true, @@ -98,7 +99,7 @@ func TestPrm_Exec(t *testing.T) { p: &prm.Prm{ RunningConfig: prm.Config{ PuppetVersion: semver.MustParse("7.15.0"), - Backend: prm.DOCKER, + Backend: backend.DOCKER, }, Backend: &mock.MockBackend{ ToolAvalible: true, @@ -117,7 +118,7 @@ func TestPrm_Exec(t *testing.T) { p: &prm.Prm{ RunningConfig: prm.Config{ PuppetVersion: semver.MustParse("7.15.0"), - Backend: prm.DOCKER, + Backend: backend.DOCKER, }, Backend: &mock.MockBackend{ ToolAvalible: true, @@ -129,7 +130,7 @@ func TestPrm_Exec(t *testing.T) { toolId: "test", toolAuthor: "user", toolVersion: "0.1.0", - expectedErrMsg: prm.ErrDockerNotRunning.Error(), + expectedErrMsg: ErrDockerNotRunning.Error(), }, } for _, tt := range tests { diff --git a/pkg/prm/validate.go b/pkg/backend/docker/validate.go similarity index 81% rename from pkg/prm/validate.go rename to pkg/backend/docker/validate.go index db0f94e..16ca262 100644 --- a/pkg/prm/validate.go +++ b/pkg/backend/docker/validate.go @@ -1,5 +1,5 @@ //nolint:structcheck,unused -package prm +package docker import ( "errors" @@ -10,6 +10,9 @@ import ( "strings" "time" + "github.com/puppetlabs/prm/pkg/backend" + "github.com/puppetlabs/prm/pkg/utils" + "github.com/olekukonko/tablewriter" "github.com/rs/zerolog/log" "github.com/spf13/afero" @@ -23,11 +26,17 @@ const ( VALIDATION_ERROR ) +type ValidationOutput struct { + err error + exitCode ValidateExitCode + stdout string +} + var ( toolLogOutputPaths map[string]string // Key = toolName, Value = logFilePath, stores each tool's log file path ) -func (p *Prm) Validate(toolsInfo []ToolInfo, workerCount int, settings OutputSettings) error { +func (p *Prm) Validate(toolsInfo []backend.ToolInfo, workerCount int, settings backend.OutputSettings) error { if status := p.Backend.Status(); !status.IsAvailable { return ErrDockerNotRunning } @@ -39,14 +48,14 @@ func (p *Prm) Validate(toolsInfo []ToolInfo, workerCount int, settings OutputSet tasks := p.createTasks(toolsInfo) - pool := CreateWorkerPool(tasks, workerCount) + pool := utils.CreateWorkerPool(tasks, workerCount) pool.Run() err := p.outputResults(tasks, settings) return err } -func (p Prm) taskFunc(tool ToolInfo) func() ValidationOutput { +func (p Prm) taskFunc(tool backend.ToolInfo) func() ValidationOutput { return func() ValidationOutput { toolName := tool.Tool.Cfg.Plugin.Id log.Info().Msgf("Validating with the %s tool", toolName) @@ -69,7 +78,7 @@ func (p Prm) taskFunc(tool ToolInfo) func() ValidationOutput { } } -func (p *Prm) outputResults(tasks []*Task[ValidationOutput], settings OutputSettings) error { +func (p *Prm) outputResults(tasks []*utils.Task[ValidationOutput], settings OutputSettings) error { err := p.writeOutputLogs(tasks, settings) if err != nil { return err @@ -89,7 +98,7 @@ func (p *Prm) outputResults(tasks []*Task[ValidationOutput], settings OutputSett return nil } -func writeOutputToTerminal(tasks []*Task[ValidationOutput]) { +func writeOutputToTerminal(tasks []*utils.Task[ValidationOutput]) { for _, task := range tasks { output := task.Output if output.err == nil { @@ -126,10 +135,10 @@ func renderTable(headers []string, data [][]string) { table.Render() } -func (p *Prm) createTasks(toolsInfo []ToolInfo) []*Task[ValidationOutput] { - tasks := make([]*Task[ValidationOutput], len(toolsInfo)) +func (p *Prm) createTasks(toolsInfo []ToolInfo) []*utils.Task[ValidationOutput] { + tasks := make([]*utils.Task[ValidationOutput], len(toolsInfo)) for i, info := range toolsInfo { - tasks[i] = CreateTask[ValidationOutput](info.Tool.Cfg.Plugin.Id, p.taskFunc(info), ValidationOutput{}) + tasks[i] = utils.CreateTask[ValidationOutput](info.Tool.Cfg.Plugin.Id, p.taskFunc(info), ValidationOutput{}) } return tasks } @@ -155,7 +164,7 @@ func createLogFilePath(outputDir string, toolId string) string { return fullPath } -func (p *Prm) writeOutputToFile(tasks []*Task[ValidationOutput], outputDir string) error { +func (p *Prm) writeOutputToFile(tasks []*utils.Task[ValidationOutput], outputDir string) error { for _, task := range tasks { err := p.checkAndCreateDir(outputDir) if err != nil { @@ -199,7 +208,7 @@ func writeStringToFile(file afero.File, output ValidationOutput) error { return nil } -func (p *Prm) writeOutputLogs(tasks []*Task[ValidationOutput], settings OutputSettings) (err error) { +func (p *Prm) writeOutputLogs(tasks []*utils.Task[ValidationOutput], settings OutputSettings) (err error) { if settings.ResultsView == "terminal" { writeOutputToTerminal(tasks) return nil @@ -213,7 +222,7 @@ func (p *Prm) writeOutputLogs(tasks []*Task[ValidationOutput], settings OutputSe return fmt.Errorf("invalid --resultsView flag specified") } -func getErrorCount(tasks []*Task[ValidationOutput]) (count int) { +func getErrorCount(tasks []*utils.Task[ValidationOutput]) (count int) { for _, task := range tasks { output := task.Output if output.err != nil { @@ -223,7 +232,7 @@ func getErrorCount(tasks []*Task[ValidationOutput]) (count int) { return count } -func createTableContents(tasks []*Task[ValidationOutput], resultsView string) (tableContents [][]string) { +func createTableContents(tasks []*utils.Task[ValidationOutput], resultsView string) (tableContents [][]string) { for _, task := range tasks { output := task.Output if resultsView == "file" { // Will also include the path to each diff --git a/pkg/prm/validate_test.go b/pkg/backend/docker/validate_test.go similarity index 87% rename from pkg/prm/validate_test.go rename to pkg/backend/docker/validate_test.go index 81bd5e8..db48e7e 100644 --- a/pkg/prm/validate_test.go +++ b/pkg/backend/docker/validate_test.go @@ -1,7 +1,8 @@ -package prm_test +package docker_test import ( "fmt" + "github.com/puppetlabs/prm/pkg/backend" "testing" "github.com/puppetlabs/prm/internal/pkg/mock" @@ -16,16 +17,16 @@ func TestPrm_Validate(t *testing.T) { RunningConfig prm.Config CodeDir string CacheDir string - Cache map[string]*prm.Tool - Backend prm.BackendI + Cache map[string]*prm.Tool + Backend backend.BackendI } type args struct { id string validateReturn string expectedErrMsg string - toolNotAvailable bool - outputSettings prm.OutputSettings - toolArgs []string + toolNotAvailable bool + outputSettings backend.OutputSettings + toolArgs []string workerCount int extraTools int statusIsNotAvailable bool @@ -41,7 +42,7 @@ func TestPrm_Validate(t *testing.T) { args: args{ id: "my-tool", validateReturn: "PASS", - outputSettings: prm.OutputSettings{ + outputSettings: backend.OutputSettings{ ResultsView: "terminal", OutputDir: pathToLogs, }, @@ -53,7 +54,7 @@ func TestPrm_Validate(t *testing.T) { args: args{ id: "my-tool", validateReturn: "PASS", - outputSettings: prm.OutputSettings{ + outputSettings: backend.OutputSettings{ ResultsView: "terminal", OutputDir: pathToLogs, }, @@ -66,7 +67,7 @@ func TestPrm_Validate(t *testing.T) { args: args{ id: "my-tool", validateReturn: "PASS", - outputSettings: prm.OutputSettings{ + outputSettings: backend.OutputSettings{ ResultsView: "file", OutputDir: pathToLogs, }, @@ -78,7 +79,7 @@ func TestPrm_Validate(t *testing.T) { args: args{ id: "my-tool", validateReturn: "PASS", - outputSettings: prm.OutputSettings{ + outputSettings: backend.OutputSettings{ ResultsView: "file", OutputDir: pathToLogs, }, @@ -92,7 +93,7 @@ func TestPrm_Validate(t *testing.T) { id: "fail", validateReturn: "FAIL", expectedErrMsg: "Validation returned 1 error", - outputSettings: prm.OutputSettings{ + outputSettings: backend.OutputSettings{ ResultsView: "terminal", OutputDir: pathToLogs, }, @@ -106,7 +107,7 @@ func TestPrm_Validate(t *testing.T) { id: "fail", validateReturn: "FAIL", expectedErrMsg: "Validation returned 11 errors", - outputSettings: prm.OutputSettings{ + outputSettings: backend.OutputSettings{ ResultsView: "terminal", OutputDir: pathToLogs, }, @@ -121,7 +122,7 @@ func TestPrm_Validate(t *testing.T) { id: "fail", validateReturn: "FAIL", expectedErrMsg: "Validation returned 1 error", - outputSettings: prm.OutputSettings{ + outputSettings: backend.OutputSettings{ ResultsView: "file", OutputDir: pathToLogs, }, @@ -135,7 +136,7 @@ func TestPrm_Validate(t *testing.T) { id: "fail", validateReturn: "FAIL", expectedErrMsg: "Validation returned 11 errors", - outputSettings: prm.OutputSettings{ + outputSettings: backend.OutputSettings{ ResultsView: "file", OutputDir: pathToLogs, }, @@ -150,7 +151,7 @@ func TestPrm_Validate(t *testing.T) { id: "fail", validateReturn: "FAIL", expectedErrMsg: "Validation returned 1 error", - outputSettings: prm.OutputSettings{ + outputSettings: backend.OutputSettings{ ResultsView: "terminal", OutputDir: pathToLogs, }, @@ -164,7 +165,7 @@ func TestPrm_Validate(t *testing.T) { args: args{ id: "error", validateReturn: "FAIL", - outputSettings: prm.OutputSettings{ + outputSettings: backend.OutputSettings{ ResultsView: "invalid flag", OutputDir: pathToLogs, }, @@ -178,12 +179,12 @@ func TestPrm_Validate(t *testing.T) { args: args{ id: "error", validateReturn: "FAIL", - outputSettings: prm.OutputSettings{ + outputSettings: backend.OutputSettings{ ResultsView: "terminal", OutputDir: pathToLogs, }, workerCount: 1, - expectedErrMsg: prm.ErrDockerNotRunning.Error(), + expectedErrMsg: ErrDockerNotRunning.Error(), statusIsNotAvailable: true, }, wantErr: true, @@ -201,7 +202,7 @@ func TestPrm_Validate(t *testing.T) { afs.MkdirAll(pathToLogs, 0755) //nolint:gosec,errcheck afs.MkdirAll(codeDirPath, 0755) //nolint:gosec,errcheck - var tools []prm.ToolInfo + var tools []backend.ToolInfo for i := 0; i < tt.args.extraTools+1; i++ { id, author, version := fmt.Sprint(tt.args.id, i), "puppetlabs", "0.1.0" tools = append(tools, CreateToolInfo(id, author, version, tt.args.toolArgs)) diff --git a/pkg/prm/config.go b/pkg/prm/config.go index e5260f7..adeca92 100644 --- a/pkg/prm/config.go +++ b/pkg/prm/config.go @@ -2,6 +2,7 @@ package prm import ( "fmt" + "github.com/puppetlabs/prm/pkg/backend" "os" "path/filepath" "time" @@ -16,16 +17,16 @@ const ( BackendCmdFlag string = "backend" PuppetVerCfgKey string = "puppetversion" // Should match Config struct key. BackendCfgKey string = "backend" // Should match Config struct key. - DefaultPuppetVer string = "7.15.0" - DefaultBackend BackendType = DOCKER - ToolPathCfgKey string = "toolpath" + DefaultPuppetVer string = "7.15.0" + DefaultBackend backend.BackendType = backend.DOCKER + ToolPathCfgKey string = "toolpath" ToolTimeoutCfgKey string = "toolTimeout" DefaultToolTimeout int = 1800 // 30 minutes ) type Config struct { PuppetVersion *semver.Version - Backend BackendType + Backend backend.BackendType ToolPath string Timeout time.Duration } @@ -68,7 +69,7 @@ func (p *Prm) LoadConfig() error { p.RunningConfig.PuppetVersion = pupperSemVer // Load Backend from config - p.RunningConfig.Backend = BackendType(viper.GetString(BackendCfgKey)) + p.RunningConfig.Backend = backend.BackendType(viper.GetString(BackendCfgKey)) // Load ToolPath from config p.RunningConfig.ToolPath = viper.GetString(ToolPathCfgKey) diff --git a/pkg/prm/config_test.go b/pkg/prm/config_test.go index 0803649..3b1e912 100644 --- a/pkg/prm/config_test.go +++ b/pkg/prm/config_test.go @@ -2,6 +2,7 @@ package prm_test import ( "fmt" + "github.com/puppetlabs/prm/pkg/backend" "testing" "github.com/puppetlabs/prm/pkg/prm" @@ -19,7 +20,7 @@ func TestGenerateDefaultCfg(t *testing.T) { { name: "Should generate default Puppet and Backend cfgs", expectedPuppetVersion: "7.15.0", - expectedBackend: string(prm.DOCKER), + expectedBackend: string(backend.DOCKER), expectedToolPath: "tools", }, } diff --git a/pkg/prm/prm.go b/pkg/prm/prm.go index f7c107d..67f3672 100644 --- a/pkg/prm/prm.go +++ b/pkg/prm/prm.go @@ -4,6 +4,7 @@ package prm import ( "bytes" "fmt" + "github.com/puppetlabs/prm/pkg/backend" "path/filepath" "sort" "strings" @@ -29,8 +30,8 @@ type Prm struct { RunningConfig Config CodeDir string CacheDir string - Cache map[string]*Tool - Backend BackendI + Cache map[string]*Tool + Backend backend.BackendI } type PuppetVersion struct { diff --git a/pkg/prm/status.go b/pkg/prm/status.go index c267521..6bd16eb 100644 --- a/pkg/prm/status.go +++ b/pkg/prm/status.go @@ -3,6 +3,7 @@ package prm import ( "encoding/json" "fmt" + "github.com/puppetlabs/prm/pkg/backend" "strings" "github.com/Masterminds/semver" @@ -10,8 +11,8 @@ import ( type Status struct { PuppetVersion *semver.Version - Backend BackendType - BackendStatus BackendStatus + Backend backend.BackendType + BackendStatus backend.BackendStatus } func (p *Prm) GetStatus() (status Status) { diff --git a/pkg/prm/status_test.go b/pkg/prm/status_test.go index adf468d..7418f74 100644 --- a/pkg/prm/status_test.go +++ b/pkg/prm/status_test.go @@ -1,6 +1,7 @@ package prm_test import ( + "github.com/puppetlabs/prm/pkg/backend" "reflect" "testing" @@ -21,7 +22,7 @@ func TestPrm_GetStatus(t *testing.T) { p: &prm.Prm{ RunningConfig: prm.Config{ PuppetVersion: semver.MustParse("7.15.0"), - Backend: prm.DOCKER, + Backend: backend.DOCKER, }, Backend: &mock.MockBackend{ StatusIsAvailable: true, @@ -30,8 +31,8 @@ func TestPrm_GetStatus(t *testing.T) { }, wantStatus: prm.Status{ PuppetVersion: semver.MustParse("7.15.0"), - Backend: prm.DOCKER, - BackendStatus: prm.BackendStatus{ + Backend: backend.DOCKER, + BackendStatus: backend.BackendStatus{ IsAvailable: true, StatusMsg: "Running just fine!", }, @@ -64,8 +65,8 @@ func TestFormatStatus(t *testing.T) { outputType: "human", status: prm.Status{ PuppetVersion: semver.MustParse("7.15.0"), - Backend: prm.DOCKER, - BackendStatus: prm.BackendStatus{ + Backend: backend.DOCKER, + BackendStatus: backend.BackendStatus{ IsAvailable: true, StatusMsg: "Running just fine", }, @@ -82,8 +83,8 @@ func TestFormatStatus(t *testing.T) { outputType: "human", status: prm.Status{ PuppetVersion: semver.MustParse("7.15.0"), - Backend: prm.DOCKER, - BackendStatus: prm.BackendStatus{ + Backend: backend.DOCKER, + BackendStatus: backend.BackendStatus{ IsAvailable: false, StatusMsg: "Descriptive error!", }, @@ -101,8 +102,8 @@ func TestFormatStatus(t *testing.T) { outputType: "json", status: prm.Status{ PuppetVersion: semver.MustParse("7.15.0"), - Backend: prm.DOCKER, - BackendStatus: prm.BackendStatus{ + Backend: backend.DOCKER, + BackendStatus: backend.BackendStatus{ IsAvailable: true, StatusMsg: "Running just fine", }, @@ -120,8 +121,8 @@ func TestFormatStatus(t *testing.T) { outputType: "json", status: prm.Status{ PuppetVersion: semver.MustParse("7.15.0"), - Backend: prm.DOCKER, - BackendStatus: prm.BackendStatus{ + Backend: backend.DOCKER, + BackendStatus: backend.BackendStatus{ IsAvailable: false, StatusMsg: "Descriptive error!", }, diff --git a/pkg/prm/tool.go b/pkg/tool/tool.go similarity index 99% rename from pkg/prm/tool.go rename to pkg/tool/tool.go index a9c54d6..1944d03 100644 --- a/pkg/prm/tool.go +++ b/pkg/tool/tool.go @@ -1,5 +1,5 @@ // nolint:structcheck,unused -package prm +package tool import ( "io" diff --git a/pkg/prm/tool_groups.go b/pkg/tool/tool_groups.go similarity index 98% rename from pkg/prm/tool_groups.go rename to pkg/tool/tool_groups.go index 76773e9..6ac05db 100644 --- a/pkg/prm/tool_groups.go +++ b/pkg/tool/tool_groups.go @@ -1,4 +1,4 @@ -package prm +package tool /* This package contains ToolGroups, which defines diff --git a/pkg/prm/worker_pool.go b/pkg/utils/worker_pool.go similarity index 93% rename from pkg/prm/worker_pool.go rename to pkg/utils/worker_pool.go index 020de64..0ceb12a 100644 --- a/pkg/prm/worker_pool.go +++ b/pkg/utils/worker_pool.go @@ -1,4 +1,4 @@ -package prm +package utils import ( "sync" @@ -79,9 +79,3 @@ func CreateTask[T any](name string, f func() T, output T) *Task[T] { f: f, } } - -type ValidationOutput struct { - err error - exitCode ValidateExitCode - stdout string -}