~cbehrens/nova/lp844160-build-works-with-zones

« back to all changes in this revision

Viewing changes to vendor/boto/boto/pyami/installers/ubuntu/ebs.py

  • Committer: Jesse Andrews
  • Date: 2010-05-28 06:05:26 UTC
  • Revision ID: git-v1:bf6e6e718cdc7488e2da87b21e258ccc065fe499
initial commit

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright (c) 2006-2009 Mitch Garnaat http://garnaat.org/
 
2
#
 
3
# Permission is hereby granted, free of charge, to any person obtaining a
 
4
# copy of this software and associated documentation files (the
 
5
# "Software"), to deal in the Software without restriction, including
 
6
# without limitation the rights to use, copy, modify, merge, publish, dis-
 
7
# tribute, sublicense, and/or sell copies of the Software, and to permit
 
8
# persons to whom the Software is furnished to do so, subject to the fol-
 
9
# lowing conditions:
 
10
#
 
11
# The above copyright notice and this permission notice shall be included
 
12
# in all copies or substantial portions of the Software.
 
13
#
 
14
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
 
15
# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL-
 
16
# ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT
 
17
# SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 
 
18
# WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 
19
# OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
 
20
# IN THE SOFTWARE.
 
21
#
 
22
"""
 
23
Automated installer to attach, format and mount an EBS volume.
 
24
This installer assumes that you want the volume formatted as
 
25
an XFS file system.  To drive this installer, you need the
 
26
following section in the boto config passed to the new instance.
 
27
You also need to install dateutil by listing python-dateutil
 
28
in the list of packages to be installed in the Pyami seciont
 
29
of your boto config file.
 
30
 
 
31
If there is already a device mounted at the specified mount point,
 
32
the installer assumes that it is the ephemeral drive and unmounts
 
33
it, remounts it as /tmp and chmods it to 777.
 
34
 
 
35
Config file section::
 
36
 
 
37
    [EBS]
 
38
    volume_id = <the id of the EBS volume, should look like vol-xxxxxxxx>
 
39
    logical_volume_name = <the name of the logical volume that contaings 
 
40
        a reference to the physical volume to be mounted. If this parameter
 
41
        is supplied, it overrides the volume_id setting.>
 
42
    device = <the linux device the EBS volume should be mounted on>
 
43
    mount_point = <directory to mount device, defaults to /ebs>
 
44
 
 
45
"""
 
46
import boto
 
47
from boto.manage.volume import Volume
 
48
import os, time
 
49
from boto.pyami.installers.ubuntu.installer import Installer
 
50
from string import Template
 
51
 
 
52
BackupScriptTemplate = """#!/usr/bin/env python
 
53
# Backup EBS volume
 
54
import boto
 
55
from boto.pyami.scriptbase import ScriptBase
 
56
import traceback
 
57
 
 
58
class Backup(ScriptBase):
 
59
 
 
60
    def main(self):
 
61
        try:
 
62
            ec2 = boto.connect_ec2()
 
63
            self.run("/usr/sbin/xfs_freeze -f ${mount_point}")
 
64
            snapshot = ec2.create_snapshot('${volume_id}')
 
65
            boto.log.info("Snapshot created: %s " %  snapshot)
 
66
        except Exception, e:
 
67
            self.notify(subject="${instance_id} Backup Failed", body=traceback.format_exc())
 
68
            boto.log.info("Snapshot created: ${volume_id}")
 
69
        except Exception, e:
 
70
            self.notify(subject="${instance_id} Backup Failed", body=traceback.format_exc())
 
71
        finally:
 
72
            self.run("/usr/sbin/xfs_freeze -u ${mount_point}")
 
73
 
 
74
if __name__ == "__main__":
 
75
    b = Backup()
 
76
    b.main()
 
77
"""
 
78
 
 
79
BackupCleanupScript= """#!/usr/bin/env python
 
80
import boto
 
81
from boto.manage.volume import Volume
 
82
 
 
83
# Cleans Backups of EBS volumes
 
84
 
 
85
for v in Volume.all():
 
86
    v.trim_snapshots(True)
 
87
"""
 
88
    
 
89
class EBSInstaller(Installer):
 
90
    """
 
91
    Set up the EBS stuff
 
92
    """
 
93
 
 
94
    def __init__(self, config_file=None):
 
95
        Installer.__init__(self, config_file)
 
96
        self.instance_id = boto.config.get('Instance', 'instance-id')
 
97
        self.device = boto.config.get('EBS', 'device', '/dev/sdp')
 
98
        self.volume_id = boto.config.get('EBS', 'volume_id')
 
99
        self.logical_volume_name = boto.config.get('EBS', 'logical_volume_name')
 
100
        self.mount_point = boto.config.get('EBS', 'mount_point', '/ebs')
 
101
 
 
102
    def attach(self):
 
103
        ec2 = boto.connect_ec2()
 
104
        if self.logical_volume_name:
 
105
            # if a logical volume was specified, override the specified volume_id
 
