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