Project

General

Profile

root / trunk / src / haizea / core / frontends / opennebula.py @ 632

1
# -------------------------------------------------------------------------- #
2
# Copyright 2006-2008, University of Chicago                                 #
3
# Copyright 2008, 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.core.scheduler.slottable import ResourceTuple
23
from haizea.common.utils import UNIX2DateTime, round_datetime, get_config, get_clock
24
from haizea.common.opennebula_xmlrpc import OpenNebulaXMLRPCClient, OpenNebulaVM
25
from mx.DateTime import DateTimeDelta, TimeDelta, ISO
26

    
27
import operator
28
import logging
29

    
30
one_rpc = None
31

    
32
def get_one_xmlrpcclient():
33
    global one_rpc
34
    if one_rpc == None:
35
        host = get_config().get("one.host")
36
        port = get_config().get("one.port")
37
        user, passw = OpenNebulaXMLRPCClient.get_userpass_from_env()
38
        one_rpc = OpenNebulaXMLRPCClient(host, port, user, passw)
39
    return one_rpc
40

    
41
class OpenNebulaHaizeaVM(object):
42
    HAIZEA_PARAM = "HAIZEA"
43
    HAIZEA_START = "START"
44
    HAIZEA_START_NOW = "now"
45
    HAIZEA_START_BESTEFFORT = "best_effort"
46
    HAIZEA_DURATION = "DURATION"
47
    HAIZEA_DURATION_UNLIMITED = "unlimited"
48
    HAIZEA_PREEMPTIBLE = "PREEMPTIBLE"
49
    HAIZEA_PREEMPTIBLE_YES = "yes"
50
    HAIZEA_PREEMPTIBLE_NO = "no"
51
    HAIZEA_GROUP = "GROUP"
52
  
53
    
54
    def __init__(self, opennebula_vm):                        
55
        # If there is no HAIZEA parameter, the default is to treat the
56
        # request as an immediate request with unlimited duration
57
        if not opennebula_vm.template.has_key(OpenNebulaHaizeaVM.HAIZEA_PARAM):
58
            self.start = OpenNebulaHaizeaVM.HAIZEA_START_NOW
59
            self.duration = OpenNebulaHaizeaVM.HAIZEA_DURATION_UNLIMITED
60
            self.preemptible = OpenNebulaHaizeaVM.HAIZEA_PREEMPTIBLE_NO
61
            self.group = None
62
        else:
63
            self.start = opennebula_vm.template[OpenNebulaHaizeaVM.HAIZEA_PARAM][OpenNebulaHaizeaVM.HAIZEA_START]
64
            self.duration = opennebula_vm.template[OpenNebulaHaizeaVM.HAIZEA_PARAM][OpenNebulaHaizeaVM.HAIZEA_DURATION]
65
            self.preemptible = opennebula_vm.template[OpenNebulaHaizeaVM.HAIZEA_PARAM][OpenNebulaHaizeaVM.HAIZEA_PREEMPTIBLE]
66
            if opennebula_vm.template[OpenNebulaHaizeaVM.HAIZEA_PARAM].has_key(OpenNebulaHaizeaVM.HAIZEA_GROUP):
67
                self.group = opennebula_vm.template[OpenNebulaHaizeaVM.HAIZEA_PARAM][OpenNebulaHaizeaVM.HAIZEA_GROUP]
68
            else:
69
                self.group = None
70
                
71
        self.submit_time = UNIX2DateTime(opennebula_vm.stime)
72
                
73
        # Create Timestamp object
74
        if self.start == OpenNebulaHaizeaVM.HAIZEA_START_NOW:
75
            self.start = Timestamp(Timestamp.NOW)
76
        elif self.start == OpenNebulaHaizeaVM.HAIZEA_START_BESTEFFORT:
77
            self.start = Timestamp(Timestamp.UNSPECIFIED)
78
        elif self.start[0] == "+":
79
            # Relative time
80
            self.start = Timestamp(round_datetime(self.submit_time + ISO.ParseTime(self.start[1:])))
81
        else:
82
            self.start = Timestamp(ISO.ParseDateTime(self.start))
83
            
84
        # Create Duration object
85
        if self.duration == OpenNebulaHaizeaVM.HAIZEA_DURATION_UNLIMITED:
86
            # This is an interim solution (make it run for a century).
87
            # TODO: Integrate concept of unlimited duration in the lease datastruct
