lib/boxgrinder-build/plugins/delivery/s3/s3-plugin.rb in boxgrinder-build-0.9.2 vs lib/boxgrinder-build/plugins/delivery/s3/s3-plugin.rb in boxgrinder-build-0.9.3
- old
+ new
@@ -20,20 +20,15 @@
require 'boxgrinder-build/plugins/base-plugin'
require 'boxgrinder-build/helpers/package-helper'
require 'AWS'
require 'aws'
-# TODO remove this when it'll become not necessary
-# quick fix for old active_support require issue in EPEL 5
-require 'active_support/basic_object'
-require 'active_support/duration'
-
module BoxGrinder
class S3Plugin < BasePlugin
REGION_OPTIONS = {
'eu-west-1' => {
- :endpoint => 's3.amazonaws.com',
+ :endpoint => 's3-eu-west-1.amazonaws.com',
:location => 'EU',
:kernel => {
'i386' => {:aki => 'aki-4deec439'},
'x86_64' => {:aki => 'aki-4feec43b'}
}
@@ -46,10 +41,20 @@
'i386' => {:aki => 'aki-13d5aa41'},
'x86_64' => {:aki => 'aki-11d5aa43'}
}
},
+ 'ap-northeast-1' => {
+ :endpoint => 's3-ap-northeast-1.amazonaws.com',
+ :location => 'ap-northeast-1',
+ :kernel => {
+ 'i386' => {:aki => 'aki-d209a2d3'},
+ 'x86_64' => {:aki => 'aki-d409a2d5'}
+ }
+
+ },
+
'us-west-1' => {
:endpoint => 's3-us-west-1.amazonaws.com',
:location => 'us-west-1',
:kernel => {
'i386' => {:aki => 'aki-99a0f1dc'},
@@ -66,42 +71,59 @@
}
}
}
def after_init
- set_default_config_value('overwrite', false)
- set_default_config_value('path', '/')
- set_default_config_value('region', 'us-east-1')
-
register_supported_os("fedora", ['13', '14', '15'])
register_supported_os("centos", ['5'])
register_supported_os("rhel", ['5', '6'])
+ register_supported_os("sl", ['5', '6'])
@ami_build_dir = "#{@dir.base}/ami"
@ami_manifest = "#{@ami_build_dir}/#{@appliance_config.name}.ec2.manifest.xml"
end
- def execute(type = :ami)
+ def validate
+ set_default_config_value('overwrite', false)
+ set_default_config_value('path', '/')
+ set_default_config_value('region', 'us-east-1')
validate_plugin_config(['bucket', 'access_key', 'secret_access_key'], 'http://boxgrinder.org/tutorials/boxgrinder-build-plugins/#S3_Delivery_Plugin')
- case type
+ subtype(:ami) do
+ set_default_config_value('snapshot', false)
+ validate_plugin_config(['cert_file', 'key_file', 'account_number'], 'http://boxgrinder.org/tutorials/boxgrinder-build-plugins/#S3_Delivery_Plugin')
+ end
+
+ raise PluginValidationError, "Invalid region specified: #{@plugin_config['region']}. This plugin only aware of the following regions: #{REGION_OPTIONS.keys.join(", ")}" unless REGION_OPTIONS.has_key?(@plugin_config['region'])
+
+ end
+
+ def execute
+ case @type
when :s3
upload_to_bucket(@previous_deliverables)
when :cloudfront
upload_to_bucket(@previous_deliverables, 'public-read')
when :ami
- set_default_config_value('snapshot', false)
- validate_plugin_config(['cert_file', 'key_file', 'account_number'], 'http://boxgrinder.org/tutorials/boxgrinder-build-plugins/#S3_Delivery_Plugin')
-
@plugin_config['account_number'] = @plugin_config['account_number'].to_s.gsub(/-/, '')
@ec2 = AWS::EC2::Base.new(:access_key_id => @plugin_config['access_key'], :secret_access_key => @plugin_config['secret_access_key'], :server => "ec2.#{@plugin_config['region']}.amazonaws.com")
ami_dir = ami_key(@appliance_config.name, @plugin_config['path'])
ami_manifest_key = "#{ami_dir}/#{@appliance_config.name}.ec2.manifest.xml"
+ s3_object_exists = s3_object_exists?(ami_manifest_key)
- if !s3_object_exists?(ami_manifest_key) or @plugin_config['snapshot']
+ @log.debug "Going to check whether s3 object exists"
+
+ if s3_object_exists and @plugin_config['overwrite']
+ @log.info "Object exists, attempting to deregister an existing image"
+ deregister_image(ami_manifest_key) # Remove existing image
+ bucket().delete_folder(ami_dir) # Avoid triggering dupe detection
+ end
+
+ if !s3_object_exists or @plugin_config['snapshot']
+ @log.info "Doing bundle/snapshot"
bundle_image(@previous_deliverables)
fix_sha1_sum
upload_image(ami_dir)
else
@log.debug "AMI for #{@appliance_config.name} appliance already uploaded, skipping..."
@@ -129,14 +151,14 @@
PackageHelper.new(@config, @appliance_config, :log => @log, :exec_helper => @exec_helper).package(File.dirname(previous_deliverables[:disk]), @deliverables[:package])
remote_path = "#{s3_path(@plugin_config['path'])}#{File.basename(@deliverables[:package])}"
size_b = File.size(@deliverables[:package])
-
key = bucket(true, permissions).key(remote_path.gsub(/^\//, '').gsub(/\/\//, ''))
- unless key.exists? or @plugin_config['overwrite']
+ if !key.exists? or @plugin_config['overwrite']
+ @log.info "Will overwrite existing file #{remote_path}" if key.exists? and @plugin_config['overwrite']
@log.info "Uploading #{File.basename(@deliverables[:package])} (#{size_b/1024/1024}MB) to '#{@plugin_config['bucket']}#{remote_path}' path..."
key.put(open(@deliverables[:package]), permissions, :server => REGION_OPTIONS[@plugin_config['region']][:endpoint])
@log.info "Appliance #{@appliance_config.name} uploaded to S3."
else
@log.info "File '#{@plugin_config['bucket']}#{remote_path}' already uploaded, skipping."
@@ -183,10 +205,20 @@
info = @ec2.register_image(:image_location => "#{@plugin_config['bucket']}/#{ami_manifest_key}")
@log.info "Image for #{@appliance_config.name} successfully registered under id: #{info.imageId} (region: #{@plugin_config['region']})."
end
end
+ def deregister_image(ami_manifest_key)
+ info = ami_info(ami_manifest_key)
+ if info
+ @ec2.deregister_image(:image_id => info.imageId)
+ @log.info "Preexisting image '#{info.imageLocation}' for #{@appliance_config.name} was successfully de-registered, it had id: #{info.imageId} (region: #{@plugin_config['region']})."
+ else # This occurs when the AMI is de-registered externally but the file structure is left intact in S3. In this instance, we simply overwrite and register the image as if it were "new".
+ @log.info "Possible dangling/unregistered AMI skeleton structure in S3, there is nothing to deregister"
+ end
+ end
+
def ami_info(ami_manifest_key)
ami_info = nil
images = @ec2.describe_images(:owner_id => @plugin_config['account_number']).imagesSet
@@ -208,25 +240,30 @@
def ami_key(appliance_name, path)
base_path = "#{s3_path(path)}#{appliance_name}/#{@appliance_config.os.name}/#{@appliance_config.os.version}/#{@appliance_config.version}.#{@appliance_config.release}"
return "#{base_path}/#{@appliance_config.hardware.arch}" unless @plugin_config['snapshot']
+ @log.info "Determining snapshot name"
+
snapshot = 1
while s3_object_exists?("#{base_path}-SNAPSHOT-#{snapshot}/#{@appliance_config.hardware.arch}/")
snapshot += 1
end
+ # Reuse the last key (if there was one)
+ snapshot -=1 if snapshot > 1 and @plugin_config['overwrite']
+
"#{base_path}-SNAPSHOT-#{snapshot}/#{@appliance_config.hardware.arch}"
end
def s3_object_exists?(path)
@log.trace "Checking if '#{path}' path exists in #{@plugin_config['bucket']}..."
begin
b = bucket(false)
- # Retrieve only one or no keys (if bucket is empty), throw an exception if bucket doesn't exists
+ # Retrieve only one or no keys (if bucket is empty), throw an exception if bucket doesn't exist
b.keys('max-keys' => 1)
if b.key(path).exists?
@log.trace "Path exists!"
return true
@@ -237,6 +274,6 @@
false
end
end
end
-plugin :class => BoxGrinder::S3Plugin, :type => :delivery, :name => :s3, :full_name => "Amazon Simple Storage Service (Amazon S3)", :types => [:s3, :cloudfront, :ami]
+plugin :class => BoxGrinder::S3Plugin, :type => :delivery, :name => :s3, :full_name => "Amazon Simple Storage Service (Amazon S3)", :types => [:s3, :cloudfront, :ami]
\ No newline at end of file