106
            # (if there was one) with the current AWS volume for the logical volume:
 
107
            logical_volume = Volume.find(name = self.logical_volume_name).next()
 
108
            self.volume_id = logical_volume._volume_id
 
109
        volume = ec2.get_all_volumes([self.volume_id])[0]
 
110
        # wait for the volume to be available. The volume may still be being created
 
111
        # from a snapshot.
 
112
        while volume.update() != 'available':
 
113
            boto.log.info('Volume %s not yet available. Current status = %s.' % (volume.id, volume.status))
 
114
            time.sleep(5)
 
115
        ec2.attach_volume(self.volume_id, self.instance_id, self.device)
 
116
        # now wait for the volume device to appear
 
117
        while not os.path.exists(self.device):
 
118
            boto.log.info('%s still does not exist, waiting 10 seconds' % self.device)
 
119
            time.sleep(10)
 
120
 
 
121
    def make_fs(self):
 
122
        boto.log.info('make_fs...')
 
123
        has_fs = self.run('fsck %s' % self.device)
 
124
        if has_fs != 0:
 
125
            self.run('mkfs -t xfs %s' % self.device)
 
126
 
 
127
    def create_backup_script(self):
 
128
        t = Template(BackupScriptTemplate)
 
129
        s = t.substitute(volume_id=self.volume_id, instance_id=self.instance_id,
 
130
                         mount_point=self.mount_point)
 
131
        fp = open('/usr/local/bin/ebs_backup', 'w')
 
132
        fp.write(s)
 
133
        fp.close()
 
134
        self.run('chmod +x /usr/local/bin/ebs_backup')
 
135
 
 
136
    def create_backup_cleanup_script(self):
 
137
        fp = open('/usr/local/bin/ebs_backup_cleanup', 'w')
 
138
        fp.write(BackupCleanupScript)
 
139
        fp.close()
 
140
        self.run('chmod +x /usr/local/bin/ebs_backup_cleanup')
 
141
 
 
142
    def handle_mount_point(self):
 
143
        boto.log.info('handle_mount_point')
 
144
        if not os.path.isdir(self.mount_point):
 
145
            boto.log.info('making directory')
 
146
            # mount directory doesn't exist so create it
 
147
            self.run("mkdir %s" % self.mount_point)
 
148
        else:
 
149
            boto.log.info('directory exists already')
 
150
            self.run('mount -l')
 
151
            lines = self.last_command.output.split('\n')
 
152
            for line in lines:
 
153
                t = line.split()
 
154
                if t and t[2] == self.mount_point:
 
155
                    # something is already mounted at the mount point
 
156
                    # unmount that and mount it as /tmp
 
157
                    if t[0] != self.device:
 
158
                        self.run('umount %s' % self.mount_point)
 
159
                        self.run('mount %s /tmp' % t[0])
 
160
                        self.run('chmod 777 /tmp')
 
161
                        break
 
162
        # Mount up our new EBS volume onto mount_point
 
163
        self.run("mount %s %s" % (self.device, self.mount_point))
 
164
        self.run('xfs_growfs %s' % self.mount_point)
 
165
 
 
166
    def update_fstab(self):
 
167
        f = open("/etc/fstab", "a")
 
168
        f.write('%s\t%s\txfs\tdefaults 0 0\n' % (self.mount_point, self.device))
 
169
        f.close()
 
170
 
 
171
    def install(self):
 
172
        # First, find and attach the volume
 
173
        self.attach()
 
174
        
 
175
        # Install the xfs tools
 
176
        self.run('apt-get -y install xfsprogs xfsdump')
 
177
 
 
178
        # Check to see if the filesystem was created or not
 
179
        self.make_fs()
 
180
 
 
181
        # create the /ebs directory for mounting
 
182
        self.handle_mount_point()
 
183
 
 
184
        # create the backup script
 
185
        self.create_backup_script()
 
186
 
 
187
        # Set up the backup script
 
188
        minute = boto.config.get('EBS', 'backup_cron_minute', '0')
 
189
        hour = boto.config.get('EBS', 'backup_cron_hour', '4,16')
 
190
        self.add_cron("ebs_backup", "/usr/local/bin/ebs_backup", minute=minute, hour=hour)
 
191
 
 
192
        # Set up the backup cleanup script
 
193
        minute = boto.config.get('EBS', 'backup_cleanup_cron_minute')
 
194
        hour = boto.config.get('EBS', 'backup_cleanup_cron_hour')
 
195
        if (minute != None) and (hour != None):
 
196
            self.create_backup_cleanup_script();
 
197
            self.add_cron("ebs_backup_cleanup", "/usr/local/bin/ebs_backup_cleanup", minute=minute, hour=hour)
 
198
 
 
199
        # Set up the fstab
 
200
        self.update_fstab()
 
201
 
 
202
    def main(self):
 
203
        if not os.path.exists(self.device):
 
204
            self.install()
 
205
        else:
 
206
            boto.log.info("Device %s is already attached, skipping EBS Installer" % self.device)