88
            self.duration = Duration(DateTimeDelta(36500))
89
        else:
90
            self.duration = Duration(ISO.ParseTimeDelta(self.duration))
91
            
92

    
93
        self.preemptible = (self.preemptible == OpenNebulaHaizeaVM.HAIZEA_PREEMPTIBLE_YES)
94

    
95
    
96
        self.capacity = Capacity([constants.RES_CPU, constants.RES_MEM, constants.RES_DISK])
97
        
98
        # CPU
99
        # CPUs in VMs are not reported the same as in hosts.
100
        # THere are two template values: CPU and VCPU.
101
        # CPU reports the percentage of the CPU needed by the VM.
102
        # VCPU, which is optional, reports how many CPUs are needed.
103
        cpu = int(float(opennebula_vm.template["CPU"]) * 100)
104
        if opennebula_vm.template.has_key("VCPU"):
105
            ncpu = int(opennebula_vm.template["VCPU"])
106
        else:
107
            ncpu = 1
108
        self.capacity.set_ninstances(constants.RES_CPU, ncpu)
109
        for i in range(ncpu):
110
            self.capacity.set_quantity_instance(constants.RES_CPU, i+1, cpu)            
111
        
112
        # Memory. Unlike hosts, memory is reported directly in MBs
113
        self.capacity.set_quantity(constants.RES_MEM, int(opennebula_vm.template["MEMORY"]))
114

    
115
        self.one_id = opennebula_vm.id
116
        
117
    
118
class OpenNebulaFrontend(RequestFrontend):    
119
    
120
    def __init__(self, manager):
121
        self.manager = manager
122
        self.processed = []
123
        self.logger = logging.getLogger("ONEREQ")
124
        self.rpc = get_one_xmlrpcclient()
125

    
126
        
127
    def get_accumulated_requests(self):
128
        vms = self.rpc.vmpool_info()
129

    
130
        # Extract the pending OpenNebula VMs
131
        pending_vms = [] 
132
        for vm in vms:
133
            if not vm.id  in self.processed and vm.state == OpenNebulaVM.STATE_PENDING:
134
                vm_detailed = self.rpc.vm_info(vm.id)        
135
                pending_vms.append(OpenNebulaHaizeaVM(vm_detailed))
136
                self.processed.append(vm.id)
137
            
138
        grouped = [vm for vm in pending_vms if vm.group != None]
139
        not_grouped = [vm for vm in pending_vms if vm.group == None]
140
        
141
        # Extract VM groups
142
        group_ids = set([vm.group for vm in grouped])
143
        groups = {}
144
        for group_id in group_ids:
145
            groups[group_id] = [vm for vm in grouped if vm.group == group_id]
146
            
147
        lease_requests = []
148
        for group_id, opennebula_vms in groups.items():
149
            lease_requests.append(self.__ONEreqs_to_lease(opennebula_vms, group_id))
150

    
151
        for opennebula_vm in not_grouped:
152
            lease_requests.append(self.__ONEreqs_to_lease([opennebula_vm]))
153
        
154
        lease_requests.sort(key=operator.attrgetter("submit_time"))
155
        return lease_requests
156

    
157
    def exists_more_requests(self):
158
        return True
159

    
160
    
161
    def __ONEreqs_to_lease(self, opennebula_vms, group_id=None):
162
        # The vm_with_params is used to extract the HAIZEA parameters.
163
        # (i.e., lease-wide attributes)
164
        vm_with_params = opennebula_vms[0]
165

    
166
        # Per-lease attributes
167
        start = vm_with_params.start
168
        duration = vm_with_params.duration
169
        preemptible = vm_with_params.preemptible
170
        submit_time = vm_with_params.submit_time
171

    
172
        # Per-vnode attributes
173
        requested_resources = dict([(i+1,vm.capacity) for i, vm in enumerate(opennebula_vms)])
174

    
175
        lease = Lease.create_new(submit_time = submit_time, 
176
                                 requested_resources = requested_resources, 
177
                                 start = start, 
178
                                 duration = duration, 
179
                                 deadline = None,
180
                                 preemptible = preemptible, 
181
                                 software = UnmanagedSoftwareEnvironment())
182
     
183
        lease.enactment_info = group_id
184
        lease.vnode_enactment_info = dict([(i+1,vm.one_id) for i, vm in enumerate(opennebula_vms)])
185
        return lease
186