/[vz-tools]/trunk/vz-clone.pl
This is repository of my old source code which isn't updated any more. Go to git.rot13.org for current projects!
ViewVC logotype

Contents of /trunk/vz-clone.pl

Parent Directory Parent Directory | Revision Log Revision Log


Revision 23 - (show annotations)
Thu Oct 4 16:58:01 2007 UTC (16 years, 5 months ago) by dpavlin
File MIME type: text/plain
File size: 3794 byte(s)
Create new logical volume for each clone of virtual machine.
That allows snapshots to actually works, because otherwise,
we would have to write content twice:

1. new cloned copy on disk
2. in snapshot (so that we see "old" copy)

This requires snapshot partition at least as big as filesystem
of cloned machine. It also slows down cloning. 

The root of the problem is usage of vg logical volume both as source
(which we want to have snapshot of to achieve consistent copy)
and destination for new cloned fs. Creating new logical volume per
VE cloned allows easy management and update also.

But, this might be optional (and there is fallback in the codei
if there is no lvm for vz data) if we want to create another
persistant clone (TODO).

If possible, we will try to use ssync binary (which sadly
isn't packaged for Debian) because it's much faster than
rsync.
1 #!/usr/bin/perl -w
2
3 use strict;
4 use Shell qw/rsync vzlist lvcreate mount umount lvremove which ssync lvdisplay mke2fs/;
5
6 my $vz = '/vz';
7 my $conf = '/etc/vz/conf';
8
9 my $snap_size = '100M';
10
11 my $VEID = shift @ARGV || die "Usage: $0 VEID\n\n",vzlist;
12
13 my $CVEID = "10$VEID";
14
15 my $orig_conf = "/etc/vz/conf/$VEID.conf";
16
17 die "$VEID config $orig_conf doesn't exist\n" unless -e $orig_conf;
18
19 print "Clone VE $VEID -> $CVEID\n";
20
21 my $vz_lv;
22
23 open(my $m, '<', '/etc/fstab') || die "can't open /etc/fstab: $!";
24 while(<$m>) {
25 next if m/^#/;
26 my @v = split(/\s+/,$_);
27 if ( $v[1] =~ m/\Q$vz\E/ ) {
28 $vz_lv = $v[0];
29 warn "found LV $vz_lv for $vz\n";
30 last;
31 }
32 }
33
34 sub fs_quota {
35 my $id = shift;
36 open(my $q, '-|', "vzquota -b show $id") || die "can't exec vzquota show $id: $!";
37 my $l = <$q>;
38 $l =~ s/^\s+//;
39 my ( $usage, $soft, $hard ) = split(/\s+/,$l);
40 warn "quota for $id | $soft < $hard | usage: $usage\n";
41 return ( $usage, $soft, $hard ) if wantarray;
42 return $soft;
43 }
44
45 sub copy_files {
46 my ( $from, $to ) = @_;
47 if ( which('ssync') ) {
48 warn "ssync $from -> $to\n";
49 ssync(qw{--log-mode file --log-path /dev/null},'-f',$from,'-t',$to);
50 } else {
51 warn "rsync $from -> $to\n";
52 rsync('-ra', "$from/", "$to/" );
53 }
54 }
55
56 if ( $vz_lv ) {
57
58 my ( $vz_lv_path, $vz_lv_name ) = ( $1, $2 ) if ( $vz_lv =~ m!^(.+)/([^/]+)$! );
59
60 my $snap = $vz_lv_name . '-snap';
61 my $clone = "$vz_lv_name-clone-$CVEID";
62
63 sub do_mount {
64 my ( $from, $to ) = @_;
65 mkdir $to || die "can't create $to: $!";
66 print "Mounting $from to $to\n";
67 mount( $from, $to, '-o', 'noatime' );
68 }
69
70 sub test_mkdir {
71 my $dir = shift;
72 if ( ! -d $dir ) {
73 mkdir $dir || die "can't mkdir $dir: $!";
74 }
75 }
76
77 sub mount_bind {
78 my ( $from, $to ) = @_;
79 die "$from doesn't exist!" unless -d $from;
80 test_mkdir( $to );
81 mount( '--bind', $from, $to );
82 }
83
84 print "Creating $snap_size snapshot $snap from $vz_lv\n";
85 lvcreate( '--size', $snap_size, '--snapshot', '--name', $snap, $vz_lv );
86
87 do_mount( "$vz_lv_path/$snap", "/tmp/$snap" );
88
89 my $clone_size = fs_quota( $VEID ) . 'k';
90 my $vg_name = $1 if ( $vz_lv_path =~ m!/([^/]+)/*$! );
91
92 if ( lvdisplay( "$vz_lv_path/$clone" ) ) {
93 warn "using existing $vz_lv_path/$clone\n";
94 } else {
95 print "Creating LV $clone ($clone_size bytes) in VG $vg_name for $VEID clone filesystem\n";
96 lvcreate( '--size', $clone_size, '--name', $clone, $vg_name );
97 mke2fs( '-m', 0, '-j', "$vz_lv_path/$clone" );
98 }
99
100 do_mount( "$vz_lv_path/$clone", "/tmp/$clone" );
101
102 test_mkdir( "/tmp/$clone/private" );
103 test_mkdir( "/tmp/$clone/root" );
104
105 mount_bind( "/tmp/$clone/private", "$vz/private/$CVEID" );
106 mount_bind( "/tmp/$clone/root", "$vz/root/$CVEID" );
107
108 copy_files( "/tmp/$snap/private/$VEID", "$vz/private/$CVEID" );
109
110 print "Cleanup\n";
111
112 umount( "$vz_lv_path/$clone" );
113 umount( "$vz_lv_path/$snap" );
114
115 lvremove( '-f', "$vz_lv_path/$snap" );
116
117 } else {
118
119 copy_files( "$vz/private/$VEID", "$vz/private/$CVEID" );
120 }
121
122 my $note = "# modified by $0\n";
123
124 sub fix_ip {
125 my $ip = shift;
126 $ip =~ s/['"]//g;
127 $ip =~ s/^\d+\./10./;
128 warn "$CVEID new IP number: $ip\n";
129 return $note . qq{IP_ADDRESS="$ip"};
130 }
131
132 sub fix_hostname {
133 my $hostname = shift;
134 $hostname =~ s/['"]//g;
135 $hostname = "clone-$hostname";
136 warn "$CVEID new hostname: $hostname\n";
137 return $note . qq{HOSTNAME="$hostname"};
138 }
139
140 open(my $o, '<', "$conf/$VEID.conf") || die "can't open $conf/$VEID.conf: $!";
141 open(my $n, '>', "$conf/$CVEID.conf") || die "can't open $conf/$CVEID.conf: $!";
142 while(<$o>) {
143 s!^HOSTNAME=(.*)$!fix_hostname($1)!ie;
144 s!^IP_ADDRESS=(.*)$!fix_ip($1)!ie;
145 s!^(ONBOOT=).*$!# modified by $0\n$1"no"!i;
146 print $n $_;
147 }
148
149 print "\nPlease review config file: $conf/$CVEID.conf\nAdd NAT for new VE with: iptables -t nat -A POSTROUTING -o eth0 -j MASQUERADE\nStart clone of $VEID with: vzctl start $CVEID\n"

Properties

Name Value
svn:executable *

  ViewVC Help
Powered by ViewVC 1.1.26