2018-06-11 13:13:19 +00:00
package endpoints
import (
"net/http"
2022-04-26 00:17:36 +00:00
"sort"
2019-07-20 23:28:11 +00:00
"strconv"
2022-03-14 01:53:23 +00:00
"time"
2019-07-20 23:28:11 +00:00
"github.com/portainer/libhttp/request"
2021-01-25 19:16:53 +00:00
portainer "github.com/portainer/portainer/api"
2019-03-21 01:20:14 +00:00
"github.com/portainer/portainer/api/http/security"
2023-04-05 21:09:22 +00:00
"github.com/portainer/portainer/api/internal/endpointutils"
2018-06-11 13:13:19 +00:00
2022-07-19 16:00:45 +00:00
httperror "github.com/portainer/libhttp/error"
"github.com/portainer/libhttp/response"
2022-04-19 18:43:36 +00:00
)
2022-04-26 23:40:23 +00:00
const (
EdgeDeviceIntervalMultiplier = 2
EdgeDeviceIntervalAdd = 20
)
2021-02-23 03:21:39 +00:00
// @id EndpointList
2021-09-20 00:14:22 +00:00
// @summary List environments(endpoints)
// @description List all environments(endpoints) based on the current user authorizations. Will
2022-06-03 04:44:42 +00:00
// @description return all environments(endpoints) if using an administrator or team leader account otherwise it will
2021-09-20 00:14:22 +00:00
// @description only return authorized environments(endpoints).
2021-02-23 03:21:39 +00:00
// @description **Access policy**: restricted
// @tags endpoints
2021-11-30 02:31:16 +00:00
// @security ApiKeyAuth
2021-02-23 03:21:39 +00:00
// @security jwt
// @produce json
// @param start query int false "Start searching from"
// @param limit query int false "Limit results to this value"
2022-07-19 16:00:45 +00:00
// @param sort query int false "Sort results by this value"
// @param order query int false "Order sorted results by desc/asc" Enum("asc", "desc")
// @param search query string false "Search query"
// @param groupIds query []int false "List environments(endpoints) of these groups"
// @param status query []int false "List environments(endpoints) by this status"
2021-09-20 00:14:22 +00:00
// @param types query []int false "List environments(endpoints) of this type"
// @param tagIds query []int false "search environments(endpoints) with these tags (depends on tagsPartialMatch)"
// @param tagsPartialMatch query bool false "If true, will return environment(endpoint) which has one of tagIds, if false (or missing) will return only environments(endpoints) that has all the tags"
// @param endpointIds query []int false "will return only these environments(endpoints)"
2022-07-19 16:00:45 +00:00
// @param provisioned query bool false "If true, will return environment(endpoint) that were provisioned"
2022-08-11 04:32:12 +00:00
// @param agentVersions query []string false "will return only environments with on of these agent versions"
2023-03-01 18:33:05 +00:00
// @param edgeAsync query bool false "if exists true show only edge async agents, false show only standard edge agents. if missing, will show both types (relevant only for edge agents)"
// @param edgeDeviceUntrusted query bool false "if true, show only untrusted edge agents, if false show only trusted edge agents (relevant only for edge agents)"
2022-05-23 14:32:51 +00:00
// @param name query string false "will return only environments(endpoints) with this name"
2021-02-23 03:21:39 +00:00
// @success 200 {array} portainer.Endpoint "Endpoints"
2021-09-13 03:42:53 +00:00
// @failure 500 "Server error"
2021-02-23 03:21:39 +00:00
// @router /endpoints [get]
2018-06-11 13:13:19 +00:00
func ( handler * Handler ) endpointList ( w http . ResponseWriter , r * http . Request ) * httperror . HandlerError {
2019-07-20 23:28:11 +00:00
start , _ := request . RetrieveNumericQueryParameter ( r , "start" , true )
if start != 0 {
start --
}
limit , _ := request . RetrieveNumericQueryParameter ( r , "limit" , true )
2022-04-26 00:17:36 +00:00
sortField , _ := request . RetrieveQueryParameter ( r , "sort" , true )
sortOrder , _ := request . RetrieveQueryParameter ( r , "order" , true )
2021-07-21 07:16:22 +00:00
2020-05-20 05:23:15 +00:00
endpointGroups , err := handler . DataStore . EndpointGroup ( ) . EndpointGroups ( )
2018-06-11 13:13:19 +00:00
if err != nil {
2022-07-19 16:00:45 +00:00
return httperror . InternalServerError ( "Unable to retrieve environment groups from the database" , err )
2018-06-11 13:13:19 +00:00
}
2020-05-20 05:23:15 +00:00
endpoints , err := handler . DataStore . Endpoint ( ) . Endpoints ( )
2019-07-20 23:28:11 +00:00
if err != nil {
2022-07-19 16:00:45 +00:00
return httperror . InternalServerError ( "Unable to retrieve environments from the database" , err )
2019-07-20 23:28:11 +00:00
}
2021-03-11 20:00:05 +00:00
settings , err := handler . DataStore . Settings ( ) . Settings ( )
if err != nil {
2022-07-19 16:00:45 +00:00
return httperror . InternalServerError ( "Unable to retrieve settings from the database" , err )
2021-03-11 20:00:05 +00:00
}
2018-06-11 13:13:19 +00:00
securityContext , err := security . RetrieveRestrictedRequestContext ( r )
if err != nil {
2022-07-19 16:00:45 +00:00
return httperror . InternalServerError ( "Unable to retrieve info from request context" , err )
2018-06-11 13:13:19 +00:00
}
2022-07-19 16:00:45 +00:00
query , err := parseQuery ( r )
if err != nil {
return httperror . BadRequest ( "Invalid query parameters" , err )
2019-07-20 23:28:11 +00:00
}
2022-07-19 16:00:45 +00:00
filteredEndpoints := security . FilterEndpoints ( endpoints , endpointGroups , securityContext )
2020-03-26 05:44:27 +00:00
2022-07-19 16:00:45 +00:00
filteredEndpoints , totalAvailableEndpoints , err := handler . filterEndpointsByQuery ( filteredEndpoints , query , endpointGroups , settings )
if err != nil {
return httperror . InternalServerError ( "Unable to filter endpoints" , err )
2020-04-08 09:14:50 +00:00
}
2022-05-30 14:22:37 +00:00
sortEndpointsByField ( filteredEndpoints , endpointGroups , sortField , sortOrder == "desc" )
2022-04-26 00:17:36 +00:00
2019-07-20 23:28:11 +00:00
filteredEndpointCount := len ( filteredEndpoints )
paginatedEndpoints := paginateEndpoints ( filteredEndpoints , start , limit )
for idx := range paginatedEndpoints {
hideFields ( & paginatedEndpoints [ idx ] )
2021-01-25 19:16:53 +00:00
paginatedEndpoints [ idx ] . ComposeSyntaxMaxVersion = handler . ComposeStackManager . ComposeSyntaxMaxVersion ( )
2021-03-11 20:00:05 +00:00
if paginatedEndpoints [ idx ] . EdgeCheckinInterval == 0 {
paginatedEndpoints [ idx ] . EdgeCheckinInterval = settings . EdgeAgentCheckinInterval
}
2022-03-14 01:53:23 +00:00
paginatedEndpoints [ idx ] . QueryDate = time . Now ( ) . Unix ( )
2023-04-05 21:09:22 +00:00
endpointutils . UpdateEdgeEndpointHeartbeat ( & paginatedEndpoints [ idx ] , settings )
2022-09-22 20:05:10 +00:00
if ! query . excludeSnapshots {
err = handler . SnapshotService . FillSnapshotData ( & paginatedEndpoints [ idx ] )
if err != nil {
return httperror . InternalServerError ( "Unable to add snapshot data" , err )
}
}
2019-07-20 23:28:11 +00:00
}
w . Header ( ) . Set ( "X-Total-Count" , strconv . Itoa ( filteredEndpointCount ) )
2022-03-08 12:14:23 +00:00
w . Header ( ) . Set ( "X-Total-Available" , strconv . Itoa ( totalAvailableEndpoints ) )
2019-07-20 23:28:11 +00:00
return response . JSON ( w , paginatedEndpoints )
}
func paginateEndpoints ( endpoints [ ] portainer . Endpoint , start , limit int ) [ ] portainer . Endpoint {
if limit == 0 {
return endpoints
}
endpointCount := len ( endpoints )
2022-11-22 12:16:34 +00:00
if start < 0 {
start = 0
}
2019-07-20 23:28:11 +00:00
if start > endpointCount {
start = endpointCount
}
end := start + limit
if end > endpointCount {
end = endpointCount
}
return endpoints [ start : end ]
}
2022-05-30 14:22:37 +00:00
func sortEndpointsByField ( endpoints [ ] portainer . Endpoint , endpointGroups [ ] portainer . EndpointGroup , sortField string , isSortDesc bool ) {
2022-04-26 00:17:36 +00:00
switch sortField {
case "Name" :
if isSortDesc {
sort . Stable ( sort . Reverse ( EndpointsByName ( endpoints ) ) )
} else {
sort . Stable ( EndpointsByName ( endpoints ) )
}
case "Group" :
2022-08-03 15:18:33 +00:00
endpointGroupNames := make ( map [ portainer . EndpointGroupID ] string , 0 )
2022-05-30 14:22:37 +00:00
for _ , group := range endpointGroups {
endpointGroupNames [ group . ID ] = group . Name
}
endpointsByGroup := EndpointsByGroup {
endpointGroupNames : endpointGroupNames ,
endpoints : endpoints ,
}
2022-04-26 00:17:36 +00:00
if isSortDesc {
2022-05-30 14:22:37 +00:00
sort . Stable ( sort . Reverse ( endpointsByGroup ) )
2022-04-26 00:17:36 +00:00
} else {
2022-05-30 14:22:37 +00:00
sort . Stable ( endpointsByGroup )
2022-04-26 00:17:36 +00:00
}
case "Status" :
if isSortDesc {
sort . Slice ( endpoints , func ( i , j int ) bool {
return endpoints [ i ] . Status > endpoints [ j ] . Status
} )
} else {
sort . Slice ( endpoints , func ( i , j int ) bool {
return endpoints [ i ] . Status < endpoints [ j ] . Status
} )
}
}
}
2020-05-14 02:14:28 +00:00
func getEndpointGroup ( groupID portainer . EndpointGroupID , groups [ ] portainer . EndpointGroup ) portainer . EndpointGroup {
2020-04-08 09:14:50 +00:00
var endpointGroup portainer . EndpointGroup
for _ , group := range groups {
if group . ID == groupID {
endpointGroup = group
break
}
}
2020-05-14 02:14:28 +00:00
return endpointGroup
}