@Override public boolean insertActions(Solution s, ReconfigurationPlan plan) { DurationEvaluators dev = rp.getDurationEvaluators(); // Only if the VM doesn't stay if (s.getIntVal(cSlice.getHoster()) != (s.getIntVal(dSlice.getHoster()))) { Action a; Node dst = rp.getNode(s.getIntVal(dSlice.getHoster())); // Migration if (s.getIntVal(doReinstantiation) == 0) { int st = s.getIntVal(getStart()); int ed = s.getIntVal(getEnd()); if (getBandwidth() != null) { a = new MigrateVM(vm, src, dst, st, ed, s.getIntVal(getBandwidth())); } else { a = new MigrateVM(vm, src, dst, st, ed); } plan.add(a); // Re-instantiation } else { VM newVM = rp.cloneVM(vm); if (newVM == null) { rp.getLogger().error("Unable to get a new int to plan the re-instantiate of VM {}", vm); return false; } org.btrplace.plan.event.ForgeVM fvm = new org.btrplace.plan.event.ForgeVM( newVM, s.getIntVal(dSlice.getStart()) - dev.evaluate(rp.getSourceModel(), org.btrplace.plan.event.ForgeVM.class, vm), s.getIntVal(dSlice.getStart())); // forge the new VM from a template plan.add(fvm); // Boot the new VM int endForging = fvm.getEnd(); org.btrplace.plan.event.BootVM boot = new org.btrplace.plan.event.BootVM( newVM, dst, endForging, endForging + dev.evaluate( rp.getSourceModel(), org.btrplace.plan.event.BootVM.class, newVM)); boot.addEvent(Action.Hook.PRE, new SubstitutedVMEvent(vm, newVM)); return plan.add(boot) && plan.add( new org.btrplace.plan.event.ShutdownVM( vm, src, boot.getEnd(), s.getIntVal(cSlice.getEnd()))); } } return true; }
/** * Make a new model. * * @param p the RP to use as a basis. * @param e the VM managed by the action * @throws org.btrplace.scheduler.SchedulerException if an error occurred */ public RelocatableVM(ReconfigurationProblem p, VM e) throws SchedulerException { // Get vars vm = e; rp = p; src = rp.getSourceModel().getMapping().getVMLocation(e); org.chocosolver.solver.Model csp = rp.getModel(); Model mo = rp.getSourceModel(); // Default values start = rp.getStart(); end = rp.getStart(); duration = csp.intVar(0); state = csp.boolVar(true); // If not manageable, the VM stays on the current host if (!p.getManageableVMs().contains(e)) { stay = csp.boolVar(true); doReinstantiation = csp.boolVar(false); manageable = false; IntVar host = rp.makeCurrentHost(vm, PREFIX_STAY, vm, ").host"); cSlice = new SliceBuilder(rp, vm, PREFIX_STAY, vm.toString(), ").cSlice") .setHoster(host) .setEnd(rp.makeUnboundedDuration(PREFIX_STAY, vm, ").cSlice_end")) .build(); dSlice = new SliceBuilder(rp, vm, PREFIX_STAY, vm, ").dSlice") .setHoster(host) .setStart(cSlice.getEnd()) .build(); return; } // The VM can move (to re-instantiate or migrate) OR STAY to the same host stay = csp.boolVar(rp.makeVarLabel(vm, "stay")); cSlice = new SliceBuilder(rp, vm, PREFIX, vm, ").cSlice") .setHoster(rp.getNode(rp.getSourceModel().getMapping().getVMLocation(vm))) .setEnd(rp.makeUnboundedDuration(PREFIX, vm, ").cSlice_end")) .build(); dSlice = new SliceBuilder(rp, vm, PREFIX, vm, ").dSlice") .setStart(rp.makeUnboundedDuration(PREFIX, vm, ").dSlice_start")) .build(); // Update start and end vars of the action start = dSlice.getStart(); end = cSlice.getEnd(); csp.post(new Arithmetic(end, Operator.LE, rp.getEnd())); // Get some static durations from evaluators DurationEvaluators dev = rp.getDurationEvaluators(); int migrateDuration = dev.evaluate(rp.getSourceModel(), MigrateVM.class, vm); int bootDuration = dev.evaluate(rp.getSourceModel(), org.btrplace.plan.event.BootVM.class, vm); int forgeD = p.getDurationEvaluators() .evaluate(p.getSourceModel(), org.btrplace.plan.event.ForgeVM.class, vm); // Compute the re-instantiation duration int reInstantiateDuration = bootDuration + forgeD; reInstantiateDuration = forgeD; // Compliant with CMaxOnlineTest and others // Get the networking view if attached Network network = Network.get(mo); IntVar migrationDuration; if (network != null) { // Set the migration algorithm postCopy = mo.getAttributes().get(vm, "postCopy", false); // Create unbounded/large domain vars for migration duration and bandwidth migrationDuration = p.makeUnboundedDuration("migration(", vm, ").duration"); bandwidth = csp.intVar(PREFIX + vm + ").bandwidth", 0, Integer.MAX_VALUE / 100, true); } // No networking view, set the duration from the evaluator else { // The duration can still be 0 => the VM STAY ! migrationDuration = csp.intVar( rp.makeVarLabel("migration(", vm, ").duration"), new int[] {0, migrateDuration}); bandwidth = null; } // Possibly re-instantiate (if some attributes are defined) if (mo.getAttributes().get(vm, "clone", false) && mo.getAttributes().isSet(vm, "template")) { doReinstantiation = csp.boolVar(rp.makeVarLabel("relocation_method(", vm, ")")); duration = csp.intVar( rp.makeVarLabel(PREFIX, vm, ").duration"), Math.min(migrationDuration.getLB(), reInstantiateDuration), Math.max(migrationDuration.getUB(), reInstantiateDuration), true); // Re-instantiate or migrate // (Prefer the re-instantiation if the duration are the same, otherwise choose the min) rp.getModel() .ifThenElse( rp.getModel() .or( new Arithmetic( doReinstantiation, Operator.EQ, 0), // can be instantiated externally ! new Arithmetic(migrationDuration, Operator.LT, reInstantiateDuration)), new Arithmetic(duration, Operator.EQ, migrationDuration), new Arithmetic(duration, Operator.EQ, reInstantiateDuration)); // If it is a re-instantiation then specify that the dSlice must start AFTER the Forge delay IntVar time = csp.intVar(rp.makeVarLabel(doReinstantiation.getName(), " * ", forgeD), 0, forgeD, false); csp.post(csp.times(doReinstantiation, forgeD, time)); csp.post(new Arithmetic(start, Operator.GE, time)); // Be sure that doReinstantiation will be instantiated csp.post(new FastIFFEq(doReinstantiation, duration, reInstantiateDuration)); } // The VM either migrate or stay but won't be re-instantiated for sure else { doReinstantiation = csp.boolVar(false); duration = migrationDuration; } // If the VM stay (src host == dst host), then duration = 0 csp.post(new FastIFFEq(stay, dSlice.getHoster(), cSlice.getHoster().getValue())); csp.post(new FastIFFEq(stay, duration, 0)); // We have to force the migration duration equals to 0 if it stays // otherwise, the variable will be free csp.post(new FastIFFEq(stay, migrationDuration, 0)); // Create the task ('default' cumulative constraint with a height of 1) migrationTask = new Task(start, duration, end); }