#!/usr/bin/python
# -*- coding: utf-8 -*-
#
# Copyright © 2014-2016 NetApp, Inc. All Rights Reserved.
#
# CONFIDENTIALITY NOTICE: THIS SOFTWARE CONTAINS CONFIDENTIAL INFORMATION OF
# NETAPP, INC. USE, DISCLOSURE OR REPRODUCTION IS PROHIBITED WITHOUT THE PRIOR
# EXPRESS WRITTEN PERMISSION OF NETAPP, INC.
"""Module implements Schedule Simplification conversion logic."""
from solidfire.apiactual import ApiSchedule, ApiScheduleInfo, ApiWeekday, \
ApiGetScheduleResult, ApiListSchedulesResult, ApiModifyScheduleResult
from solidfire.custom.models import Weekday, DaysOfMonthFrequency, \
DaysOfWeekFrequency, TimeIntervalFrequency
from solidfire.models import Schedule, Frequency, ScheduleInfo, GetScheduleResult, ListSchedulesResult, \
CreateScheduleResult, ModifyScheduleResult
import logging
LOG = logging.getLogger('solidfire.Element')
[docs]class ScheduleAdaptor:
"""
This class contains the implementation of the schedule specific adaptor
calls for simplifying Snapshot Scheduling.
"""
[docs] @staticmethod
def get_schedule(element, params, since, deprecated):
"""
Calls to this static method should ONLY originate from the
get_schedule method in the Element class. DO NOT CALL THIS directly.
Documentation here is intentionally brief.
"""
api_result = element.send_request("GetSchedule",
ApiGetScheduleResult, params,
since, deprecated)
return GetScheduleResult(schedule=ScheduleAdaptor.to_schedule(api_result.schedule))
[docs] @staticmethod
def list_schedules(element, params, since, deprecated):
"""
Calls to this static method should ONLY originate from the
list_schedules method in the Element class. DO NOT CALL THIS directly.
Documentation here is intentionally brief.
"""
api_result = element.send_request("ListSchedules",
ApiListSchedulesResult, params,
since, deprecated)
schedules = []
for schedule in api_result.schedules:
schedules.append(ScheduleAdaptor.to_schedule(schedule))
return ListSchedulesResult(schedules=schedules)
[docs] @staticmethod
def modify_schedule(element, params, since, deprecated):
"""
Calls to this static method should ONLY originate from the
modify_schedules method in the Element class. DO NOT CALL THIS
directly. Documentation here is intentionally brief.
"""
if params['schedule'].schedule_id is None:
raise AttributeError("ScheduleID is missing. Cannot modify a "
"schedule without a ScheduleID")
if params['schedule'].frequency is None:
raise AttributeError("Frequency is not present. Make sure the "
"schedule object has a value in the "
"frequency property before attempting to "
"create a Schedule.")
if params['schedule'].schedule_info is None:
raise AttributeError("Schedule_info is not present. Make sure the "
"schedule object has a value in the "
"schedule_info property before attempting to "
"modify a Schedule.")
api_schedule = ScheduleAdaptor.to_api_schedule(params['schedule'])
api_result = element.send_request("ModifySchedule",
ApiModifyScheduleResult, api_schedule.to_json(),
since, deprecated)
if api_result.schedule is not None:
return ModifyScheduleResult(schedule=ScheduleAdaptor.to_schedule(api_result.schedule))
else:
return ModifyScheduleResult()
[docs] @staticmethod
def create_schedule(element, params, since, deprecated):
"""
Calls to this static method should ONLY originate from the
create_schedules method in the Element class. DO NOT CALL THIS
directly. Documentation here is intentionally brief.
"""
if params['schedule'] is None:
raise AttributeError("Please provide a valid schedule object "
"instead of None.")
if params['schedule'].schedule_id is not None:
raise AttributeError("ScheduleID should not be present. Do "
"not specify ScheduleID when creating a "
"Schedule. One will be assigned upon "
"creation.")
if params['schedule'].frequency is None:
raise AttributeError("Frequency is not present. Make sure the "
"schedule object has a value in the "
"frequency property before attempting to "
"create a Schedule.")
if params['schedule'].schedule_info is None:
raise AttributeError("Schedule_info is not present. Make sure the "
"schedule object has a value in the "
"schedule_info property before attempting to "
"modify a Schedule.")
if params["schedule"].frequency.minutes is None:
params.setdefault("frequency", {})["minutes"] = 0
if params["schedule"].frequency.hours is None:
params.setdefault("frequency", {})["hours"] = 0
api_schedule = ScheduleAdaptor.to_api_schedule(params['schedule'])
api_result = element.send_request("CreateSchedule",
CreateScheduleResult,
api_schedule.to_json(),
since, deprecated)
return api_result
[docs] @staticmethod
def to_schedule(api):
"""
Converts an ApiSchedule object into a Schedule object
:param api: the ApiSchedule object to be converted
:type api: solidfire.apiactual.ApiSchedule
:return: solidfire.models.Schedule
"""
schedule_info = ScheduleAdaptor.to_schedule_info(
api.schedule_info)
frequency = None
try:
freq = api.attributes["frequency"]
if freq == "Time Interval":
frequency = TimeIntervalFrequency(
days=int(api.hours/24),
hours=int(api.hours%24),
minutes=api.minutes
)
elif freq == "Days Of Month":
frequency = DaysOfMonthFrequency(
hours=api.hours,
minutes=api.minutes,
monthdays=api.monthdays,
)
elif freq == "Days Of Week":
frequency = DaysOfWeekFrequency(
hours=api.hours,
minutes=api.minutes,
weekdays=ScheduleAdaptor.to_weekdays(api.weekdays),
)
else:
raise Exception("Cannot determine frequency")
except:
LOG.error("Cannot deserialize Schedule {0}. The frequency "
"property has an unknown value.".format(api.schedule_name))
return Schedule(
has_error=api.has_error,
last_run_status=api.last_run_status,
last_run_time_started=api.last_run_time_started,
name=api.schedule_name,
paused=api.paused,
recurring=api.recurring,
run_next_interval=api.run_next_interval,
schedule_id=api.schedule_id,
starting_date=api.starting_date,
to_be_deleted=api.to_be_deleted,
schedule_info=schedule_info,
frequency=frequency
)
[docs] @staticmethod
def to_schedule_info(api):
"""
Convert an ApiScheduleInfo object into a ScheduleInfo object
:param api: the ApiScheduleInfo object
:type api: solidfire.apiactual.ApiScheduleInfo
:return: solidfire.models.ScheduleInfo
"""
volume_ids = []
if api.volume_id is not None:
volume_ids.append(int(api.volume_id))
if api.volumes is not None:
# noinspection PyTypeChecker
volume_ids.extend([int(vol) for vol in api.volumes])
info = ScheduleInfo(
enable_remote_replication=api.enable_remote_replication,
snapshot_name=api.name,
retention=api.retention,
volume_ids=volume_ids
)
return info
[docs] @staticmethod
def to_weekdays(api):
"""
Converts an ApiWeekday object array into a Weekday object array
:param api: array of ApiWeekday objects
:type api: solidfire.apiactual.ApiWeekday[]
:return: solidfire.custom.models.Weekday[]
"""
weekdays = []
for api_day in api:
weekdays.append(Weekday.from_id(api_day.day))
return weekdays
[docs] @staticmethod
def to_api_schedule(schedule):
"""
Converts a Schedule object into an ApiSchedule object
:param schedule: the Schedule object
:type schedule: Schedule
:return: solidfire.apiactual.ApiSchedule
"""
schedule_info = ScheduleAdaptor \
.to_api_schedule_info(schedule.schedule_info)
frequency = schedule.frequency
attributes = {}
if type(frequency) is TimeIntervalFrequency:
if hasattr(frequency.days, '_member_type') or frequency.days is \
None:
frequency.days = 0
if hasattr(frequency.hours, '_member_type') or frequency.hours is \
None:
frequency.hours = 0
if hasattr(frequency.minutes, '_member_type') or \
frequency.minutes is None:
frequency.minutes = 0
minutes = frequency.minutes
hours = frequency.days * 24 + frequency.hours
attributes["frequency"] = "Time Interval"
weekdays = None
monthdays = None
if type(frequency) is DaysOfMonthFrequency:
minutes = frequency.minutes
hours = frequency.hours
monthdays = frequency.monthdays
weekdays = None
attributes["frequency"] = "Days Of Month"
if type(frequency) is DaysOfWeekFrequency:
minutes = frequency.minutes
hours = frequency.hours
api_weekdays = []
for weekday in frequency.weekdays:
api_weekday = ApiWeekday(day=weekday[1],
offset=1)
api_weekdays.append(api_weekday)
weekdays = api_weekdays
monthdays = None
attributes["frequency"] = "Days Of Week"
api = ApiSchedule(has_error=schedule.has_error,
last_run_status=schedule.last_run_status,
last_run_time_started=schedule.last_run_time_started,
schedule_name=schedule.name,
paused=schedule.paused,
recurring=schedule.recurring,
run_next_interval=schedule.run_next_interval,
schedule_id=schedule.schedule_id,
starting_date=schedule.starting_date,
to_be_deleted=schedule.to_be_deleted,
schedule_type='Snapshot',
attributes=attributes,
minutes=minutes,
hours=hours,
monthdays=monthdays,
weekdays=weekdays,
schedule_info=schedule_info)
return api
[docs] @staticmethod
def to_api_schedule_info(info):
"""
Converts a ScheduleInfo object into an ApiScheduleInfo object
:param info: the ScheduleInfo object
:type info: ScheduleInfo
:return: solidfire.apiactual.ApiScheduleInfo
"""
volumes=None
# noinspection PyTypeChecker
if hasattr(info.volume_ids, '_member_type') or info.volume_ids \
is None or len(info.volume_ids) == 0:
raise AttributeError('ScheduleInfo.VolumeIDs are missing. '
'Cannot create or modify a schedule without at '
'least one VolumeID.')
else:
volumes = info.volume_ids
api = ApiScheduleInfo(enable_remote_replication=info.enable_remote_replication,
name=info.snapshot_name,
retention=info.retention,
volumes=volumes)
return api