karbor/karbor/services/operationengine/operations/retention_operation.py

193 lines
8.2 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.
from datetime import datetime
from oslo_utils import uuidutils
from karbor.common import constants
from karbor import context
from karbor import exception
from karbor.i18n import _
from karbor import objects
from karbor.services.operationengine.operations import base
class RetentionProtectOperation(base.Operation):
"""Protect operation."""
OPERATION_TYPE = "retention_protect"
def check_operation_definition(self, operation_definition):
provider_id = operation_definition.get("provider_id")
if not provider_id or not uuidutils.is_uuid_like(provider_id):
reason = _("Provider_id is invalid")
raise exception.InvalidOperationDefinition(reason=reason)
plan_id = operation_definition.get("plan_id")
if not plan_id or not uuidutils.is_uuid_like(plan_id):
reason = _("Plan_id is invalid")
raise exception.InvalidOperationDefinition(reason=reason)
plan = objects.Plan.get_by_id(context.get_admin_context(), plan_id)
if provider_id != plan.provider_id:
reason = _("Provider_id is conflict")
raise exception.InvalidOperationDefinition(reason=reason)
def _execute(self, operation_definition, param):
log_ref = self._create_operation_log(param)
self._run(operation_definition, param, log_ref)
def _resume(self, operation_definition, param, log_ref):
self._run(operation_definition, param, log_ref)
def _run(self, operation_definition, param, log_ref):
project_id = param.get("project_id")
client = self._create_karbor_client(
param.get("user_id"), project_id)
provider_id = operation_definition.get("provider_id")
plan_id = operation_definition.get("plan_id")
trigger_id = param.get("trigger_id", None)
scheduled_operation_id = param.get("scheduled_operation_id", None)
extra_info = {
'created_by': constants.OPERATION_ENGINE,
'trigger_id': trigger_id,
'scheduled_operation_id': scheduled_operation_id
}
try:
client.checkpoints.create(provider_id, plan_id, extra_info)
except Exception:
state = constants.OPERATION_EXE_STATE_FAILED
else:
state = constants.OPERATION_EXE_STATE_SUCCESS
finally:
self._update_log_when_operation_finished(log_ref, state)
try:
max_backups = int(operation_definition.get("max_backups", -1))
max_backups = -1 if max_backups <= 0 else max_backups
except Exception:
state = constants.OPERATION_GET_MAX_BACKUP_STATE_FAILED
self._update_log_when_operation_finished(log_ref, state)
reason = _("Failed to get max_backups")
raise exception.InvalidOperationDefinition(reason=reason)
try:
retention_duration = int(operation_definition.get(
"retention_duration", -1))
retention_duration = -1 if retention_duration <= 0\
else retention_duration
except Exception:
state = constants.OPERATION_GET_DURATION_STATE_FAILED
self._update_log_when_operation_finished(log_ref, state)
reason = _("Failed to get retention_duration")
raise exception.InvalidOperationDefinition(reason=reason)
try:
self._delete_old_backup_by_max_backups(
client, max_backups, project_id, provider_id, plan_id)
state = constants.OPERATION_EXE_MAX_BACKUP_STATE_SUCCESS
except Exception:
state = constants.OPERATION_EXE_MAX_BACKUP_STATE_FAILED
reason = (_("Can't execute retention policy provider_id: "
"%(provider_id)s plan_id:%(plan_id)s"
" max_backups:%(max_backups)s") %
{"provider_id": provider_id, "plan_id": plan_id,
"max_backups": max_backups})
raise exception.InvalidOperationDefinition(reason=reason)
finally:
self._update_log_when_operation_finished(log_ref, state)
try:
self._delete_old_backup_by_duration(
client, retention_duration, project_id, provider_id, plan_id)
state = constants.OPERATION_EXE_DURATION_STATE_SUCCESS
except Exception:
state = constants.OPERATION_EXE_DURATION_STATE_FAILED
reason = (_("Can't execute retention policy provider_id: "
"%(provider_id)s plan_id:%(plan_id)s"
" retention_duration:%(retention_duration)s") %
{"provider_id": provider_id, "plan_id": plan_id,
"retention_duration": retention_duration})
raise exception.InvalidOperationDefinition(reason=reason)
finally:
self._update_log_when_operation_finished(log_ref, state)
@staticmethod
def _list_available_checkpoint(client, project_id,
provider_id, plan_id):
search_opts = {'project_id': project_id,
'plan_id': plan_id,
"status": constants.CHECKPOINT_STATUS_AVAILABLE
}
sort = {"created_at": "desc"}
try:
checkpoints = client.checkpoints.list(
provider_id=provider_id,
search_opts=search_opts,
limit=None,
sort=sort)
avi_check = [x for x in checkpoints if x.status ==
constants.CHECKPOINT_STATUS_AVAILABLE]
except Exception as e:
reason = (_("Failed to list checkpoint by %(provider_id)s"
"and %(plan_id)s reason: %(reason)s") %
{"provider_id": provider_id,
"plan_id": plan_id, "reason": e})
raise exception.InvalidOperationDefinition(reason=reason)
return avi_check
def _delete_old_backup_by_max_backups(
self, client, max_backups, project_id, provider_id, plan_id):
if max_backups == -1:
return
backup_items = self._list_available_checkpoint(
client, project_id, provider_id, plan_id)
count = len(backup_items)
if count > max_backups:
for item in backup_items[max_backups:]:
try:
client.checkpoints.delete(provider_id, item.id)
except Exception as e:
reason = (_("Failed to delete checkpoint: %(cp_id)s by "
"max_backups with the reason: %(reason)s") %
{"cp_id": item.id, "reason": e})
raise exception.InvalidOperationDefinition(reason=reason)
def _delete_old_backup_by_duration(
self, client, retention_duration,
project_id, provider_id, plan_id):
if retention_duration == -1:
return
backup_items = self._list_available_checkpoint(
client, project_id, provider_id, plan_id)
now = datetime.utcnow()
for item in backup_items:
created_at = datetime.strptime(item.created_at, "%Y-%m-%d")
interval = (now - created_at).days
if interval > retention_duration:
try:
client.checkpoints.delete(provider_id, item.id)
except Exception as e:
reason = (_("Failed to delete checkpoint: %(cp_id)s "
"by retention_duration with the reasion: "
"%(reason)s") %
{"cp_id": item.id, "reason": e})
raise exception.InvalidOperationDefinition(reason=reason)