fleetctl can now transfer hosts to No team (#16759)

#16466 
fleetctl can now transfer hosts to No team like: `fleetctl hosts
transfer --team '' --hosts yourHost`

# 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. -->

- [x] 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.
- [x] Added/updated tests
- [x] Manual QA for all new/changed functionality
This commit is contained in:
Victor Lyuboslavsky
2024-02-13 10:17:59 -06:00
committed by GitHub
parent fb75073a6d
commit ed9d155249
4 changed files with 57 additions and 21 deletions
+1
View File
@@ -0,0 +1 @@
fleetctl can now transfer hosts to No team like: fleetctl hosts transfer --team '' --hosts yourHost
+1 -1
View File
@@ -31,7 +31,7 @@ func transferCommand() *cli.Command {
Flags: []cli.Flag{
&cli.StringFlag{
Name: teamFlagName,
Usage: "Team name hosts will be transferred to",
Usage: "Team name hosts will be transferred to. Use '' for No team",
Required: true,
},
&cli.StringSliceFlag{
+27 -1
View File
@@ -64,7 +64,20 @@ func TestHostsTransferByHosts(t *testing.T) {
}
assert.Equal(t, "", runAppForTest(t, []string{"hosts", "transfer", "--team", "team1", "--hosts", "host1"}))
require.True(t, ds.NewActivityFuncInvoked)
assert.True(t, ds.AddHostsToTeamFuncInvoked)
assert.True(t, ds.NewActivityFuncInvoked)
// Now, transfer out of the team.
ds.AddHostsToTeamFunc = func(ctx context.Context, teamID *uint, hostIDs []uint) error {
assert.Nil(t, teamID)
assert.Equal(t, []uint{42}, hostIDs)
return nil
}
ds.NewActivityFuncInvoked = false
ds.AddHostsToTeamFuncInvoked = false
assert.Equal(t, "", runAppForTest(t, []string{"hosts", "transfer", "--team", "", "--hosts", "host1"}))
assert.True(t, ds.AddHostsToTeamFuncInvoked)
assert.True(t, ds.NewActivityFuncInvoked)
}
func TestHostsTransferByLabel(t *testing.T) {
@@ -121,6 +134,19 @@ func TestHostsTransferByLabel(t *testing.T) {
assert.Equal(t, "", runAppForTest(t, []string{"hosts", "transfer", "--team", "team1", "--label", "label1"}))
require.True(t, ds.NewActivityFuncInvoked)
assert.True(t, ds.AddHostsToTeamFuncInvoked)
// Now, transfer out of the team.
ds.AddHostsToTeamFunc = func(ctx context.Context, teamID *uint, hostIDs []uint) error {
assert.Nil(t, teamID)
require.Equal(t, []uint{32, 12}, hostIDs)
return nil
}
ds.NewActivityFuncInvoked = false
ds.AddHostsToTeamFuncInvoked = false
assert.Equal(t, "", runAppForTest(t, []string{"hosts", "transfer", "--team", "", "--label", "label1"}))
assert.True(t, ds.AddHostsToTeamFuncInvoked)
assert.True(t, ds.NewActivityFuncInvoked)
}
func TestHostsTransferByStatus(t *testing.T) {
+28 -19
View File
@@ -7,7 +7,6 @@ import (
"strings"
"github.com/fleetdm/fleet/v4/server/fleet"
"github.com/fleetdm/fleet/v4/server/ptr"
)
// GetHosts retrieves the list of all Hosts
@@ -55,23 +54,28 @@ func (c *Client) translateTransferHostsToIDs(hosts []string, label string, team
translatePayloads = append(translatePayloads, translatedPayload)
}
translatedPayload, err := encodeTranslatedPayload(fleet.TranslatorTypeTeam, team)
if err != nil {
return nil, 0, 0, err
}
translatePayloads = append(translatePayloads, translatedPayload)
params := translatorRequest{List: translatePayloads}
err = c.authenticatedRequest(&params, verb, path, &responseBody)
if err != nil {
return nil, 0, 0, err
if team != "" {
translatedPayload, err := encodeTranslatedPayload(fleet.TranslatorTypeTeam, team)
if err != nil {
return nil, 0, 0, err
}
translatePayloads = append(translatePayloads, translatedPayload)
}
var hostIDs []uint
var labelID uint
var teamID uint
if len(translatePayloads) == 0 {
return hostIDs, labelID, teamID, nil
}
params := translatorRequest{List: translatePayloads}
err := c.authenticatedRequest(&params, verb, path, &responseBody)
if err != nil {
return nil, 0, 0, err
}
for _, payload := range responseBody.List {
switch payload.Type {
case fleet.TranslatorTypeLabel:
@@ -99,10 +103,14 @@ func (c *Client) TransferHosts(hosts []string, label string, status, searchQuery
return err
}
var teamIDPtr *uint
if teamID != 0 {
teamIDPtr = &teamID
}
if len(hosts) != 0 {
verb, path := "POST", "/api/latest/fleet/hosts/transfer"
var responseBody addHostsToTeamResponse
params := addHostsToTeamRequest{TeamID: ptr.Uint(teamID), HostIDs: hostIDs}
params := addHostsToTeamRequest{TeamID: teamIDPtr, HostIDs: hostIDs}
return c.authenticatedRequest(params, verb, path, &responseBody)
}
@@ -113,15 +121,16 @@ func (c *Client) TransferHosts(hosts []string, label string, status, searchQuery
verb, path := "POST", "/api/latest/fleet/hosts/transfer/filter"
var responseBody addHostsToTeamByFilterResponse
params := addHostsToTeamByFilterRequest{TeamID: ptr.Uint(teamID), Filters: struct {
MatchQuery string `json:"query"`
Status fleet.HostStatus `json:"status"`
LabelID *uint `json:"label_id"`
}{MatchQuery: searchQuery, Status: fleet.HostStatus(status), LabelID: labelIDPtr}}
params := addHostsToTeamByFilterRequest{
TeamID: teamIDPtr, Filters: struct {
MatchQuery string `json:"query"`
Status fleet.HostStatus `json:"status"`
LabelID *uint `json:"label_id"`
}{MatchQuery: searchQuery, Status: fleet.HostStatus(status), LabelID: labelIDPtr}}
return c.authenticatedRequest(params, verb, path, &responseBody)
}
// GetHosts returns a report of all hosts.
// GetHostsReport returns a report of all hosts.
//
// The first row holds the name of the columns and each subsequent row are
// the column values for each host.