Project

General

Profile

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