Skip to content

Commit 7b2a44b

Browse files
authored
Merge pull request #857 from globocom/dev
Dev to Master
2 parents 380cfca + 11c97c2 commit 7b2a44b

File tree

12 files changed

+1360
-3
lines changed

12 files changed

+1360
-3
lines changed

dbaas/backup/tasks.py

Lines changed: 140 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ def unlock_instance(driver, instance, client):
8686
return False
8787

8888

89-
def make_instance_snapshot_backup(instance, error, group,
89+
def make_instance_old_snapshot_backup(instance, error, group,
9090
provider_class=VolumeProviderSnapshot,
9191
target_volume=None,
9292
current_hour=None,
@@ -211,6 +211,144 @@ def make_instance_snapshot_backup(instance, error, group,
211211

212212
return snapshot
213213

214+
def make_instance_snapshot_backup(
215+
instance, error, group, provider_class=VolumeProviderSnapshot, target_volume=None,
216+
current_hour=None, task=None, persist=0
217+
):
218+
LOG.info("Make instance backup for {}".format(instance))
219+
provider = provider_class(instance)
220+
infra = instance.databaseinfra
221+
database = infra.databases.first()
222+
223+
backup_retry_attempts = Configuration.get_by_name_as_int('backup_retry_attempts', default=3)
224+
225+
snapshot = Snapshot.create(
226+
instance, group, target_volume or provider.volume,
227+
environment=provider.environment, persistent=True if persist != 0 else False
228+
)
229+
230+
snapshot_final_status = Snapshot.SUCCESS
231+
232+
locked = None
233+
client = None
234+
driver = infra.get_driver()
235+
try:
236+
client = driver.get_client(instance)
237+
locked = lock_instance(driver, instance, client)
238+
if not locked:
239+
snapshot_final_status = Snapshot.WARNING
240+
241+
if 'MySQL' in type(driver).__name__:
242+
mysql_binlog_save(client, instance)
243+
244+
has_snapshot = Snapshot.objects.filter(
245+
status=Snapshot.WARNING, instance=instance, end_at__year=datetime.now().year,
246+
end_at__month=datetime.now().month, end_at__day=datetime.now().day
247+
)
248+
backup_hour_list = Configuration.get_by_name_as_list('make_database_backup_hour')
249+
if not snapshot_final_status == Snapshot.WARNING and not has_snapshot:
250+
cont = 0
251+
for _ in range(backup_retry_attempts):
252+
cont += 1
253+
try:
254+
code = 201
255+
response, data = provider.new_take_snapshot(persist=persist)
256+
257+
if response.status_code < 400:
258+
break
259+
260+
if cont >= 3:
261+
raise IndexError
262+
263+
except IndexError as e:
264+
content, response = e
265+
if response.status_code == 503:
266+
errormsg = "{} - 503 error creating snapshot for instance: {}. It will try again in 30 seconds. ".format(
267+
strftime("%d/%m/%Y %H:%M:%S"), instance
268+
)
269+
LOG.error(errormsg)
270+
if task:
271+
task.add_detail(errormsg)
272+
sleep(30)
273+
else:
274+
raise e
275+
276+
if response.status_code < 400:
277+
while code != 200:
278+
sleep(20)
279+
snap_response, snap_status = provider.take_snapshot_status(data['identifier'])
280+
if snap_response.status_code in [200, 202]:
281+
unlock_instance(driver, instance, client)
282+
if snap_response.status_code == 200:
283+
break
284+
if snap_response.status_code >= 400:
285+
raise error
286+
code = snap_response.status_code
287+
288+
snapshot.done(snap_status)
289+
snapshot.save()
290+
else:
291+
errormsg = response['message']
292+
set_backup_error(infra, snapshot, errormsg)
293+
else:
294+
if str(current_hour) in backup_hour_list:
295+
raise Exception("Backup with WARNING already created today.")
296+
297+
except Exception as e:
298+
errormsg = "Error creating snapshot: {}".format(e)
299+
error['errormsg'] = errormsg
300+
set_backup_error(infra, snapshot, errormsg)
301+
return snapshot
302+
finally:
303+
unlock_instance(driver, instance, client)
304+
305+
if not snapshot.size:
306+
command = "du -sb /data/.snapshot/%s | awk '{print $1}'" % (
307+
snapshot.snapshot_name
308+
)
309+
try:
310+
output = instance.hostname.ssh.run_script(command)
311+
size = int(output['stdout'][0])
312+
snapshot.size = size
313+
except Exception as e:
314+
snapshot.size = 0
315+
LOG.error("Error exec remote command {}".format(e))
316+
317+
backup_path = database.backup_path
318+
if backup_path:
319+
now = datetime.now()
320+
target_path = "{}/{}/{}/{}/{}".format(
321+
backup_path,
322+
now.strftime("%Y_%m_%d"),
323+
instance.hostname.hostname.split('.')[0],
324+
now.strftime("%Y%m%d%H%M%S"),
325+
infra.name
326+
)
327+
snapshot_path = "/data/.snapshot/{}/data/".format(
328+
snapshot.snapshot_name
329+
)
330+
command = """
331+
if [ -d "{backup_path}" ]
332+
then
333+
rm -rf {backup_path}/20[0-9][0-9]_[0-1][0-9]_[0-3][0-9] &
334+
mkdir -p {target_path}
335+
cp -r {snapshot_path} {target_path} &
336+
fi
337+
""".format(backup_path=backup_path,
338+
target_path=target_path,
339+
snapshot_path=snapshot_path)
340+
try:
341+
instance.hostname.ssh.run_script(command)
342+
except Exception as e:
343+
LOG.error("Error exec remote command {}".format(e))
344+
345+
snapshot.status = snapshot_final_status
346+
snapshot.end_at = datetime.now()
347+
snapshot.save()
348+
register_backup_dbmonitor(infra, snapshot)
349+
350+
return snapshot
351+
214352

215353
def make_instance_snapshot_backup_upgrade_disk(instance, error, group, provider_class=VolumeProviderSnapshot,
216354
target_volume=None,
@@ -742,6 +880,7 @@ def _create_database_backup(instance, task, group, current_hour, persist):
742880

743881
error = {}
744882
try:
883+
LOG.info('Starting make database snapshot')
745884
snapshot = make_instance_snapshot_backup(
746885
instance=instance,
747886
error=error,

dbaas/drivers/replication_topologies/base.py

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -732,6 +732,9 @@ def get_stop_database_vm_steps(self):
732732
'workflow.steps.util.host_provider.StopIfRunning',
733733
)
734734
}]
735+
736+
def get_auto_upgrade_database_vm_offering(self):
737+
raise NotImplementedError('Not implemented for topology')
735738

736739
def get_start_database_vm_steps(self):
737740
return [{

dbaas/logical/views.py

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2741,6 +2741,14 @@ def check_offering_sizes(request):
27412741
@method_decorator(csrf_exempt)
27422742
def resize_vm_from_btn(request, database_id, resize_target):
27432743
database = get_object_or_404(Database, pk=database_id)
2744+
user = request.user
2745+
from notification.tasks import TaskRegister
2746+
2747+
LOG.info("Starting database auto upgrade: database {}, user: {}".format(database, user))
2748+
2749+
TaskRegister.auto_upgrade_database_vm_offering(
2750+
database=database, user=user
2751+
)
27442752

27452753
future_offering = database.get_future_offering(resize_target)
27462754
return HttpResponse(json.dumps({'future_offering': future_offering.name}), content_type="application/json")

dbaas/maintenance/admin/__init__.py

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828
from . database_upgrade_disk_type import DatabaseUpgradeDiskTypeAdmin
2929
from . database_start_database_vm import DatabaseStartDatabaseVMAdmin
3030
from . database_stop_database_vm import DatabaseStopDatabaseVMAdmin
31+
from . database_auto_upgrade_vm_offering import DatabaseAutoUpgradeVMOferringAdmin
3132

3233

3334
admin.site.register(models.Maintenance, MaintenanceAdmin)
@@ -74,3 +75,7 @@
7475
admin.site.register(
7576
models.DatabaseStopDatabaseVM, DatabaseStopDatabaseVMAdmin
7677
)
78+
79+
admin.site.register(
80+
models.DatabaseAutoUpgradeVMOffering, DatabaseAutoUpgradeVMOferringAdmin
81+
)
Lines changed: 92 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,92 @@
1+
# -*- coding: utf-8 -*-
2+
from __future__ import absolute_import, unicode_literals
3+
from django.conf.urls import patterns, url
4+
from django.contrib import messages
5+
from django.core.urlresolvers import reverse
6+
from django.http import HttpResponseRedirect
7+
from django.shortcuts import get_object_or_404
8+
from django.utils.html import format_html
9+
from .database_maintenance_task import DatabaseMaintenanceTaskAdmin
10+
from ..models import DatabaseAutoUpgradeVMOffering
11+
from notification.tasks import TaskRegister
12+
13+
14+
class DatabaseAutoUpgradeVMOferringAdmin(DatabaseMaintenanceTaskAdmin):
15+
search_fields = (
16+
"database__name", "database__databaseinfra__name", "task__id", "task__task_id"
17+
)
18+
19+
list_display = (
20+
"database", "database_team", "current_step", "current_step_class", "friendly_status",
21+
"maintenance_action", "link_task", "started_at", "finished_at"
22+
)
23+
24+
readonly_fields = (
25+
"database", "task",
26+
"started_at", "link_task", "finished_at", "status",
27+
"maintenance_action", "task_schedule"
28+
)
29+
30+
def maintenance_action(self, maintenance):
31+
if not maintenance.is_status_error:
32+
return 'N/A'
33+
34+
if not maintenance.can_do_retry:
35+
return 'N/A'
36+
37+
url = "/admin/maintenance/databaseautoupgradevmoffering/{}/retry/".format(
38+
maintenance.id
39+
)
40+
html = ("<a title='Retry' class='btn btn-info' "
41+
"href='{}'>Retry</a>").format(url)
42+
return format_html(html)
43+
44+
def get_urls(self):
45+
base = super(DatabaseAutoUpgradeVMOferringAdmin, self).get_urls()
46+
47+
admin = patterns(
48+
'',
49+
url(
50+
r'^/?(?P<auto_upgrade_vm_offering_id>\d+)/retry/$',
51+
self.admin_site.admin_view(self.retry_view),
52+
name="auto_upgrade_vm_offering_retry"
53+
),
54+
)
55+
return admin + base
56+
57+
def retry_view(self, request, auto_upgrade_vm_offering_id):
58+
retry_from = get_object_or_404(DatabaseAutoUpgradeVMOffering, pk=auto_upgrade_vm_offering_id)
59+
60+
error = False
61+
if not retry_from.is_status_error:
62+
error = True
63+
messages.add_message(
64+
request, messages.ERROR,
65+
"You can not do retry because auto upgrade database vm offering status is '{}'".format(
66+
retry_from.get_status_display()
67+
),
68+
)
69+
70+
if not retry_from.can_do_retry:
71+
error = True
72+
messages.add_message(
73+
request, messages.ERROR, "Auto Upgrade VM Offering retry is disabled"
74+
)
75+
76+
if error:
77+
return HttpResponseRedirect(
78+
reverse(
79+
'admin:maintenance_databaseautoupgradevmoffering_change',
80+
args=(auto_upgrade_vm_offering_id,)
81+
)
82+
)
83+
84+
TaskRegister.auto_upgrade_database_vm_offering(
85+
database=retry_from.database,
86+
user=request.user,
87+
retry_from=retry_from
88+
)
89+
90+
url = reverse('admin:notification_taskhistory_changelist')
91+
filter = "user={}".format(request.user.username)
92+
return HttpResponseRedirect('{}?{}'.format(url, filter))

0 commit comments

Comments
 (0)