1
# Copyright (c) 2012 OpenStack, LLC.
4
# Licensed under the Apache License, Version 2.0 (the "License"); you may
5
# not use this file except in compliance with the License. You may obtain
6
# a copy of the License at
8
# http://www.apache.org/licenses/LICENSE-2.0
10
# Unless required by applicable law or agreed to in writing, software
11
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13
# License for the specific language governing permissions and limitations
17
Claim objects for use with resource tracking.
20
from nova.openstack.common import jsonutils
21
from nova.openstack.common import lockutils
22
from nova.openstack.common import log as logging
24
LOG = logging.getLogger(__name__)
25
COMPUTE_RESOURCE_SEMAPHORE = "compute_resources"
28
class NopClaim(object):
29
"""For use with compute drivers that do not support resource tracking"""
31
def __init__(self, migration=None):
32
self.migration = migration
49
def __exit__(self, exc_type, exc_val, exc_tb):
50
if exc_type is not None:
57
return "[Claim: %d MB memory, %d GB disk, %d VCPUS]" % (self.memory_mb,
58
self.disk_gb, self.vcpus)
61
class Claim(NopClaim):
62
"""A declaration that a compute host operation will require free resources.
63
Claims serve as marker objects that resources are being held until the
64
update_available_resource audit process runs to do a full reconciliation
67
This information will be used to help keep the local compute hosts's
68
ComputeNode model in sync to aid the scheduler in making efficient / more
69
correct decisions with respect to host selection.
72
def __init__(self, instance, tracker):
73
super(Claim, self).__init__()
74
self.instance = jsonutils.to_primitive(instance)
75
self.tracker = tracker
79
return self.instance['root_gb'] + self.instance['ephemeral_gb']
83
return self.instance['memory_mb']
87
return self.instance['vcpus']
89
@lockutils.synchronized(COMPUTE_RESOURCE_SEMAPHORE, 'nova-')
91
"""Compute operation requiring claimed resources has failed or
94
LOG.debug(_("Aborting claim: %s") % self, instance=self.instance)
95
self.tracker.abort_instance_claim(self.instance)
97
def test(self, resources, limits=None):
98
"""Test if this claim can be satisfied given available resources and
99
optional oversubscription limits
101
This should be called before the compute node actually consumes the
102
resources required to execute the claim.
104
:param resources: available local compute node resources
105
:returns: Return true if resources are available to claim.
110
# If an individual limit is None, the resource will be considered
112
memory_mb_limit = limits.get('memory_mb')
113
disk_gb_limit = limits.get('disk_gb')
114
vcpu_limit = limits.get('vcpu')
116
msg = _("Attempting claim: memory %(memory_mb)d MB, disk %(disk_gb)d "
117
"GB, VCPUs %(vcpus)d")
118
params = {'memory_mb': self.memory_mb, 'disk_gb': self.disk_gb,
120
LOG.audit(msg % params, instance=self.instance)
122
# Test for resources:
123
can_claim = (self._test_memory(resources, memory_mb_limit) and
124
self._test_disk(resources, disk_gb_limit) and
125
self._test_cpu(resources, vcpu_limit))
128
LOG.audit(_("Claim successful"), instance=self.instance)
130
LOG.audit(_("Claim failed"), instance=self.instance)
134
def _test_memory(self, resources, limit):
137
total = resources['memory_mb']
138
used = resources['memory_mb_used']
139
requested = self.memory_mb
141
return self._test(type_, unit, total, used, requested, limit)
143
def _test_disk(self, resources, limit):
146
total = resources['local_gb']
147
used = resources['local_gb_used']
148
requested = self.disk_gb
150
return self._test(type_, unit, total, used, requested, limit)
152
def _test_cpu(self, resources, limit):
155
total = resources['vcpus']
156
used = resources['vcpus_used']
157
requested = self.vcpus
159
return self._test(type_, unit, total, used, requested, limit)
161
def _test(self, type_, unit, total, used, requested, limit):
162
"""Test if the given type of resource needed for a claim can be safely
165
msg = _("Total %(type_)s: %(total)d %(unit)s, used: %(used)d %(unit)s")
166
LOG.audit(msg % locals(), instance=self.instance)
169
# treat resource as unlimited:
170
LOG.audit(_("%(type_)s limit not specified, defaulting to "
171
"unlimited") % locals(), instance=self.instance)
176
# Oversubscribed resource policy info:
177
msg = _("%(type_)s limit: %(limit)d %(unit)s, free: %(free)d "
178
"%(unit)s") % locals()
179
LOG.audit(msg, instance=self.instance)
181
can_claim = requested <= free
184
msg = _("Unable to claim resources. Free %(type_)s %(free)d "
185
"%(unit)s < requested %(requested)d %(unit)s") % locals()
186
LOG.info(msg, instance=self.instance)
191
class ResizeClaim(Claim):
192
"""Claim used for holding resources for an incoming resize/migration
195
def __init__(self, instance, instance_type, tracker):
196
super(ResizeClaim, self).__init__(instance, tracker)
197
self.instance_type = instance_type
198
self.migration = None
202
return (self.instance_type['root_gb'] +
203
self.instance_type['ephemeral_gb'])
207
return self.instance_type['memory_mb']
211
return self.instance_type['vcpus']
213
@lockutils.synchronized(COMPUTE_RESOURCE_SEMAPHORE, 'nova-')
215
"""Compute operation requiring claimed resources has failed or
218
LOG.debug(_("Aborting claim: %s") % self, instance=self.instance)
219
self.tracker.abort_resize_claim(self.instance['uuid'],