All Downloads are FREE. Search and download functionalities are using the official Maven repository.

com.netflix.fenzo.samples.SampleFramework Maven / Gradle / Ivy

/*
 * Copyright 2015 Netflix, Inc.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *    http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.netflix.fenzo.samples;

import com.netflix.fenzo.SchedulingResult;
import com.netflix.fenzo.TaskAssignmentResult;
import com.netflix.fenzo.TaskRequest;
import com.netflix.fenzo.TaskScheduler;
import com.netflix.fenzo.VMAssignmentResult;
import com.netflix.fenzo.VirtualMachineLease;
import org.apache.mesos.MesosSchedulerDriver;
import org.apache.mesos.Protos;
import org.apache.mesos.Scheduler;
import org.apache.mesos.SchedulerDriver;
import rx.functions.Action1;
import rx.functions.Func1;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicBoolean;
import java.util.concurrent.atomic.AtomicReference;

public class SampleFramework {

    public class MesosScheduler implements Scheduler {

        @Override
        public void registered(SchedulerDriver driver, Protos.FrameworkID frameworkId, Protos.MasterInfo masterInfo) {
            System.out.println("Registered! ID = " + frameworkId.getValue());
            scheduler.expireAllLeases();
        }
        @Override
        public void reregistered(SchedulerDriver driver, Protos.MasterInfo masterInfo) {
            System.out.println("Re-registered " + masterInfo.getId());
            scheduler.expireAllLeases();
        }

        @Override
        public void resourceOffers(SchedulerDriver driver, List offers) {
            for(Protos.Offer offer: offers) {
                System.out.println("Adding offer " + offer.getId() + " from host " + offer.getHostname());
                leasesQueue.offer(new VMLeaseObject(offer));
            }
        }

        @Override
        public void offerRescinded(SchedulerDriver driver, Protos.OfferID offerId) {
            scheduler.expireLease(offerId.getValue());
        }

        @Override
        public void statusUpdate(SchedulerDriver driver, Protos.TaskStatus status) {
            System.out.println("Task Update: " + status.getTaskId().getValue() + " in state " + status.getState());
            switch (status.getState()) {
                case TASK_FAILED:
                case TASK_LOST:
                case TASK_FINISHED:
                    onTaskComplete.call(status.getTaskId().getValue());
                    scheduler.getTaskUnAssigner().call(status.getTaskId().getValue(), launchedTasks.get(status.getTaskId().getValue()));
                    break;
            }
        }

        @Override
        public void frameworkMessage(SchedulerDriver driver, Protos.ExecutorID executorId, Protos.SlaveID slaveId, byte[] data) {}

        @Override
        public void disconnected(SchedulerDriver driver) {}

        @Override
        public void slaveLost(SchedulerDriver driver, Protos.SlaveID slaveId) {}

        @Override
        public void executorLost(SchedulerDriver driver, Protos.ExecutorID executorId, Protos.SlaveID slaveId, int status) {
            System.out.println("Executor " + executorId.getValue() + " lost, status=" + status);
        }

        @Override
        public void error(SchedulerDriver driver, String message) {}
    }

    private static class VMLeaseObject implements VirtualMachineLease {
        private Protos.Offer offer;
        private double cpuCores;
        private double memoryMB;
        private double networkMbps=0.0;
        private double diskMB;
        private String hostname;
        private String vmID;
        private List portRanges;
        private Map attributeMap;
        private long offeredTime;
        VMLeaseObject(Protos.Offer offer) {
            this.offer = offer;
            hostname = offer.getHostname();
            this.vmID = offer.getSlaveId().getValue();
            offeredTime = System.currentTimeMillis();
            // parse out resources from offer
            // expects network bandwidth to come in as consumable scalar resource named "network"
            for (Protos.Resource resource : offer.getResourcesList()) {
                if ("cpus".equals(resource.getName())) {
                    cpuCores = resource.getScalar().getValue();
                } else if ("mem".equals(resource.getName())) {
                    memoryMB = resource.getScalar().getValue();
                } else if("network".equals(resource.getName())) {
                    networkMbps = resource.getScalar().getValue();
                } else if ("disk".equals(resource.getName())) {
                    diskMB = resource.getScalar().getValue();
                } else if ("ports".equals(resource.getName())) {
                    portRanges = new ArrayList<>();
                    for (Protos.Value.Range range : resource.getRanges().getRangeList()) {
                        portRanges.add(new Range((int)range.getBegin(), (int) range.getEnd()));
                    }
                }
            }
            attributeMap = new HashMap<>();
            if(offer.getAttributesCount()>0) {
                for(Protos.Attribute attribute: offer.getAttributesList()) {
                    attributeMap.put(attribute.getName(), attribute);
                }
            }
        }
        @Override
        public String hostname() {
            return hostname;
        }
        @Override
        public String getVMID() {
            return vmID;
        }
        @Override
        public double cpuCores() {
            return cpuCores;
        }
        @Override
        public double memoryMB() {
            return memoryMB;
        }
        @Override
        public double networkMbps() {
            return networkMbps;
        }
        @Override
        public double diskMB() {
            return diskMB;
        }
        public Protos.Offer getOffer(){
            return offer;
        }
        @Override
        public String getId() {
            return offer.getId().getValue();
        }
        @Override
        public long getOfferedTime() {
            return offeredTime;
        }
        @Override
        public List portRanges() {
            return portRanges;
        }
        @Override
        public Map getAttributeMap() {
            return attributeMap;
        }
    }

    private final BlockingQueue taskQueue;
    private final BlockingQueue leasesQueue;
    private final Map launchedTasks;
    private final TaskScheduler scheduler;
    private final MesosSchedulerDriver mesosSchedulerDriver;
    private final AtomicReference ref = new AtomicReference<>();
    private final Map pendingTasksMap = new HashMap<>();
    private final Action1 onTaskComplete;
    private final Func1 taskCmdGetter;
    private final AtomicBoolean isShutdown = new AtomicBoolean(false);

    public SampleFramework(BlockingQueue taskQueue, String mesosMaster, Action1 onTaskComplete,
                           Func1 taskCmdGetter) {
        this.taskQueue = taskQueue;
        this.leasesQueue = new LinkedBlockingQueue<>();
        this.onTaskComplete = onTaskComplete;
        this.taskCmdGetter = taskCmdGetter;
        launchedTasks = new HashMap<>();
        scheduler = new TaskScheduler.Builder()
                .withLeaseOfferExpirySecs(1000000000)
                .withLeaseRejectAction(new Action1() {
                    @Override
                    public void call(VirtualMachineLease lease) {
                        System.out.println("Declining offer on " + lease.hostname());
                        ref.get().declineOffer(lease.getOffer().getId());
                    }
                })
                .build();
        Protos.FrameworkInfo framework = Protos.FrameworkInfo.newBuilder()
                .setName("Sample Fenzo Framework")
                .setUser("")
                .build();
        Scheduler mesosScheduler = new MesosScheduler();
        mesosSchedulerDriver = new MesosSchedulerDriver(mesosScheduler, framework, mesosMaster);
        ref.set(mesosSchedulerDriver);
        new Thread() {
            public void run() {
                mesosSchedulerDriver.run();
            }
        }.start();
    }

    public void shutdown() {
        System.out.println("Stopping down mesos driver");
        Protos.Status status = mesosSchedulerDriver.stop();
        isShutdown.set(true);
    }

    public void start() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                runAll();
            }
        }).start();
    }

    void runAll() {
        System.out.println("Running all");
        List newLeases = new ArrayList<>();
        while(true) {
            if(isShutdown.get())
                return;
            newLeases.clear();
            List newTaskRequests = new ArrayList<>();
            System.out.println("#Pending tasks: " + pendingTasksMap.size());
            TaskRequest taskRequest=null;
            try {
                taskRequest = pendingTasksMap.size()==0?
                        taskQueue.poll(5, TimeUnit.SECONDS) :
                        taskQueue.poll(1, TimeUnit.MILLISECONDS);
            }
            catch (InterruptedException ie) {
                System.err.println("Error polling task queue: " + ie.getMessage());
            }
            if(taskRequest!=null) {
                taskQueue.drainTo(newTaskRequests);
                newTaskRequests.add(0, taskRequest);
                for(TaskRequest request: newTaskRequests)
                    pendingTasksMap.put(request.getId(), request);
            }
            leasesQueue.drainTo(newLeases);
            SchedulingResult schedulingResult = scheduler.scheduleOnce(new ArrayList<>(pendingTasksMap.values()), newLeases);
            System.out.println("result=" + schedulingResult);
            Map resultMap = schedulingResult.getResultMap();
            if(!resultMap.isEmpty()) {
                for(VMAssignmentResult result: resultMap.values()) {
                    List leasesUsed = result.getLeasesUsed();
                    List taskInfos = new ArrayList<>();
                    StringBuilder stringBuilder = new StringBuilder("Launching on VM " + leasesUsed.get(0).hostname() + " tasks ");
                    for(TaskAssignmentResult t: result.getTasksAssigned()) {
                        stringBuilder.append(t.getTaskId()).append(", ");
                        taskInfos.add(getTaskInfo(leasesUsed, t.getTaskId()));
                        pendingTasksMap.remove(t.getTaskId());
                        launchedTasks.put(t.getTaskId(), leasesUsed.get(0).hostname());
                        scheduler.getTaskAssigner().call(t.getRequest(), leasesUsed.get(0).hostname());
                    }
                    List offerIDs = new ArrayList<>();
                    for(VirtualMachineLease l: leasesUsed)
                        offerIDs.add(l.getOffer().getId());
                    System.out.println(stringBuilder.toString());
                    mesosSchedulerDriver.launchTasks(offerIDs, taskInfos);
                }
            }
            // sleep a bit before looping for new tasks to launch
            try{Thread.sleep(100);}catch(InterruptedException ie){}
        }
    }
    private Protos.TaskInfo getTaskInfo(List leasesUsed, final String taskId) {
        Protos.TaskID pTaskId = Protos.TaskID.newBuilder()
                .setValue(taskId).build();
        return Protos.TaskInfo.newBuilder()
                .setName("task " + pTaskId.getValue())
                .setTaskId(pTaskId)
                .setSlaveId(leasesUsed.get(0).getOffer().getSlaveId())
                .addResources(Protos.Resource.newBuilder()
                        .setName("cpus")
                        .setType(Protos.Value.Type.SCALAR)
                        .setScalar(Protos.Value.Scalar.newBuilder().setValue(1)))
                .addResources(Protos.Resource.newBuilder()
                        .setName("mem")
                        .setType(Protos.Value.Type.SCALAR)
                        .setScalar(Protos.Value.Scalar.newBuilder().setValue(128)))
                .setCommand(Protos.CommandInfo.newBuilder().setValue(taskCmdGetter.call(taskId)).build())
                .build();
    }

}




© 2015 - 2025 Weber Informatics LLC | Privacy Policy