-
Notifications
You must be signed in to change notification settings - Fork 2
/
snapshots.py
155 lines (120 loc) · 5.67 KB
/
snapshots.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
import pyocean
import datetime
import time
import socket
import json
from alert import Alert
class Backup:
def __init__(self, access_token=None):
self.digital_ocean = access_token
self.report = ""
config_file = open("config.json", "r")
self.backup_data = json.load(config_file)
self.alert = Alert(self.backup_data["femail"], self.backup_data["temail"])
def print_snapshots(self, droplet=None):
if droplet is None:
return None
self.report += "[Snapshots for:] " + droplet.name + "\n"
for snap in droplet.get_snapshots():
self.report += str(snap) + "\n"
def snapshot(self, droplet=None):
if droplet is None:
return None
try:
# if the droplet is active we must power of the droplet and then
# make the snapshot and then power on again
if droplet.status == "active":
try:
self.report += "[Power off:] " + droplet.name + "\n"
# attempt grateful shutdown
droplet.shutdown()
# now we must refresh the droplet state
droplet = self.digital_ocean.droplet.get(droplet.id)
timeout = 0
while droplet.status != "off" and timeout < 20:
# try to see if is power off
droplet = self.digital_ocean.droplet.get(droplet.id)
# wait 1 sec
time.sleep(1)
# now power off
droplet.power_off()
time.sleep(20)
# now we must refresh the droplet state
droplet = self.digital_ocean.droplet.get(droplet.id)
except pyocean.exceptions.DOException as e:
if e.code is not 422:
self.report += ('ERROR: %s' % e)
self.report += "[Create snapshot for:] " + droplet.name + "\n"
droplet.create_snapshot(droplet.name + str(datetime.datetime.now().day) +
str(datetime.datetime.now().month) + str(datetime.datetime.now().year))
# now we must refresh the droplet state
droplet = self.digital_ocean.droplet.get(droplet.id)
# print all the snapshots taken so far
self.print_snapshots(droplet)
time.sleep(20)
except pyocean.exceptions.DOException as e:
self.report += ('ERROR: %s' % e)
@staticmethod
def need_to_backup(droplet=None):
if droplet is None:
return False
# get a list of snapshots
snaps = [snap for snap in droplet.get_snapshots()]
# if the last one snapshot has a today date, it don't need to be backup
if len(snaps) == 0:
return True
return snaps[-1].name != (droplet.name + str(datetime.datetime.now().day) + str(datetime.datetime.now().month) +
str(datetime.datetime.now().year))
def clean_snapshots(self, droplet=None):
if droplet is None:
return None
snaps = [snap for snap in droplet.get_snapshots()]
if len(snaps) <= self.backup_data["max_snaps"]:
self.report += "[No need to clean snaps for:] " + droplet.name + "\n"
else:
while len(snaps) > self.backup_data["max_snaps"]:
self.report += "[TASK: Destroying snap:] " + snaps[0].name + "\n"
snaps[0].destroy()
self.report += "[DONE: left:] " + str(len(snaps) - (self.backup_data["max_snaps"] + 1)) + "\n"
# refresh the list
snaps = [snap for snap in droplet.get_snapshots()]
return self.report
def run(self):
try:
for account in self.backup_data["accountsList"]:
self.digital_ocean = pyocean.DigitalOcean(account)
for droplet in self.digital_ocean.droplet.all():
# refresh the state of the digital ocean droplet
droplet = self.digital_ocean.droplet.get(droplet.id)
# if need to be backup the droplet must be made a snapshot to the droplet
if self.need_to_backup(droplet):
self.snapshot(droplet)
self.clean_snapshots(droplet)
else:
self.report += "[Snapshot already taken for:] " + droplet.name + "\n"
# see if apache is running
host = droplet.networks['v4'][0]['ip_address']
port = 80
try:
socket.socket().connect((host, port))
except socket.error:
self.alert.send_alert_droplet_down(droplet)
self.report += "\n"
# make all droplets active, they must be active
for droplet in self.digital_ocean.droplet.all():
# refresh the state of the digital ocean droplet
droplet = self.digital_ocean.droplet.get(droplet.id)
if droplet.status == "off":
try:
droplet.power_on()
except pyocean.exceptions.DOException as e:
if e.code is 422:
continue
else:
self.report += ('ERROR: %s' % e)
except pyocean.exceptions.DOException as e:
self.report += ('ERROR: %s' % e)
self.alert.send_report(self.report)
if __name__ == "__main__":
backup = Backup()
backup.run()