Files
heat/heat/scaling/cooldown.py
T
Hervé Beraud 9bc5c23885 Remove six and python 2.7 full support
Six is in use to help us to keep support for python 2.7.
Since the ussuri cycle we decide to remove the python 2.7
support so we can go ahead and also remove six usage from
the python code.

Review process and help
-----------------------
Removing six introduce a lot of changes and an huge amount of modified files
To simplify reviews we decided to split changes into several patches to avoid
painful reviews and avoid mistakes.

To review this patch you can use the six documentation [1] to obtain help and
understand choices.

Additional informations
-----------------------
Changes related to 'six.b(data)' [2]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

six.b [2] encode the given datas in latin-1 in python3 so I did the same
things in this patch.

Latin-1 is equal to iso-8859-1 [3].

This encoding is the default encoding [4] of certain descriptive HTTP
headers.

I suggest to keep latin-1 for the moment and to move to another encoding
in a follow-up patch if needed to move to most powerful encoding (utf8).

HTML4 support utf8 charset and utf8 is the default charset for HTML5 [5].

Note that this commit message is autogenerated and not necesserly contains
changes related to 'six.b'

[1] https://six.readthedocs.io/
[2] https://six.readthedocs.io/#six.b
[3] https://docs.python.org/3/library/codecs.html#standard-encodings
[4] https://www.w3schools.com/charsets/ref_html_8859.asp
[5] https://www.w3schools.com/html/html_charset.asp

Patch 14 of a serie of 28 patches

Change-Id: Iccb743056c631f2e0728013942d764cd8b1ecfe0
2020-04-23 14:49:12 +02:00

107 lines
4.3 KiB
Python

#
# 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.
import datetime
from heat.common import exception
from heat.common.i18n import _
from heat.engine import resource
from oslo_log import log as logging
from oslo_utils import timeutils
LOG = logging.getLogger(__name__)
class CooldownMixin(object):
"""Utility class to encapsulate Cooldown related logic.
This logic includes both cooldown timestamp comparing and scaling in
progress checking.
"""
def _sanitize_cooldown(self, cooldown):
if cooldown is None:
return 0
return max(0, cooldown)
def _check_scaling_allowed(self, cooldown):
metadata = self.metadata_get()
if metadata.get('scaling_in_progress'):
LOG.info("Can not perform scaling action: resource %s "
"is already in scaling.", self.name)
reason = _('due to scaling activity')
raise resource.NoActionRequired(res_name=self.name,
reason=reason)
cooldown = self._sanitize_cooldown(cooldown)
# if both cooldown and cooldown_end not in metadata
if all(k not in metadata for k in ('cooldown', 'cooldown_end')):
# Note: this is for supporting old version cooldown checking
metadata.pop('scaling_in_progress', None)
if metadata and cooldown != 0:
last_adjust = next(iter(metadata.keys()))
if not timeutils.is_older_than(last_adjust, cooldown):
self._log_and_raise_no_action(cooldown)
elif 'cooldown_end' in metadata:
cooldown_end = next(iter(metadata['cooldown_end'].keys()))
now = timeutils.utcnow().isoformat()
if now < cooldown_end:
self._log_and_raise_no_action(cooldown)
elif cooldown != 0:
# Note: this is also for supporting old version cooldown checking
last_adjust = next(iter(metadata['cooldown'].keys()))
if not timeutils.is_older_than(last_adjust, cooldown):
self._log_and_raise_no_action(cooldown)
# Assumes _finished_scaling is called
# after the scaling operation completes
metadata['scaling_in_progress'] = True
self.metadata_set(metadata)
def _log_and_raise_no_action(self, cooldown):
LOG.info("Can not perform scaling action: "
"resource %(name)s is in cooldown (%(cooldown)s).",
{'name': self.name,
'cooldown': cooldown})
reason = _('due to cooldown, '
'cooldown %s') % cooldown
raise resource.NoActionRequired(
res_name=self.name, reason=reason)
def _finished_scaling(self, cooldown,
cooldown_reason, size_changed=True):
# If we wanted to implement the AutoScaling API like AWS does,
# we could maintain event history here, but since we only need
# the latest event for cooldown, just store that for now
metadata = self.metadata_get()
if size_changed:
cooldown = self._sanitize_cooldown(cooldown)
cooldown_end = (timeutils.utcnow() + datetime.timedelta(
seconds=cooldown)).isoformat()
if 'cooldown_end' in metadata:
cooldown_end = max(
next(iter(metadata['cooldown_end'].keys())),
cooldown_end)
metadata['cooldown_end'] = {cooldown_end: cooldown_reason}
metadata['scaling_in_progress'] = False
try:
self.metadata_set(metadata)
except exception.NotFound:
pass
def handle_metadata_reset(self):
metadata = self.metadata_get()
if 'scaling_in_progress' in metadata:
metadata['scaling_in_progress'] = False
self.metadata_set(metadata)