fleet/server/service/client_scripts.go
Sarah Gillespie c29f0abf92
Update API and CLI to enable running scripts by name and team id (#17322)
TODO:
- Integration tests

# Checklist for submitter

If some of the following don't apply, delete the relevant line.

<!-- Note that API documentation changes are now addressed by the
product design team. -->

- [ ] Changes file added for user-visible changes in `changes/` or
`orbit/changes/`.
See [Changes
files](https://fleetdm.com/docs/contributing/committing-changes#changes-files)
for more information.
- [ ] Documented any permissions changes (docs/Using
Fleet/manage-access.md)
- [ ] Input data is properly validated, `SELECT *` is avoided, SQL
injection is prevented (using placeholders for values in statements)
- [ ] Added support on fleet's osquery simulator `cmd/osquery-perf` for
new osquery data ingestion features.
- [ ] Added/updated tests
- [ ] If database migrations are included, checked table schema to
confirm autoupdate
- For database migrations:
- [ ] Checked schema for all modified table for columns that will
auto-update timestamps during migration.
- [ ] Confirmed that updating the timestamps is acceptable, and will not
cause unwanted side effects.
- [ ] Manual QA for all new/changed functionality
  - For Orbit and Fleet Desktop changes:
- [ ] Manual QA must be performed in the three main OSs, macOS, Windows
and Linux.
- [ ] Auto-update manual QA, from released version of component to new
version (see [tools/tuf/test](../tools/tuf/test/README.md)).
2024-03-05 08:53:17 -06:00

79 lines
2.1 KiB
Go

package service
import (
"encoding/json"
"errors"
"fmt"
"io"
"net/http"
"strings"
"github.com/fleetdm/fleet/v4/server/fleet"
)
func (c *Client) RunHostScriptSync(hostID uint, scriptContents []byte, scriptName string, teamID uint) (*fleet.HostScriptResult, error) {
verb, path := "POST", "/api/latest/fleet/scripts/run/sync"
req := fleet.HostScriptRequestPayload{
HostID: hostID,
ScriptName: scriptName,
TeamID: teamID,
}
if len(scriptContents) > 0 {
req.ScriptContents = string(scriptContents)
}
var result fleet.HostScriptResult
res, err := c.AuthenticatedDo(verb, path, "", &req)
if err != nil {
return nil, err
}
defer res.Body.Close()
switch res.StatusCode {
case http.StatusOK:
b, err := io.ReadAll(res.Body)
if err != nil {
return nil, fmt.Errorf("reading %s %s response: %w", verb, path, err)
}
if err := json.Unmarshal(b, &result); err != nil {
return nil, fmt.Errorf("decoding %s %s response: %w, body: %s", verb, path, err, b)
}
case http.StatusForbidden:
errMsg, err := extractServerErrMsg(verb, path, res)
if err != nil {
return nil, err
}
if strings.Contains(errMsg, fleet.RunScriptScriptsDisabledGloballyErrMsg) {
return nil, errors.New(fleet.RunScriptScriptsDisabledGloballyErrMsg)
}
return nil, errors.New(fleet.RunScriptForbiddenErrMsg)
case http.StatusPaymentRequired:
if teamID > 0 {
return nil, errors.New("Team id parameter requires Fleet Premium license.")
}
fallthrough // if no team id, fall through to default error message
default:
msg, err := extractServerErrMsg(verb, path, res)
if err != nil {
return nil, err
}
if msg == "" {
msg = fmt.Sprintf("decoding %d response is missing expected message.", res.StatusCode)
}
return nil, errors.New(msg)
}
return &result, nil
}
// ApplyNoTeamScripts sends the list of scripts to be applied for the hosts in
// no team.
func (c *Client) ApplyNoTeamScripts(scripts []fleet.ScriptPayload, opts fleet.ApplySpecOptions) error {
verb, path := "POST", "/api/latest/fleet/scripts/batch"
return c.authenticatedRequestWithQuery(map[string]interface{}{"scripts": scripts}, verb, path, nil, opts.RawQuery())
}