diff --git a/components/command/package.go b/components/command/package.go index f9c48613c..3c6a1fe04 100644 --- a/components/command/package.go +++ b/components/command/package.go @@ -54,7 +54,7 @@ func (m *GenericPackageManager) Ensure(packageRef string, transform Transformer, } cmdName := m.namer.ResourceName("install-"+packageRef, utils.StrHash(cmdStr)) - cmdArgs := Args{ + var cmdArgs CommandArgs = &Args{ Create: pulumi.String(cmdStr), Environment: m.env, Sudo: true, @@ -65,7 +65,7 @@ func (m *GenericPackageManager) Ensure(packageRef string, transform Transformer, cmdName, cmdArgs = transform(cmdName, cmdArgs) } - cmd, err := m.runner.Command(cmdName, &cmdArgs, opts...) + cmd, err := m.runner.Command(cmdName, cmdArgs, opts...) if err != nil { return nil, err } diff --git a/components/command/runner.go b/components/command/runner.go index 8ff4832d2..2c1f6fb3d 100644 --- a/components/command/runner.go +++ b/components/command/runner.go @@ -12,6 +12,10 @@ import ( "github.com/DataDog/test-infra-definitions/common/utils" ) +type CommandArgs interface { + Arguments() *Args +} + type Args struct { Create pulumi.StringInput Update pulumi.StringInput @@ -21,32 +25,56 @@ type Args struct { Environment pulumi.StringMap RequirePasswordFromStdin bool Sudo bool +} + +type LocalArgs struct { + Args // Only used for local commands LocalAssetPaths pulumi.StringArrayInput LocalDir pulumi.StringInput } -func (args *Args) toLocalCommandArgs(config RunnerConfiguration, osCommand OSCommand) (*local.CommandArgs, error) { +var _ CommandArgs = &Args{} +var _ CommandArgs = &LocalArgs{} + +func (args *Args) Arguments() *Args { + return args +} + +func (args *LocalArgs) Arguments() *Args { + return &args.Args +} + +func toLocalCommandArgs(cmdArgs CommandArgs, config RunnerConfiguration, osCommand OSCommand) (*local.CommandArgs, error) { + // Retrieve local specific arguments if provided + var assetsPath pulumi.StringArrayInput + var dir pulumi.StringInput + if localArgs, ok := cmdArgs.(*LocalArgs); ok { + assetsPath = localArgs.LocalAssetPaths + dir = localArgs.LocalDir + } + + args := cmdArgs.Arguments() + return &local.CommandArgs{ Create: osCommand.BuildCommandString(args.Create, args.Environment, args.Sudo, args.RequirePasswordFromStdin, config.user), Update: osCommand.BuildCommandString(args.Update, args.Environment, args.Sudo, args.RequirePasswordFromStdin, config.user), Delete: osCommand.BuildCommandString(args.Delete, args.Environment, args.Sudo, args.RequirePasswordFromStdin, config.user), Triggers: args.Triggers, Stdin: args.Stdin, - AssetPaths: args.LocalAssetPaths, - Dir: args.LocalDir, + AssetPaths: assetsPath, + Dir: dir, }, nil } -func (args *Args) toRemoteCommandArgs(config RunnerConfiguration, osCommand OSCommand) (*remote.CommandArgs, error) { +func toRemoteCommandArgs(cmdArgs CommandArgs, config RunnerConfiguration, osCommand OSCommand) (*remote.CommandArgs, error) { // Ensure no local arguments are passed to remote commands - if args.LocalAssetPaths != nil { - return nil, fmt.Errorf("local asset paths are not supported in remote commands") - } - if args.LocalDir != nil { - return nil, fmt.Errorf("local dir is not supported in remote commands") + if _, ok := cmdArgs.(*LocalArgs); ok { + return nil, fmt.Errorf("local arguments are not allowed for remote commands") } + args := cmdArgs.Arguments() + return &remote.CommandArgs{ Connection: config.connection, Create: osCommand.BuildCommandString(args.Create, args.Environment, args.Sudo, args.RequirePasswordFromStdin, config.user), @@ -59,7 +87,7 @@ func (args *Args) toRemoteCommandArgs(config RunnerConfiguration, osCommand OSCo // Transformer is a function that can be used to modify the command name and args. // Examples: swapping `args.Delete` with `args.Create`, or adding `args.Triggers`, or editing the name -type Transformer func(name string, args Args) (string, Args) +type Transformer func(name string, args CommandArgs) (string, CommandArgs) type RunnerConfiguration struct { user string @@ -107,7 +135,7 @@ type Runner interface { OsCommand() OSCommand PulumiOptions() []pulumi.ResourceOption - Command(name string, args *Args, opts ...pulumi.ResourceOption) (Command, error) + Command(name string, args CommandArgs, opts ...pulumi.ResourceOption) (Command, error) newCopyFile(name string, localPath, remotePath pulumi.StringInput, opts ...pulumi.ResourceOption) (pulumi.Resource, error) } @@ -179,12 +207,12 @@ func (r *RemoteRunner) OsCommand() OSCommand { return r.osCommand } -func (r *RemoteRunner) Command(name string, args *Args, opts ...pulumi.ResourceOption) (Command, error) { - if args.Sudo && r.config.user != "" { +func (r *RemoteRunner) Command(name string, args CommandArgs, opts ...pulumi.ResourceOption) (Command, error) { + if args.Arguments().Sudo && r.config.user != "" { r.e.Ctx().Log.Info(fmt.Sprintf("warning: running sudo command on a runner with user %s, discarding user", r.config.user), nil) } - remoteArgs, err := args.toRemoteCommandArgs(r.config, r.osCommand) + remoteArgs, err := toRemoteCommandArgs(args, r.config, r.osCommand) if err != nil { return nil, err } @@ -247,9 +275,9 @@ func (r *LocalRunner) OsCommand() OSCommand { return r.osCommand } -func (r *LocalRunner) Command(name string, args *Args, opts ...pulumi.ResourceOption) (Command, error) { +func (r *LocalRunner) Command(name string, args CommandArgs, opts ...pulumi.ResourceOption) (Command, error) { opts = utils.MergeOptions[pulumi.ResourceOption](opts, r.e.WithProviders(config.ProviderCommand)) - localArgs, err := args.toLocalCommandArgs(r.config, r.osCommand) + localArgs, err := toLocalCommandArgs(args, r.config, r.osCommand) if err != nil { return nil, err } diff --git a/components/datadog/agent/host.go b/components/datadog/agent/host.go index 70dc131bc..e0d8e7c4b 100644 --- a/components/datadog/agent/host.go +++ b/components/datadog/agent/host.go @@ -120,9 +120,10 @@ func (h *HostAgent) installAgent(env config.Env, params *agentparams.Params, bas // For this reason we have another `restartAgentServices` in `installIntegrationConfigsAndFiles` that is triggered when an integration is deleted. _, err = h.manager.restartAgentServices( // Transformer used to add triggers to the restart command - func(name string, args command.Args) (string, command.Args) { + func(name string, cmdArgs command.CommandArgs) (string, command.CommandArgs) { + args := *cmdArgs.Arguments() args.Triggers = pulumi.Array{configFiles["datadog.yaml"], configFiles["system-probe.yaml"], configFiles["security-agent.yaml"], pulumi.String(intgHash)} - return name, args + return name, &args }, utils.PulumiDependsOn(h), ) @@ -214,11 +215,12 @@ func (h *HostAgent) installIntegrationConfigsAndFiles( restartCmd, err := h.manager.restartAgentServices( // Use a transformer to inject triggers on intg hash and move `restart` command from `Create` to `Delete` // so that it's run after the `Delete` commands of the integrations. - func(name string, args command.Args) (string, command.Args) { + func(name string, cmdArgs command.CommandArgs) (string, command.CommandArgs) { + args := *cmdArgs.Arguments() args.Triggers = pulumi.Array{pulumi.String(hash)} args.Delete = args.Create args.Create = nil - return name + "-on-intg-removal", args + return name + "-on-intg-removal", &args }) if err != nil { return nil, "", err diff --git a/components/datadog/agent/host_windowsos.go b/components/datadog/agent/host_windowsos.go index 63283b04c..71bb9a0a2 100644 --- a/components/datadog/agent/host_windowsos.go +++ b/components/datadog/agent/host_windowsos.go @@ -97,7 +97,7 @@ while ($tries -lt 5) { Exit $exitCode ` - cmdArgs := command.Args{ + var cmdArgs command.CommandArgs = &command.Args{ Create: pulumi.String(cmd), } @@ -106,7 +106,7 @@ while ($tries -lt 5) { cmdName, cmdArgs = transform(cmdName, cmdArgs) } - return am.host.OS.Runner().Command(cmdName, &cmdArgs, opts...) + return am.host.OS.Runner().Command(cmdName, cmdArgs, opts...) } func getAgentURL(version agentparams.PackageVersion) (string, error) { diff --git a/components/os/linux_servicemanagers.go b/components/os/linux_servicemanagers.go index b78da21c7..6fe0ad47d 100644 --- a/components/os/linux_servicemanagers.go +++ b/components/os/linux_servicemanagers.go @@ -19,7 +19,7 @@ func newSystemdServiceManager(e config.Env, runner command.Runner) ServiceManage func (s *systemdServiceManager) EnsureRestarted(serviceName string, transform command.Transformer, opts ...pulumi.ResourceOption) (command.Command, error) { cmdName := s.e.CommonNamer().ResourceName("running", serviceName) - cmdArgs := command.Args{ + var cmdArgs command.CommandArgs = &command.Args{ Sudo: true, Create: pulumi.String("systemctl restart " + serviceName), } @@ -29,7 +29,7 @@ func (s *systemdServiceManager) EnsureRestarted(serviceName string, transform co cmdName, cmdArgs = transform(cmdName, cmdArgs) } - return s.runner.Command(cmdName, &cmdArgs, opts...) + return s.runner.Command(cmdName, cmdArgs, opts...) } type sysvinitServiceManager struct { @@ -45,7 +45,7 @@ func (s *sysvinitServiceManager) EnsureRestarted(serviceName string, transform c cmdName := s.e.CommonNamer().ResourceName("running", serviceName) // To the difference of systemctl the restart doesn't work if the service isn't already running // so instead we run a stop command that we allow to fail and then a start command - cmdArgs := command.Args{ + var cmdArgs command.CommandArgs = &command.Args{ Sudo: false, Create: pulumi.String(fmt.Sprintf("sudo stop %[1]s; sudo start %[1]s", serviceName)), } @@ -55,5 +55,5 @@ func (s *sysvinitServiceManager) EnsureRestarted(serviceName string, transform c cmdName, cmdArgs = transform(cmdName, cmdArgs) } - return s.runner.Command(cmdName, &cmdArgs, opts...) + return s.runner.Command(cmdName, cmdArgs, opts...) } diff --git a/components/os/macos_servicemanagers.go b/components/os/macos_servicemanagers.go index 8ebd8a8d4..8ab561f2a 100644 --- a/components/os/macos_servicemanagers.go +++ b/components/os/macos_servicemanagers.go @@ -19,7 +19,7 @@ func newMacOSServiceManager(e config.Env, runner command.Runner) ServiceManager func (s *macOSServiceManager) EnsureRestarted(serviceName string, transform command.Transformer, opts ...pulumi.ResourceOption) (command.Command, error) { cmdName := s.e.CommonNamer().ResourceName("running", serviceName) - cmdArgs := command.Args{ + var cmdArgs command.CommandArgs = &command.Args{ Sudo: true, Create: pulumi.String(fmt.Sprintf("launchctl stop %s && launchctl start %s", serviceName, serviceName)), } @@ -29,5 +29,5 @@ func (s *macOSServiceManager) EnsureRestarted(serviceName string, transform comm cmdName, cmdArgs = transform(cmdName, cmdArgs) } - return s.runner.Command(cmdName, &cmdArgs, opts...) + return s.runner.Command(cmdName, cmdArgs, opts...) } diff --git a/components/os/windows_servicemanagers.go b/components/os/windows_servicemanagers.go index fb2afdf9e..17d9e6bb3 100644 --- a/components/os/windows_servicemanagers.go +++ b/components/os/windows_servicemanagers.go @@ -17,7 +17,7 @@ func newWindowsServiceManager(e config.Env, runner command.Runner) ServiceManage func (s *windowsServiceManager) EnsureRestarted(serviceName string, transform command.Transformer, opts ...pulumi.ResourceOption) (command.Command, error) { cmdName := s.e.CommonNamer().ResourceName("running", serviceName) - cmdArgs := command.Args{ + var cmdArgs command.CommandArgs = &command.Args{ Create: pulumi.String("Restart-Service -Name " + serviceName), } @@ -26,5 +26,5 @@ func (s *windowsServiceManager) EnsureRestarted(serviceName string, transform co cmdName, cmdArgs = transform(cmdName, cmdArgs) } - return s.runner.Command(cmdName, &cmdArgs, opts...) + return s.runner.Command(cmdName, cmdArgs, opts...) } diff --git a/resources/local/podman/vm.go b/resources/local/podman/vm.go index 242271106..f8befac16 100644 --- a/resources/local/podman/vm.go +++ b/resources/local/podman/vm.go @@ -56,11 +56,13 @@ func NewInstance(e resourceslocal.Environment, args VMArgs, opts ...pulumi.Resou podmanCommand := "podman --config " + dataPath opts = utils.MergeOptions(opts, pulumi.DependsOn([]pulumi.Resource{dockerFile, dockerConfig})) - buildPodman, err := runner.Command("podman-build"+args.Name, &command.Args{ - Environment: pulumi.StringMap{"DOCKER_HOST_SSH_PUBLIC_KEY": pulumi.String(string(publicKey))}, - Create: pulumi.Sprintf("%s build --format=docker --build-arg DOCKER_HOST_SSH_PUBLIC_KEY=\"$DOCKER_HOST_SSH_PUBLIC_KEY\" -t %s .", podmanCommand, args.Name), - Delete: pulumi.Sprintf("%s rmi %s", podmanCommand, args.Name), - Triggers: pulumi.Array{}, + buildPodman, err := runner.Command("podman-build"+args.Name, &command.LocalArgs{ + Args: command.Args{ + Environment: pulumi.StringMap{"DOCKER_HOST_SSH_PUBLIC_KEY": pulumi.String(string(publicKey))}, + Create: pulumi.Sprintf("%s build --format=docker --build-arg DOCKER_HOST_SSH_PUBLIC_KEY=\"$DOCKER_HOST_SSH_PUBLIC_KEY\" -t %s .", podmanCommand, args.Name), + Delete: pulumi.Sprintf("%s rmi %s", podmanCommand, args.Name), + Triggers: pulumi.Array{}, + }, LocalAssetPaths: pulumi.StringArray{}, LocalDir: pulumi.String(dataPath), }, opts...) @@ -68,11 +70,13 @@ func NewInstance(e resourceslocal.Environment, args VMArgs, opts ...pulumi.Resou return pulumi.StringOutput{}, "", -1, err } opts = utils.MergeOptions(opts, pulumi.DependsOn([]pulumi.Resource{buildPodman})) - runPodman, err := runner.Command("podman-run"+args.Name, &command.Args{ - Environment: pulumi.StringMap{"DOCKER_HOST_SSH_PUBLIC_KEY": pulumi.String(string(publicKey))}, - Create: pulumi.Sprintf("%s run -d --name=%[2]s_run -p 50022:22 %[2]s", podmanCommand, args.Name), - Delete: pulumi.Sprintf("%s stop %[2]s_run && podman rm %[2]s_run", podmanCommand, args.Name), - Triggers: pulumi.Array{}, + runPodman, err := runner.Command("podman-run"+args.Name, &command.LocalArgs{ + Args: command.Args{ + Environment: pulumi.StringMap{"DOCKER_HOST_SSH_PUBLIC_KEY": pulumi.String(string(publicKey))}, + Create: pulumi.Sprintf("%s run -d --name=%[2]s_run -p 50022:22 %[2]s", podmanCommand, args.Name), + Delete: pulumi.Sprintf("%s stop %[2]s_run && podman rm %[2]s_run", podmanCommand, args.Name), + Triggers: pulumi.Array{}, + }, LocalAssetPaths: pulumi.StringArray{}, LocalDir: pulumi.String(dataPath), }, opts...)