slaprunner-backup: doesn't destroy symlinks for Software Releases
[slapos.git] / slapos / recipe / slaprunner / backup.py
1 ##############################################################################
2 #
3 # Copyright (c) 2013 Vifib SARL and Contributors. All Rights Reserved.
4 #
5 # WARNING: This program as such is intended to be used by professional
6 # programmers who take the whole responsibility of assessing all potential
7 # consequences resulting from its eventual inadequacies and bugs
8 # End users who are looking for a ready-to-use solution with commercial
9 # guarantees and support are strongly adviced to contract a Free Software
10 # Service Company
11 #
12 # This program is Free Software; you can redistribute it and/or
13 # modify it under the terms of the GNU General Public License
14 # as published by the Free Software Foundation; either version 3
15 # of the License, or (at your option) any later version.
16 #
17 # This program is distributed in the hope that it will be useful,
18 # but WITHOUT ANY WARRANTY; without even the implied warranty of
19 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 # GNU General Public License for more details.
21 #
22 # You should have received a copy of the GNU General Public License
23 # along with this program; if not, write to the Free Software
24 # Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
25 #
26 ##############################################################################
27
28 import textwrap
29
30 from slapos.recipe.librecipe import GenericBaseRecipe
31
32
33
34 class ExportRecipe(GenericBaseRecipe):
35 """\
36 This recipe creates an exporter script for using with the resilient stack.
37
38 Required options:
39 backup-directory
40 folder that will contain the dump file.
41 srv-directory
42 folder that contain the runner directory.
43 wrapper
44 full path of the exporter script to create.
45 """
46
47 def install(self):
48 wrapper = self.options['wrapper']
49 self.createBackupScript(wrapper)
50 return [wrapper]
51
52
53 def createBackupScript(self, wrapper):
54 """\
55 Create a script to backup the database in 'custom' format.
56 """
57 content = textwrap.dedent("""\
58 #!%(shell-binary)s
59 umask 077
60 sync_element () {
61 path=$1
62 backup_path=$2
63 shift 2
64 element_list=$*
65 for element in $element_list
66 do
67 cd $path;
68 if [ -f $element ] || [ -d $element ]; then
69 %(rsync-binary)s -avz --safe-links --delete $element $backup_path;
70 fi
71 done
72 }
73 sync_element %(srv-directory)s/runner %(backup-directory)s/runner/ instance project proxy.db
74 sync_element %(etc-directory)s %(backup-directory)s/etc/ .rcode .project .users .htpasswd ssh
75 if [ -d %(backup-directory)s/runner/software ]; then
76 rm %(backup-directory)s/runner/software/*
77 fi
78 """ % self.options)
79 self.createExecutable(wrapper, content=content)
80
81
82
83 class ImportRecipe(GenericBaseRecipe):
84 """\
85 This recipe creates an importer script for using with the resilient stack.
86
87 Required options:
88 backup-directory
89 folder that will contain the dump file.
90 srv-directory
91 folder that contain the runner directory.
92 wrapper
93 full path of the exporter script to create.
94 """
95
96 def install(self):
97 wrapper = self.options['wrapper']
98 self.createRestoreScript(wrapper)
99 return [wrapper]
100
101
102 def createRestoreScript(self, wrapper):
103 """\
104 Create a script to restore the database from 'custom' format.
105 """
106 content = textwrap.dedent("""\
107 #!%(shell-binary)s
108 umask 077
109 restore_element () {
110 backup_path=$1
111 restore_path=$2
112 shift 2
113 element_list=$*
114 for element in $element_list
115 do
116 cd $backup_path;
117 if [ -f $element ] || [ -d $element ]; then
118 %(rsync-binary)s -avz --delete $backup_path/$element $restore_path;
119 fi
120 done
121 }
122 restore_element %(backup-directory)s/runner/ %(srv-directory)s/runner instance project proxy.db
123 restore_element %(backup-directory)s/etc/ %(etc-directory)s .rcode .project .users .htpasswd ssh
124 ifs=$IFS IFS=';'
125 read user pass remaining < %(etc-directory)s/.users
126 IFS=$ifs
127 %(curl-binary)s --insecure -vg6L -F clogin="$user" -F cpwd="$pass" --dump-header login_cookie %(backend-url)s/doLogin;
128 %(curl-binary)s --insecure -vg6LX POST --cookie login_cookie --max-time 5 %(backend-url)s/runSoftwareProfile --user "$user":"$pass";
129 rm -f login_cookie
130 """ % self.options)
131 self.createExecutable(wrapper, content=content)
132
133