-
Notifications
You must be signed in to change notification settings - Fork 488
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Issue 1359 fleetctl team transfer (#1413)
* wip * Add delete user command and translator * Add host transfer command * Add changes file * Undo bad refactor * Fix copypaste error * Implement with interfaces instead of assertions * Ad documentation and simplify implementation further * Update docs/1-Using-Fleet/3-REST-API.md Co-authored-by: Zach Wasserman <[email protected]> Co-authored-by: Zach Wasserman <[email protected]>
- Loading branch information
Showing
17 changed files
with
703 additions
and
3 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
* Add host transfer capabilities to fleetctl. Fixes issue 1359. |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
* Add user delete capabilities to fleetctl. Fixes issue 1360 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,82 @@ | ||
package main | ||
|
||
import ( | ||
"github.com/pkg/errors" | ||
"github.com/urfave/cli/v2" | ||
) | ||
|
||
const ( | ||
hostsFlagName = "hosts" | ||
labelFlagName = "label" | ||
statusFlagName = "status" | ||
searchQueryFlagName = "search_query" | ||
) | ||
|
||
func hostsCommand() *cli.Command { | ||
return &cli.Command{ | ||
Name: "hosts", | ||
Usage: "Manage Fleet hosts", | ||
Subcommands: []*cli.Command{ | ||
transferCommand(), | ||
}, | ||
} | ||
} | ||
|
||
func transferCommand() *cli.Command { | ||
return &cli.Command{ | ||
Name: "transfer", | ||
Usage: "Transfer one or more hosts to a team", | ||
UsageText: `This command will gather the set of hosts specified and transfer them to the team.`, | ||
Flags: []cli.Flag{ | ||
&cli.StringFlag{ | ||
Name: teamFlagName, | ||
Usage: "Team name hosts will be transferred to", | ||
Required: true, | ||
}, | ||
&cli.StringSliceFlag{ | ||
Name: hostsFlagName, | ||
Usage: "Comma separated hostnames to transfer", | ||
}, | ||
&cli.StringFlag{ | ||
Name: labelFlagName, | ||
Usage: "Label name to transfer", | ||
}, | ||
&cli.StringFlag{ | ||
Name: statusFlagName, | ||
Usage: "Status to use when filtering hosts", | ||
}, | ||
&cli.StringFlag{ | ||
Name: searchQueryFlagName, | ||
Usage: "A search query that returns matching hostnames to be transferred", | ||
}, | ||
configFlag(), | ||
contextFlag(), | ||
yamlFlag(), | ||
debugFlag(), | ||
}, | ||
Action: func(c *cli.Context) error { | ||
client, err := clientFromCLI(c) | ||
if err != nil { | ||
return err | ||
} | ||
|
||
team := c.String(teamFlagName) | ||
hosts := c.StringSlice(hostsFlagName) | ||
label := c.String(labelFlagName) | ||
status := c.String(statusFlagName) | ||
searchQuery := c.String(searchQueryFlagName) | ||
|
||
if hosts != nil { | ||
if label != "" || searchQuery != "" || status != "" { | ||
return errors.New("--hosts cannot be used along side any other flag") | ||
} | ||
} else { | ||
if label == "" && searchQuery == "" && status == "" { | ||
return errors.New("You need to define either --hosts, or one or more of --label, --status, --search_query") | ||
} | ||
} | ||
|
||
return client.TransferHosts(hosts, label, status, searchQuery, team) | ||
}, | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,153 @@ | ||
package main | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/fleetdm/fleet/v4/server/fleet" | ||
"github.com/stretchr/testify/assert" | ||
"github.com/stretchr/testify/require" | ||
) | ||
|
||
func TestHostTransferFlagChecks(t *testing.T) { | ||
server, _ := runServerWithMockedDS(t) | ||
defer server.Close() | ||
|
||
runAppCheckErr(t, | ||
[]string{"hosts", "transfer", "--team", "team1", "--hosts", "host1", "--label", "AAA"}, | ||
"--hosts cannot be used along side any other flag", | ||
) | ||
runAppCheckErr(t, | ||
[]string{"hosts", "transfer", "--team", "team1"}, | ||
"You need to define either --hosts, or one or more of --label, --status, --search_query", | ||
) | ||
} | ||
|
||
func TestHostsTransferByHosts(t *testing.T) { | ||
server, ds := runServerWithMockedDS(t) | ||
defer server.Close() | ||
|
||
ds.HostByIdentifierFunc = func(identifier string) (*fleet.Host, error) { | ||
require.Equal(t, "host1", identifier) | ||
return &fleet.Host{ID: 42}, nil | ||
} | ||
|
||
ds.TeamByNameFunc = func(name string) (*fleet.Team, error) { | ||
require.Equal(t, "team1", name) | ||
return &fleet.Team{ID: 99, Name: "team1"}, nil | ||
} | ||
|
||
ds.AddHostsToTeamFunc = func(teamID *uint, hostIDs []uint) error { | ||
require.NotNil(t, teamID) | ||
require.Equal(t, uint(99), *teamID) | ||
require.Equal(t, []uint{42}, hostIDs) | ||
return nil | ||
} | ||
|
||
assert.Equal(t, "", runAppForTest(t, []string{"hosts", "transfer", "--team", "team1", "--hosts", "host1"})) | ||
} | ||
|
||
func TestHostsTransferByLabel(t *testing.T) { | ||
server, ds := runServerWithMockedDS(t) | ||
defer server.Close() | ||
|
||
ds.HostByIdentifierFunc = func(identifier string) (*fleet.Host, error) { | ||
require.Equal(t, "host1", identifier) | ||
return &fleet.Host{ID: 42}, nil | ||
} | ||
|
||
ds.TeamByNameFunc = func(name string) (*fleet.Team, error) { | ||
require.Equal(t, "team1", name) | ||
return &fleet.Team{ID: 99, Name: "team1"}, nil | ||
} | ||
|
||
ds.LabelIDsByNameFunc = func(labels []string) ([]uint, error) { | ||
require.Equal(t, []string{"label1"}, labels) | ||
return []uint{uint(11)}, nil | ||
} | ||
|
||
ds.ListHostsInLabelFunc = func(filter fleet.TeamFilter, lid uint, opt fleet.HostListOptions) ([]*fleet.Host, error) { | ||
require.Equal(t, fleet.HostStatus(""), opt.StatusFilter) | ||
require.Equal(t, uint(11), lid) | ||
return []*fleet.Host{{ID: 32}, {ID: 12}}, nil | ||
} | ||
|
||
ds.AddHostsToTeamFunc = func(teamID *uint, hostIDs []uint) error { | ||
require.NotNil(t, teamID) | ||
require.Equal(t, uint(99), *teamID) | ||
require.Equal(t, []uint{32, 12}, hostIDs) | ||
return nil | ||
} | ||
|
||
assert.Equal(t, "", runAppForTest(t, []string{"hosts", "transfer", "--team", "team1", "--label", "label1"})) | ||
} | ||
|
||
func TestHostsTransferByStatus(t *testing.T) { | ||
server, ds := runServerWithMockedDS(t) | ||
defer server.Close() | ||
|
||
ds.HostByIdentifierFunc = func(identifier string) (*fleet.Host, error) { | ||
require.Equal(t, "host1", identifier) | ||
return &fleet.Host{ID: 42}, nil | ||
} | ||
|
||
ds.TeamByNameFunc = func(name string) (*fleet.Team, error) { | ||
require.Equal(t, "team1", name) | ||
return &fleet.Team{ID: 99, Name: "team1"}, nil | ||
} | ||
|
||
ds.LabelIDsByNameFunc = func(labels []string) ([]uint, error) { | ||
require.Equal(t, []string{"label1"}, labels) | ||
return []uint{uint(11)}, nil | ||
} | ||
|
||
ds.ListHostsFunc = func(filter fleet.TeamFilter, opt fleet.HostListOptions) ([]*fleet.Host, error) { | ||
require.Equal(t, fleet.StatusOnline, opt.StatusFilter) | ||
return []*fleet.Host{{ID: 32}, {ID: 12}}, nil | ||
} | ||
|
||
ds.AddHostsToTeamFunc = func(teamID *uint, hostIDs []uint) error { | ||
require.NotNil(t, teamID) | ||
require.Equal(t, uint(99), *teamID) | ||
require.Equal(t, []uint{32, 12}, hostIDs) | ||
return nil | ||
} | ||
|
||
assert.Equal(t, "", runAppForTest(t, | ||
[]string{"hosts", "transfer", "--team", "team1", "--status", "online"})) | ||
} | ||
|
||
func TestHostsTransferByStatusAndSearchQuery(t *testing.T) { | ||
server, ds := runServerWithMockedDS(t) | ||
defer server.Close() | ||
|
||
ds.HostByIdentifierFunc = func(identifier string) (*fleet.Host, error) { | ||
require.Equal(t, "host1", identifier) | ||
return &fleet.Host{ID: 42}, nil | ||
} | ||
|
||
ds.TeamByNameFunc = func(name string) (*fleet.Team, error) { | ||
require.Equal(t, "team1", name) | ||
return &fleet.Team{ID: 99, Name: "team1"}, nil | ||
} | ||
|
||
ds.LabelIDsByNameFunc = func(labels []string) ([]uint, error) { | ||
require.Equal(t, []string{"label1"}, labels) | ||
return []uint{uint(11)}, nil | ||
} | ||
|
||
ds.ListHostsFunc = func(filter fleet.TeamFilter, opt fleet.HostListOptions) ([]*fleet.Host, error) { | ||
require.Equal(t, fleet.StatusOnline, opt.StatusFilter) | ||
require.Equal(t, "somequery", opt.MatchQuery) | ||
return []*fleet.Host{{ID: 32}, {ID: 12}}, nil | ||
} | ||
|
||
ds.AddHostsToTeamFunc = func(teamID *uint, hostIDs []uint) error { | ||
require.NotNil(t, teamID) | ||
require.Equal(t, uint(99), *teamID) | ||
require.Equal(t, []uint{32, 12}, hostIDs) | ||
return nil | ||
} | ||
|
||
assert.Equal(t, "", runAppForTest(t, | ||
[]string{"hosts", "transfer", "--team", "team1", "--status", "online", "--search_query", "somequery"})) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
package main | ||
|
||
import ( | ||
"testing" | ||
|
||
"github.com/fleetdm/fleet/v4/server/fleet" | ||
"github.com/stretchr/testify/assert" | ||
) | ||
|
||
func TestUserDelete(t *testing.T) { | ||
server, ds := runServerWithMockedDS(t) | ||
defer server.Close() | ||
|
||
ds.UserByEmailFunc = func(email string) (*fleet.User, error) { | ||
return &fleet.User{ | ||
ID: 42, | ||
Name: "test1", | ||
Email: "[email protected]", | ||
}, nil | ||
} | ||
|
||
deletedUser := uint(0) | ||
|
||
ds.DeleteUserFunc = func(id uint) error { | ||
deletedUser = id | ||
return nil | ||
} | ||
|
||
assert.Equal(t, "", runAppForTest(t, []string{"user", "delete", "--email", "[email protected]"})) | ||
assert.Equal(t, uint(42), deletedUser) | ||
} |
Oops, something went wrong.