// NewExecutorResourceProcurer returns a Procurement procuring executor resources // If a given offer has no executor IDs set, the given prototype executor resources are considered for procurement. // If a given offer has one executor ID set, only pod resources are being procured. // An offer with more than one executor ID implies an invariant violation and the first executor ID is being considered. func NewExecutorResourceProcurer(rs []*mesos.Resource, registry executorinfo.Registry) Procurement { return ProcurementFunc(func(t *T, _ *api.Node, ps *ProcureState) error { eids := len(ps.offer.GetExecutorIds()) switch { case eids == 0: wantedCpus := resources.Sum(resources.Filter(rs, resources.IsScalar, resources.HasName("cpus"))) wantedMem := resources.Sum(resources.Filter(rs, resources.IsScalar, resources.HasName("mem"))) procuredCpu, remaining := procureScalarResources("cpus", wantedCpus, t.FrameworkRoles, ps.offer.GetResources()) if procuredCpu == nil { return fmt.Errorf("not enough cpu resources for executor: want=%v", wantedCpus) } procuredMem, remaining := procureScalarResources("mem", wantedMem, t.FrameworkRoles, remaining) if procuredMem == nil { return fmt.Errorf("not enough mem resources for executor: want=%v", wantedMem) } ps.offer.Resources = remaining ps.spec.Executor = registry.New(ps.offer.GetHostname(), append(procuredCpu, procuredMem...)) return nil case eids == 1: e, err := registry.Get(ps.offer.GetHostname()) if err != nil { return err } ps.spec.Executor = e return nil default: // offers with more than 1 ExecutorId should be rejected by the // framework long before they arrive here. return fmt.Errorf("got offer with more than 1 executor id: %v", ps.offer.GetExecutorIds()) } }) }
// procureScalarResources procures offered resources that // 1. Match the given name // 2. Match the given roles // 3. The given wanted scalar value can be fully consumed by offered resources // Roles are being considered in the specified roles slice ordering. func procureScalarResources( name string, want float64, roles []string, offered []*mesos.Resource, ) (procured, remaining []*mesos.Resource) { sorted := resources.ByRoles(roles...).Sort(offered) procured = make([]*mesos.Resource, 0, len(sorted)) remaining = make([]*mesos.Resource, 0, len(sorted)) for _, r := range sorted { if want >= epsilon && resources.MatchesAll(r, resources.HasName(name), resources.IsScalar) { left, role := r.GetScalar().GetValue(), r.Role consumed := math.Min(want, left) want -= consumed left -= consumed if left >= epsilon { r = mesosutil.NewScalarResource(name, left) r.Role = role remaining = append(remaining, r) } consumedRes := mesosutil.NewScalarResource(name, consumed) consumedRes.Role = role procured = append(procured, consumedRes) } else { remaining = append(remaining, r) } } // demanded value (want) was not fully consumed violating invariant 3. // thus no resources must be procured if want >= epsilon { return nil, offered } return }