diff --git a/grid-proxy/docs/docs.go b/grid-proxy/docs/docs.go index a4b2c88b..b45996a5 100644 --- a/grid-proxy/docs/docs.go +++ b/grid-proxy/docs/docs.go @@ -1123,6 +1123,12 @@ const docTemplate = `{ "name": "available_for", "in": "query" }, + { + "type": "integer", + "description": "rented by a twin id or available to rent", + "name": "rentable_by", + "in": "query" + }, { "type": "string", "description": "List of farms separated by comma to fetch nodes from (e.g. '1,2,3')", diff --git a/grid-proxy/docs/swagger.json b/grid-proxy/docs/swagger.json index c7d1942a..496f7511 100644 --- a/grid-proxy/docs/swagger.json +++ b/grid-proxy/docs/swagger.json @@ -1115,6 +1115,12 @@ "name": "available_for", "in": "query" }, + { + "type": "integer", + "description": "rented by a twin id or available to rent", + "name": "rentable_by", + "in": "query" + }, { "type": "string", "description": "List of farms separated by comma to fetch nodes from (e.g. '1,2,3')", diff --git a/grid-proxy/docs/swagger.yaml b/grid-proxy/docs/swagger.yaml index 57e6e0cc..864640d0 100644 --- a/grid-proxy/docs/swagger.yaml +++ b/grid-proxy/docs/swagger.yaml @@ -1197,6 +1197,10 @@ paths: in: query name: available_for type: integer + - description: rented by a twin id or available to rent + in: query + name: rentable_by + type: integer - description: List of farms separated by comma to fetch nodes from (e.g. '1,2,3') in: query name: farm_ids diff --git a/grid-proxy/internal/explorer/db/postgres.go b/grid-proxy/internal/explorer/db/postgres.go index db14418f..77a1bcba 100644 --- a/grid-proxy/internal/explorer/db/postgres.go +++ b/grid-proxy/internal/explorer/db/postgres.go @@ -717,6 +717,12 @@ func (d *PostgresDatabase) GetNodes(ctx context.Context, filter types.NodeFilter if filter.RentedBy != nil { q = q.Where(`COALESCE(resources_cache.renter, 0) = ?`, *filter.RentedBy) } + if filter.RentableOrRentedBy != nil { + q = q.Where(`((farm.dedicated_farm = true OR resources_cache.node_contracts_count = 0) + AND resources_cache.renter is null) + OR COALESCE(resources_cache.renter, 0) = ? + `, *filter.RentableOrRentedBy) + } if filter.Rented != nil { q = q.Where(`? = (resources_cache.renter is not null)`, *filter.Rented) } @@ -734,7 +740,8 @@ func (d *PostgresDatabase) GetNodes(ctx context.Context, filter types.NodeFilter if limit.Randomize { q = q.Order("random()") } else { - if filter.AvailableFor != nil { + // prioritize the rented (by the twin) nodes + if filter.AvailableFor != nil || filter.RentableOrRentedBy != nil { q = q.Order("(case when resources_cache.renter is not null then 1 else 2 end)") } diff --git a/grid-proxy/internal/explorer/server.go b/grid-proxy/internal/explorer/server.go index 46e159d7..44b92593 100644 --- a/grid-proxy/internal/explorer/server.go +++ b/grid-proxy/internal/explorer/server.go @@ -145,6 +145,7 @@ func (a *App) getStats(r *http.Request) (interface{}, mw.Response) { // @Param rented query bool false "Set to true to filter rented nodes" // @Param rented_by query int false "rented by twin id" // @Param available_for query int false "available for twin id" +// @Param rentable_by query int false "rented by a twin id or available to rent" // @Param farm_ids query string false "List of farms separated by comma to fetch nodes from (e.g. '1,2,3')" // @Param certification_type query string false "certificate type" Enums(Certified, DIY) // @Param has_gpu query bool false "filter nodes on whether they have GPU support or not" diff --git a/grid-proxy/pkg/types/nodes.go b/grid-proxy/pkg/types/nodes.go index 9d7aefa2..74001547 100644 --- a/grid-proxy/pkg/types/nodes.go +++ b/grid-proxy/pkg/types/nodes.go @@ -117,47 +117,48 @@ type Capacity struct { // NodeFilter node filters type NodeFilter struct { - Status []string `schema:"status,omitempty"` - FreeMRU *uint64 `schema:"free_mru,omitempty"` - FreeHRU *uint64 `schema:"free_hru,omitempty"` - FreeSRU *uint64 `schema:"free_sru,omitempty"` - TotalMRU *uint64 `schema:"total_mru,omitempty"` - TotalHRU *uint64 `schema:"total_hru,omitempty"` - TotalSRU *uint64 `schema:"total_sru,omitempty"` - TotalCRU *uint64 `schema:"total_cru,omitempty"` - Country *string `schema:"country,omitempty"` - CountryContains *string `schema:"country_contains,omitempty"` - City *string `schema:"city,omitempty"` - CityContains *string `schema:"city_contains,omitempty"` - Region *string `schema:"region,omitempty"` - FarmName *string `schema:"farm_name,omitempty"` - FarmNameContains *string `schema:"farm_name_contains,omitempty"` - FarmIDs []uint64 `schema:"farm_ids,omitempty"` - FreeIPs *uint64 `schema:"free_ips,omitempty"` - IPv4 *bool `schema:"ipv4,omitempty"` - IPv6 *bool `schema:"ipv6,omitempty"` - Domain *bool `schema:"domain,omitempty"` - Dedicated *bool `schema:"dedicated,omitempty"` - InDedicatedFarm *bool `schema:"in_dedicated_farm,omitempty"` - Rentable *bool `schema:"rentable,omitempty"` - OwnedBy *uint64 `schema:"owned_by,omitempty"` - Rented *bool `schema:"rented,omitempty"` - RentedBy *uint64 `schema:"rented_by,omitempty"` - AvailableFor *uint64 `schema:"available_for,omitempty"` - NodeID *uint64 `schema:"node_id,omitempty"` - NodeIDs []uint64 `schema:"node_ids,omitempty"` - TwinID *uint64 `schema:"twin_id,omitempty"` - CertificationType *string `schema:"certification_type,omitempty"` - HasGPU *bool `schema:"has_gpu,omitempty"` - NumGPU *uint64 `schema:"num_gpu,omitempty"` - GpuDeviceID *string `schema:"gpu_device_id,omitempty"` - GpuDeviceName *string `schema:"gpu_device_name,omitempty"` - GpuVendorID *string `schema:"gpu_vendor_id,omitempty"` - GpuVendorName *string `schema:"gpu_vendor_name,omitempty"` - GpuAvailable *bool `schema:"gpu_available,omitempty"` - Healthy *bool `schema:"healthy,omitempty"` - PriceMin *float64 `schema:"price_min,omitempty"` - PriceMax *float64 `schema:"price_max,omitempty"` - Excluded []uint64 `schema:"excluded,omitempty"` - HasIpv6 *bool `schema:"has_ipv6,omitempty"` + Status []string `schema:"status,omitempty"` + FreeMRU *uint64 `schema:"free_mru,omitempty"` + FreeHRU *uint64 `schema:"free_hru,omitempty"` + FreeSRU *uint64 `schema:"free_sru,omitempty"` + TotalMRU *uint64 `schema:"total_mru,omitempty"` + TotalHRU *uint64 `schema:"total_hru,omitempty"` + TotalSRU *uint64 `schema:"total_sru,omitempty"` + TotalCRU *uint64 `schema:"total_cru,omitempty"` + Country *string `schema:"country,omitempty"` + CountryContains *string `schema:"country_contains,omitempty"` + City *string `schema:"city,omitempty"` + CityContains *string `schema:"city_contains,omitempty"` + Region *string `schema:"region,omitempty"` + FarmName *string `schema:"farm_name,omitempty"` + FarmNameContains *string `schema:"farm_name_contains,omitempty"` + FarmIDs []uint64 `schema:"farm_ids,omitempty"` + FreeIPs *uint64 `schema:"free_ips,omitempty"` + IPv4 *bool `schema:"ipv4,omitempty"` + IPv6 *bool `schema:"ipv6,omitempty"` + Domain *bool `schema:"domain,omitempty"` + Dedicated *bool `schema:"dedicated,omitempty"` + InDedicatedFarm *bool `schema:"in_dedicated_farm,omitempty"` + Rentable *bool `schema:"rentable,omitempty"` + OwnedBy *uint64 `schema:"owned_by,omitempty"` + Rented *bool `schema:"rented,omitempty"` + RentedBy *uint64 `schema:"rented_by,omitempty"` + RentableOrRentedBy *uint64 `schema:"rentable_by,omitempty"` // rented by twin or rentable + AvailableFor *uint64 `schema:"available_for,omitempty"` // rented by twin or free + NodeID *uint64 `schema:"node_id,omitempty"` + NodeIDs []uint64 `schema:"node_ids,omitempty"` + TwinID *uint64 `schema:"twin_id,omitempty"` + CertificationType *string `schema:"certification_type,omitempty"` + HasGPU *bool `schema:"has_gpu,omitempty"` + NumGPU *uint64 `schema:"num_gpu,omitempty"` + GpuDeviceID *string `schema:"gpu_device_id,omitempty"` + GpuDeviceName *string `schema:"gpu_device_name,omitempty"` + GpuVendorID *string `schema:"gpu_vendor_id,omitempty"` + GpuVendorName *string `schema:"gpu_vendor_name,omitempty"` + GpuAvailable *bool `schema:"gpu_available,omitempty"` + Healthy *bool `schema:"healthy,omitempty"` + PriceMin *float64 `schema:"price_min,omitempty"` + PriceMax *float64 `schema:"price_max,omitempty"` + Excluded []uint64 `schema:"excluded,omitempty"` + HasIpv6 *bool `schema:"has_ipv6,omitempty"` } diff --git a/grid-proxy/tests/queries/mock_client/nodes.go b/grid-proxy/tests/queries/mock_client/nodes.go index 73a238e2..1228bc45 100644 --- a/grid-proxy/tests/queries/mock_client/nodes.go +++ b/grid-proxy/tests/queries/mock_client/nodes.go @@ -427,6 +427,13 @@ func (n *Node) satisfies(f types.NodeFilter, data *DBData) bool { } renter, ok := data.NodeRentedBy[n.NodeID] + + if f.RentableOrRentedBy != nil && + ((ok && renter != *f.RentableOrRentedBy) || + (!ok && !(data.Farms[n.FarmID].DedicatedFarm || len(data.NonDeletedContracts[n.NodeID]) == 0))) { + return false + } + if f.AvailableFor != nil && ((ok && renter != *f.AvailableFor) || (!ok && (data.Farms[n.FarmID].DedicatedFarm || n.ExtraFee != 0))) { diff --git a/grid-proxy/tests/queries/node_test.go b/grid-proxy/tests/queries/node_test.go index 6668d83e..7cd34d5a 100644 --- a/grid-proxy/tests/queries/node_test.go +++ b/grid-proxy/tests/queries/node_test.go @@ -265,6 +265,13 @@ var nodeFilterRandomValueGenerator = map[string]func(agg NodesAggregate) interfa } return &c }, + "RentableOrRentedBy": func(agg NodesAggregate) interface{} { + c := agg.twins[rand.Intn(len(agg.twins))] + if flip(.2) && len(agg.nodeRenters) != 0 { + c = agg.nodeRenters[rand.Intn(len(agg.nodeRenters))] + } + return &c + }, "AvailableFor": func(agg NodesAggregate) interface{} { c := agg.twins[rand.Intn(len(agg.twins))] if flip(.1) && len(agg.nodeRenters) != 0 {