/[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

Annotation of /trunk/vz-clone.pl

Parent Directory Parent Directory | Revision Log Revision Log


Revision 23 - (hide annotations)
Thu Oct 4 16:58:01 2007 UTC (16 years, 6 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 dpavlin 20 #!/usr/bin/perl -w
2    
3     use strict;
4 dpavlin 23 use Shell qw/rsync vzlist lvcreate mount umount lvremove which ssync lvdisplay mke2fs/;
5 dpavlin 20
6     my $vz = '/vz';
7     my $conf = '/etc/vz/conf';
8    
9 dpavlin 21 my $snap_size = '100M';
10    
11 dpavlin 20 my $VEID = shift @ARGV || die "Usage: $0 VEID\n\n",vzlist;
12    
13 dpavlin 21 my $CVEID = "10$VEID";
14 dpavlin 20
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 dpavlin 21 my $vz_lv;
22 dpavlin 20
23 dpavlin 21 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 dpavlin 23 warn "found LV $vz_lv for $vz\n";
30 dpavlin 21 last;
31     }
32     }
33    
34 dpavlin 23 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 dpavlin 21 sub copy_files {
46     my ( $from, $to ) = @_;
47 dpavlin 23 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 dpavlin 21 }
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 dpavlin 23 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 dpavlin 21 print "Creating $snap_size snapshot $snap from $vz_lv\n";
85     lvcreate( '--size', $snap_size, '--snapshot', '--name', $snap, $vz_lv );
86    
87 dpavlin 23 do_mount( "$vz_lv_path/$snap", "/tmp/$snap" );
88 dpavlin 21
89 dpavlin 23 my $clone_size = fs_quota( $VEID ) . 'k';
90     my $vg_name = $1 if ( $vz_lv_path =~ m!/([^/]+)/*$! );
91 dpavlin 21
92 dpavlin 23 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 dpavlin 21
100 dpavlin 23 do_mount( "$vz_lv_path/$clone", "/tmp/$clone" );
101 dpavlin 21
102 dpavlin 23 test_mkdir( "/tmp/$clone/private" );
103     test_mkdir( "/tmp/$clone/root" );
104 dpavlin 21
105 dpavlin 23 mount_bind( "/tmp/$clone/private", "$vz/private/$CVEID" );
106     mount_bind( "/tmp/$clone/root", "$vz/root/$CVEID" );
107 dpavlin 21
108 dpavlin 23 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 dpavlin 21 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 dpavlin 20 sub fix_ip {
125     my $ip = shift;
126 dpavlin 21 $ip =~ s/['"]//g;
127 dpavlin 20 $ip =~ s/^\d+\./10./;
128     warn "$CVEID new IP number: $ip\n";
129 dpavlin 21 return $note . qq{IP_ADDRESS="$ip"};
130 dpavlin 20 }
131    
132 dpavlin 21 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 dpavlin 20 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 dpavlin 21 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 dpavlin 20 print $n $_;
147     }
148    
149 dpavlin 22 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