| 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 | }
|