Update fleetctl client urls and params (#41463)
<!-- Add the related story/sub-task/bug number, like Resolves #123, or remove if NA --> **Related issue:** Resolves #41385 # Details This PR updates `fleetctl` to use the new API urls and params when communicating with Fleet server. This avoids deprecation warnings showing up on the server that users won't be able to fix. Most of the changes are straightforward `team_id` -> `fleet_id`. A couple of code changes have been pointed out. The most interesting is in icon URLs, which can be persisted in the database (so we'll need to do a migration in Fleet 5 if we want to drop support for `team_id`. Similarly the FMA download urls are briefly persisted in the db for the purpose of sending MDM commands. If we drop team_id support in Fleet 5 there could be a brief window where there are unprocessed commands in the db still with `team_id` in them, so we'll probably want to migrate those as well. # Checklist for submitter If some of the following don't apply, delete the relevant line. - [ ] Changes file added for user-visible changes in `changes/`, `orbit/changes/` or `ee/fleetd-chrome/changes`. See [Changes files](https://github.com/fleetdm/fleet/blob/main/docs/Contributing/guides/committing-changes.md#changes-files) for more information. n/a - all internal ## Testing - [X] Added/updated automated tests - [X] QA'd all new/changed functionality manually - [X] ran `fleetctl gitops` on main and saw a bunch of deprecation warnings, ran it on this branch and the warnings were gone 💨 - [X] same with `fleetctl generate-gitops` - [X] ran `fleetctl get` commands and verified that the new URLs and params were used - [X] ran `fleetctl apply` commands and verified that the new URLs and params were used
This commit is contained in:
@@ -1388,7 +1388,7 @@ func (cmd *GenerateGitopsCommand) generateScripts(teamId *uint, teamName string)
|
||||
// Get scripts.
|
||||
query := ""
|
||||
if teamId != nil {
|
||||
query = fmt.Sprintf("team_id=%d", *teamId)
|
||||
query = fmt.Sprintf("fleet_id=%d", *teamId)
|
||||
}
|
||||
scripts, err := cmd.Client.ListScripts(query)
|
||||
if err != nil {
|
||||
@@ -1568,7 +1568,7 @@ func (cmd *GenerateGitopsCommand) generateSoftware(filePath string, teamID uint,
|
||||
return nil, nil // software is premium-only
|
||||
}
|
||||
|
||||
query := fmt.Sprintf("available_for_install=1&team_id=%d", teamID)
|
||||
query := fmt.Sprintf("available_for_install=1&fleet_id=%d", teamID)
|
||||
software, err := cmd.Client.ListSoftwareTitles(query)
|
||||
if err != nil {
|
||||
fmt.Fprintf(cmd.CLI.App.ErrWriter, "Error getting software: %s\n", err)
|
||||
|
||||
@@ -98,23 +98,23 @@ func (c *MockClient) ListTeams(query string) ([]fleet.Team, error) {
|
||||
|
||||
func (MockClient) ListScripts(query string) ([]*fleet.Script, error) {
|
||||
switch query {
|
||||
case "team_id=1":
|
||||
case "fleet_id=1":
|
||||
return []*fleet.Script{{
|
||||
ID: 2,
|
||||
TeamID: ptr.Uint(1),
|
||||
Name: "Script B.ps1",
|
||||
ScriptContentID: 2,
|
||||
}}, nil
|
||||
case "team_id=0":
|
||||
case "fleet_id=0":
|
||||
return []*fleet.Script{{
|
||||
ID: 3,
|
||||
TeamID: ptr.Uint(0),
|
||||
Name: "Script Z.ps1",
|
||||
ScriptContentID: 3,
|
||||
}}, nil
|
||||
case "team_id=2", "team_id=3", "team_id=4", "team_id=5":
|
||||
case "fleet_id=2", "fleet_id=3", "fleet_id=4", "fleet_id=5":
|
||||
return nil, nil
|
||||
case "team_id=6":
|
||||
case "fleet_id=6":
|
||||
return nil, nil
|
||||
default:
|
||||
return nil, fmt.Errorf("unexpected query: %s", query)
|
||||
@@ -249,7 +249,7 @@ func (MockClient) GetTeam(teamID uint) (*fleet.Team, error) {
|
||||
|
||||
func (MockClient) ListSoftwareTitles(query string) ([]fleet.SoftwareTitleListResult, error) {
|
||||
switch query {
|
||||
case "available_for_install=1&team_id=1":
|
||||
case "available_for_install=1&fleet_id=1":
|
||||
return []fleet.SoftwareTitleListResult{
|
||||
{
|
||||
ID: 1,
|
||||
@@ -312,7 +312,7 @@ func (MockClient) ListSoftwareTitles(query string) ([]fleet.SoftwareTitleListRes
|
||||
},
|
||||
},
|
||||
}, nil
|
||||
case "available_for_install=1&team_id=0":
|
||||
case "available_for_install=1&fleet_id=0":
|
||||
return []fleet.SoftwareTitleListResult{}, nil
|
||||
default:
|
||||
return nil, fmt.Errorf("unexpected query: %s", query)
|
||||
@@ -1592,7 +1592,7 @@ type MockClientWithScriptPackage struct {
|
||||
|
||||
func (c *MockClientWithScriptPackage) ListSoftwareTitles(query string) ([]fleet.SoftwareTitleListResult, error) {
|
||||
switch query {
|
||||
case "available_for_install=1&team_id=2":
|
||||
case "available_for_install=1&fleet_id=2":
|
||||
return []fleet.SoftwareTitleListResult{
|
||||
{
|
||||
ID: 3,
|
||||
|
||||
@@ -884,7 +884,7 @@ func getHostsCommand() *cli.Command {
|
||||
query := url.Values{}
|
||||
query.Set("additional_info_filters", "*")
|
||||
if teamID := c.Uint(fleetFlagName); teamID > 0 {
|
||||
query.Set("team_id", strconv.FormatUint(uint64(teamID), 10))
|
||||
query.Set("fleet_id", strconv.FormatUint(uint64(teamID), 10))
|
||||
}
|
||||
|
||||
if c.Bool("mdm") || c.Bool("mdm-pending") {
|
||||
@@ -1306,7 +1306,7 @@ func getSoftwareCommand() *cli.Command {
|
||||
|
||||
teamID := c.Uint(fleetFlagName)
|
||||
if teamID != 0 {
|
||||
query.Set("team_id", strconv.FormatUint(uint64(teamID), 10))
|
||||
query.Set("fleet_id", strconv.FormatUint(uint64(teamID), 10))
|
||||
}
|
||||
|
||||
if c.Bool("versions") {
|
||||
|
||||
@@ -171,7 +171,7 @@ func (svc *Service) GetInHouseAppManifest(ctx context.Context, titleID uint, tea
|
||||
return nil, ctxerr.Wrap(ctx, err, "get in house app manifest: get in house app metadata")
|
||||
}
|
||||
|
||||
downloadURL := fmt.Sprintf("%s/api/latest/fleet/software/titles/%d/in_house_app?team_id=%d", appConfig.ServerSettings.ServerURL, titleID, ptr.ValOrZero(teamID))
|
||||
downloadURL := fmt.Sprintf("%s/api/latest/fleet/software/titles/%d/in_house_app?fleet_id=%d", appConfig.ServerSettings.ServerURL, titleID, ptr.ValOrZero(teamID))
|
||||
|
||||
if svc.config.S3.SoftwareInstallersCloudFrontSigner != nil {
|
||||
signedURL, err := svc.softwareInstallStore.Sign(ctx, meta.StorageID, fleet.InHouseAppSignedURLExpiry)
|
||||
@@ -184,7 +184,7 @@ func (svc *Service) GetInHouseAppManifest(ctx context.Context, titleID uint, tea
|
||||
}
|
||||
|
||||
// Escape & characters in case of using CloudFront signed URL
|
||||
var funcMap = map[string]any{
|
||||
funcMap := map[string]any{
|
||||
"xml": mobileconfig.XMLEscapeString,
|
||||
}
|
||||
|
||||
@@ -235,7 +235,6 @@ func (svc *Service) GetInHouseAppManifest(ctx context.Context, titleID uint, tea
|
||||
Name string
|
||||
URL string
|
||||
}{meta.BundleIdentifier, meta.Version, meta.SoftwareTitle, downloadURL})
|
||||
|
||||
if err != nil {
|
||||
return nil, ctxerr.Wrap(ctx, err, "rendering app manifest")
|
||||
}
|
||||
|
||||
@@ -512,7 +512,7 @@ func TestGetInHouseAppManifest(t *testing.T) {
|
||||
<key>kind</key>
|
||||
<string>software-package</string>
|
||||
<key>url</key>
|
||||
<string>https://example.com/api/latest/fleet/software/titles/1/in_house_app?team_id=0</string>
|
||||
<string>https://example.com/api/latest/fleet/software/titles/1/in_house_app?fleet_id=0</string>
|
||||
</dict>
|
||||
<dict>
|
||||
<key>kind</key>
|
||||
|
||||
@@ -126,7 +126,7 @@ func (svc *Service) UploadSoftwareTitleIcon(ctx context.Context, payload *fleet.
|
||||
|
||||
// if anything on the icon has changed, we need to generate a new activity
|
||||
if icon == nil || icon.StorageID != softwareTitleIcon.StorageID || icon.Filename != softwareTitleIcon.Filename {
|
||||
iconUrl := fmt.Sprintf("/api/latest/fleet/software/titles/%d/icon?team_id=%d", softwareTitleIcon.SoftwareTitleID, softwareTitleIcon.TeamID)
|
||||
iconUrl := softwareTitleIcon.IconUrl()
|
||||
activityDetailsForSoftwareTitleIcon, err := svc.ds.ActivityDetailsForSoftwareTitleIcon(ctxdb.RequirePrimary(ctx, true), payload.TeamID, payload.TitleID)
|
||||
if err != nil {
|
||||
return fleet.SoftwareTitleIcon{}, ctxerr.Wrap(ctx, err, "fetching software title icon activity details")
|
||||
|
||||
@@ -15,9 +15,7 @@ import (
|
||||
"github.com/jmoiron/sqlx"
|
||||
)
|
||||
|
||||
var (
|
||||
deleteIDsBatchSize = 1000
|
||||
)
|
||||
var deleteIDsBatchSize = 1000
|
||||
|
||||
// ListHostUpcomingActivities returns the list of activities pending execution
|
||||
// or processing for the specific host. It is the "unified queue" of work to be
|
||||
@@ -1487,7 +1485,7 @@ WHERE
|
||||
return ctxerr.Wrap(ctx, err, "get in-house app title id")
|
||||
}
|
||||
|
||||
manifestURL := fmt.Sprintf("%s/api/latest/fleet/software/titles/%d/in_house_app/manifest?team_id=%d", appConfig.ServerSettings.ServerURL, titleID, tid)
|
||||
manifestURL := fmt.Sprintf("%s/api/latest/fleet/software/titles/%d/in_house_app/manifest?fleet_id=%d", appConfig.ServerSettings.ServerURL, titleID, tid)
|
||||
|
||||
// insert the nano command
|
||||
namedArgs := map[string]any{
|
||||
|
||||
@@ -109,7 +109,7 @@ func TestForMyDevicePage(t *testing.T) {
|
||||
{
|
||||
name: "matching custom icon url",
|
||||
before: func() {
|
||||
iconUrl = ptr.String("/api/latest/fleet/software/titles/42/icon?team_id=7")
|
||||
iconUrl = ptr.String("/api/latest/fleet/software/titles/42/icon?fleet_id=7")
|
||||
hostSoftwareInstaller = HostSoftwareWithInstaller{
|
||||
IconUrl: iconUrl,
|
||||
ID: 1,
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
"time"
|
||||
)
|
||||
|
||||
var SoftwareTitleIconURLRegex = regexp.MustCompile(`fleet/software/titles/\d+/icon\?team_id=\d+`)
|
||||
var SoftwareTitleIconURLRegex = regexp.MustCompile(`fleet/software/titles/\d+/icon\?(?:team_id|fleet_id)=\d+`)
|
||||
|
||||
const SoftwareTitleIconSignedURLExpiry = 6 * time.Hour
|
||||
|
||||
@@ -37,7 +37,7 @@ func (s *SoftwareTitleIcon) AuthzType() string {
|
||||
}
|
||||
|
||||
func (s *SoftwareTitleIcon) IconUrl() string {
|
||||
return fmt.Sprintf("/api/latest/fleet/software/titles/%d/icon?team_id=%d", s.SoftwareTitleID, s.TeamID)
|
||||
return fmt.Sprintf("/api/latest/fleet/software/titles/%d/icon?fleet_id=%d", s.SoftwareTitleID, s.TeamID)
|
||||
}
|
||||
|
||||
func (s *SoftwareTitleIcon) IconUrlWithDeviceToken(deviceToken string) string {
|
||||
|
||||
@@ -145,6 +145,20 @@ func RewriteDeprecatedKeys(data []byte, rules []AliasRule) ([]byte, map[string]s
|
||||
return buf.Bytes(), deprecatedKeysMap, nil
|
||||
}
|
||||
|
||||
// RewriteOldToNewKeys is the reverse of RewriteDeprecatedKey; it takes
|
||||
// the rules and reverses them before translating keys.
|
||||
// Use this in situations where a payload was rewritten from new to old keys
|
||||
// for deserialization, but you want to return a response with the new keys
|
||||
// for forward compatibility.
|
||||
func RewriteOldToNewKeys(data []byte, rules []AliasRule) ([]byte, error) {
|
||||
reversed := make([]AliasRule, len(rules))
|
||||
for i, r := range rules {
|
||||
reversed[i] = AliasRule{OldKey: r.NewKey, NewKey: r.OldKey}
|
||||
}
|
||||
result, _, err := RewriteDeprecatedKeys(data, reversed)
|
||||
return result, err
|
||||
}
|
||||
|
||||
// rewrite reads tokens from src, rewrites deprecated keys, checks for alias
|
||||
// conflicts, and writes the transformed JSON to w.
|
||||
func (r *JSONKeyRewriteReader) rewrite(src io.Reader, w io.Writer) error {
|
||||
|
||||
@@ -468,3 +468,35 @@ func TestAliasConflictError_ErrorMessage(t *testing.T) {
|
||||
assert.Contains(t, err.Error(), "team_id")
|
||||
assert.Contains(t, err.Error(), "fleet_id")
|
||||
}
|
||||
|
||||
func TestRewriteOldToNewKeys(t *testing.T) {
|
||||
rules := []AliasRule{
|
||||
{OldKey: "team_id", NewKey: "fleet_id"},
|
||||
{OldKey: "team", NewKey: "fleet"},
|
||||
{OldKey: "custom_settings", NewKey: "configuration_profiles"},
|
||||
}
|
||||
|
||||
t.Run("rewrites old keys to new", func(t *testing.T) {
|
||||
input := `{"team_id":42,"name":"hello","team":"engineering"}`
|
||||
out, err := RewriteOldToNewKeys([]byte(input), rules)
|
||||
require.NoError(t, err)
|
||||
|
||||
var result map[string]any
|
||||
require.NoError(t, json.Unmarshal(out, &result))
|
||||
assert.Equal(t, float64(42), result["fleet_id"])
|
||||
assert.Equal(t, "engineering", result["fleet"])
|
||||
assert.Equal(t, "hello", result["name"])
|
||||
assert.Nil(t, result["team_id"])
|
||||
assert.Nil(t, result["team"])
|
||||
})
|
||||
|
||||
t.Run("new keys pass through unchanged", func(t *testing.T) {
|
||||
input := `{"fleet_id":42}`
|
||||
out, err := RewriteOldToNewKeys([]byte(input), rules)
|
||||
require.NoError(t, err)
|
||||
|
||||
var result map[string]any
|
||||
require.NoError(t, json.Unmarshal(out, &result))
|
||||
assert.Equal(t, float64(42), result["fleet_id"])
|
||||
})
|
||||
}
|
||||
|
||||
@@ -2780,12 +2780,12 @@ func (c *Client) doGitOpsPolicies(config *spec.GitOps, teamSoftwareInstallers []
|
||||
for _, softwareInstaller := range teamSoftwareInstallers {
|
||||
if softwareInstaller.TitleID == nil {
|
||||
// Should not happen, but to not panic we just log a warning.
|
||||
logFn("[!] software installer without title id: team_id=%d, url=%s\n", *teamID, softwareInstaller.URL)
|
||||
logFn("[!] software installer without title id: fleet_id=%d, url=%s\n", *teamID, softwareInstaller.URL)
|
||||
continue
|
||||
}
|
||||
if softwareInstaller.URL == "" && softwareInstaller.HashSHA256 == "" {
|
||||
// Should not happen because we previously applied packages via gitops, but to not panic we just log a warning.
|
||||
logFn("[!] software installer without url: team_id=%d, title_id=%d\n", *teamID, *softwareInstaller.TitleID)
|
||||
logFn("[!] software installer without url: fleet_id=%d, title_id=%d\n", *teamID, *softwareInstaller.TitleID)
|
||||
continue
|
||||
}
|
||||
softwareTitleIDsByInstallerURL[softwareInstaller.URL] = *softwareInstaller.TitleID
|
||||
@@ -2797,12 +2797,12 @@ func (c *Client) doGitOpsPolicies(config *spec.GitOps, teamSoftwareInstallers []
|
||||
}
|
||||
if vppApp.TitleID == nil {
|
||||
// Should not happen, but to not panic we just log a warning.
|
||||
logFn("[!] VPP app without title id: team_id=%d, app_store_id=%s\n", *teamID, vppApp.AppStoreID)
|
||||
logFn("[!] VPP app without title id: fleet_id=%d, app_store_id=%s\n", *teamID, vppApp.AppStoreID)
|
||||
continue
|
||||
}
|
||||
if vppApp.AppStoreID == "" {
|
||||
// Should not happen because we previously applied apps via gitops, but to not panic we just log a warning.
|
||||
logFn("[!] VPP app without app ID: team_id=%d, title_id=%d\n", *teamID, *vppApp.TitleID)
|
||||
logFn("[!] VPP app without app ID: fleet_id=%d, title_id=%d\n", *teamID, *vppApp.TitleID)
|
||||
continue
|
||||
}
|
||||
softwareTitleIDsByAppStoreAppID[vppApp.AppStoreID] = *vppApp.TitleID
|
||||
|
||||
@@ -8,7 +8,7 @@ import (
|
||||
func (c *Client) GetCertificateTemplates(teamID string) ([]*fleet.CertificateTemplateResponseSummary, error) {
|
||||
verb, path := "GET", "/api/latest/fleet/certificates"
|
||||
var responseBody listCertificateTemplatesResponse
|
||||
query := "team_id=" + teamID
|
||||
query := "fleet_id=" + teamID
|
||||
err := c.authenticatedRequestWithQuery(nil, verb, path, &responseBody, query)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/fleetdm/fleet/v4/server/fleet"
|
||||
"github.com/fleetdm/fleet/v4/server/platform/endpointer"
|
||||
"github.com/fleetdm/fleet/v4/server/version"
|
||||
)
|
||||
|
||||
@@ -9,7 +12,15 @@ import (
|
||||
func (c *Client) ApplyAppConfig(payload interface{}, opts fleet.ApplySpecOptions) error {
|
||||
verb, path := "PATCH", "/api/latest/fleet/config"
|
||||
var responseBody appConfigResponse
|
||||
return c.authenticatedRequestWithQuery(payload, verb, path, &responseBody, opts.RawQuery())
|
||||
data, err := json.Marshal(payload)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
data, err = endpointer.RewriteOldToNewKeys(data, endpointer.ExtractAliasRules(fleet.AppConfig{}))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return c.authenticatedRequestWithQuery(data, verb, path, &responseBody, opts.RawQuery())
|
||||
}
|
||||
|
||||
// ApplyNoTeamProfiles sends the list of profiles to be applied for the hosts
|
||||
|
||||
@@ -24,7 +24,7 @@ func (c *Client) ApplyLabels(
|
||||
verb,
|
||||
path,
|
||||
&responseBody,
|
||||
fmt.Sprintf("team_id=%d", *teamID),
|
||||
fmt.Sprintf("fleet_id=%d", *teamID),
|
||||
)
|
||||
}
|
||||
return c.authenticatedRequest(req, verb, path, &responseBody)
|
||||
@@ -42,7 +42,7 @@ func (c *Client) GetLabel(name string) (*fleet.LabelSpec, error) {
|
||||
func (c *Client) GetLabels(teamID uint) ([]*fleet.LabelSpec, error) {
|
||||
verb, path := "GET", "/api/latest/fleet/spec/labels"
|
||||
var responseBody getLabelSpecsResponse
|
||||
err := c.authenticatedRequestWithQuery(nil, verb, path, &responseBody, fmt.Sprintf("team_id=%d", teamID))
|
||||
err := c.authenticatedRequestWithQuery(nil, verb, path, &responseBody, fmt.Sprintf("fleet_id=%d", teamID))
|
||||
return responseBody.Specs, err
|
||||
}
|
||||
|
||||
|
||||
@@ -74,7 +74,7 @@ func (c *Client) LiveQueryWithContext(
|
||||
QuerySQL: query,
|
||||
Selected: distributedQueryCampaignTargetsByIdentifiers{Labels: labels, Hosts: hostIdentifiers},
|
||||
}
|
||||
verb, path := "POST", "/api/latest/fleet/queries/run_by_identifiers"
|
||||
verb, path := "POST", "/api/latest/fleet/reports/run_by_identifiers"
|
||||
var responseBody createDistributedQueryCampaignResponse
|
||||
err := c.authenticatedRequest(req, verb, path, &responseBody)
|
||||
if err != nil {
|
||||
|
||||
@@ -20,7 +20,7 @@ func TestLiveQueryWithContext(t *testing.T) {
|
||||
upgrader := websocket.Upgrader{}
|
||||
ts := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
|
||||
switch r.URL.Path {
|
||||
case "/api/latest/fleet/queries/run_by_identifiers":
|
||||
case "/api/latest/fleet/reports/run_by_identifiers":
|
||||
resp := createDistributedQueryCampaignResponse{
|
||||
Campaign: &fleet.DistributedQueryCampaign{
|
||||
UpdateCreateTimestamps: fleet.UpdateCreateTimestamps{
|
||||
|
||||
@@ -116,8 +116,8 @@ func (c *Client) UploadBootstrapPackage(pkg *fleet.MDMAppleBootstrapPackage, dry
|
||||
return err
|
||||
}
|
||||
|
||||
// add the team_id field
|
||||
if err := w.WriteField("team_id", fmt.Sprint(pkg.TeamID)); err != nil {
|
||||
// add the fleet_id field
|
||||
if err := w.WriteField("fleet_id", fmt.Sprint(pkg.TeamID)); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
|
||||
"github.com/fleetdm/fleet/v4/server/fleet"
|
||||
"github.com/fleetdm/fleet/v4/server/platform/endpointer"
|
||||
)
|
||||
|
||||
func (c *Client) CreateGlobalPolicy(name, query, description, resolution, platform string) error {
|
||||
@@ -25,14 +27,22 @@ func (c *Client) ApplyPolicies(specs []*fleet.PolicySpec) error {
|
||||
req := applyPolicySpecsRequest{Specs: specs}
|
||||
verb, path := "POST", "/api/latest/fleet/spec/policies"
|
||||
var responseBody applyPolicySpecsResponse
|
||||
return c.authenticatedRequest(req, verb, path, &responseBody)
|
||||
data, err := json.Marshal(req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
data, err = endpointer.RewriteOldToNewKeys(data, endpointer.ExtractAliasRules(req))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return c.authenticatedRequest(data, verb, path, &responseBody)
|
||||
}
|
||||
|
||||
// GetPolicies retrieves the list of Policies. Inherited policies are excluded.
|
||||
func (c *Client) GetPolicies(teamID *uint) ([]*fleet.Policy, error) {
|
||||
verb, path := "GET", ""
|
||||
if teamID != nil {
|
||||
path = fmt.Sprintf("/api/latest/fleet/teams/%d/policies", *teamID)
|
||||
path = fmt.Sprintf("/api/latest/fleet/fleets/%d/policies", *teamID)
|
||||
} else {
|
||||
path = "/api/latest/fleet/policies"
|
||||
}
|
||||
@@ -50,7 +60,7 @@ func (c *Client) DeletePolicies(teamID *uint, ids []uint) error {
|
||||
verb, path := "POST", ""
|
||||
req := deleteTeamPoliciesRequest{IDs: ids}
|
||||
if teamID != nil {
|
||||
path = fmt.Sprintf("/api/latest/fleet/teams/%d/policies/delete", *teamID)
|
||||
path = fmt.Sprintf("/api/latest/fleet/fleets/%d/policies/delete", *teamID)
|
||||
req.TeamID = *teamID
|
||||
} else {
|
||||
path = "/api/latest/fleet/policies/delete"
|
||||
|
||||
@@ -27,7 +27,7 @@ func (c *Client) ListProfiles(teamID *uint) ([]*fleet.MDMAppleConfigProfile, err
|
||||
verb, path := "GET", "/api/latest/fleet/mdm/apple/profiles"
|
||||
query := make(url.Values)
|
||||
if teamID != nil {
|
||||
query.Add("team_id", strconv.FormatUint(uint64(*teamID), 10))
|
||||
query.Add("fleet_id", strconv.FormatUint(uint64(*teamID), 10))
|
||||
}
|
||||
var responseBody listMDMAppleConfigProfilesResponse
|
||||
if err := c.authenticatedRequestWithQuery(nil, verb, path, &responseBody, query.Encode()); err != nil {
|
||||
@@ -40,7 +40,7 @@ func (c *Client) ListConfigurationProfiles(teamID *uint) ([]*fleet.MDMConfigProf
|
||||
verb, path := "GET", "/api/latest/fleet/configuration_profiles"
|
||||
query := make(url.Values)
|
||||
if teamID != nil {
|
||||
query.Add("team_id", strconv.FormatUint(uint64(*teamID), 10))
|
||||
query.Add("fleet_id", strconv.FormatUint(uint64(*teamID), 10))
|
||||
}
|
||||
var responseBody listMDMConfigProfilesResponse
|
||||
if err := c.authenticatedRequestWithQuery(nil, verb, path, &responseBody, query.Encode()); err != nil {
|
||||
@@ -77,7 +77,7 @@ func (c *Client) AddProfile(teamID uint, configurationProfile []byte) (uint, err
|
||||
}
|
||||
body := &bytes.Buffer{}
|
||||
writer := multipart.NewWriter(body)
|
||||
teamIDField, err := writer.CreateFormField("team_id")
|
||||
teamIDField, err := writer.CreateFormField("fleet_id")
|
||||
if err != nil {
|
||||
return 0, err
|
||||
}
|
||||
@@ -138,7 +138,7 @@ func (c *Client) GetConfigProfilesSummary(teamID *uint) (*fleet.MDMProfilesSumma
|
||||
verb, path := "GET", "/api/latest/fleet/mdm/profiles/summary"
|
||||
query := make(url.Values)
|
||||
if teamID != nil {
|
||||
query.Add("team_id", strconv.FormatUint(uint64(*teamID), 10))
|
||||
query.Add("fleet_id", strconv.FormatUint(uint64(*teamID), 10))
|
||||
}
|
||||
var responseBody getMDMProfilesSummaryResponse
|
||||
if err := c.authenticatedRequestWithQuery(nil, verb, path, &responseBody, query.Encode()); err != nil {
|
||||
@@ -152,7 +152,7 @@ func (c *Client) GetAppleMDMEnrollmentProfile(teamID uint) (*fleet.MDMAppleSetup
|
||||
verb, path := "GET", "/api/latest/fleet/enrollment_profiles/automatic"
|
||||
var query string
|
||||
if teamID != 0 {
|
||||
query = fmt.Sprintf("team_id=%d", teamID)
|
||||
query = fmt.Sprintf("fleet_id=%d", teamID)
|
||||
}
|
||||
var responseBody createMDMAppleSetupAssistantResponse
|
||||
if err := c.authenticatedRequestWithQuery(nil, verb, path, &responseBody, query); err != nil {
|
||||
|
||||
@@ -1,27 +1,37 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/url"
|
||||
|
||||
"github.com/fleetdm/fleet/v4/server/fleet"
|
||||
"github.com/fleetdm/fleet/v4/server/platform/endpointer"
|
||||
)
|
||||
|
||||
// ApplyQueries sends the list of Queries to be applied (upserted) to the
|
||||
// Fleet instance.
|
||||
func (c *Client) ApplyQueries(specs []*fleet.QuerySpec) error {
|
||||
req := applyQuerySpecsRequest{Specs: specs}
|
||||
verb, path := "POST", "/api/latest/fleet/spec/queries"
|
||||
verb, path := "POST", "/api/latest/fleet/spec/reports"
|
||||
var responseBody applyQuerySpecsResponse
|
||||
return c.authenticatedRequest(req, verb, path, &responseBody)
|
||||
data, err := json.Marshal(req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
data, err = endpointer.RewriteOldToNewKeys(data, endpointer.ExtractAliasRules(req))
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return c.authenticatedRequest(data, verb, path, &responseBody)
|
||||
}
|
||||
|
||||
// GetQuerySpec returns the query spec of a query by its team+name.
|
||||
func (c *Client) GetQuerySpec(teamID *uint, name string) (*fleet.QuerySpec, error) {
|
||||
verb, path := "GET", "/api/latest/fleet/spec/queries/"+url.PathEscape(name)
|
||||
verb, path := "GET", "/api/latest/fleet/spec/reports/"+url.PathEscape(name)
|
||||
query := url.Values{}
|
||||
if teamID != nil {
|
||||
query.Set("team_id", fmt.Sprint(*teamID))
|
||||
query.Set("fleet_id", fmt.Sprint(*teamID))
|
||||
}
|
||||
var responseBody getQuerySpecResponse
|
||||
err := c.authenticatedRequestWithQuery(nil, verb, path, &responseBody, query.Encode())
|
||||
@@ -30,10 +40,10 @@ func (c *Client) GetQuerySpec(teamID *uint, name string) (*fleet.QuerySpec, erro
|
||||
|
||||
// GetQueries retrieves the list of all Queries.
|
||||
func (c *Client) GetQueries(teamID *uint, name *string) ([]fleet.Query, error) {
|
||||
verb, path := "GET", "/api/latest/fleet/queries"
|
||||
verb, path := "GET", "/api/latest/fleet/reports"
|
||||
query := url.Values{}
|
||||
if teamID != nil {
|
||||
query.Set("team_id", fmt.Sprint(*teamID))
|
||||
query.Set("fleet_id", fmt.Sprint(*teamID))
|
||||
}
|
||||
if name != nil {
|
||||
query.Set("query", *name)
|
||||
@@ -48,7 +58,7 @@ func (c *Client) GetQueries(teamID *uint, name *string) ([]fleet.Query, error) {
|
||||
|
||||
// DeleteQuery deletes the query with the matching name.
|
||||
func (c *Client) DeleteQuery(name string) error {
|
||||
verb, path := "DELETE", "/api/latest/fleet/queries/"+url.PathEscape(name)
|
||||
verb, path := "DELETE", "/api/latest/fleet/reports/"+url.PathEscape(name)
|
||||
var responseBody deleteQueryResponse
|
||||
return c.authenticatedRequest(nil, verb, path, &responseBody)
|
||||
}
|
||||
@@ -56,7 +66,7 @@ func (c *Client) DeleteQuery(name string) error {
|
||||
// DeleteQueries deletes several queries.
|
||||
func (c *Client) DeleteQueries(ids []uint) error {
|
||||
req := deleteQueriesRequest{IDs: ids}
|
||||
verb, path := "POST", "/api/latest/fleet/queries/delete"
|
||||
verb, path := "POST", "/api/latest/fleet/reports/delete"
|
||||
var responseBody deleteQueriesResponse
|
||||
return c.authenticatedRequest(req, verb, path, &responseBody)
|
||||
}
|
||||
|
||||
@@ -159,7 +159,7 @@ func (c *Client) validateMacOSSetupScript(fileName string) ([]byte, error) {
|
||||
func (c *Client) deleteMacOSSetupScript(teamID *uint) error {
|
||||
var query string
|
||||
if teamID != nil {
|
||||
query = fmt.Sprintf("team_id=%d", *teamID)
|
||||
query = fmt.Sprintf("fleet_id=%d", *teamID)
|
||||
}
|
||||
|
||||
verb, path := "DELETE", "/api/latest/fleet/setup_experience/script"
|
||||
@@ -181,9 +181,9 @@ func (c *Client) uploadMacOSSetupScript(filename string, data []byte, teamID *ui
|
||||
return err
|
||||
}
|
||||
|
||||
// add the team_id field
|
||||
// add the fleet_id field
|
||||
if teamID != nil {
|
||||
if err := w.WriteField("team_id", fmt.Sprint(*teamID)); err != nil {
|
||||
if err := w.WriteField("fleet_id", fmt.Sprint(*teamID)); err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
@@ -248,7 +248,7 @@ func (c *Client) GetSetupExperienceScript(teamID uint) (*fleet.Script, error) {
|
||||
verb, path := "GET", "/api/latest/fleet/setup_experience/script"
|
||||
var query string
|
||||
if teamID != 0 {
|
||||
query = fmt.Sprintf("team_id=%d", teamID)
|
||||
query = fmt.Sprintf("fleet_id=%d", teamID)
|
||||
}
|
||||
var responseBody getSetupExperienceScriptResponse
|
||||
err := c.authenticatedRequestWithQuery(nil, verb, path, &responseBody, query)
|
||||
|
||||
@@ -40,7 +40,7 @@ func (c *Client) ListSoftwareTitles(query string) ([]fleet.SoftwareTitleListResu
|
||||
func (c *Client) GetSetupExperienceSoftware(platform string, teamID uint) ([]fleet.SoftwareTitleListResult, error) {
|
||||
verb, path := "GET", "/api/latest/fleet/setup_experience/software"
|
||||
var responseBody getSetupExperienceSoftwareResponse
|
||||
query := fmt.Sprintf("platform=%s&team_id=%d", platform, teamID)
|
||||
query := fmt.Sprintf("platform=%s&fleet_id=%d", platform, teamID)
|
||||
err := c.authenticatedRequestWithQuery(nil, verb, path, &responseBody, query)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
@@ -54,7 +54,7 @@ func (c *Client) GetSetupExperienceSoftware(platform string, teamID uint) ([]fle
|
||||
func (c *Client) GetSoftwareTitleByID(ID uint, teamID *uint) (*fleet.SoftwareTitle, error) {
|
||||
var query string
|
||||
if teamID != nil {
|
||||
query = fmt.Sprintf("team_id=%d", *teamID)
|
||||
query = fmt.Sprintf("fleet_id=%d", *teamID)
|
||||
}
|
||||
verb, path := "GET", "/api/latest/fleet/software/titles/"+fmt.Sprint(ID)
|
||||
var responseBody getSoftwareTitleResponse
|
||||
@@ -67,7 +67,7 @@ func (c *Client) GetSoftwareTitleByID(ID uint, teamID *uint) (*fleet.SoftwareTit
|
||||
|
||||
func (c *Client) GetSoftwareTitleIcon(titleID uint, teamID uint) ([]byte, error) {
|
||||
verb, path := "GET", fmt.Sprintf("/api/latest/fleet/software/titles/%d/icon", titleID)
|
||||
response, err := c.AuthenticatedDo(verb, path, fmt.Sprintf("team_id=%d", teamID), nil)
|
||||
response, err := c.AuthenticatedDo(verb, path, fmt.Sprintf("fleet_id=%d", teamID), nil)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("%s %s: %w", verb, path, err)
|
||||
}
|
||||
@@ -211,7 +211,7 @@ func (c *Client) putIcon(teamID uint, titleID uint, writer *multipart.Writer, bu
|
||||
context.Background(),
|
||||
"PUT",
|
||||
fmt.Sprintf("/api/latest/fleet/software/titles/%d/icon", titleID),
|
||||
fmt.Sprintf("team_id=%d", teamID),
|
||||
fmt.Sprintf("fleet_id=%d", teamID),
|
||||
buf.Bytes(),
|
||||
map[string]string{
|
||||
"Content-Type": writer.FormDataContentType(),
|
||||
@@ -235,7 +235,7 @@ func (c *Client) DeleteIcon(teamID uint, titleID uint) error {
|
||||
response, err := c.AuthenticatedDo(
|
||||
"DELETE",
|
||||
fmt.Sprintf("/api/latest/fleet/software/titles/%d/icon", titleID),
|
||||
fmt.Sprintf("team_id=%d", teamID),
|
||||
fmt.Sprintf("fleet_id=%d", teamID),
|
||||
nil,
|
||||
)
|
||||
if err != nil {
|
||||
|
||||
@@ -7,11 +7,12 @@ import (
|
||||
"strconv"
|
||||
|
||||
"github.com/fleetdm/fleet/v4/server/fleet"
|
||||
"github.com/fleetdm/fleet/v4/server/platform/endpointer"
|
||||
)
|
||||
|
||||
// ListTeams retrieves the list of teams.
|
||||
func (c *Client) ListTeams(query string) ([]fleet.Team, error) {
|
||||
verb, path := "GET", "/api/latest/fleet/teams"
|
||||
verb, path := "GET", "/api/latest/fleet/fleets"
|
||||
var responseBody listTeamsResponse
|
||||
err := c.authenticatedRequestWithQuery(nil, verb, path, &responseBody, query)
|
||||
if err != nil {
|
||||
@@ -25,7 +26,7 @@ func (c *Client) CreateTeam(teamPayload fleet.TeamPayload) (*fleet.Team, error)
|
||||
req := createTeamRequest{
|
||||
TeamPayload: teamPayload,
|
||||
}
|
||||
verb, path := "POST", "/api/latest/fleet/teams"
|
||||
verb, path := "POST", "/api/latest/fleet/fleets"
|
||||
var responseBody teamResponse
|
||||
err := c.authenticatedRequest(req, verb, path, &responseBody)
|
||||
if err != nil {
|
||||
@@ -35,7 +36,7 @@ func (c *Client) CreateTeam(teamPayload fleet.TeamPayload) (*fleet.Team, error)
|
||||
}
|
||||
|
||||
func (c *Client) GetTeam(teamID uint) (*fleet.Team, error) {
|
||||
verb, path := "GET", fmt.Sprintf("/api/latest/fleet/teams/%d", teamID)
|
||||
verb, path := "GET", fmt.Sprintf("/api/latest/fleet/fleets/%d", teamID)
|
||||
var responseBody getTeamResponse
|
||||
if err := c.authenticatedRequest(nil, verb, path, &responseBody); err != nil {
|
||||
return nil, err
|
||||
@@ -45,7 +46,7 @@ func (c *Client) GetTeam(teamID uint) (*fleet.Team, error) {
|
||||
|
||||
// DeleteTeam deletes a team.
|
||||
func (c *Client) DeleteTeam(teamID uint) error {
|
||||
verb, path := "DELETE", "/api/latest/fleet/teams/"+strconv.FormatUint(uint64(teamID), 10)
|
||||
verb, path := "DELETE", "/api/latest/fleet/fleets/"+strconv.FormatUint(uint64(teamID), 10)
|
||||
var responseBody deleteTeamResponse
|
||||
return c.authenticatedRequest(nil, verb, path, &responseBody)
|
||||
}
|
||||
@@ -53,9 +54,19 @@ func (c *Client) DeleteTeam(teamID uint) error {
|
||||
// ApplyTeams sends the list of Teams to be applied to the
|
||||
// Fleet instance.
|
||||
func (c *Client) ApplyTeams(specs []json.RawMessage, opts fleet.ApplyTeamSpecOptions) (map[string]uint, error) {
|
||||
verb, path := "POST", "/api/latest/fleet/spec/teams"
|
||||
verb, path := "POST", "/api/latest/fleet/spec/fleets"
|
||||
var responseBody applyTeamSpecsResponse
|
||||
params := map[string]interface{}{"specs": specs}
|
||||
// Rewrite deprecated key names in each team spec to use the new names.
|
||||
rules := endpointer.ExtractAliasRules(fleet.TeamSpec{})
|
||||
rewritten := make([]json.RawMessage, len(specs))
|
||||
for i, spec := range specs {
|
||||
updated, err := endpointer.RewriteOldToNewKeys(spec, rules)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
rewritten[i] = updated
|
||||
}
|
||||
params := map[string]any{"specs": rewritten}
|
||||
if opts.DryRun && opts.DryRunAssumptions != nil {
|
||||
params["dry_run_assumptions"] = opts.DryRunAssumptions
|
||||
}
|
||||
@@ -68,7 +79,7 @@ func (c *Client) ApplyTeams(specs []json.RawMessage, opts fleet.ApplyTeamSpecOpt
|
||||
|
||||
// PatchFleet sends a partial update to the specified team.
|
||||
func (c *Client) PatchFleet(teamID uint, payload fleet.TeamPayload) error {
|
||||
verb, path := "PATCH", "/api/latest/fleet/teams/"+strconv.FormatUint(uint64(teamID), 10)
|
||||
verb, path := "PATCH", "/api/latest/fleet/fleets/"+strconv.FormatUint(uint64(teamID), 10)
|
||||
var resp teamResponse
|
||||
return c.authenticatedRequest(payload, verb, path, &resp)
|
||||
}
|
||||
@@ -81,7 +92,7 @@ func (c *Client) ApplyTeamProfiles(tmName string, profiles []fleet.MDMProfileBat
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
query.Add("team_name", tmName)
|
||||
query.Add("fleet_name", tmName)
|
||||
if opts.DryRunAssumptions != nil && opts.DryRunAssumptions.WindowsEnabledAndConfigured.Valid {
|
||||
query.Add("assume_enabled", strconv.FormatBool(opts.DryRunAssumptions.WindowsEnabledAndConfigured.Value))
|
||||
}
|
||||
@@ -96,7 +107,7 @@ func (c *Client) ApplyTeamScripts(tmName string, scripts []fleet.ScriptPayload,
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
query.Add("team_name", tmName)
|
||||
query.Add("fleet_name", tmName)
|
||||
|
||||
var resp batchSetScriptsResponse
|
||||
err = c.authenticatedRequestWithQuery(map[string]interface{}{"scripts": scripts}, verb, path, &resp, query.Encode())
|
||||
@@ -108,7 +119,7 @@ func (c *Client) ApplyTeamSoftwareInstallers(tmName string, softwareInstallers [
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
query.Add("team_name", tmName)
|
||||
query.Add("fleet_name", tmName)
|
||||
return c.applySoftwareInstallers(softwareInstallers, query, opts.DryRun)
|
||||
}
|
||||
|
||||
@@ -117,7 +128,7 @@ func (c *Client) ApplyTeamAppStoreAppsAssociation(tmName string, vppBatchPayload
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
query.Add("team_name", tmName)
|
||||
query.Add("fleet_name", tmName)
|
||||
return c.applyAppStoreAppsAssociation(vppBatchPayload, query)
|
||||
}
|
||||
|
||||
|
||||
@@ -3232,12 +3232,12 @@ func hostListOptionsFromFilters(filter *map[string]interface{}) (*fleet.HostList
|
||||
} else {
|
||||
return nil, nil, badRequest("label_id must be a number")
|
||||
}
|
||||
case "team_id":
|
||||
case "fleet_id", "team_id":
|
||||
if teamID, ok := v.(float64); ok { // json unmarshals numbers as float64
|
||||
teamID := uint(teamID)
|
||||
opt.TeamFilter = &teamID
|
||||
} else {
|
||||
return nil, nil, badRequest("team_id must be a number")
|
||||
return nil, nil, badRequest("fleet_id must be a number")
|
||||
}
|
||||
case "status":
|
||||
status, ok := v.(string)
|
||||
|
||||
@@ -12517,7 +12517,7 @@ func (s *integrationEnterpriseTestSuite) TestSoftwareInstallerUploadDownloadAndD
|
||||
|
||||
// check activity
|
||||
s.lastActivityOfTypeMatches(fleet.ActivityTypeDeletedSoftware{}.ActivityName(),
|
||||
fmt.Sprintf(`{"software_title": "ruby", "software_package": "ruby.deb", "software_icon_url": "/api/latest/fleet/software/titles/%d/icon?team_id=0", "team_name": null, "team_id": null, "fleet_name": null, "fleet_id": null, "self_service": true}`, titleID), 0)
|
||||
fmt.Sprintf(`{"software_title": "ruby", "software_package": "ruby.deb", "software_icon_url": "/api/latest/fleet/software/titles/%d/icon?fleet_id=0", "team_name": null, "team_id": null, "fleet_name": null, "fleet_id": null, "self_service": true}`, titleID), 0)
|
||||
|
||||
// download the installer, not found anymore
|
||||
s.Do("GET", fmt.Sprintf("/api/latest/fleet/software/titles/%d/package?alt=media", titleID), nil, http.StatusNotFound, "team_id", fmt.Sprintf("%d", 0))
|
||||
@@ -13043,7 +13043,7 @@ func (s *integrationEnterpriseTestSuite) TestSoftwareTitleIcons() {
|
||||
headers,
|
||||
)
|
||||
result := parsePutResponse(resp)
|
||||
iconUrl := fmt.Sprintf("/api/latest/fleet/software/titles/%d/icon?team_id=%d", titleID, tm.ID)
|
||||
iconUrl := fmt.Sprintf("/api/latest/fleet/software/titles/%d/icon?fleet_id=%d", titleID, tm.ID)
|
||||
require.Nil(t, result.Err)
|
||||
require.Contains(t, result.IconUrl, iconUrl)
|
||||
|
||||
|
||||
@@ -13841,7 +13841,7 @@ func (s *integrationMDMTestSuite) TestVPPApps() {
|
||||
"team_id",
|
||||
fmt.Sprint(team.ID))
|
||||
s.lastActivityMatches(fleet.ActivityDeletedAppStoreApp{}.ActivityName(),
|
||||
fmt.Sprintf(`{"team_name": "%s", "fleet_name": "%s", "software_title": "%s", "app_store_id": "%s", "software_icon_url": "/api/latest/fleet/software/titles/%d/icon?team_id=%d", "team_id": %d, "fleet_id": %d, "platform": "%s"}`, team.Name, team.Name,
|
||||
fmt.Sprintf(`{"team_name": "%s", "fleet_name": "%s", "software_title": "%s", "app_store_id": "%s", "software_icon_url": "/api/latest/fleet/software/titles/%d/icon?fleet_id=%d", "team_id": %d, "fleet_id": %d, "platform": "%s"}`, team.Name, team.Name,
|
||||
addedApp.Name, addedApp.AdamID, macOSTitleID, team.ID, team.ID, team.ID, addedApp.Platform), 0)
|
||||
|
||||
var count int
|
||||
@@ -14583,7 +14583,7 @@ func (s *integrationMDMTestSuite) TestNoTeamVPPAppIcons() {
|
||||
"team_id",
|
||||
fmt.Sprint(fleet.PolicyNoTeamID))
|
||||
s.lastActivityMatches(fleet.ActivityDeletedAppStoreApp{}.ActivityName(),
|
||||
fmt.Sprintf(`{"team_name": null, "fleet_name": null, "software_title": "%s", "app_store_id": "%s", "software_icon_url": "/api/latest/fleet/software/titles/%d/icon?team_id=%d", "team_id": %d, "fleet_id": %d, "platform": "%s"}`,
|
||||
fmt.Sprintf(`{"team_name": null, "fleet_name": null, "software_title": "%s", "app_store_id": "%s", "software_icon_url": "/api/latest/fleet/software/titles/%d/icon?fleet_id=%d", "team_id": %d, "fleet_id": %d, "platform": "%s"}`,
|
||||
addedApp.Name, addedApp.AdamID, macOSTitleID, fleet.PolicyNoTeamID, fleet.PolicyNoTeamID, fleet.PolicyNoTeamID, addedApp.Platform), 0)
|
||||
|
||||
mysql.ExecAdhocSQL(t, s.ds, func(q sqlx.ExtContext) error {
|
||||
|
||||
@@ -1612,7 +1612,7 @@ func (s *integrationMDMTestSuite) TestInHouseAppInstall() {
|
||||
assert.Equal(t, installCmdUUID, cmd.CommandUUID)
|
||||
|
||||
// Points at the expected manifest URL
|
||||
expectedManifestURL := fmt.Sprintf("%s/api/latest/fleet/software/titles/%d/in_house_app/manifest?team_id=%d", s.server.URL, titleID, 0)
|
||||
expectedManifestURL := fmt.Sprintf("%s/api/latest/fleet/software/titles/%d/in_house_app/manifest?fleet_id=%d", s.server.URL, titleID, 0)
|
||||
assert.Contains(t, string(cmd.Raw), expectedManifestURL)
|
||||
|
||||
cmd, err = iosDevice.Acknowledge(cmd.CommandUUID)
|
||||
@@ -1792,7 +1792,7 @@ func (s *integrationMDMTestSuite) TestInHouseAppSelfInstall() {
|
||||
assert.Equal(t, installCmdUUID, cmd.CommandUUID)
|
||||
|
||||
// Points at the expected manifest URL
|
||||
expectedManifestURL := fmt.Sprintf("%s/api/latest/fleet/software/titles/%d/in_house_app/manifest?team_id=%d", s.server.URL, titleID, 0)
|
||||
expectedManifestURL := fmt.Sprintf("%s/api/latest/fleet/software/titles/%d/in_house_app/manifest?fleet_id=%d", s.server.URL, titleID, 0)
|
||||
assert.Contains(t, string(cmd.Raw), expectedManifestURL)
|
||||
|
||||
cmd, err = iosDevice.Acknowledge(cmd.CommandUUID)
|
||||
@@ -1891,7 +1891,7 @@ func (s *integrationMDMTestSuite) TestGetInHouseAppManifestUnsignedURL() {
|
||||
|
||||
manifest := readManifest(res)
|
||||
require.NotNil(t, manifest)
|
||||
require.Contains(t, string(manifest), fmt.Sprintf("/%d/in_house_app?team_id=%d", titleID, *teamID))
|
||||
require.Contains(t, string(manifest), fmt.Sprintf("/%d/in_house_app?fleet_id=%d", titleID, *teamID))
|
||||
}
|
||||
|
||||
func (s *integrationMDMTestSuite) addHostIdentityCertificate(hostUUID string, certSerial uint64) {
|
||||
|
||||
@@ -126,7 +126,12 @@ func (putSoftwareTitleIconRequest) DecodeRequest(ctx context.Context, r *http.Re
|
||||
if titleIDUint64 > math.MaxUint {
|
||||
return nil, &fleet.BadRequestError{Message: "title_id value too large"}
|
||||
}
|
||||
teamID := r.URL.Query().Get("team_id")
|
||||
// Accept both fleet_id and team_id without deprecation warning, since
|
||||
// persisted icon URLs may still contain team_id.
|
||||
teamID := r.URL.Query().Get("fleet_id")
|
||||
if teamID == "" {
|
||||
teamID = r.URL.Query().Get("team_id")
|
||||
}
|
||||
if teamID == "" {
|
||||
return nil, &fleet.BadRequestError{Message: "team_id is required"}
|
||||
}
|
||||
|
||||
@@ -4,13 +4,16 @@ import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log/slog"
|
||||
"net/http"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/fleetdm/fleet/v4/server/contexts/ctxerr"
|
||||
"github.com/fleetdm/fleet/v4/server/contexts/logging"
|
||||
"github.com/fleetdm/fleet/v4/server/fleet"
|
||||
"github.com/fleetdm/fleet/v4/server/platform/endpointer"
|
||||
platform_logging "github.com/fleetdm/fleet/v4/server/platform/logging"
|
||||
"github.com/fleetdm/fleet/v4/server/ptr"
|
||||
"github.com/gorilla/mux"
|
||||
)
|
||||
@@ -143,7 +146,14 @@ func hostListOptionsFromRequest(r *http.Request) (fleet.HostListOptions, error)
|
||||
teamID := r.URL.Query().Get("fleet_id")
|
||||
if teamID == "" {
|
||||
teamID = r.URL.Query().Get("team_id")
|
||||
// TODO: warn about deprecated team_id parameter if team_id is used instead of fleet_id.
|
||||
if teamID != "" &&
|
||||
platform_logging.TopicEnabled(platform_logging.DeprecatedFieldTopic) {
|
||||
logging.WithLevel(r.Context(), slog.LevelWarn)
|
||||
logging.WithExtras(r.Context(),
|
||||
"deprecated_param", "team_id",
|
||||
"deprecation_warning", "'team_id' is deprecated, use 'fleet_id' instead",
|
||||
)
|
||||
}
|
||||
}
|
||||
if teamID != "" {
|
||||
id, err := strconv.ParseUint(teamID, 10, 32)
|
||||
@@ -618,8 +628,18 @@ func userListOptionsFromRequest(r *http.Request) (fleet.UserListOptions, error)
|
||||
}
|
||||
|
||||
userOpts := fleet.UserListOptions{ListOptions: opt}
|
||||
|
||||
if tid := r.URL.Query().Get("team_id"); tid != "" {
|
||||
tid := r.URL.Query().Get("fleet_id")
|
||||
if tid == "" {
|
||||
tid = r.URL.Query().Get("team_id")
|
||||
if tid != "" && platform_logging.TopicEnabled(platform_logging.DeprecatedFieldTopic) {
|
||||
logging.WithLevel(r.Context(), slog.LevelWarn)
|
||||
logging.WithExtras(r.Context(),
|
||||
"deprecated_param", "team_id",
|
||||
"deprecation_warning", "'team_id' is deprecated, use 'fleet_id' instead",
|
||||
)
|
||||
}
|
||||
}
|
||||
if tid != "" {
|
||||
teamID, err := strconv.ParseUint(tid, 10, 64)
|
||||
if err != nil {
|
||||
return userOpts, ctxerr.Wrap(r.Context(), badRequest(fmt.Sprintf("Invalid team_id: %s", tid)))
|
||||
|
||||
@@ -87,7 +87,7 @@ This issue was created automatically by your Fleet Jira integration.
|
||||
* [{{ .DisplayName }}|{{ $.FleetURL }}/hosts/{{ .ID }}]
|
||||
{{ end }}
|
||||
|
||||
View hosts that failed {{ .PolicyName }} on the [*Hosts*|{{ .FleetURL }}/hosts/manage/?order_key=hostname&order_direction=asc&{{ if .TeamID }}team_id={{ .TeamID }}&{{ end }}policy_id={{ .PolicyID }}&policy_response=failing] page in Fleet.
|
||||
View hosts that failed {{ .PolicyName }} on the [*Hosts*|{{ .FleetURL }}/hosts/manage/?order_key=hostname&order_direction=asc&{{ if .TeamID }}fleet_id={{ .TeamID }}&{{ end }}policy_id={{ .PolicyID }}&policy_response=failing] page in Fleet.
|
||||
|
||||
----
|
||||
|
||||
|
||||
@@ -146,14 +146,14 @@ func TestJiraRun(t *testing.T) {
|
||||
`{"failing_policy":{"policy_id": 1, "policy_name": "test-policy", "hosts": []}}`,
|
||||
`"summary":"test-policy policy failed on 0 host(s)"`,
|
||||
[]string{"\\u0026policy_id=1\\u0026policy_response=failing"},
|
||||
"\\u0026team_id=",
|
||||
"\\u0026fleet_id=",
|
||||
},
|
||||
{
|
||||
"failing team policy",
|
||||
fleet.TierPremium,
|
||||
`{"failing_policy":{"policy_id": 2, "policy_name": "test-policy-2", "team_id": 123, "hosts": [{"id": 1, "hostname": "test-1"}, {"id": 2, "hostname": "test-2"}]}}`,
|
||||
`"summary":"test-policy-2 policy failed on 2 host(s)"`,
|
||||
[]string{"\\u0026team_id=123\\u0026policy_id=2\\u0026policy_response=failing"},
|
||||
[]string{"\\u0026fleet_id=123\\u0026policy_id=2\\u0026policy_response=failing"},
|
||||
"",
|
||||
},
|
||||
{
|
||||
|
||||
@@ -88,7 +88,7 @@ This ticket was created automatically by your Fleet Zendesk integration.
|
||||
* [{{ .DisplayName }}]({{ $.FleetURL }}/hosts/{{ .ID }})
|
||||
{{ end }}
|
||||
|
||||
View hosts that failed {{ .PolicyName }} on the [**Hosts**]({{ .FleetURL }}/hosts/manage/?order_key=hostname&order_direction=asc&{{ if .TeamID }}team_id={{ .TeamID }}&{{ end }}policy_id={{ .PolicyID }}&policy_response=failing) page in Fleet.
|
||||
View hosts that failed {{ .PolicyName }} on the [**Hosts**]({{ .FleetURL }}/hosts/manage/?order_key=hostname&order_direction=asc&{{ if .TeamID }}fleet_id={{ .TeamID }}&{{ end }}policy_id={{ .PolicyID }}&policy_response=failing) page in Fleet.
|
||||
|
||||
----
|
||||
|
||||
|
||||
@@ -129,14 +129,14 @@ func TestZendeskRun(t *testing.T) {
|
||||
`{"failing_policy":{"policy_id": 1, "policy_name": "test-policy", "hosts": [{"id": 123, "hostname": "host-123"}]}}`,
|
||||
`"subject":"test-policy policy failed on 1 host(s)"`,
|
||||
[]string{"\\u0026policy_id=1\\u0026policy_response=failing"},
|
||||
"\\u0026team_id=",
|
||||
"\\u0026fleet_id=",
|
||||
},
|
||||
{
|
||||
"failing team policy",
|
||||
fleet.TierPremium,
|
||||
`{"failing_policy":{"policy_id": 2, "policy_name": "test-policy-2", "team_id": 123, "hosts": [{"id": 1, "hostname": "host-1"}, {"id": 2, "hostname": "host-2"}]}}`,
|
||||
`"subject":"test-policy-2 policy failed on 2 host(s)"`,
|
||||
[]string{"\\u0026team_id=123\\u0026policy_id=2\\u0026policy_response=failing"},
|
||||
[]string{"\\u0026fleet_id=123\\u0026policy_id=2\\u0026policy_response=failing"},
|
||||
"",
|
||||
},
|
||||
{
|
||||
|
||||
Reference in New Issue
Block a user