1 // Copyright (C) The Arvados Authors. All rights reserved.
3 // SPDX-License-Identifier: AGPL-3.0
11 "git.curoverse.com/arvados.git/sdk/go/arvados"
14 var ErrInstanceTypesNotConfigured = errors.New("site configuration does not list any instance types")
16 var discountConfiguredRAMPercent = 5
18 // ConstraintsNotSatisfiableError includes a list of available instance types
19 // to be reported back to the user.
20 type ConstraintsNotSatisfiableError struct {
22 AvailableTypes []arvados.InstanceType
25 // ChooseInstanceType returns the cheapest available
26 // arvados.InstanceType big enough to run ctr.
27 func ChooseInstanceType(cc *arvados.Cluster, ctr *arvados.Container) (best arvados.InstanceType, err error) {
28 if len(cc.InstanceTypes) == 0 {
29 err = ErrInstanceTypesNotConfigured
33 needScratch := int64(0)
34 for _, m := range ctr.Mounts {
36 needScratch += m.Capacity
40 needVCPUs := ctr.RuntimeConstraints.VCPUs
42 needRAM := ctr.RuntimeConstraints.RAM + ctr.RuntimeConstraints.KeepCacheRAM
43 needRAM = (needRAM * 100) / int64(100-discountConfiguredRAMPercent)
46 for _, it := range cc.InstanceTypes {
48 case ok && it.Price > best.Price:
49 case int64(it.Scratch) < needScratch:
50 case int64(it.RAM) < needRAM:
51 case it.VCPUs < needVCPUs:
52 case it.Preemptible != ctr.SchedulingParameters.Preemptible:
53 case it.Price == best.Price && (it.RAM < best.RAM || it.VCPUs < best.VCPUs):
54 // Equal price, but worse specs
56 // Lower price || (same price && better specs)
62 availableTypes := make([]arvados.InstanceType, 0, len(cc.InstanceTypes))
63 for _, t := range cc.InstanceTypes {
64 availableTypes = append(availableTypes, t)
66 sort.Slice(availableTypes, func(a, b int) bool {
67 return availableTypes[a].Price < availableTypes[b].Price
69 err = ConstraintsNotSatisfiableError{
70 errors.New("constraints not satisfiable by any configured instance type"),