Skip to main content

AvoidAssignments

Type: Constraint

Forbid specific objects from being placed on specific scope items. For example, keep certain tasks off certain hosts (say, because those hosts lack hardware the task needs).

Parameters

ParameterTypeRequiredDefaultDescription
namestringNo""Descriptive name for logging/debugging.
scopestringYes-The scope the listed scope items belong to (e.g. "host").
assignmentslist of AvoidAssignmentYesemptyThe forbidden (object, scope item) pairs.

AvoidAssignment entries

Each AvoidAssignment forbids one object from a set of scope items:

FieldTypeDescription
objectstringThe object being restricted
scopeItemslist of stringThe scope items this object may not be placed on

Example

An example use: tasks on hosts, where certain tasks may not go on certain hosts. Forbid t0 from h0 and h1, t1 from h0 and h2, and t2 from h0.

solver.setObjectName("task");
solver.setContainerName("host");

solver.setAssignment(std::map<std::string, std::vector<std::string>>{
{"h0", {"t0", "t1"}},
{"h1", {"t2"}},
{"h2", {"t3"}},
});

auto forbid = [](std::string object, std::vector<std::string> scopeItems) {
AvoidAssignment entry;
entry.object() = std::move(object);
entry.scopeItems() = std::move(scopeItems);
return entry;
};

AvoidAssignmentsSpec avoidSpec;
avoidSpec.scope() = "host";
avoidSpec.assignments() = {
forbid("t0", {"h0", "h1"}),
forbid("t1", {"h0", "h2"}),
forbid("t2", {"h0"}),
};
solver.addConstraint(avoidSpec);

t0 and t1 both start on h0, which is forbidden for both, so they move: t0 to h2 (its only allowed host) and t1 to h1. t2 is already on an allowed host (h1) and stays. t3 is unconstrained.

Constraint only

AvoidAssignmentsSpec cannot be used as a goal; passing it to addGoal throws.

If the initial assignment already respects every forbidden pair, so does the final one. If an object starts on a scope item it is forbidden from, that pair is initially broken, and the general constraint policy takes over: under the default policy Rebalancer moves the offending objects off as best it can without breaking constraints that held initially.

Avoiding many pairs

Listing every pair gets unwieldy when a large share of objects must be kept off a scope item. An equivalent formulation scales better: add a dynamic object dimension (addDynamicObjectDimension) that is 1 for each disallowed (scope item, object) placement and 0 otherwise, choosing the defaultValue (0 or 1) that leaves fewer explicit entries. Then add a CapacitySpec on it with an ABSOLUTE MAX limit of 0, so no disallowed placement fits.

Source