Class BoxGrinder::EBSPlugin
In: lib/boxgrinder-build/plugins/delivery/ebs/ebs-plugin.rb
lib/boxgrinder-build/plugins/delivery/ebs/ebs-plugin.rb
Parent: BasePlugin

Methods

Constants

KERNELS = { 'eu-west-1' => { 'i386' => {:aki => 'aki-4deec439'}, 'x86_64' => {:aki => 'aki-4feec43b'}
KERNELS = { 'eu-west-1' => { 'i386' => {:aki => 'aki-4deec439'}, 'x86_64' => {:aki => 'aki-4feec43b'}

Public Instance methods

[Source]

     # File lib/boxgrinder-build/plugins/delivery/ebs/ebs-plugin.rb, line 203
203:     def adjust_fstab(guestfs)
204:       guestfs.sh("cat /etc/fstab | grep -v '/mnt' | grep -v '/data' | grep -v 'swap' > /etc/fstab.new")
205:       guestfs.mv("/etc/fstab.new", "/etc/fstab")
206:     end

[Source]

     # File lib/boxgrinder-build/plugins/delivery/ebs/ebs-plugin.rb, line 203
203:     def adjust_fstab(guestfs)
204:       guestfs.sh("cat /etc/fstab | grep -v '/mnt' | grep -v '/data' | grep -v 'swap' > /etc/fstab.new")
205:       guestfs.mv("/etc/fstab.new", "/etc/fstab")
206:     end

[Source]

    # File lib/boxgrinder-build/plugins/delivery/ebs/ebs-plugin.rb, line 45
45:     def after_init
46:       if valid_platform?
47:         @current_avaibility_zone = open('http://169.254.169.254/latest/meta-data/placement/availability-zone').string
48:         @region = @current_avaibility_zone.scan(/((\w+)-(\w+)-(\d+))/).flatten.first
49:       end
50: 
51:       set_default_config_value('availability_zone', @current_avaibility_zone)
52:       set_default_config_value('delete_on_termination', true)
53: 
54:       register_supported_os('fedora', ['13', '14', '15'])
55:       register_supported_os('rhel', ['6'])
56:     end

[Source]

    # File lib/boxgrinder-build/plugins/delivery/ebs/ebs-plugin.rb, line 45
45:     def after_init
46:       if valid_platform?
47:         @current_avaibility_zone = open('http://169.254.169.254/latest/meta-data/placement/availability-zone').string
48:         @region = @current_avaibility_zone.scan(/((\w+)-(\w+)-(\d+))/).flatten.first
49:       end
50: 
51:       set_default_config_value('availability_zone', @current_avaibility_zone)
52:       set_default_config_value('delete_on_termination', true)
53: 
54:       register_supported_os('fedora', ['13', '14', '15'])
55:       register_supported_os('rhel', ['6'])
56:     end

[Source]

     # File lib/boxgrinder-build/plugins/delivery/ebs/ebs-plugin.rb, line 193
193:     def already_registered?(name)
194:       images = @ec2.describe_images(:owner_id => @plugin_config['account_number'].to_s.gsub(/-/, ''))
195: 
196:       return false if images.nil? or images['imagesSet'].nil?
197: 
198:       images['imagesSet']['item'].each { |image| return image['imageId'] if image['name'] == name }
199: 
200:       false
201:     end

[Source]

     # File lib/boxgrinder-build/plugins/delivery/ebs/ebs-plugin.rb, line 193
193:     def already_registered?(name)
194:       images = @ec2.describe_images(:owner_id => @plugin_config['account_number'].to_s.gsub(/-/, ''))
195: 
196:       return false if images.nil? or images['imagesSet'].nil?
197: 
198:       images['imagesSet']['item'].each { |image| return image['imageId'] if image['name'] == name }
199: 
200:       false
201:     end

[Source]

     # File lib/boxgrinder-build/plugins/delivery/ebs/ebs-plugin.rb, line 226
226:     def device_for_suffix(suffix)
227:       return "/dev/sd#{suffix}" if File.exists?("/dev/sd#{suffix}")
228:       return "/dev/xvd#{suffix}" if File.exists?("/dev/xvd#{suffix}")
229: 
230:       raise "Device for suffix '#{suffix}' not found!"
231:     end

[Source]

     # File lib/boxgrinder-build/plugins/delivery/ebs/ebs-plugin.rb, line 226
226:     def device_for_suffix(suffix)
227:       return "/dev/sd#{suffix}" if File.exists?("/dev/sd#{suffix}")
228:       return "/dev/xvd#{suffix}" if File.exists?("/dev/xvd#{suffix}")
229: 
230:       raise "Device for suffix '#{suffix}' not found!"
231:     end

[Source]

     # File lib/boxgrinder-build/plugins/delivery/ebs/ebs-plugin.rb, line 179
179:     def ebs_appliance_name
180:       base_path = "#{@appliance_config.name}/#{@appliance_config.os.name}/#{@appliance_config.os.version}/#{@appliance_config.version}.#{@appliance_config.release}"
181: 
182:       return "#{base_path}/#{@appliance_config.hardware.arch}" unless @plugin_config['snapshot']
183: 
184:       snapshot = 1
185: 
186:       while already_registered?("#{base_path}-SNAPSHOT-#{snapshot}/#{@appliance_config.hardware.arch}")
187:         snapshot += 1
188:       end
189: 
190:       "#{base_path}-SNAPSHOT-#{snapshot}/#{@appliance_config.hardware.arch}"
191:     end

[Source]

     # File lib/boxgrinder-build/plugins/delivery/ebs/ebs-plugin.rb, line 179
179:     def ebs_appliance_name
180:       base_path = "#{@appliance_config.name}/#{@appliance_config.os.name}/#{@appliance_config.os.version}/#{@appliance_config.version}.#{@appliance_config.release}"
181: 
182:       return "#{base_path}/#{@appliance_config.hardware.arch}" unless @plugin_config['snapshot']
183: 
184:       snapshot = 1
185: 
186:       while already_registered?("#{base_path}-SNAPSHOT-#{snapshot}/#{@appliance_config.hardware.arch}")
187:         snapshot += 1
188:       end
189: 
190:       "#{base_path}-SNAPSHOT-#{snapshot}/#{@appliance_config.hardware.arch}"
191:     end

[Source]

     # File lib/boxgrinder-build/plugins/delivery/ebs/ebs-plugin.rb, line 58
 58:     def execute(type = :ebs)
 59:       validate_plugin_config(['access_key', 'secret_access_key', 'account_number'], 'http://boxgrinder.org/tutorials/boxgrinder-build-plugins/#EBS_Delivery_Plugin')
 60: 
 61:       raise "You try to run this plugin on invalid platform. You can run EBS delivery plugin only on EC2." unless valid_platform?
 62:       raise "You can only convert to EBS type AMI appliances converted to EC2 format. Use '-p ec2' switch. For more info about EC2 plugin see http://boxgrinder.org/tutorials/boxgrinder-build-plugins/#EC2_Platform_Plugin." unless @previous_plugin_info[:name] == :ec2
 63:       raise "You selected #{@plugin_config['availability_zone']} avaibility zone, but your instance is running in #{@current_avaibility_zone} zone. Please change avaibility zone in plugin configuration file to #{@current_avaibility_zone} (see http://boxgrinder.org/tutorials/boxgrinder-build-plugins/#EBS_Delivery_Plugin) or use another instance in #{@plugin_config['availability_zone']} zone to create your EBS AMI." if @plugin_config['availability_zone'] != @current_avaibility_zone
 64: 
 65:       ebs_appliance_description = "#{@appliance_config.summary} | Appliance version #{@appliance_config.version}.#{@appliance_config.release} | #{@appliance_config.hardware.arch} architecture"
 66: 
 67:       @ec2 = AWS::EC2::Base.new(:access_key_id => @plugin_config['access_key'], :secret_access_key => @plugin_config['secret_access_key'])
 68: 
 69:       @log.debug "Checking if appliance is already registered..."
 70: 
 71:       ami_id = already_registered?(ebs_appliance_name)
 72: 
 73:       if ami_id
 74:         @log.warn "EBS AMI '#{ebs_appliance_name}' is already registered as '#{ami_id}' (region: #{@region})."
 75:         return
 76:       end
 77: 
 78:       @log.info "Creating new EBS volume..."
 79: 
 80:       size = 0
 81: 
 82:       @appliance_config.hardware.partitions.each_value { |partition| size += partition['size'] }
 83: 
 84:       # create_volume with 10GB size
 85:       volume_id = @ec2.create_volume(:size => size.to_s, :availability_zone => @plugin_config['availability_zone'])['volumeId']
 86: 
 87:       @log.debug "Volume #{volume_id} created."
 88:       @log.debug "Waiting for EBS volume #{volume_id} to be available..."
 89: 
 90:       # wait fo volume to be created
 91:       wait_for_volume_status('available', volume_id)
 92: 
 93:       # get first free device to mount the volume
 94:       suffix = free_device_suffix
 95: 
 96:       @log.trace "Got free device suffix: '#{suffix}'"
 97:       @log.trace "Reading current instance id..."
 98: 
 99:       # read current instance id
100:       instance_id = open('http://169.254.169.254/latest/meta-data/instance-id').string
101: 
102:       @log.trace "Got: #{instance_id}"
103:       @log.info "Attaching created volume..."
104: 
105:       # attach the volume to current host
106:       @ec2.attach_volume(:device => "/dev/sd#{suffix}", :volume_id => volume_id, :instance_id => instance_id)
107: 
108:       @log.debug "Waiting for EBS volume to be attached..."
109: 
110:       # wait for volume to be attached
111:       wait_for_volume_status('in-use', volume_id)
112: 
113:       sleep 10 # let's wait to discover the attached volume by OS
114: 
115:       @log.info "Copying data to EBS volume..."
116: 
117:       @image_helper.customize([@previous_deliverables.disk, device_for_suffix(suffix)], :automount => false) do |guestfs, guestfs_helper|
118:         @image_helper.sync_filesystem(guestfs, guestfs_helper)
119: 
120:         @log.debug "Adjusting /etc/fstab..."
121:         adjust_fstab(guestfs)
122:       end
123: 
124:       @log.debug "Detaching EBS volume..."
125: 
126:       @ec2.detach_volume(:device => "/dev/sd#{suffix}", :volume_id => volume_id, :instance_id => instance_id)
127: 
128:       @log.debug "Waiting for EBS volume to be available..."
129: 
130:       wait_for_volume_status('available', volume_id)
131: 
132:       @log.info "Creating snapshot from EBS volume..."
133: 
134:       snapshot_id = @ec2.create_snapshot(
135:           :volume_id => volume_id,
136:           :description => ebs_appliance_description)['snapshotId']
137: 
138:       @log.debug "Waiting for snapshot #{snapshot_id} to be completed..."
139: 
140:       wait_for_snapshot_status('completed', snapshot_id)
141: 
142:       @log.debug "Deleting temporary EBS volume..."
143: 
144:       @ec2.delete_volume(:volume_id => volume_id)
145: 
146:       @log.info "Registering image..."
147: 
148:       image_id = @ec2.register_image(
149:           :block_device_mapping => [{
150:                                         :device_name => '/dev/sda1',
151:                                         :ebs_snapshot_id => snapshot_id,
152:                                         :ebs_delete_on_termination => @plugin_config['delete_on_termination']
153:                                     },
154:                                     {
155:                                         :device_name => '/dev/sdb',
156:                                         :virtual_name => 'ephemeral0'
157:                                     },
158:                                     {
159:                                         :device_name => '/dev/sdc',
160:                                         :virtual_name => 'ephemeral1'
161:                                     },
162:                                     {
163:                                         :device_name => '/dev/sdd',
164:                                         :virtual_name => 'ephemeral2'
165:                                     },
166:                                     {
167:                                         :device_name => '/dev/sde',
168:                                         :virtual_name => 'ephemeral3'
169:                                     }],
170:           :root_device_name => '/dev/sda1',
171:           :architecture => @appliance_config.hardware.base_arch,
172:           :kernel_id => KERNELS[@region][@appliance_config.hardware.base_arch][:aki],
173:           :name => ebs_appliance_name,
174:           :description => ebs_appliance_description)['imageId']
175: 
176:       @log.info "EBS AMI '#{ebs_appliance_name}' registered: #{image_id} (region: #{@region})"
177:     end

[Source]

     # File lib/boxgrinder-build/plugins/delivery/ebs/ebs-plugin.rb, line 58
 58:     def execute(type = :ebs)
 59:       validate_plugin_config(['access_key', 'secret_access_key', 'account_number'], 'http://boxgrinder.org/tutorials/boxgrinder-build-plugins/#EBS_Delivery_Plugin')
 60: 
 61:       raise "You try to run this plugin on invalid platform. You can run EBS delivery plugin only on EC2." unless valid_platform?
 62:       raise "You can only convert to EBS type AMI appliances converted to EC2 format. Use '-p ec2' switch. For more info about EC2 plugin see http://boxgrinder.org/tutorials/boxgrinder-build-plugins/#EC2_Platform_Plugin." unless @previous_plugin_info[:name] == :ec2
 63:       raise "You selected #{@plugin_config['availability_zone']} avaibility zone, but your instance is running in #{@current_avaibility_zone} zone. Please change avaibility zone in plugin configuration file to #{@current_avaibility_zone} (see http://boxgrinder.org/tutorials/boxgrinder-build-plugins/#EBS_Delivery_Plugin) or use another instance in #{@plugin_config['availability_zone']} zone to create your EBS AMI." if @plugin_config['availability_zone'] != @current_avaibility_zone
 64: 
 65:       ebs_appliance_description = "#{@appliance_config.summary} | Appliance version #{@appliance_config.version}.#{@appliance_config.release} | #{@appliance_config.hardware.arch} architecture"
 66: 
 67:       @ec2 = AWS::EC2::Base.new(:access_key_id => @plugin_config['access_key'], :secret_access_key => @plugin_config['secret_access_key'])
 68: 
 69:       @log.debug "Checking if appliance is already registered..."
 70: 
 71:       ami_id = already_registered?(ebs_appliance_name)
 72: 
 73:       if ami_id
 74:         @log.warn "EBS AMI '#{ebs_appliance_name}' is already registered as '#{ami_id}' (region: #{@region})."
 75:         return
 76:       end
 77: 
 78:       @log.info "Creating new EBS volume..."
 79: 
 80:       size = 0
 81: 
 82:       @appliance_config.hardware.partitions.each_value { |partition| size += partition['size'] }
 83: 
 84:       # create_volume with 10GB size
 85:       volume_id = @ec2.create_volume(:size => size.to_s, :availability_zone => @plugin_config['availability_zone'])['volumeId']
 86: 
 87:       @log.debug "Volume #{volume_id} created."
 88:       @log.debug "Waiting for EBS volume #{volume_id} to be available..."
 89: 
 90:       # wait fo volume to be created
 91:       wait_for_volume_status('available', volume_id)
 92: 
 93:       # get first free device to mount the volume
 94:       suffix = free_device_suffix
 95: 
 96:       @log.trace "Got free device suffix: '#{suffix}'"
 97:       @log.trace "Reading current instance id..."
 98: 
 99:       # read current instance id
100:       instance_id = open('http://169.254.169.254/latest/meta-data/instance-id').string
101: 
102:       @log.trace "Got: #{instance_id}"
103:       @log.info "Attaching created volume..."
104: 
105:       # attach the volume to current host
106:       @ec2.attach_volume(:device => "/dev/sd#{suffix}", :volume_id => volume_id, :instance_id => instance_id)
107: 
108:       @log.debug "Waiting for EBS volume to be attached..."
109: 
110:       # wait for volume to be attached
111:       wait_for_volume_status('in-use', volume_id)
112: 
113:       sleep 10 # let's wait to discover the attached volume by OS
114: 
115:       @log.info "Copying data to EBS volume..."
116: 
117:       @image_helper.customize([@previous_deliverables.disk, device_for_suffix(suffix)], :automount => false) do |guestfs, guestfs_helper|
118:         @image_helper.sync_filesystem(guestfs, guestfs_helper)
119: 
120:         @log.debug "Adjusting /etc/fstab..."
121:         adjust_fstab(guestfs)
122:       end
123: 
124:       @log.debug "Detaching EBS volume..."
125: 
126:       @ec2.detach_volume(:device => "/dev/sd#{suffix}", :volume_id => volume_id, :instance_id => instance_id)
127: 
128:       @log.debug "Waiting for EBS volume to be available..."
129: 
130:       wait_for_volume_status('available', volume_id)
131: 
132:       @log.info "Creating snapshot from EBS volume..."
133: 
134:       snapshot_id = @ec2.create_snapshot(
135:           :volume_id => volume_id,
136:           :description => ebs_appliance_description)['snapshotId']
137: 
138:       @log.debug "Waiting for snapshot #{snapshot_id} to be completed..."
139: 
140:       wait_for_snapshot_status('completed', snapshot_id)
141: 
142:       @log.debug "Deleting temporary EBS volume..."
143: 
144:       @ec2.delete_volume(:volume_id => volume_id)
145: 
146:       @log.info "Registering image..."
147: 
148:       image_id = @ec2.register_image(
149:           :block_device_mapping => [{
150:                                         :device_name => '/dev/sda1',
151:                                         :ebs_snapshot_id => snapshot_id,
152:                                         :ebs_delete_on_termination => @plugin_config['delete_on_termination']
153:                                     },
154:                                     {
155:                                         :device_name => '/dev/sdb',
156:                                         :virtual_name => 'ephemeral0'
157:                                     },
158:                                     {
159:                                         :device_name => '/dev/sdc',
160:                                         :virtual_name => 'ephemeral1'
161:                                     },
162:                                     {
163:                                         :device_name => '/dev/sdd',
164:                                         :virtual_name => 'ephemeral2'
165:                                     },
166:                                     {
167:                                         :device_name => '/dev/sde',
168:                                         :virtual_name => 'ephemeral3'
169:                                     }],
170:           :root_device_name => '/dev/sda1',
171:           :architecture => @appliance_config.hardware.base_arch,
172:           :kernel_id => KERNELS[@region][@appliance_config.hardware.base_arch][:aki],
173:           :name => ebs_appliance_name,
174:           :description => ebs_appliance_description)['imageId']
175: 
176:       @log.info "EBS AMI '#{ebs_appliance_name}' registered: #{image_id} (region: #{@region})"
177:     end

[Source]

     # File lib/boxgrinder-build/plugins/delivery/ebs/ebs-plugin.rb, line 233
233:     def free_device_suffix
234:       ("f".."p").each do |suffix|
235:         return suffix unless File.exists?("/dev/sd#{suffix}") or File.exists?("/dev/xvd#{suffix}")
236:       end
237: 
238:       raise "Found too many attached devices. Cannot attach EBS volume."
239:     end

[Source]

     # File lib/boxgrinder-build/plugins/delivery/ebs/ebs-plugin.rb, line 233
233:     def free_device_suffix
234:       ("f".."p").each do |suffix|
235:         return suffix unless File.exists?("/dev/sd#{suffix}") or File.exists?("/dev/xvd#{suffix}")
236:       end
237: 
238:       raise "Found too many attached devices. Cannot attach EBS volume."
239:     end

[Source]

     # File lib/boxgrinder-build/plugins/delivery/ebs/ebs-plugin.rb, line 241
241:     def valid_platform?
242:       begin
243:         return Resolv.getname("169.254.169.254").include?(".ec2.internal")
244:       rescue Resolv::ResolvError
245:         false
246:       end
247:     end

[Source]

     # File lib/boxgrinder-build/plugins/delivery/ebs/ebs-plugin.rb, line 241
241:     def valid_platform?
242:       begin
243:         return Resolv.getname("169.254.169.254").include?(".ec2.internal")
244:       rescue Resolv::ResolvError
245:         false
246:       end
247:     end

[Source]

     # File lib/boxgrinder-build/plugins/delivery/ebs/ebs-plugin.rb, line 208
208:     def wait_for_snapshot_status(status, snapshot_id)
209:       snapshot = @ec2.describe_snapshots(:snapshot_id => snapshot_id)['snapshotSet']['item'].first
210: 
211:       unless snapshot['status'] == status
212:         sleep 2
213:         wait_for_snapshot_status(status, snapshot_id)
214:       end
215:     end

[Source]

     # File lib/boxgrinder-build/plugins/delivery/ebs/ebs-plugin.rb, line 208
208:     def wait_for_snapshot_status(status, snapshot_id)
209:       snapshot = @ec2.describe_snapshots(:snapshot_id => snapshot_id)['snapshotSet']['item'].first
210: 
211:       unless snapshot['status'] == status
212:         sleep 2
213:         wait_for_snapshot_status(status, snapshot_id)
214:       end
215:     end

[Source]

     # File lib/boxgrinder-build/plugins/delivery/ebs/ebs-plugin.rb, line 217
217:     def wait_for_volume_status(status, volume_id)
218:       volume = @ec2.describe_volumes(:volume_id => volume_id)['volumeSet']['item'].first
219: 
220:       unless volume['status'] == status
221:         sleep 2
222:         wait_for_volume_status(status, volume_id)
223:       end
224:     end

[Source]

     # File lib/boxgrinder-build/plugins/delivery/ebs/ebs-plugin.rb, line 217
217:     def wait_for_volume_status(status, volume_id)
218:       volume = @ec2.describe_volumes(:volume_id => volume_id)['volumeSet']['item'].first
219: 
220:       unless volume['status'] == status
221:         sleep 2
222:         wait_for_volume_status(status, volume_id)
223:       end
224:     end

[Validate]