Use --team flag for run-script command (#17373)

This commit is contained in:
Sarah Gillespie
2024-03-05 11:54:26 -06:00
committed by GitHub
parent 1440584d06
commit 1e43cd813c
3 changed files with 88 additions and 38 deletions
+3
View File
@@ -0,0 +1,3 @@
- Updated `fleetctl run-script` to include new `--team` and `--script-name` flags that enable users
to run live script on a host using a previously saved script referenced by the script name and team ID.
- Updated `POST /scripts/run/sync` API to receive new `script_name` and `team_id` parameters.
+5 -5
View File
@@ -38,7 +38,7 @@ func runScriptCommand() *cli.Command {
Required: false,
},
&cli.UintFlag{
Name: "team-id",
Name: "team",
Usage: `Available in Fleet Premium. ID of the team that the saved script belongs to. 0 targets hosts assigned to “No team” (default: 0).`,
Required: false,
},
@@ -65,11 +65,11 @@ func runScriptCommand() *cli.Command {
name := c.String("script-name")
if path == "" && name == "" {
return errors.New("One of --script-path or --script-name must be specified.")
return errors.New("One of '--script-path' or '--script-name' must be specified.")
}
if path != "" && name != "" {
return errors.New("Only one of --script-path or --script-name is allowed.")
return errors.New("Only one of '--script-path' or '--script-name' is allowed.")
}
if path != "" {
@@ -117,10 +117,10 @@ func runScriptCommand() *cli.Command {
fmt.Println("\nScript is running. Please wait for it to finish...")
res, err := client.RunHostScriptSync(h.ID, b, name, c.Uint("team-id"))
res, err := client.RunHostScriptSync(h.ID, b, name, c.Uint("team"))
if err != nil {
if strings.Contains(err.Error(), `Only one of 'script_contents' or 'team_id' is allowed`) {
return errors.New("Only one of --script-path or --team-id is allowed.")
return errors.New("Only one of '--script-path' or '--team' is allowed.")
}
return err
}
+80 -33
View File
@@ -51,26 +51,37 @@ func TestRunScriptCommand(t *testing.T) {
ds.IsExecutionPendingForHostFunc = func(ctx context.Context, hid uint, scriptID uint) ([]*uint, error) {
return []*uint{}, nil
}
ds.GetScriptContentsFunc = func(ctx context.Context, id uint) ([]byte, error) {
return []byte("echo hello world"), nil
}
generateValidPath := func() string {
return writeTmpScriptContents(t, "echo hello world", ".sh")
}
maxChars := strings.Repeat("a", 10001)
exceedsMaxCharsUnsaved := strings.Repeat("a", fleet.UnsavedScriptMaxRuneLen+1)
exceedsMaxCharsSaved := strings.Repeat("a", fleet.SavedScriptMaxRuneLen+1)
expectedOutputSuccess := `
Exit code: 0 (Script ran successfully.)
Output:
-------------------------------------------------------------------------------------
hello world
-------------------------------------------------------------------------------------
`
type testCase struct {
name string
scriptPath func() string
scriptName string
teamID *uint
scriptResult *fleet.HostScriptResult
expectOutput string
expectErrMsg string
expectNotFound bool
expectOffline bool
expectPending bool
name string
scriptPath func() string
scriptName string
teamID *uint
savedScriptContents func() ([]byte, error)
scriptResult *fleet.HostScriptResult
expectOutput string
expectErrMsg string
expectNotFound bool
expectOffline bool
expectPending bool
}
cases := []testCase{
@@ -99,25 +110,56 @@ func TestRunScriptCommand(t *testing.T) {
{
name: "script too long (unsaved)",
scriptPath: func() string {
return writeTmpScriptContents(t, maxChars, ".sh")
return writeTmpScriptContents(t, exceedsMaxCharsUnsaved, ".sh")
},
expectErrMsg: "Script is too large. Script referenced by '--script-path' is limited to 10,000 characters. To run larger script save it to Fleet and use '--script-name'.",
},
{
name: "script not too long (unsaved)",
scriptPath: func() string {
return writeTmpScriptContents(t, exceedsMaxCharsUnsaved[:fleet.UnsavedScriptMaxRuneLen], ".sh")
},
scriptResult: &fleet.HostScriptResult{
ExitCode: ptr.Int64(0),
Output: "hello world",
},
expectOutput: expectedOutputSuccess,
},
{
name: "script too long (saved)",
scriptName: "foo",
savedScriptContents: func() ([]byte, error) {
return []byte(exceedsMaxCharsSaved), nil
},
expectErrMsg: "Script is too large. It's limited to 500,000 characters (approximately 10,000 lines).",
},
{
name: "script not too long (saved)",
scriptName: "foo",
savedScriptContents: func() ([]byte, error) {
return []byte(exceedsMaxCharsUnsaved), nil
},
scriptResult: &fleet.HostScriptResult{
ExitCode: ptr.Int64(0),
Output: "hello world",
},
expectOutput: expectedOutputSuccess,
},
{
name: "script-path and script-name disallowed",
scriptPath: generateValidPath,
scriptName: "foo",
expectErrMsg: `Only one of --script-path or --script-name is allowed.`,
expectErrMsg: `Only one of '--script-path' or '--script-name' is allowed.`,
},
{
name: "missing one of script-path and script-nqme",
expectErrMsg: `One of --script-path or --script-name must be specified.`,
expectErrMsg: `One of '--script-path' or '--script-name' must be specified.`,
},
{
name: "script-path and team-id disallowed",
name: "script-path and team disallowed",
scriptPath: generateValidPath,
teamID: ptr.Uint(1),
expectErrMsg: `Only one of --script-path or --team-id is allowed.`,
expectErrMsg: `Only one of '--script-path' or '--team' is allowed.`,
},
{
name: "script empty",
@@ -142,17 +184,7 @@ func TestRunScriptCommand(t *testing.T) {
ExitCode: ptr.Int64(0),
Output: "hello world",
},
expectOutput: `
Exit code: 0 (Script ran successfully.)
Output:
-------------------------------------------------------------------------------------
hello world
-------------------------------------------------------------------------------------
`,
expectOutput: expectedOutputSuccess,
},
{
name: "script failed",
@@ -211,7 +243,7 @@ Error: Scripts are disabled for this host. To run scripts, deploy the fleetd age
scriptPath: generateValidPath,
scriptResult: &fleet.HostScriptResult{
ExitCode: ptr.Int64(0),
Output: maxChars,
Output: exceedsMaxCharsUnsaved,
},
expectOutput: fmt.Sprintf(`
Exit code: 0 (Script ran successfully.)
@@ -225,7 +257,7 @@ Fleet records the last 10,000 characters to prevent downtime.
%s
-------------------------------------------------------------------------------------
`, maxChars),
`, exceedsMaxCharsUnsaved),
},
// TODO: this would take 5 minutes to run, we don't want that kind of slowdown in our test suite
// but can be useful to have around for manual testing.
@@ -287,6 +319,21 @@ Fleet records the last 10,000 characters to prevent downtime.
return &fleet.AppConfig{ServerSettings: fleet.ServerSettings{ScriptsDisabled: false}}, nil
}
}
if c.savedScriptContents != nil {
ds.GetScriptContentsFunc = func(ctx context.Context, id uint) ([]byte, error) {
return c.savedScriptContents()
}
ds.ScriptFunc = func(ctx context.Context, id uint) (*fleet.Script, error) {
return &fleet.Script{ID: id, Name: "foo"}, nil
}
} else {
ds.GetScriptContentsFunc = func(ctx context.Context, id uint) ([]byte, error) {
return []byte("echo hello world"), nil
}
ds.ScriptFunc = func(ctx context.Context, id uint) (*fleet.Script, error) {
return &fleet.Script{ID: id, Name: "foo"}, nil
}
}
}
for _, c := range cases {
@@ -305,7 +352,7 @@ Fleet records the last 10,000 characters to prevent downtime.
}
if c.teamID != nil {
args = append(args, "--team-id", fmt.Sprintf("%d", *c.teamID))
args = append(args, "--team", fmt.Sprintf("%d", *c.teamID))
}
b, err := runAppNoChecks(args)