vpsbackup.php

Lars Nordseth, 07/27/2010 01:58 am

Download (8.5 kB)

 
1
<?php 
2
3
include_once "htmllib/lib/include.php";
4
5
include_once "lib/vpsbackuplib.php";
6
exit_if_another_instance_running();
7
8
$vpb = new vpsbackup();
9
10
try { 
11
        $vpb->main();
12
} catch( Exception $e ) {
13
        print("Program Did not Complete because of error {$e->getMessage()}\n");
14
        exit;
15
}
16
17
18
class vpsbackup {
19
public $bserver_list;
20
public $global_list;
21
22
23
function main()
24
{
25
        global $gbl, $sgbl, $login, $ghtml; 
26
        global $argv;
27
28
        initProgram('admin');
29
        $login->loadAllObjects('vps');
30
31
        $this->bserver_l = $login->getList('centralbackupserver');
32
        $list = $login->getList('vps');
33
34
        foreach($this->bserver_l as $bso) {
35
                $bso->setMyselfUp();
36
        }
37
38
        $opt = parse_opt($argv);
39
40
        if (!isset($opt['newarg'])) {
41
                $mess = "\n\nThe architecture of centalized backup has been completely rewritten, and now we have per slave backup-server; you will need to supply --newarg=true for this to work. ";
42
                $mess .= "Please see http://lxlabs.com/software/hypervm/backup/ for more info.";
43
                print($mess);
44
                log_log("centralbackup_flag", $mess);
45
                send_mail_to_admin("Central Backup Failed", $mess);
46
                exit;
47
        }
48
49
50
        $this->stopvps = opt_get_single_flag($opt, 'stopvps');
51
        //$stopxen = opt_get_single_flag($opt, 'stopxen');
52
        //$stopopenvz = opt_get_single_flag($opt, 'stopopenvz');
53
54
55
        foreach($list as $l) {
56
                $this->backup_one_vps($l);
57
        }
58
59
        foreach((array) $this->global_list as $k => $s) {
60
                //$res = rl_exec_get(null, $k, 'remove_scpid', array($backupiddsa));
61
        }
62
63
}
64
65
function backup_one_vps($l)
66
{
67
        if (!$l->priv->isOn('centralbackup_flag')) {
68
                print("Central Backup flag is off for vps $l->nname... skipping...\n");
69
                return;
70
        }
71
72
        $l->truehostname = getInternalNetworkIp($l->syncserver);
73
74
75
        $bserver = $l->getBackupServer();
76
77
        if (is_disabled_or_null($bserver)) {
78
                $msg = "Backup server for $l->syncserver is disabled.. Skipping $l->nname\n";
79
                print($msg);
80
                log_log("centralbackup_error", $msg);
81
                return;
82
        }
83
84
        if (!isset($this->bserver_l[$bserver])) {
85
                print("The backup server $bserver doesn't exist\n");
86
                return;
87
        }
88
89
        $bs = $this->bserver_l[$bserver];
90
91
92
        if (!isset($this->global_list[$l->syncserver])) {
93
94
                try {
95
                        $res = rl_exec_get(null, $l->syncserver,  'setup_scpid', array($bs->backupiddsa));
96
                } catch( Exception $e ) {
97
                        $msg = "Could not connect to $l->syncserver Skipping $l->nname: {$e->getMessage()}\n";
98
                        log_log("centralbackup_error", $msg);
99
                        print($msg);
100
                        return;
101
                }
102
103
                $this->addknownHost($bs, "$l->truehostname $res");
104
                $this->global_list[$l->syncserver] = $l->truehostname;
105
        } else {
106
        }
107
108
        $msg = "Backing Up $l->nname on $l->truehostname to $bs->nname($bs->ssh_port):$bs->snapshotdir \n";
109
        log_log("centralbackup", $msg);
110
        print($msg);
111
        $l->setUpdateSubaction('top_level_central_back');
112
113
        $l->__var_bc_backupextra_stopvpsflag = ($this->stopvps? 'on': 'off');
114
115
        if ($l->isWindows()) {
116
                // 2010-07-13 LN: Add a flag to indicate central backup - not sure if the old code is used for scheduled backups.
117
                $l->isCentralBackup = true;
118
        }
119
120
        try {
121
                $res = rl_exec_set(null, $l->syncserver,  $l);
122
        } catch( Exception $e ) {
123
                $msg = "Failed Preparing... Skipping $l->nname on $l->syncserver: {$e->getMessage()}\n";
124
                log_log("centralbackup_error", $msg);
125
                print($msg);
126
                return;
127
        }
128
129
        $l->subaction = null;
130
        if ($res['savelist']) foreach($res['savelist'] as $k => $v) {
131
                $l->$k = $v;
132
        }
133
134
        $l->__save_bc = $res['back'];
135
        if ($l->isXen()) {
136
                $localdir = $l->nname;
137
        } else {
138
                $localdir = "$l->vpsid-$l->nname";
139
        }
140
        $ssh_port_for_slave = db_get_value("sshconfig", $l->syncserver, "ssh_port");
141
        if (!$ssh_port_for_slave) { $ssh_port_for_slave = "22"; }
142
143
        $l->__var_ssh_port_for_slave = $ssh_port_for_slave;
144
        if ($l->isWindows()) {
145
                $snapshotAndPartitions = $res['back'];
146
                $this->run_ntfsclone($bs, $l);
147
                $l->setUpdateSubaction('top_level_central_back_clean');
148
                $res = rl_exec_set(null, $l->syncserver,  $l);
149
        } else {
150
                $l->__var_remotedir = $res['back'][0];
151
                $this->run_rsnapshot($bs, $l);
152
                $l->setUpdateSubaction('top_level_central_back_clean');
153
                $res = rl_exec_set(null, $l->syncserver,  $l);
154
        }
155
}
156
157
/**
158
 * Backup Windows VPS using ntfsclone.
159
 * ntfsclone is executed via the backup server to re-use the key based login established by the existing code,
160
 * but since rsnapshot is not used, ntfsclone could run directly on the slave. Running it on the slave would simplify the code,
161
 * but requires key based login from the slave servers to the backup server.
162
 * Disk space requirement on the backup server:
163
 *    Used blocks on the Windows VPS x gzip compression ratio
164
 * There's no need for temporary storage, the data is streamed to the backup server immediately.
165
 * Example: Windows VPS, 100GB LVM, 37GB used, backup size 20GB
166
 * @param centralbackupserver $bs Backup server
167
 * @param Vps $vps VPS VPS to backup
168
 * @return void The backups should be rotated and the new backup be placed in daily.0
169
 */
170
function run_ntfsclone($bs, $vps)
171
{
172
        $machine = $vps->truehostname;
173
        $corerootdir = $bs->snapshotdir; 
174
        $vmtype =  $vps->ttype;
175
        $template = $vps->ostemplate;
176
        $vmname = $vps->nname;
177
        $ssh_port_for_slave = $vps->__var_ssh_port_for_slave;
178
        $backup_ssh_port_string = $bs->ssh_port_string;
179
        $backupserver = $bs->nname;
180
        $partitions = $vps->__save_bc->partitions;
181
182
   $backupRoot = "$corerootdir/vps/$vmtype/$vmname";
183
   $sshCmd = "ssh $backup_ssh_port_string $backupserver";
184
        
185
        // Create backup root
186
        //--------------------
187
   exec("$sshCmd '[ ! -d $backupRoot ] && mkdir -p $backupRoot'");
188
        
189
        // Rotate backups,
190
        // should be done only on successful backup, but that would require more disk space.
191
        //-----------------------------------------------------------------------------------
192
   $day = $bs->backup_num - 1;
193
   exec("$sshCmd '[ -d $backupRoot/daily.$day ] && rm -Rf $backupRoot/daily.$day'");
194
   for (; $day > 0; $day--) {
195
      $src = "$backupRoot/daily." . ($day - 1);
196
      $dst = "$backupRoot/daily." . $day;
197
      exec("$sshCmd '[ -d $src ] && rm -Rf $dst && mv $src $dst'");
198
   }
199
   exec("$sshCmd '[ ! -d $backupRoot/daily.0 ] && mkdir -p $backupRoot/daily.0'");
200
        
201
        // Backup MBR
202
        //------------
203
        $runOnSyncServer = "ssh -p$ssh_port_for_slave root@$machine 'dd if={$vps->__save_bc->snapshot} bs=512 count=1'";
204
        $runOnBackupServer = "$sshCmd \"$runOnSyncServer | cat > $backupRoot/daily.0/$vmname.mbr\"";
205
        exec($runOnBackupServer, $output, $returnvalue);
206
   log_log("centralbackup", implode("\n", $output));
207
        
208
        // Backup partitions
209
        //-------------------
210
        $n = 1;
211
        print_time('ntfsclone');
212
        foreach ($partitions as $partition) {
213
                $runOnSyncServer = "ssh -p$ssh_port_for_slave root@$machine 'ntfsclone -o - -s $partition | nice -n19 gzip -c'";
214
                $runOnBackupServer = "$sshCmd \"$runOnSyncServer | cat > $backupRoot/daily.0/$vmname.part$n.gz\"";
215
                $n++;
216
                exec($runOnBackupServer, $output, $returnvalue);
217
      log_log("centralbackup", implode("\n", $output));
218
        }
219
        $msg = print_time("ntfsclone", "ntfsclone of $vmname@$machine took:", -1);
220
        print("\n$msg\n");
221
        log_log("centralbackup", $msg);
222
        return;
223
}
224
225
function run_rsnapshot($bs, $vps)
226
{
227
        $machine = $vps->truehostname;
228
        $corerootdir = $bs->snapshotdir; 
229
        $vmtype =  $vps->ttype;
230
        $template = $vps->ostemplate;
231
        $vmname = $vps->nname;
232
        $ssh_port_for_slave = $vps->__var_ssh_port_for_slave;
233
        $remotedir = $vps->__var_remotedir;
234
        $backup_ssh_port_string = $bs->ssh_port_string;
235
        $backupserver = $bs->nname;
236
237
        if (!$remotedir) {
238
                print("Critical Error, no remotedir set for $vmname\n");
239
                return;
240
        }
241
242
        print_time('rsnapshot');
243
        if (!lxfile_exists("../file/rsnapshot.conf")) {
244
                lxfile_cp("../file/rsnapshot.conf.dist", "../file/rsnapshot.conf");
245
        }
246
        $string  = lfile_get_contents("../file/rsnapshot.conf");
247
        $string .= "\n";
248
249
        $string .= "ssh_args        -p $ssh_port_for_slave\n";
250
        $string .= "interval        daily        $bs->backup_num\n";
251
252
        $string .= "logfile        $corerootdir/rsnapshot.log\n";
253
        $string .= "lockfile        $corerootdir/rsnapshot.pid\n";
254
        $string .= "snapshot_root        $corerootdir/vps/$vmtype/$vmname\n";
255
        $string .= "backup        root@$machine:$remotedir/*        ./\n";
256
        $cmd = "ssh $backup_ssh_port_string $backupserver '(tmpnm=/tmp/rsnapshot_config.$$ ; cat > \$tmpnm ; sh ./lxvpsbackupserver.sh $corerootdir $vmtype $template $vmname \$tmpnm ; )'";
257
        $cmd = "echo '$string' | $cmd";
258
        print("Execing rsnapshot\n");
259
        exec($cmd, $output, $returnvalue);
260
        $msg = print_time("rsnapshot", "Rsnaphost of $machine $remotedir took:", -1);
261
        print("\n$msg\n");
262
        log_log("centralbackup", $msg);
263
        log_log("rsnapshot_log", implode("\n", $output));
264
}
265
266
function addknownHost($bs, $rsakey)
267
{
268
        $backup_ssh_port_string = $bs->ssh_port_string;
269
        $server = $bs->nname;
270
        $rsakey = trim($rsakey);
271
        print("Adding known host...\n");
272
        $cmd = "ssh $backup_ssh_port_string $bs->nname \"(if ! grep -i '$rsakey' ~/.ssh/known_hosts ; then  echo '$rsakey' >> ~/.ssh/known_hosts; fi)\"";
273
        //dprint($cmd);
274
        exec($cmd);
275
276
}
277
278
279
}