Move targets and secret variables to server/fleet/ (#46196)
Resolves #36087 (one of several PRs). ## Testing - [x] QA'd all new/changed functionality manually. <!-- This is an auto-generated comment: release notes by coderabbit.ai --> ## Summary by CodeRabbit * **New Features** * Dry-run support when creating secret variables. * **Improvements** * Standardized API models for secret-variables and targets for more consistent behavior. * List secret variables now includes pagination metadata. * More consistent error reporting across secret-variables and targets APIs. * Target search/count behavior refined: pre-selected built-in labels are omitted as expected. * **Tests** * Integration tests updated to validate the new request/response behavior and target-selection logic. <!-- review_stack_entry_start --> [](https://app.coderabbit.ai/change-stack/fleetdm/fleet/pull/46196?utm_source=github_walkthrough&utm_medium=github&utm_campaign=change_stack) <!-- review_stack_entry_end --> <!-- end of auto-generated comment: release notes by coderabbit.ai --> --------- Co-authored-by: Copilot Autofix powered by AI <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
co-authored by
Copilot Autofix powered by AI
parent
06cfd32e89
commit
441e31c705
@@ -0,0 +1,66 @@
|
||||
package fleet
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
// Create secret variables (spec)
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
type CreateSecretVariablesRequest struct {
|
||||
DryRun bool `json:"dry_run"`
|
||||
SecretVariables []SecretVariable `json:"secrets"`
|
||||
}
|
||||
|
||||
type CreateSecretVariablesResponse struct {
|
||||
Err error `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
func (r CreateSecretVariablesResponse) Error() error { return r.Err }
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
// Create secret variable
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
type CreateSecretVariableRequest struct {
|
||||
Name string `json:"name"`
|
||||
Value string `json:"value"`
|
||||
}
|
||||
|
||||
type CreateSecretVariableResponse struct {
|
||||
ID uint `json:"id"`
|
||||
Name string `json:"name"`
|
||||
|
||||
Err error `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
func (r CreateSecretVariableResponse) Error() error { return r.Err }
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
// List secret variables
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
type ListSecretVariablesRequest struct {
|
||||
ListOptions ListOptions `url:"list_options"`
|
||||
}
|
||||
|
||||
type ListSecretVariablesResponse struct {
|
||||
CustomVariables []SecretVariableIdentifier `json:"custom_variables"`
|
||||
Meta *PaginationMetadata `json:"meta"`
|
||||
Count int `json:"count"`
|
||||
|
||||
Err error `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
func (r ListSecretVariablesResponse) Error() error { return r.Err }
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
// Delete secret variable
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
type DeleteSecretVariableRequest struct {
|
||||
ID uint `url:"id"`
|
||||
}
|
||||
|
||||
type DeleteSecretVariableResponse struct {
|
||||
Err error `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
func (r DeleteSecretVariableResponse) Error() error { return r.Err }
|
||||
@@ -0,0 +1,146 @@
|
||||
package fleet
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"time"
|
||||
)
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Search Targets
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
type SearchTargetsRequest struct {
|
||||
// MatchQuery is the free-text search query used to match hosts, labels, and teams.
|
||||
MatchQuery string `json:"query"`
|
||||
// QueryID is the ID of a saved query to run (used to determine if this is a
|
||||
// query that observers can run).
|
||||
QueryID *uint `json:"query_id" renameto:"report_id"`
|
||||
// Selected is the list of IDs that are already selected on the caller side
|
||||
// (e.g. the UI), so those are IDs that will be omitted from the returned
|
||||
// payload.
|
||||
Selected HostTargets `json:"selected"`
|
||||
}
|
||||
|
||||
type LabelSearchResult struct {
|
||||
*Label
|
||||
DisplayText string `json:"display_text"`
|
||||
Count int `json:"count"`
|
||||
}
|
||||
|
||||
type TeamSearchResult struct {
|
||||
*Team
|
||||
DisplayText string `json:"display_text"`
|
||||
Count int `json:"count"`
|
||||
}
|
||||
|
||||
func (t TeamSearchResult) MarshalJSON() ([]byte, error) {
|
||||
if t.Team == nil {
|
||||
return nil, errors.New("team search result: nil team")
|
||||
}
|
||||
|
||||
x := struct {
|
||||
ID uint `json:"id"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description"`
|
||||
TeamConfig
|
||||
UserCount int `json:"user_count"`
|
||||
Users []TeamUser `json:"users,omitempty"`
|
||||
HostCount int `json:"host_count"`
|
||||
Hosts []HostResponse `json:"hosts,omitempty"`
|
||||
Secrets []*EnrollSecret `json:"secrets,omitempty"`
|
||||
DisplayText string `json:"display_text"`
|
||||
Count int `json:"count"`
|
||||
}{
|
||||
ID: t.ID,
|
||||
CreatedAt: t.CreatedAt,
|
||||
Name: t.Name,
|
||||
Description: t.Description,
|
||||
TeamConfig: t.Config,
|
||||
UserCount: t.UserCount,
|
||||
Users: t.Users,
|
||||
HostCount: t.HostCount,
|
||||
Hosts: HostResponsesForHostsCheap(t.Hosts),
|
||||
Secrets: t.Secrets,
|
||||
DisplayText: t.DisplayText,
|
||||
Count: t.Count,
|
||||
}
|
||||
|
||||
return json.Marshal(x)
|
||||
}
|
||||
|
||||
func (t *TeamSearchResult) UnmarshalJSON(b []byte) error {
|
||||
var x struct {
|
||||
ID uint `json:"id"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description"`
|
||||
TeamConfig
|
||||
UserCount int `json:"user_count"`
|
||||
Users []TeamUser `json:"users,omitempty"`
|
||||
HostCount int `json:"host_count"`
|
||||
Hosts []Host `json:"hosts,omitempty"`
|
||||
Secrets []*EnrollSecret `json:"secrets,omitempty"`
|
||||
DisplayText string `json:"display_text"`
|
||||
Count int `json:"count"`
|
||||
}
|
||||
|
||||
if err := json.Unmarshal(b, &x); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
*t = TeamSearchResult{
|
||||
Team: &Team{
|
||||
ID: x.ID,
|
||||
CreatedAt: x.CreatedAt,
|
||||
Name: x.Name,
|
||||
Description: x.Description,
|
||||
Config: x.TeamConfig,
|
||||
UserCount: x.UserCount,
|
||||
Users: x.Users,
|
||||
HostCount: x.HostCount,
|
||||
Hosts: x.Hosts,
|
||||
Secrets: x.Secrets,
|
||||
},
|
||||
DisplayText: x.DisplayText,
|
||||
Count: x.Count,
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type TargetsData struct {
|
||||
Hosts []*HostResponse `json:"hosts"`
|
||||
Labels []LabelSearchResult `json:"labels"`
|
||||
Teams []TeamSearchResult `json:"teams" renameto:"fleets"`
|
||||
}
|
||||
|
||||
type SearchTargetsResponse struct {
|
||||
Targets *TargetsData `json:"targets,omitempty"`
|
||||
TargetsCount uint `json:"targets_count"`
|
||||
TargetsOnline uint `json:"targets_online"`
|
||||
TargetsOffline uint `json:"targets_offline"`
|
||||
TargetsMissingInAction uint `json:"targets_missing_in_action"`
|
||||
Err error `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
func (r SearchTargetsResponse) Error() error { return r.Err }
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// Count Targets
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
type CountTargetsRequest struct {
|
||||
Selected HostTargets `json:"selected"`
|
||||
QueryID *uint `json:"query_id" renameto:"report_id"`
|
||||
}
|
||||
|
||||
type CountTargetsResponse struct {
|
||||
TargetsCount uint `json:"targets_count"`
|
||||
TargetsOnline uint `json:"targets_online"`
|
||||
TargetsOffline uint `json:"targets_offline"`
|
||||
Err error `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
func (r CountTargetsResponse) Error() error { return r.Err }
|
||||
@@ -4,10 +4,10 @@ import "github.com/fleetdm/fleet/v4/server/fleet"
|
||||
|
||||
func (c *Client) SaveSecretVariables(secretVariables []fleet.SecretVariable, dryRun bool) error {
|
||||
verb, path := "PUT", "/api/latest/fleet/spec/secret_variables"
|
||||
params := createSecretVariablesRequest{
|
||||
params := fleet.CreateSecretVariablesRequest{
|
||||
SecretVariables: secretVariables,
|
||||
DryRun: dryRun,
|
||||
}
|
||||
var responseBody createSecretVariablesResponse
|
||||
var responseBody fleet.CreateSecretVariablesResponse
|
||||
return c.authenticatedRequest(params, verb, path, &responseBody)
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ import (
|
||||
|
||||
// SearchTargets searches for the supplied targets in the Fleet instance.
|
||||
func (c *Client) SearchTargets(query string, hostIDs, labelIDs []uint) (*fleet.TargetSearchResults, error) {
|
||||
req := searchTargetsRequest{
|
||||
req := fleet.SearchTargetsRequest{
|
||||
MatchQuery: query,
|
||||
Selected: fleet.HostTargets{
|
||||
LabelIDs: labelIDs,
|
||||
@@ -15,7 +15,7 @@ func (c *Client) SearchTargets(query string, hostIDs, labelIDs []uint) (*fleet.T
|
||||
},
|
||||
}
|
||||
verb, path := "POST", "/api/latest/fleet/targets"
|
||||
var responseBody searchTargetsResponse
|
||||
var responseBody fleet.SearchTargetsResponse
|
||||
err := c.authenticatedRequest(req, verb, path, &responseBody)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
||||
@@ -334,8 +334,8 @@ func attachFleetAPIRoutes(r *mux.Router, svc fleet.Service, config config.FleetC
|
||||
|
||||
ue.GET("/api/_version_/fleet/email/change/{token}", changeEmailEndpoint, changeEmailRequest{})
|
||||
// TODO: searchTargetsEndpoint will be removed in Fleet 5.0
|
||||
ue.POST("/api/_version_/fleet/targets", searchTargetsEndpoint, searchTargetsRequest{})
|
||||
ue.POST("/api/_version_/fleet/targets/count", countTargetsEndpoint, countTargetsRequest{})
|
||||
ue.POST("/api/_version_/fleet/targets", searchTargetsEndpoint, fleet.SearchTargetsRequest{})
|
||||
ue.POST("/api/_version_/fleet/targets/count", countTargetsEndpoint, fleet.CountTargetsRequest{})
|
||||
|
||||
ue.POST("/api/_version_/fleet/invites", createInviteEndpoint, createInviteRequest{})
|
||||
ue.GET("/api/_version_/fleet/invites", listInvitesEndpoint, listInvitesRequest{})
|
||||
@@ -583,10 +583,10 @@ func attachFleetAPIRoutes(r *mux.Router, svc fleet.Service, config config.FleetC
|
||||
ue.POST("/api/_version_/fleet/autofill/policy", autofillPoliciesEndpoint, fleet.AutofillPoliciesRequest{})
|
||||
|
||||
// Secret variables
|
||||
ue.PUT("/api/_version_/fleet/spec/secret_variables", createSecretVariablesEndpoint, createSecretVariablesRequest{})
|
||||
ue.POST("/api/_version_/fleet/custom_variables", createSecretVariableEndpoint, createSecretVariableRequest{})
|
||||
ue.GET("/api/_version_/fleet/custom_variables", listSecretVariablesEndpoint, listSecretVariablesRequest{})
|
||||
ue.DELETE("/api/_version_/fleet/custom_variables/{id:[0-9]+}", deleteSecretVariableEndpoint, deleteSecretVariableRequest{})
|
||||
ue.PUT("/api/_version_/fleet/spec/secret_variables", createSecretVariablesEndpoint, fleet.CreateSecretVariablesRequest{})
|
||||
ue.POST("/api/_version_/fleet/custom_variables", createSecretVariableEndpoint, fleet.CreateSecretVariableRequest{})
|
||||
ue.GET("/api/_version_/fleet/custom_variables", listSecretVariablesEndpoint, fleet.ListSecretVariablesRequest{})
|
||||
ue.DELETE("/api/_version_/fleet/custom_variables/{id:[0-9]+}", deleteSecretVariableEndpoint, fleet.DeleteSecretVariableRequest{})
|
||||
|
||||
// API end-points
|
||||
ue.GET("/api/_version_/fleet/rest_api", listAPIEndpointsEndpoint, listAPIEndpointsRequest{})
|
||||
|
||||
@@ -9540,8 +9540,8 @@ func (s *integrationTestSuite) TestSearchTargets() {
|
||||
require.Len(t, lblMap, len(builtinNames))
|
||||
|
||||
// no search criteria
|
||||
var searchResp searchTargetsResponse
|
||||
s.DoJSON("POST", "/api/latest/fleet/targets", searchTargetsRequest{}, http.StatusOK, &searchResp)
|
||||
var searchResp fleet.SearchTargetsResponse
|
||||
s.DoJSON("POST", "/api/latest/fleet/targets", fleet.SearchTargetsRequest{}, http.StatusOK, &searchResp)
|
||||
require.Equal(t, uint(0), searchResp.TargetsCount)
|
||||
require.Len(t, searchResp.Targets.Hosts, len(hosts)) // the HostTargets.HostIDs are actually host IDs to *omit* from the search
|
||||
require.Len(t, searchResp.Targets.Labels, len(lblMap))
|
||||
@@ -9552,22 +9552,22 @@ func (s *integrationTestSuite) TestSearchTargets() {
|
||||
lblIDs = append(lblIDs, labelID)
|
||||
}
|
||||
|
||||
searchResp = searchTargetsResponse{}
|
||||
s.DoJSON("POST", "/api/latest/fleet/targets", searchTargetsRequest{Selected: fleet.HostTargets{LabelIDs: lblIDs}}, http.StatusOK, &searchResp)
|
||||
searchResp = fleet.SearchTargetsResponse{}
|
||||
s.DoJSON("POST", "/api/latest/fleet/targets", fleet.SearchTargetsRequest{Selected: fleet.HostTargets{LabelIDs: lblIDs}}, http.StatusOK, &searchResp)
|
||||
require.Equal(t, uint(0), searchResp.TargetsCount)
|
||||
require.Len(t, searchResp.Targets.Hosts, len(hosts)) // no omitted host id
|
||||
require.Len(t, searchResp.Targets.Labels, 0) // All built-in labels have been omitted (pre-selected)
|
||||
require.Len(t, searchResp.Targets.Teams, 0)
|
||||
|
||||
searchResp = searchTargetsResponse{}
|
||||
s.DoJSON("POST", "/api/latest/fleet/targets", searchTargetsRequest{Selected: fleet.HostTargets{HostIDs: []uint{hosts[1].ID}}}, http.StatusOK, &searchResp)
|
||||
searchResp = fleet.SearchTargetsResponse{}
|
||||
s.DoJSON("POST", "/api/latest/fleet/targets", fleet.SearchTargetsRequest{Selected: fleet.HostTargets{HostIDs: []uint{hosts[1].ID}}}, http.StatusOK, &searchResp)
|
||||
require.Equal(t, uint(1), searchResp.TargetsCount)
|
||||
require.Len(t, searchResp.Targets.Hosts, len(hosts)-1) // one omitted host id
|
||||
require.Len(t, searchResp.Targets.Labels, len(lblMap)) // labels have not been omitted
|
||||
require.Len(t, searchResp.Targets.Teams, 0)
|
||||
|
||||
searchResp = searchTargetsResponse{}
|
||||
s.DoJSON("POST", "/api/latest/fleet/targets", searchTargetsRequest{MatchQuery: "foo.local1"}, http.StatusOK, &searchResp)
|
||||
searchResp = fleet.SearchTargetsResponse{}
|
||||
s.DoJSON("POST", "/api/latest/fleet/targets", fleet.SearchTargetsRequest{MatchQuery: "foo.local1"}, http.StatusOK, &searchResp)
|
||||
require.Equal(t, uint(0), searchResp.TargetsCount)
|
||||
require.Len(t, searchResp.Targets.Hosts, 1)
|
||||
require.Len(t, searchResp.Targets.Labels, 1) // with a match query, only matching label names and "All Hosts" can be returned (here, only all hosts)
|
||||
@@ -9673,12 +9673,12 @@ func (s *integrationTestSuite) TestCountTargets() {
|
||||
err = s.ds.AddHostsToTeam(context.Background(), fleet.NewAddHostsToTeamParams(ptr.Uint(team.ID), []uint{hostIDs[0]}))
|
||||
require.NoError(t, err)
|
||||
|
||||
var countResp countTargetsResponse
|
||||
var countResp fleet.CountTargetsResponse
|
||||
// sleep to reduce flake in last seen time so that online/offline counts can be tested
|
||||
time.Sleep(1 * time.Second)
|
||||
|
||||
// none selected
|
||||
s.DoJSON("POST", "/api/latest/fleet/targets/count", countTargetsRequest{}, http.StatusOK, &countResp)
|
||||
s.DoJSON("POST", "/api/latest/fleet/targets/count", fleet.CountTargetsRequest{}, http.StatusOK, &countResp)
|
||||
require.Equal(t, uint(0), countResp.TargetsCount)
|
||||
require.Equal(t, uint(0), countResp.TargetsOnline)
|
||||
require.Equal(t, uint(0), countResp.TargetsOffline)
|
||||
@@ -9688,23 +9688,23 @@ func (s *integrationTestSuite) TestCountTargets() {
|
||||
lblIDs = append(lblIDs, labelID)
|
||||
}
|
||||
// all hosts label selected
|
||||
countResp = countTargetsResponse{}
|
||||
s.DoJSON("POST", "/api/latest/fleet/targets/count", countTargetsRequest{Selected: fleet.HostTargets{LabelIDs: lblIDs}}, http.StatusOK, &countResp)
|
||||
countResp = fleet.CountTargetsResponse{}
|
||||
s.DoJSON("POST", "/api/latest/fleet/targets/count", fleet.CountTargetsRequest{Selected: fleet.HostTargets{LabelIDs: lblIDs}}, http.StatusOK, &countResp)
|
||||
require.Equal(t, uint(3), countResp.TargetsCount)
|
||||
require.Equal(t, uint(1), countResp.TargetsOnline)
|
||||
require.Equal(t, uint(2), countResp.TargetsOffline)
|
||||
|
||||
// team selected
|
||||
countResp = countTargetsResponse{}
|
||||
s.DoJSON("POST", "/api/latest/fleet/targets/count", countTargetsRequest{Selected: fleet.HostTargets{TeamIDs: []uint{team.ID}}}, http.StatusOK, &countResp)
|
||||
countResp = fleet.CountTargetsResponse{}
|
||||
s.DoJSON("POST", "/api/latest/fleet/targets/count", fleet.CountTargetsRequest{Selected: fleet.HostTargets{TeamIDs: []uint{team.ID}}}, http.StatusOK, &countResp)
|
||||
require.Equal(t, uint(1), countResp.TargetsCount)
|
||||
require.Equal(t, uint(1), countResp.TargetsOnline)
|
||||
require.Equal(t, uint(0), countResp.TargetsOffline)
|
||||
|
||||
// 'No team' selected
|
||||
countResp = countTargetsResponse{}
|
||||
countResp = fleet.CountTargetsResponse{}
|
||||
s.DoJSON(
|
||||
"POST", "/api/latest/fleet/targets/count", countTargetsRequest{Selected: fleet.HostTargets{TeamIDs: []uint{0}}},
|
||||
"POST", "/api/latest/fleet/targets/count", fleet.CountTargetsRequest{Selected: fleet.HostTargets{TeamIDs: []uint{0}}},
|
||||
http.StatusOK, &countResp,
|
||||
)
|
||||
assert.Equal(t, uint(2), countResp.TargetsCount)
|
||||
@@ -9712,8 +9712,8 @@ func (s *integrationTestSuite) TestCountTargets() {
|
||||
assert.Equal(t, uint(2), countResp.TargetsOffline)
|
||||
|
||||
// host id selected
|
||||
countResp = countTargetsResponse{}
|
||||
s.DoJSON("POST", "/api/latest/fleet/targets/count", countTargetsRequest{Selected: fleet.HostTargets{HostIDs: []uint{hosts[1].ID}}}, http.StatusOK, &countResp)
|
||||
countResp = fleet.CountTargetsResponse{}
|
||||
s.DoJSON("POST", "/api/latest/fleet/targets/count", fleet.CountTargetsRequest{Selected: fleet.HostTargets{HostIDs: []uint{hosts[1].ID}}}, http.StatusOK, &countResp)
|
||||
require.Equal(t, uint(1), countResp.TargetsCount)
|
||||
require.Equal(t, uint(0), countResp.TargetsOnline)
|
||||
require.Equal(t, uint(1), countResp.TargetsOffline)
|
||||
@@ -15075,12 +15075,12 @@ func (s *integrationTestSuite) TestSecretVariablesGitOps() {
|
||||
s.setTokenForTest(t, "gitops1@example.com", test.GoodPassword)
|
||||
|
||||
// Empty request
|
||||
req := createSecretVariablesRequest{}
|
||||
var resp createSecretVariablesResponse
|
||||
req := fleet.CreateSecretVariablesRequest{}
|
||||
var resp fleet.CreateSecretVariablesResponse
|
||||
s.DoJSON("PUT", "/api/latest/fleet/spec/secret_variables", req, http.StatusOK, &resp)
|
||||
|
||||
// Secret variable name too long
|
||||
req = createSecretVariablesRequest{
|
||||
req = fleet.CreateSecretVariablesRequest{
|
||||
SecretVariables: []fleet.SecretVariable{
|
||||
{
|
||||
Name: strings.Repeat("a", 256),
|
||||
@@ -15092,7 +15092,7 @@ func (s *integrationTestSuite) TestSecretVariablesGitOps() {
|
||||
assertBodyContains(t, httpResp, "secret variable name is too long")
|
||||
|
||||
// Secret variable name empty
|
||||
req = createSecretVariablesRequest{
|
||||
req = fleet.CreateSecretVariablesRequest{
|
||||
SecretVariables: []fleet.SecretVariable{
|
||||
{
|
||||
Name: " ",
|
||||
@@ -15104,7 +15104,7 @@ func (s *integrationTestSuite) TestSecretVariablesGitOps() {
|
||||
assertBodyContains(t, httpResp, "secret variable name cannot be empty")
|
||||
|
||||
validName := strings.Repeat("G", 255)
|
||||
req = createSecretVariablesRequest{
|
||||
req = fleet.CreateSecretVariablesRequest{
|
||||
SecretVariables: []fleet.SecretVariable{
|
||||
{
|
||||
Name: "FLEET_SECRET_" + validName,
|
||||
@@ -15134,8 +15134,8 @@ func (s *integrationTestSuite) TestSecretVariables() {
|
||||
ctx := context.Background()
|
||||
|
||||
// Create a single secret variable.
|
||||
var csvr createSecretVariableResponse
|
||||
s.DoJSON("POST", "/api/latest/fleet/custom_variables", createSecretVariableRequest{
|
||||
var csvr fleet.CreateSecretVariableResponse
|
||||
s.DoJSON("POST", "/api/latest/fleet/custom_variables", fleet.CreateSecretVariableRequest{
|
||||
Name: "NAME1",
|
||||
Value: "value1",
|
||||
}, http.StatusOK, &csvr)
|
||||
@@ -15143,8 +15143,8 @@ func (s *integrationTestSuite) TestSecretVariables() {
|
||||
require.NotZero(t, firstVariableID)
|
||||
|
||||
// List (no-filtering).
|
||||
var lsvr listSecretVariablesResponse
|
||||
s.DoJSON("GET", "/api/latest/fleet/custom_variables", listSecretVariablesRequest{}, http.StatusOK, &lsvr)
|
||||
var lsvr fleet.ListSecretVariablesResponse
|
||||
s.DoJSON("GET", "/api/latest/fleet/custom_variables", fleet.ListSecretVariablesRequest{}, http.StatusOK, &lsvr)
|
||||
require.Equal(t, lsvr.Count, 1)
|
||||
require.Len(t, lsvr.CustomVariables, 1)
|
||||
require.NotZero(t, lsvr.CustomVariables[0].ID)
|
||||
@@ -15160,21 +15160,21 @@ func (s *integrationTestSuite) TestSecretVariables() {
|
||||
require.NotZero(t, secretVariables[0].UpdatedAt)
|
||||
|
||||
// Creating the same variable should fail with conflict.
|
||||
s.DoJSON("POST", "/api/latest/fleet/custom_variables", createSecretVariableRequest{
|
||||
s.DoJSON("POST", "/api/latest/fleet/custom_variables", fleet.CreateSecretVariableRequest{
|
||||
Name: "NAME1",
|
||||
Value: "value1",
|
||||
}, http.StatusConflict, &csvr)
|
||||
|
||||
// Creating a variable with invalid name should fail with 422.
|
||||
s.DoJSON("POST", "/api/latest/fleet/custom_variables", createSecretVariableRequest{
|
||||
s.DoJSON("POST", "/api/latest/fleet/custom_variables", fleet.CreateSecretVariableRequest{
|
||||
Name: "lowercase",
|
||||
Value: "foobar",
|
||||
}, http.StatusUnprocessableEntity, &csvr)
|
||||
s.DoJSON("POST", "/api/latest/fleet/custom_variables", createSecretVariableRequest{
|
||||
s.DoJSON("POST", "/api/latest/fleet/custom_variables", fleet.CreateSecretVariableRequest{
|
||||
Name: "",
|
||||
Value: "foobar",
|
||||
}, http.StatusUnprocessableEntity, &csvr)
|
||||
s.DoJSON("POST", "/api/latest/fleet/custom_variables", createSecretVariableRequest{
|
||||
s.DoJSON("POST", "/api/latest/fleet/custom_variables", fleet.CreateSecretVariableRequest{
|
||||
Name: strings.Repeat("HA ", 255/3+1),
|
||||
Value: "foobar",
|
||||
}, http.StatusUnprocessableEntity, &csvr)
|
||||
@@ -15183,7 +15183,7 @@ func (s *integrationTestSuite) TestSecretVariables() {
|
||||
defer func() {
|
||||
testSetEmptyPrivateKey = false
|
||||
}()
|
||||
s.DoJSON("POST", "/api/latest/fleet/custom_variables", createSecretVariableRequest{
|
||||
s.DoJSON("POST", "/api/latest/fleet/custom_variables", fleet.CreateSecretVariableRequest{
|
||||
Name: "NAME2",
|
||||
Value: "foobar",
|
||||
}, http.StatusBadRequest, &csvr)
|
||||
@@ -15191,13 +15191,13 @@ func (s *integrationTestSuite) TestSecretVariables() {
|
||||
testSetEmptyPrivateKey = false
|
||||
|
||||
// Creating a variable with empty value should fail with 422.
|
||||
s.DoJSON("POST", "/api/latest/fleet/custom_variables", createSecretVariableRequest{
|
||||
s.DoJSON("POST", "/api/latest/fleet/custom_variables", fleet.CreateSecretVariableRequest{
|
||||
Name: "ANOTHER_NAME",
|
||||
Value: "",
|
||||
}, http.StatusUnprocessableEntity, &csvr)
|
||||
|
||||
// Creating a second variable.
|
||||
s.DoJSON("POST", "/api/latest/fleet/custom_variables", createSecretVariableRequest{
|
||||
s.DoJSON("POST", "/api/latest/fleet/custom_variables", fleet.CreateSecretVariableRequest{
|
||||
Name: "ANOTHER_NAME",
|
||||
Value: "value2",
|
||||
}, http.StatusOK, &csvr)
|
||||
@@ -15205,7 +15205,7 @@ func (s *integrationTestSuite) TestSecretVariables() {
|
||||
require.NotZero(t, secondVariableID)
|
||||
|
||||
// List (no-filtering) with pagination (first page).
|
||||
lsvr = listSecretVariablesResponse{}
|
||||
lsvr = fleet.ListSecretVariablesResponse{}
|
||||
s.DoJSON("GET", "/api/latest/fleet/custom_variables", nil, http.StatusOK, &lsvr, "per_page", "1", "page", "0")
|
||||
require.Equal(t, 2, lsvr.Count)
|
||||
require.NotNil(t, lsvr.Meta)
|
||||
@@ -15216,7 +15216,7 @@ func (s *integrationTestSuite) TestSecretVariables() {
|
||||
require.Equal(t, "ANOTHER_NAME", lsvr.CustomVariables[0].Name)
|
||||
require.NotZero(t, lsvr.CustomVariables[0].UpdatedAt)
|
||||
// List (no-filtering) with pagination (second page).
|
||||
lsvr = listSecretVariablesResponse{}
|
||||
lsvr = fleet.ListSecretVariablesResponse{}
|
||||
s.DoJSON("GET", "/api/latest/fleet/custom_variables", nil, http.StatusOK, &lsvr, "per_page", "1", "page", "1")
|
||||
require.Equal(t, 2, lsvr.Count)
|
||||
require.NotNil(t, lsvr.Meta)
|
||||
@@ -15228,7 +15228,7 @@ func (s *integrationTestSuite) TestSecretVariables() {
|
||||
require.NotZero(t, lsvr.CustomVariables[0].UpdatedAt)
|
||||
// List (no-filtering) with pagination (one page, two secrets).
|
||||
// Must be ordered alphabetically.
|
||||
lsvr = listSecretVariablesResponse{}
|
||||
lsvr = fleet.ListSecretVariablesResponse{}
|
||||
s.DoJSON("GET", "/api/latest/fleet/custom_variables", nil, http.StatusOK, &lsvr, "per_page", "20", "page", "0")
|
||||
require.Equal(t, 2, lsvr.Count)
|
||||
require.NotNil(t, lsvr.Meta)
|
||||
@@ -15243,14 +15243,14 @@ func (s *integrationTestSuite) TestSecretVariables() {
|
||||
require.NotZero(t, lsvr.CustomVariables[1].UpdatedAt)
|
||||
|
||||
// Test deletion of non-existent ID
|
||||
var dsvr deleteSecretVariableResponse
|
||||
var dsvr fleet.DeleteSecretVariableResponse
|
||||
s.DoJSON("DELETE", "/api/latest/fleet/custom_variables/999", nil, http.StatusNotFound, &dsvr)
|
||||
|
||||
s.DoJSON("DELETE", fmt.Sprintf("/api/latest/fleet/custom_variables/%d", firstVariableID), nil, http.StatusOK, &dsvr)
|
||||
s.DoJSON("DELETE", fmt.Sprintf("/api/latest/fleet/custom_variables/%d", secondVariableID), nil, http.StatusOK, &dsvr)
|
||||
|
||||
// List after deletions should be empty.
|
||||
lsvr = listSecretVariablesResponse{}
|
||||
lsvr = fleet.ListSecretVariablesResponse{}
|
||||
s.DoJSON("GET", "/api/latest/fleet/custom_variables", nil, http.StatusOK, &lsvr)
|
||||
require.Equal(t, 0, lsvr.Count)
|
||||
require.Empty(t, lsvr.CustomVariables)
|
||||
@@ -15266,8 +15266,8 @@ func (s *integrationTestSuite) TestSecretVariablesInUse() {
|
||||
require.NoError(t, err)
|
||||
|
||||
// Create a single secret variable.
|
||||
var csvr createSecretVariableResponse
|
||||
s.DoJSON("POST", "/api/latest/fleet/custom_variables", createSecretVariableRequest{
|
||||
var csvr fleet.CreateSecretVariableResponse
|
||||
s.DoJSON("POST", "/api/latest/fleet/custom_variables", fleet.CreateSecretVariableRequest{
|
||||
Name: "NAME1",
|
||||
Value: "value1",
|
||||
}, http.StatusOK, &csvr)
|
||||
@@ -15350,7 +15350,7 @@ func (s *integrationTestSuite) TestSecretVariablesInUse() {
|
||||
require.NoError(t, err)
|
||||
|
||||
// Finally, delete now should work.
|
||||
var dsvr deleteSecretVariableResponse
|
||||
var dsvr fleet.DeleteSecretVariableResponse
|
||||
s.DoJSON("DELETE", fmt.Sprintf("/api/latest/fleet/custom_variables/%d", firstVariableID), nil, http.StatusOK, &dsvr)
|
||||
}
|
||||
|
||||
@@ -15359,8 +15359,8 @@ func (s *integrationTestSuite) TestSecretVariablesPermissions() {
|
||||
ctx := context.Background()
|
||||
|
||||
// Create a single secret variable.
|
||||
var csvr createSecretVariableResponse
|
||||
s.DoJSON("POST", "/api/latest/fleet/custom_variables", createSecretVariableRequest{
|
||||
var csvr fleet.CreateSecretVariableResponse
|
||||
s.DoJSON("POST", "/api/latest/fleet/custom_variables", fleet.CreateSecretVariableRequest{
|
||||
Name: "NAME1",
|
||||
Value: "foobar",
|
||||
}, http.StatusOK, &csvr)
|
||||
@@ -15376,14 +15376,14 @@ func (s *integrationTestSuite) TestSecretVariablesPermissions() {
|
||||
require.NoError(t, err)
|
||||
s.setTokenForTest(t, "observer@example.com", test.GoodPassword)
|
||||
|
||||
s.DoJSON("POST", "/api/latest/fleet/custom_variables", createSecretVariableRequest{
|
||||
s.DoJSON("POST", "/api/latest/fleet/custom_variables", fleet.CreateSecretVariableRequest{
|
||||
Name: "NAME1",
|
||||
Value: "foobar",
|
||||
}, http.StatusForbidden, &csvr)
|
||||
|
||||
// List (no-filtering) should work for non-admins.
|
||||
var lsvr listSecretVariablesResponse
|
||||
s.DoJSON("GET", "/api/latest/fleet/custom_variables", listSecretVariablesRequest{}, http.StatusOK, &lsvr)
|
||||
var lsvr fleet.ListSecretVariablesResponse
|
||||
s.DoJSON("GET", "/api/latest/fleet/custom_variables", fleet.ListSecretVariablesRequest{}, http.StatusOK, &lsvr)
|
||||
require.Equal(t, lsvr.Count, 1)
|
||||
require.Len(t, lsvr.CustomVariables, 1)
|
||||
require.NotZero(t, lsvr.CustomVariables[0].ID)
|
||||
|
||||
@@ -7358,20 +7358,20 @@ func (s *integrationEnterpriseTestSuite) TestGitOpsUserActions() {
|
||||
s.DoJSON("GET", fmt.Sprintf("/api/latest/fleet/carves/%d", carveID), fleet.GetCarveRequest{}, http.StatusForbidden, &fleet.GetCarveResponse{})
|
||||
|
||||
// Attempt to search hosts, should fail.
|
||||
s.DoJSON("POST", "/api/latest/fleet/targets", searchTargetsRequest{
|
||||
s.DoJSON("POST", "/api/latest/fleet/targets", fleet.SearchTargetsRequest{
|
||||
MatchQuery: "foo",
|
||||
QueryID: &q1.ID,
|
||||
}, http.StatusForbidden, &searchTargetsResponse{})
|
||||
}, http.StatusForbidden, &fleet.SearchTargetsResponse{})
|
||||
|
||||
// Attempt to count target hosts, should fail.
|
||||
s.DoJSON("POST", "/api/latest/fleet/targets/count", countTargetsRequest{
|
||||
s.DoJSON("POST", "/api/latest/fleet/targets/count", fleet.CountTargetsRequest{
|
||||
Selected: fleet.HostTargets{
|
||||
HostIDs: []uint{h1.ID},
|
||||
LabelIDs: []uint{clr.Label.ID},
|
||||
TeamIDs: []uint{t1.ID},
|
||||
},
|
||||
QueryID: &q1.ID,
|
||||
}, http.StatusForbidden, &countTargetsResponse{})
|
||||
}, http.StatusForbidden, &fleet.CountTargetsResponse{})
|
||||
|
||||
//
|
||||
// Start running permission tests with user gitops2 (which is a GitOps use for team t1).
|
||||
@@ -7594,20 +7594,20 @@ func (s *integrationEnterpriseTestSuite) TestGitOpsUserActions() {
|
||||
}, http.StatusForbidden, &teamResponse{})
|
||||
|
||||
// Attempt to search hosts, should fail.
|
||||
s.DoJSON("POST", "/api/latest/fleet/targets", searchTargetsRequest{
|
||||
s.DoJSON("POST", "/api/latest/fleet/targets", fleet.SearchTargetsRequest{
|
||||
MatchQuery: "foo",
|
||||
QueryID: &q1.ID,
|
||||
}, http.StatusForbidden, &searchTargetsResponse{})
|
||||
}, http.StatusForbidden, &fleet.SearchTargetsResponse{})
|
||||
|
||||
// Attempt to count target hosts, should fail.
|
||||
s.DoJSON("POST", "/api/latest/fleet/targets/count", countTargetsRequest{
|
||||
s.DoJSON("POST", "/api/latest/fleet/targets/count", fleet.CountTargetsRequest{
|
||||
Selected: fleet.HostTargets{
|
||||
HostIDs: []uint{h1.ID},
|
||||
LabelIDs: []uint{clr.Label.ID},
|
||||
TeamIDs: []uint{t1.ID},
|
||||
},
|
||||
QueryID: &q1.ID,
|
||||
}, http.StatusForbidden, &countTargetsResponse{})
|
||||
}, http.StatusForbidden, &fleet.CountTargetsResponse{})
|
||||
|
||||
// Listing software titles for the team it owns is allowed.
|
||||
s.DoJSON("GET", "/api/latest/fleet/software/titles", listSoftwareTitlesRequest{}, http.StatusOK, &listSoftwareTitlesResponse{}, "team_id", fmt.Sprint(t1.ID))
|
||||
@@ -7684,7 +7684,7 @@ func (s *integrationEnterpriseTestSuite) TestRunHostScript() {
|
||||
|
||||
// Upload a valid secret
|
||||
secretValue := "abc123"
|
||||
req := createSecretVariablesRequest{
|
||||
req := fleet.CreateSecretVariablesRequest{
|
||||
SecretVariables: []fleet.SecretVariable{
|
||||
{
|
||||
Name: "FLEET_SECRET_TEST_RUN_HOST_SCRIPT",
|
||||
@@ -7692,7 +7692,7 @@ func (s *integrationEnterpriseTestSuite) TestRunHostScript() {
|
||||
},
|
||||
},
|
||||
}
|
||||
secretResp := createSecretVariablesResponse{}
|
||||
secretResp := fleet.CreateSecretVariablesResponse{}
|
||||
s.DoJSON("PUT", "/api/latest/fleet/spec/secret_variables", req, http.StatusOK, &secretResp)
|
||||
|
||||
// create a valid script execution request
|
||||
|
||||
@@ -525,7 +525,7 @@ func (s *integrationMDMTestSuite) TestAppleDDMSecretVariables() {
|
||||
require.Empty(t, resp.Profiles)
|
||||
|
||||
// Add secrets to server
|
||||
req := createSecretVariablesRequest{
|
||||
req := fleet.CreateSecretVariablesRequest{
|
||||
SecretVariables: []fleet.SecretVariable{
|
||||
{
|
||||
Name: "FLEET_SECRET_BASH",
|
||||
@@ -537,7 +537,7 @@ func (s *integrationMDMTestSuite) TestAppleDDMSecretVariables() {
|
||||
},
|
||||
},
|
||||
}
|
||||
secretResp := createSecretVariablesResponse{}
|
||||
secretResp := fleet.CreateSecretVariablesResponse{}
|
||||
s.DoJSON("PUT", "/api/latest/fleet/spec/secret_variables", req, http.StatusOK, &secretResp)
|
||||
|
||||
// Now real run
|
||||
@@ -654,7 +654,7 @@ WHERE name = ?`
|
||||
|
||||
// Change the secrets.
|
||||
myBash = "my.new.bash"
|
||||
req = createSecretVariablesRequest{
|
||||
req = fleet.CreateSecretVariablesRequest{
|
||||
SecretVariables: []fleet.SecretVariable{
|
||||
{
|
||||
Name: "FLEET_SECRET_BASH",
|
||||
|
||||
@@ -243,7 +243,7 @@ func (s *integrationMDMTestSuite) TestAppleProfileManagement() {
|
||||
secretIdentifier := "secret-identifier-1"
|
||||
secretType := "secret.type.1"
|
||||
secretProfile := string(mobileconfigForTest("NS1", "IS1"))
|
||||
req := createSecretVariablesRequest{
|
||||
req := fleet.CreateSecretVariablesRequest{
|
||||
SecretVariables: []fleet.SecretVariable{
|
||||
{
|
||||
Name: "FLEET_SECRET_IDENTIFIER",
|
||||
@@ -259,7 +259,7 @@ func (s *integrationMDMTestSuite) TestAppleProfileManagement() {
|
||||
},
|
||||
},
|
||||
}
|
||||
secretResp := createSecretVariablesResponse{}
|
||||
secretResp := fleet.CreateSecretVariablesResponse{}
|
||||
s.DoJSON("PUT", "/api/latest/fleet/spec/secret_variables", req, http.StatusOK, &secretResp)
|
||||
|
||||
// set new team profiles (delete + addition)
|
||||
@@ -305,7 +305,7 @@ func (s *integrationMDMTestSuite) TestAppleProfileManagement() {
|
||||
|
||||
// Change the secret variable and upload the profiles again. We should see the profile with updated secret installed.
|
||||
secretType = "new.secret.type.1"
|
||||
req = createSecretVariablesRequest{
|
||||
req = fleet.CreateSecretVariablesRequest{
|
||||
SecretVariables: []fleet.SecretVariable{
|
||||
{
|
||||
Name: "FLEET_SECRET_IDENTIFIER",
|
||||
@@ -379,7 +379,7 @@ func (s *integrationMDMTestSuite) TestAppleProfileManagement() {
|
||||
|
||||
// Change the secret variable and upload the profiles again. We should see the profile with updated secret installed.
|
||||
secretType = "new2.secret.type.1"
|
||||
req = createSecretVariablesRequest{
|
||||
req = fleet.CreateSecretVariablesRequest{
|
||||
SecretVariables: []fleet.SecretVariable{
|
||||
{
|
||||
Name: "FLEET_SECRET_IDENTIFIER",
|
||||
@@ -6668,7 +6668,7 @@ func (s *integrationMDMTestSuite) testSecretVariablesUpload(newProfileBytes func
|
||||
assertBodyContains(t, res, `Secret variable \"$FLEET_SECRET_BASH\" missing`)
|
||||
|
||||
// Add secret(s) to server
|
||||
req := createSecretVariablesRequest{
|
||||
req := fleet.CreateSecretVariablesRequest{
|
||||
SecretVariables: []fleet.SecretVariable{
|
||||
{
|
||||
Name: "FLEET_SECRET_BASH",
|
||||
@@ -6680,7 +6680,7 @@ func (s *integrationMDMTestSuite) testSecretVariablesUpload(newProfileBytes func
|
||||
},
|
||||
},
|
||||
}
|
||||
secretResp := createSecretVariablesResponse{}
|
||||
secretResp := fleet.CreateSecretVariablesResponse{}
|
||||
s.DoJSON("PUT", "/api/latest/fleet/spec/secret_variables", req, http.StatusOK, &secretResp)
|
||||
res = s.DoRawWithHeaders("POST", "/api/latest/fleet/configuration_profiles", body.Bytes(), http.StatusOK, headers)
|
||||
var resp newMDMConfigProfileResponse
|
||||
|
||||
@@ -3979,7 +3979,7 @@ func (s *integrationMDMTestSuite) TestEnqueueMDMCommandWithSecret() {
|
||||
|
||||
// Load secret(s)
|
||||
secretValue := "*abc123*"
|
||||
req := createSecretVariablesRequest{
|
||||
req := fleet.CreateSecretVariablesRequest{
|
||||
SecretVariables: []fleet.SecretVariable{
|
||||
{
|
||||
Name: "FLEET_SECRET_VALUE",
|
||||
@@ -3987,7 +3987,7 @@ func (s *integrationMDMTestSuite) TestEnqueueMDMCommandWithSecret() {
|
||||
},
|
||||
},
|
||||
}
|
||||
secretResp := createSecretVariablesResponse{}
|
||||
secretResp := fleet.CreateSecretVariablesResponse{}
|
||||
s.DoJSON("PUT", "/api/latest/fleet/spec/secret_variables", req, http.StatusOK, &secretResp)
|
||||
|
||||
// call with enrolled host UUID
|
||||
@@ -9154,7 +9154,7 @@ func (s *integrationMDMTestSuite) TestWindowsMDMCommandWithSecret() {
|
||||
orbitHost, d := createWindowsHostThenEnrollMDM(s.ds, s.server.URL, t)
|
||||
|
||||
secretValue := "abcd1234"
|
||||
req := createSecretVariablesRequest{
|
||||
req := fleet.CreateSecretVariablesRequest{
|
||||
SecretVariables: []fleet.SecretVariable{
|
||||
{
|
||||
Name: "FLEET_SECRET_DATA",
|
||||
@@ -9162,7 +9162,7 @@ func (s *integrationMDMTestSuite) TestWindowsMDMCommandWithSecret() {
|
||||
},
|
||||
},
|
||||
}
|
||||
secretResp := createSecretVariablesResponse{}
|
||||
secretResp := fleet.CreateSecretVariablesResponse{}
|
||||
s.DoJSON("PUT", "/api/latest/fleet/spec/secret_variables", req, http.StatusOK, &secretResp)
|
||||
|
||||
cmdOneUUID := uuid.New().String()
|
||||
@@ -23005,20 +23005,20 @@ func (s *integrationMDMTestSuite) TestTechnicianPermissions() {
|
||||
s.DoJSON("GET", fmt.Sprintf("/api/latest/fleet/carves/%d", carveID), fleet.GetCarveRequest{}, http.StatusForbidden, &fleet.GetCarveResponse{})
|
||||
|
||||
// Attempt to search hosts, should allow.
|
||||
s.DoJSON("POST", "/api/latest/fleet/targets", searchTargetsRequest{
|
||||
s.DoJSON("POST", "/api/latest/fleet/targets", fleet.SearchTargetsRequest{
|
||||
MatchQuery: "foo",
|
||||
QueryID: &q1.ID,
|
||||
}, http.StatusOK, &searchTargetsResponse{})
|
||||
}, http.StatusOK, &fleet.SearchTargetsResponse{})
|
||||
|
||||
// Attempt to count target hosts, should allow.
|
||||
s.DoJSON("POST", "/api/latest/fleet/targets/count", countTargetsRequest{
|
||||
s.DoJSON("POST", "/api/latest/fleet/targets/count", fleet.CountTargetsRequest{
|
||||
Selected: fleet.HostTargets{
|
||||
HostIDs: []uint{h1.ID},
|
||||
LabelIDs: []uint{clr.Label.ID},
|
||||
TeamIDs: []uint{t1.ID},
|
||||
},
|
||||
QueryID: &q1.ID,
|
||||
}, http.StatusOK, &countTargetsResponse{})
|
||||
}, http.StatusOK, &fleet.CountTargetsResponse{})
|
||||
|
||||
checkDownloadResponse := func(t *testing.T, r *http.Response, expectedFilename string) {
|
||||
require.Equal(t, "application/octet-stream", r.Header.Get("Content-Type"))
|
||||
@@ -23356,20 +23356,20 @@ func (s *integrationMDMTestSuite) TestTechnicianPermissions() {
|
||||
}, http.StatusForbidden, &teamResponse{})
|
||||
|
||||
// Attempt to search hosts, should allow.
|
||||
s.DoJSON("POST", "/api/latest/fleet/targets", searchTargetsRequest{
|
||||
s.DoJSON("POST", "/api/latest/fleet/targets", fleet.SearchTargetsRequest{
|
||||
MatchQuery: "foo",
|
||||
QueryID: &q1.ID,
|
||||
}, http.StatusOK, &searchTargetsResponse{})
|
||||
}, http.StatusOK, &fleet.SearchTargetsResponse{})
|
||||
|
||||
// Attempt to count target hosts, should allow.
|
||||
s.DoJSON("POST", "/api/latest/fleet/targets/count", countTargetsRequest{
|
||||
s.DoJSON("POST", "/api/latest/fleet/targets/count", fleet.CountTargetsRequest{
|
||||
Selected: fleet.HostTargets{
|
||||
HostIDs: []uint{h1.ID},
|
||||
LabelIDs: []uint{clr.Label.ID},
|
||||
TeamIDs: []uint{t1.ID},
|
||||
},
|
||||
QueryID: &q1.ID,
|
||||
}, http.StatusOK, &countTargetsResponse{})
|
||||
}, http.StatusOK, &fleet.CountTargetsResponse{})
|
||||
|
||||
// Attempt to download installer from t1, should allow.
|
||||
tokenResp = getSoftwareInstallerTokenResponse{}
|
||||
|
||||
@@ -19,21 +19,10 @@ const (
|
||||
// Create secret variables (spec)
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
type createSecretVariablesRequest struct {
|
||||
DryRun bool `json:"dry_run"`
|
||||
SecretVariables []fleet.SecretVariable `json:"secrets"`
|
||||
}
|
||||
|
||||
type createSecretVariablesResponse struct {
|
||||
Err error `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
func (r createSecretVariablesResponse) Error() error { return r.Err }
|
||||
|
||||
func createSecretVariablesEndpoint(ctx context.Context, request interface{}, svc fleet.Service) (fleet.Errorer, error) {
|
||||
req := request.(*createSecretVariablesRequest)
|
||||
req := request.(*fleet.CreateSecretVariablesRequest)
|
||||
err := svc.CreateSecretVariables(ctx, req.SecretVariables, req.DryRun)
|
||||
return createSecretVariablesResponse{Err: err}, nil
|
||||
return fleet.CreateSecretVariablesResponse{Err: err}, nil
|
||||
}
|
||||
|
||||
func (svc *Service) CreateSecretVariables(ctx context.Context, secretVariables []fleet.SecretVariable, dryRun bool) error {
|
||||
@@ -77,27 +66,13 @@ func (svc *Service) CreateSecretVariables(ctx context.Context, secretVariables [
|
||||
// Create secret variable
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
type createSecretVariableRequest struct {
|
||||
Name string `json:"name"`
|
||||
Value string `json:"value"`
|
||||
}
|
||||
|
||||
type createSecretVariableResponse struct {
|
||||
ID uint `json:"id"`
|
||||
Name string `json:"name"`
|
||||
|
||||
Err error `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
func (r createSecretVariableResponse) Error() error { return r.Err }
|
||||
|
||||
func createSecretVariableEndpoint(ctx context.Context, request interface{}, svc fleet.Service) (fleet.Errorer, error) {
|
||||
req := request.(*createSecretVariableRequest)
|
||||
req := request.(*fleet.CreateSecretVariableRequest)
|
||||
id, err := svc.CreateSecretVariable(ctx, req.Name, req.Value)
|
||||
if err != nil {
|
||||
return createSecretVariableResponse{Err: err}, nil
|
||||
return fleet.CreateSecretVariableResponse{Err: err}, nil
|
||||
}
|
||||
return createSecretVariableResponse{
|
||||
return fleet.CreateSecretVariableResponse{
|
||||
ID: id,
|
||||
Name: req.Name,
|
||||
}, nil
|
||||
@@ -150,24 +125,10 @@ func (svc *Service) CreateSecretVariable(ctx context.Context, name string, value
|
||||
// List secret variables
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
type listSecretVariablesRequest struct {
|
||||
ListOptions fleet.ListOptions `url:"list_options"`
|
||||
}
|
||||
|
||||
type listSecretVariablesResponse struct {
|
||||
CustomVariables []fleet.SecretVariableIdentifier `json:"custom_variables"`
|
||||
Meta *fleet.PaginationMetadata `json:"meta"`
|
||||
Count int `json:"count"`
|
||||
|
||||
Err error `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
func (r listSecretVariablesResponse) Error() error { return r.Err }
|
||||
|
||||
func listSecretVariablesEndpoint(ctx context.Context, request interface{}, svc fleet.Service) (fleet.Errorer, error) {
|
||||
req := request.(*listSecretVariablesRequest)
|
||||
req := request.(*fleet.ListSecretVariablesRequest)
|
||||
secretVariables, meta, count, err := svc.ListSecretVariables(ctx, req.ListOptions)
|
||||
return listSecretVariablesResponse{
|
||||
return fleet.ListSecretVariablesResponse{
|
||||
CustomVariables: secretVariables,
|
||||
Meta: meta,
|
||||
Count: count,
|
||||
@@ -210,20 +171,10 @@ func (svc *Service) ListSecretVariables(
|
||||
// Delete secret variable
|
||||
//////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
type deleteSecretVariableRequest struct {
|
||||
ID uint `url:"id"`
|
||||
}
|
||||
|
||||
type deleteSecretVariableResponse struct {
|
||||
Err error `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
func (r deleteSecretVariableResponse) Error() error { return r.Err }
|
||||
|
||||
func deleteSecretVariableEndpoint(ctx context.Context, request interface{}, svc fleet.Service) (fleet.Errorer, error) {
|
||||
req := request.(*deleteSecretVariableRequest)
|
||||
req := request.(*fleet.DeleteSecretVariableRequest)
|
||||
err := svc.DeleteSecretVariable(ctx, req.ID)
|
||||
return deleteSecretVariableResponse{
|
||||
return fleet.DeleteSecretVariableResponse{
|
||||
Err: err,
|
||||
}, nil
|
||||
}
|
||||
|
||||
+12
-141
@@ -2,8 +2,6 @@ package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"time"
|
||||
|
||||
"github.com/fleetdm/fleet/v4/server/contexts/viewer"
|
||||
"github.com/fleetdm/fleet/v4/server/fleet"
|
||||
@@ -13,131 +11,18 @@ import (
|
||||
// Search Targets
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
type searchTargetsRequest struct {
|
||||
// MatchQuery is the query SQL
|
||||
MatchQuery string `json:"query"`
|
||||
// QueryID is the ID of a saved query to run (used to determine if this is a
|
||||
// query that observers can run).
|
||||
QueryID *uint `json:"query_id" renameto:"report_id"`
|
||||
// Selected is the list of IDs that are already selected on the caller side
|
||||
// (e.g. the UI), so those are IDs that will be omitted from the returned
|
||||
// payload.
|
||||
Selected fleet.HostTargets `json:"selected"`
|
||||
}
|
||||
|
||||
type labelSearchResult struct {
|
||||
*fleet.Label
|
||||
DisplayText string `json:"display_text"`
|
||||
Count int `json:"count"`
|
||||
}
|
||||
|
||||
type teamSearchResult struct {
|
||||
*fleet.Team
|
||||
DisplayText string `json:"display_text"`
|
||||
Count int `json:"count"`
|
||||
}
|
||||
|
||||
func (t teamSearchResult) MarshalJSON() ([]byte, error) {
|
||||
x := struct {
|
||||
ID uint `json:"id"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description"`
|
||||
fleet.TeamConfig
|
||||
UserCount int `json:"user_count"`
|
||||
Users []fleet.TeamUser `json:"users,omitempty"`
|
||||
HostCount int `json:"host_count"`
|
||||
Hosts []fleet.HostResponse `json:"hosts,omitempty"`
|
||||
Secrets []*fleet.EnrollSecret `json:"secrets,omitempty"`
|
||||
DisplayText string `json:"display_text"`
|
||||
Count int `json:"count"`
|
||||
}{
|
||||
ID: t.ID,
|
||||
CreatedAt: t.CreatedAt,
|
||||
Name: t.Name,
|
||||
Description: t.Description,
|
||||
TeamConfig: t.Config,
|
||||
UserCount: t.UserCount,
|
||||
Users: t.Users,
|
||||
HostCount: t.HostCount,
|
||||
Hosts: fleet.HostResponsesForHostsCheap(t.Hosts),
|
||||
Secrets: t.Secrets,
|
||||
DisplayText: t.DisplayText,
|
||||
Count: t.Count,
|
||||
}
|
||||
|
||||
return json.Marshal(x)
|
||||
}
|
||||
|
||||
func (t *teamSearchResult) UnmarshalJSON(b []byte) error {
|
||||
var x struct {
|
||||
ID uint `json:"id"`
|
||||
CreatedAt time.Time `json:"created_at"`
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description"`
|
||||
fleet.TeamConfig
|
||||
UserCount int `json:"user_count"`
|
||||
Users []fleet.TeamUser `json:"users,omitempty"`
|
||||
HostCount int `json:"host_count"`
|
||||
Hosts []fleet.Host `json:"hosts,omitempty"`
|
||||
Secrets []*fleet.EnrollSecret `json:"secrets,omitempty"`
|
||||
DisplayText string `json:"display_text"`
|
||||
Count int `json:"count"`
|
||||
}
|
||||
|
||||
if err := json.Unmarshal(b, &x); err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
*t = teamSearchResult{
|
||||
Team: &fleet.Team{
|
||||
ID: x.ID,
|
||||
CreatedAt: x.CreatedAt,
|
||||
Name: x.Name,
|
||||
Description: x.Description,
|
||||
Config: x.TeamConfig,
|
||||
UserCount: x.UserCount,
|
||||
Users: x.Users,
|
||||
HostCount: x.HostCount,
|
||||
Hosts: x.Hosts,
|
||||
Secrets: x.Secrets,
|
||||
},
|
||||
DisplayText: x.DisplayText,
|
||||
Count: x.Count,
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
type targetsData struct {
|
||||
Hosts []*fleet.HostResponse `json:"hosts"`
|
||||
Labels []labelSearchResult `json:"labels"`
|
||||
Teams []teamSearchResult `json:"teams" renameto:"fleets"`
|
||||
}
|
||||
|
||||
type searchTargetsResponse struct {
|
||||
Targets *targetsData `json:"targets,omitempty"`
|
||||
TargetsCount uint `json:"targets_count"`
|
||||
TargetsOnline uint `json:"targets_online"`
|
||||
TargetsOffline uint `json:"targets_offline"`
|
||||
TargetsMissingInAction uint `json:"targets_missing_in_action"`
|
||||
Err error `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
func (r searchTargetsResponse) Error() error { return r.Err }
|
||||
|
||||
func searchTargetsEndpoint(ctx context.Context, request interface{}, svc fleet.Service) (fleet.Errorer, error) {
|
||||
req := request.(*searchTargetsRequest)
|
||||
req := request.(*fleet.SearchTargetsRequest)
|
||||
|
||||
results, err := svc.SearchTargets(ctx, req.MatchQuery, req.QueryID, req.Selected)
|
||||
if err != nil {
|
||||
return searchTargetsResponse{Err: err}, nil
|
||||
return fleet.SearchTargetsResponse{Err: err}, nil
|
||||
}
|
||||
|
||||
targets := &targetsData{
|
||||
targets := &fleet.TargetsData{
|
||||
Hosts: []*fleet.HostResponse{},
|
||||
Labels: []labelSearchResult{},
|
||||
Teams: []teamSearchResult{},
|
||||
Labels: []fleet.LabelSearchResult{},
|
||||
Teams: []fleet.TeamSearchResult{},
|
||||
}
|
||||
|
||||
for _, host := range results.Hosts {
|
||||
@@ -146,7 +31,7 @@ func searchTargetsEndpoint(ctx context.Context, request interface{}, svc fleet.S
|
||||
|
||||
for _, label := range results.Labels {
|
||||
targets.Labels = append(targets.Labels,
|
||||
labelSearchResult{
|
||||
fleet.LabelSearchResult{
|
||||
Label: label,
|
||||
DisplayText: label.Name,
|
||||
Count: label.HostCount,
|
||||
@@ -156,7 +41,7 @@ func searchTargetsEndpoint(ctx context.Context, request interface{}, svc fleet.S
|
||||
|
||||
for _, team := range results.Teams {
|
||||
targets.Teams = append(targets.Teams,
|
||||
teamSearchResult{
|
||||
fleet.TeamSearchResult{
|
||||
Team: team,
|
||||
DisplayText: team.Name,
|
||||
Count: team.HostCount,
|
||||
@@ -166,10 +51,10 @@ func searchTargetsEndpoint(ctx context.Context, request interface{}, svc fleet.S
|
||||
|
||||
metrics, err := svc.CountHostsInTargets(ctx, req.QueryID, req.Selected)
|
||||
if err != nil {
|
||||
return searchTargetsResponse{Err: err}, nil
|
||||
return fleet.SearchTargetsResponse{Err: err}, nil
|
||||
}
|
||||
|
||||
return searchTargetsResponse{
|
||||
return fleet.SearchTargetsResponse{
|
||||
Targets: targets,
|
||||
TargetsCount: metrics.TotalHosts,
|
||||
TargetsOnline: metrics.OnlineHosts,
|
||||
@@ -258,29 +143,15 @@ func (svc *Service) CountHostsInTargets(ctx context.Context, queryID *uint, targ
|
||||
return &metrics, nil
|
||||
}
|
||||
|
||||
type countTargetsRequest struct {
|
||||
Selected fleet.HostTargets `json:"selected"`
|
||||
QueryID *uint `json:"query_id" renameto:"report_id"`
|
||||
}
|
||||
|
||||
type countTargetsResponse struct {
|
||||
TargetsCount uint `json:"targets_count"`
|
||||
TargetsOnline uint `json:"targets_online"`
|
||||
TargetsOffline uint `json:"targets_offline"`
|
||||
Err error `json:"error,omitempty"`
|
||||
}
|
||||
|
||||
func (r countTargetsResponse) Error() error { return r.Err }
|
||||
|
||||
func countTargetsEndpoint(ctx context.Context, request interface{}, svc fleet.Service) (fleet.Errorer, error) {
|
||||
req := request.(*countTargetsRequest)
|
||||
req := request.(*fleet.CountTargetsRequest)
|
||||
|
||||
counts, err := svc.CountHostsInTargets(ctx, req.QueryID, req.Selected)
|
||||
if err != nil {
|
||||
return searchTargetsResponse{Err: err}, nil
|
||||
return fleet.CountTargetsResponse{Err: err}, nil
|
||||
}
|
||||
|
||||
return countTargetsResponse{
|
||||
return fleet.CountTargetsResponse{
|
||||
TargetsCount: counts.TotalHosts,
|
||||
TargetsOnline: counts.OnlineHosts,
|
||||
TargetsOffline: counts.OfflineHosts,
|
||||
|
||||
Reference in New Issue
Block a user