193 lines
8.2 KiB
Python
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)
|