1#!/usr/bin/python
2# (c) 2017, NetApp, Inc
3# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)
4
5from __future__ import absolute_import, division, print_function
6__metaclass__ = type
7
8
9ANSIBLE_METADATA = {'metadata_version': '1.1',
10                    'status': ['deprecated'],
11                    'supported_by': 'community'}
12
13
14DOCUMENTATION = '''
15
16module: sf_snapshot_schedule_manager
17deprecated:
18  removed_in: "2.11"
19  why: This Module has been replaced
20  alternative: please use M(na_elementsw_snapshot_schedule)
21short_description: Manage SolidFire snapshot schedules
22extends_documentation_fragment:
23    - netapp.solidfire
24version_added: '2.3'
25author: Sumit Kumar (@timuster) <sumit4@netapp.com>
26description:
27- Create, destroy, or update accounts on SolidFire
28
29options:
30
31    state:
32        description:
33        - Whether the specified schedule should exist or not.
34        required: true
35        choices: ['present', 'absent']
36
37    paused:
38        description:
39        - Pause / Resume a schedule.
40        required: false
41
42    recurring:
43        description:
44        - Should the schedule recur?
45        required: false
46
47    time_interval_days:
48        description: Time interval in days.
49        required: false
50        default: 1
51
52    time_interval_hours:
53        description: Time interval in hours.
54        required: false
55        default: 0
56
57    time_interval_minutes:
58        description: Time interval in minutes.
59        required: false
60        default: 0
61
62    name:
63        description:
64        - Name for the snapshot schedule.
65        required: true
66
67    snapshot_name:
68        description:
69        - Name for the created snapshots.
70        required: false
71
72    volumes:
73        description:
74        - Volume IDs that you want to set the snapshot schedule for.
75        - At least 1 volume ID is required for creating a new schedule.
76        - required when C(state=present)
77        required: false
78
79    retention:
80        description:
81        - Retention period for the snapshot.
82        - Format is 'HH:mm:ss'.
83        required: false
84
85    schedule_id:
86        description:
87        - The schedule ID for the schedule that you want to update or delete.
88        required: false
89
90    starting_date:
91        description:
92        - Starting date for the schedule.
93        - Required when C(state=present).
94        - Please use two '-' in the above format, or you may see an error- TypeError, is not JSON serializable description.
95        - "Format: C(2016--12--01T00:00:00Z)"
96        required: false
97'''
98
99EXAMPLES = """
100   - name: Create Snapshot schedule
101     sf_snapshot_schedule_manager:
102       hostname: "{{ solidfire_hostname }}"
103       username: "{{ solidfire_username }}"
104       password: "{{ solidfire_password }}"
105       state: present
106       name: Schedule_A
107       time_interval_days: 1
108       starting_date: 2016--12--01T00:00:00Z
109       volumes: 7
110
111   - name: Update Snapshot schedule
112     sf_snapshot_schedule_manager:
113       hostname: "{{ solidfire_hostname }}"
114       username: "{{ solidfire_username }}"
115       password: "{{ solidfire_password }}"
116       state: present
117       schedule_id: 6
118       recurring: True
119       snapshot_name: AnsibleSnapshots
120
121   - name: Delete Snapshot schedule
122     sf_snapshot_schedule_manager:
123       hostname: "{{ solidfire_hostname }}"
124       username: "{{ solidfire_username }}"
125       password: "{{ solidfire_password }}"
126       state: absent
127       schedule_id: 6
128"""
129
130RETURN = """
131
132schedule_id:
133    description: Schedule ID of the newly created schedule
134    returned: success
135    type: str
136"""
137import traceback
138
139from ansible.module_utils.basic import AnsibleModule
140from ansible.module_utils._text import to_native
141import ansible.module_utils.netapp as netapp_utils
142
143
144HAS_SF_SDK = netapp_utils.has_sf_sdk()
145
146
147class SolidFireSnapShotSchedule(object):
148
149    def __init__(self):
150
151        self.argument_spec = netapp_utils.ontap_sf_host_argument_spec()
152        self.argument_spec.update(dict(
153            state=dict(required=True, choices=['present', 'absent']),
154            name=dict(required=True, type='str'),
155
156            time_interval_days=dict(required=False, type='int', default=1),
157            time_interval_hours=dict(required=False, type='int', default=0),
158            time_interval_minutes=dict(required=False, type='int', default=0),
159
160            paused=dict(required=False, type='bool'),
161            recurring=dict(required=False, type='bool'),
162
163            starting_date=dict(type='str'),
164
165            snapshot_name=dict(required=False, type='str'),
166            volumes=dict(required=False, type='list'),
167            retention=dict(required=False, type='str'),
168
169            schedule_id=dict(type='int'),
170        ))
171
172        self.module = AnsibleModule(
173            argument_spec=self.argument_spec,
174            required_if=[
175                ('state', 'present', ['starting_date', 'volumes'])
176            ],
177            supports_check_mode=True
178        )
179
180        p = self.module.params
181
182        # set up state variables
183        self.state = p['state']
184        self.name = p['name']
185
186        # self.interval = p['interval']
187
188        self.time_interval_days = p['time_interval_days']
189        self.time_interval_hours = p['time_interval_hours']
190        self.time_interval_minutes = p['time_interval_minutes']
191
192        self.paused = p['paused']
193        self.recurring = p['recurring']
194
195        self.starting_date = p['starting_date']
196        if self.starting_date is not None:
197            self.starting_date = self.starting_date.replace("--", "-")
198
199        self.snapshot_name = p['snapshot_name']
200        self.volumes = p['volumes']
201        self.retention = p['retention']
202
203        self.schedule_id = p['schedule_id']
204
205        self.create_schedule_result = None
206
207        if HAS_SF_SDK is False:
208            self.module.fail_json(msg="Unable to import the SolidFire Python SDK")
209        else:
210            self.sfe = netapp_utils.create_sf_connection(module=self.module)
211
212    def get_schedule(self):
213        schedule_list = self.sfe.list_schedules()
214        for schedule in schedule_list.schedules:
215            if schedule.name == self.name:
216                # Update self.schedule_id:
217                if self.schedule_id is not None:
218                    if schedule.schedule_id == self.schedule_id:
219                        return schedule
220                else:
221                    self.schedule_id = schedule.schedule_id
222                    return schedule
223
224        return None
225
226    def create_schedule(self):
227
228        try:
229            sched = netapp_utils.Schedule()
230            # if self.interval == 'time_interval':
231            sched.frequency = netapp_utils.TimeIntervalFrequency(days=self.time_interval_days,
232                                                                 hours=self.time_interval_hours,
233                                                                 minutes=self.time_interval_minutes)
234
235            # Create schedule
236            sched.name = self.name
237            sched.schedule_info = netapp_utils.ScheduleInfo(
238                volume_ids=self.volumes,
239                snapshot_name=self.snapshot_name,
240                retention=self.retention
241            )
242            sched.paused = self.paused
243            sched.recurring = self.recurring
244            sched.starting_date = self.starting_date
245
246            self.create_schedule_result = self.sfe.create_schedule(schedule=sched)
247
248        except Exception as e:
249            self.module.fail_json(msg='Error creating schedule %s: %s' % (self.name, to_native(e)),
250                                  exception=traceback.format_exc())
251
252    def delete_schedule(self):
253
254        try:
255            get_schedule_result = self.sfe.get_schedule(schedule_id=self.schedule_id)
256            sched = get_schedule_result.schedule
257            sched.to_be_deleted = True
258            self.sfe.modify_schedule(schedule=sched)
259
260        except Exception as e:
261            self.module.fail_json(msg='Error deleting schedule %s: %s' % (self.name, to_native(e)),
262                                  exception=traceback.format_exc())
263
264    def update_schedule(self):
265
266        try:
267            get_schedule_result = self.sfe.get_schedule(schedule_id=self.schedule_id)
268            sched = get_schedule_result.schedule
269
270            # Update schedule properties
271
272            # if self.interval == 'time_interval':
273            temp_frequency = netapp_utils.TimeIntervalFrequency(days=self.time_interval_days,
274                                                                hours=self.time_interval_hours,
275                                                                minutes=self.time_interval_minutes)
276
277            if sched.frequency.days != temp_frequency.days or \
278                sched.frequency.hours != temp_frequency.hours \
279                    or sched.frequency.minutes != temp_frequency.minutes:
280                sched.frequency = temp_frequency
281
282            sched.name = self.name
283            if self.volumes is not None:
284                sched.schedule_info.volume_ids = self.volumes
285            if self.retention is not None:
286                sched.schedule_info.retention = self.retention
287            if self.snapshot_name is not None:
288                sched.schedule_info.snapshot_name = self.snapshot_name
289            if self.paused is not None:
290                sched.paused = self.paused
291            if self.recurring is not None:
292                sched.recurring = self.recurring
293            if self.starting_date is not None:
294                sched.starting_date = self.starting_date
295
296            # Make API call
297            self.sfe.modify_schedule(schedule=sched)
298
299        except Exception as e:
300            self.module.fail_json(msg='Error updating schedule %s: %s' % (self.name, to_native(e)),
301                                  exception=traceback.format_exc())
302
303    def apply(self):
304        changed = False
305        schedule_exists = False
306        update_schedule = False
307        schedule_detail = self.get_schedule()
308
309        if schedule_detail:
310            schedule_exists = True
311
312            if self.state == 'absent':
313                changed = True
314
315            elif self.state == 'present':
316                # Check if we need to update the account
317
318                if self.retention is not None and schedule_detail.schedule_info.retention != self.retention:
319                    update_schedule = True
320                    changed = True
321
322                elif schedule_detail.name != self.name:
323                    update_schedule = True
324                    changed = True
325
326                elif self.snapshot_name is not None and schedule_detail.schedule_info.snapshot_name != self.snapshot_name:
327                    update_schedule = True
328                    changed = True
329
330                elif self.volumes is not None and schedule_detail.schedule_info.volume_ids != self.volumes:
331                    update_schedule = True
332                    changed = True
333
334                elif self.paused is not None and schedule_detail.paused != self.paused:
335                    update_schedule = True
336                    changed = True
337
338                elif self.recurring is not None and schedule_detail.recurring != self.recurring:
339                    update_schedule = True
340                    changed = True
341
342                elif self.starting_date is not None and schedule_detail.starting_date != self.starting_date:
343                    update_schedule = True
344                    changed = True
345
346                elif self.time_interval_minutes is not None or self.time_interval_hours is not None \
347                        or self.time_interval_days is not None:
348
349                    temp_frequency = netapp_utils.TimeIntervalFrequency(days=self.time_interval_days,
350                                                                        hours=self.time_interval_hours,
351                                                                        minutes=self.time_interval_minutes)
352
353                    if schedule_detail.frequency.days != temp_frequency.days or \
354                            schedule_detail.frequency.hours != temp_frequency.hours \
355                            or schedule_detail.frequency.minutes != temp_frequency.minutes:
356                        update_schedule = True
357                        changed = True
358
359        else:
360            if self.state == 'present':
361                changed = True
362
363        if changed:
364            if self.module.check_mode:
365                # Skip changes
366                pass
367            else:
368                if self.state == 'present':
369                    if not schedule_exists:
370                        self.create_schedule()
371                    elif update_schedule:
372                        self.update_schedule()
373
374                elif self.state == 'absent':
375                    self.delete_schedule()
376
377        if self.create_schedule_result is not None:
378            self.module.exit_json(changed=changed, schedule_id=self.create_schedule_result.schedule_id)
379        else:
380            self.module.exit_json(changed=changed)
381
382
383def main():
384    v = SolidFireSnapShotSchedule()
385    v.apply()
386
387
388if __name__ == '__main__':
389    main()
390