root / branches / 1.1 / src / haizea / core / frontends / opennebula.py @ 843
1 |
# -------------------------------------------------------------------------- #
|
---|---|
2 |
# Copyright 2006-2009, University of Chicago #
|
3 |
# Copyright 2008-2009, Distributed Systems Architecture Group, Universidad #
|
4 |
# Complutense de Madrid (dsa-research.org) #
|
5 |
# #
|
6 |
# Licensed under the Apache License, Version 2.0 (the "License"); you may #
|
7 |
# not use this file except in compliance with the License. You may obtain #
|
8 |
# a copy of the License at #
|
9 |
# #
|
10 |
# http://www.apache.org/licenses/LICENSE-2.0 #
|
11 |
# #
|
12 |
# Unless required by applicable law or agreed to in writing, software #
|
13 |
# distributed under the License is distributed on an "AS IS" BASIS, #
|
14 |
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. #
|
15 |
# See the License for the specific language governing permissions and #
|
16 |
# limitations under the License. #
|
17 |
# -------------------------------------------------------------------------- #
|
18 |
|
19 |
import haizea.common.constants as constants |
20 |
from haizea.core.leases import Lease, Capacity, Timestamp, Duration, UnmanagedSoftwareEnvironment |
21 |
from haizea.core.frontends import RequestFrontend |
22 |
from haizea.common.utils import UNIX2DateTime, round_datetime, get_config, OpenNebulaXMLRPCClientSingleton |
23 |
from haizea.common.opennebula_xmlrpc import OpenNebulaVM |
24 |
from mx.DateTime import DateTimeDelta, Parser |
25 |
|
26 |
import operator |
27 |
import logging |
28 |
|
29 |
class OpenNebulaHaizeaVM(object): |
30 |
HAIZEA_PARAM = "HAIZEA"
|
31 |
HAIZEA_START = "START"
|
32 |
HAIZEA_START_NOW = "now"
|
33 |
HAIZEA_START_BESTEFFORT = "best_effort"
|
34 |
HAIZEA_DURATION = "DURATION"
|
35 |
HAIZEA_DURATION_UNLIMITED = "unlimited"
|
36 |
HAIZEA_PREEMPTIBLE = "PREEMPTIBLE"
|
37 |
HAIZEA_PREEMPTIBLE_YES = "yes"
|
38 |
HAIZEA_PREEMPTIBLE_NO = "no"
|
39 |
HAIZEA_GROUP = "GROUP"
|
40 |
|
41 |
|
42 |
def __init__(self, opennebula_vm): |
43 |
# If there is no HAIZEA parameter, the default is to treat the
|
44 |
# request as an immediate request with unlimited duration
|
45 |
if not opennebula_vm.template.has_key(OpenNebulaHaizeaVM.HAIZEA_PARAM): |
46 |
self.start = OpenNebulaHaizeaVM.HAIZEA_START_NOW
|
47 |
self.duration = OpenNebulaHaizeaVM.HAIZEA_DURATION_UNLIMITED
|
48 |
self.preemptible = OpenNebulaHaizeaVM.HAIZEA_PREEMPTIBLE_NO
|
49 |
self.group = None |
50 |
else:
|
51 |
self.start = opennebula_vm.template[OpenNebulaHaizeaVM.HAIZEA_PARAM][OpenNebulaHaizeaVM.HAIZEA_START]
|
52 |
self.duration = opennebula_vm.template[OpenNebulaHaizeaVM.HAIZEA_PARAM][OpenNebulaHaizeaVM.HAIZEA_DURATION]
|
53 |
self.preemptible = opennebula_vm.template[OpenNebulaHaizeaVM.HAIZEA_PARAM][OpenNebulaHaizeaVM.HAIZEA_PREEMPTIBLE]
|
54 |
if opennebula_vm.template[OpenNebulaHaizeaVM.HAIZEA_PARAM].has_key(OpenNebulaHaizeaVM.HAIZEA_GROUP):
|
55 |
self.group = opennebula_vm.template[OpenNebulaHaizeaVM.HAIZEA_PARAM][OpenNebulaHaizeaVM.HAIZEA_GROUP]
|
56 |
else:
|
57 |
self.group = None |
58 |
|
59 |
self.submit_time = UNIX2DateTime(opennebula_vm.stime)
|
60 |
|
61 |
# Create Timestamp object
|
62 |
if self.start == OpenNebulaHaizeaVM.HAIZEA_START_NOW: |
63 |
self.start = Timestamp(Timestamp.NOW)
|
64 |
elif self.start == OpenNebulaHaizeaVM.HAIZEA_START_BESTEFFORT: |
65 |
self.start = Timestamp(Timestamp.UNSPECIFIED)
|
66 |
elif self.start[0] == "+": |
67 |
# Relative time
|
68 |
self.start = Timestamp(round_datetime(self.submit_time + Parser.TimeDeltaFromString(self.start[1:]))) |
69 |
else:
|
70 |
self.start = Timestamp(Parser.TimeDeltaFromString(self.start)) |
71 |
|
72 |
# Create Duration object
|
73 |
if self.duration == OpenNebulaHaizeaVM.HAIZEA_DURATION_UNLIMITED: |
74 |
# This is an interim solution (make it run for a century).
|
75 |
# TODO: Integrate concept of unlimited duration in the lease datastruct
|
76 |
self.duration = Duration(DateTimeDelta(36500)) |
77 |
else:
|
78 |
self.duration = Duration(Parser.TimeDeltaFromString(self.duration)) |
79 |
|
80 |
|
81 |
self.preemptible = (self.preemptible == OpenNebulaHaizeaVM.HAIZEA_PREEMPTIBLE_YES) |
82 |
|
83 |
|
84 |
self.capacity = Capacity([constants.RES_CPU, constants.RES_MEM, constants.RES_DISK])
|
85 |
|
86 |
# CPU
|
87 |
# CPUs in VMs are not reported the same as in hosts.
|
88 |
# THere are two template values: CPU and VCPU.
|
89 |
# CPU reports the percentage of the CPU needed by the VM.
|
90 |
# VCPU, which is optional, reports how many CPUs are needed.
|
91 |
cpu = int(float(opennebula_vm.template["CPU"]) * 100) |
92 |
if opennebula_vm.template.has_key("VCPU"): |
93 |
ncpu = int(opennebula_vm.template["VCPU"]) |
94 |
else:
|
95 |
ncpu = 1
|
96 |
self.capacity.set_ninstances(constants.RES_CPU, ncpu)
|
97 |
for i in range(ncpu): |
98 |
self.capacity.set_quantity_instance(constants.RES_CPU, i+1, cpu) |
99 |
|
100 |
# Memory. Unlike hosts, memory is reported directly in MBs
|
101 |
self.capacity.set_quantity(constants.RES_MEM, int(opennebula_vm.template["MEMORY"])) |
102 |
|
103 |
self.one_id = opennebula_vm.id
|
104 |
|
105 |
|
106 |
class OpenNebulaFrontend(RequestFrontend): |
107 |
|
108 |
def __init__(self): |
109 |
self.processed = []
|
110 |
self.logger = logging.getLogger("ONEREQ") |
111 |
self.rpc = OpenNebulaXMLRPCClientSingleton().client
|
112 |
|
113 |
def load(self, manager): |
114 |
pass
|
115 |
|
116 |
def get_accumulated_requests(self): |
117 |
vms = self.rpc.vmpool_info()
|
118 |
|
119 |
# Extract the pending OpenNebula VMs
|
120 |
pending_vms = [] |
121 |
for vm in vms: |
122 |
if not vm.id in self.processed and vm.state == OpenNebulaVM.STATE_PENDING: |
123 |
vm_detailed = self.rpc.vm_info(vm.id)
|
124 |
pending_vms.append(OpenNebulaHaizeaVM(vm_detailed)) |
125 |
self.processed.append(vm.id)
|
126 |
|
127 |
grouped = [vm for vm in pending_vms if vm.group != None] |
128 |
not_grouped = [vm for vm in pending_vms if vm.group == None] |
129 |
|
130 |
# Extract VM groups
|
131 |
group_ids = set([vm.group for vm in grouped]) |
132 |
groups = {} |
133 |
for group_id in group_ids: |
134 |
groups[group_id] = [vm for vm in grouped if vm.group == group_id] |
135 |
|
136 |
lease_requests = [] |
137 |
for group_id, opennebula_vms in groups.items(): |
138 |
lease_requests.append(self.__ONEreqs_to_lease(opennebula_vms, group_id))
|
139 |
|
140 |
for opennebula_vm in not_grouped: |
141 |
lease_requests.append(self.__ONEreqs_to_lease([opennebula_vm]))
|
142 |
|
143 |
lease_requests.sort(key=operator.attrgetter("submit_time"))
|
144 |
return lease_requests
|
145 |
|
146 |
def exists_more_requests(self): |
147 |
return True |
148 |
|
149 |
|
150 |
def __ONEreqs_to_lease(self, opennebula_vms, group_id=None): |
151 |
# The vm_with_params is used to extract the HAIZEA parameters.
|
152 |
# (i.e., lease-wide attributes)
|
153 |
vm_with_params = opennebula_vms[0]
|
154 |
|
155 |
# Per-lease attributes
|
156 |
start = vm_with_params.start |
157 |
duration = vm_with_params.duration |
158 |
preemptible = vm_with_params.preemptible |
159 |
submit_time = vm_with_params.submit_time |
160 |
|
161 |
# Per-vnode attributes
|
162 |
requested_resources = dict([(i+1,vm.capacity) for i, vm in enumerate(opennebula_vms)]) |
163 |
|
164 |
lease = Lease.create_new(submit_time = submit_time, |
165 |
user_id = None, # TODO |
166 |
requested_resources = requested_resources, |
167 |
start = start, |
168 |
duration = duration, |
169 |
deadline = None,
|
170 |
preemptible = preemptible, |
171 |
software = UnmanagedSoftwareEnvironment()) |
172 |
|
173 |
lease.enactment_info = group_id |
174 |
lease.vnode_enactment_info = dict([(i+1,vm.one_id) for i, vm in enumerate(opennebula_vms)]) |
175 |
return lease
|
176 |
|