Class: RightAws::AcfInterface

Inherits:
RightAwsBase show all
Includes:
RightAwsBaseInterface
Defined in:
lib/acf/right_acf_interface.rb

Overview

RightAws::AcfInterface – RightScale Amazon’s CloudFront interface

The AcfInterface class provides a complete interface to Amazon’s CloudFront service.

For explanations of the semantics of each call, please refer to Amazon’s documentation at developer.amazonwebservices.com/connect/kbcategory.jspa?categoryID=211

Example:

acf = RightAws::AcfInterface.new('1E3GDYEOGFJPIT7XXXXXX','hgTHt68JY07JKUY08ftHYtERkjgtfERn57XXXXXX')

list = acf.list_distributions #=>
  [{:status             => "Deployed",
    :domain_name        => "d74zzrxmpmygb.6hops.net",
    :aws_id             => "E4U91HCJHGXVC",
    :origin             => "my-bucket.s3.amazonaws.com",
    :cnames             => ["x1.my-awesome-site.net", "x1.my-awesome-site.net"]
    :comment            => "My comments",
    :last_modified_time => Wed Sep 10 17:00:04 UTC 2008 }, ..., {...} ]

distibution = list.first

info = acf.get_distribution(distibution[:aws_id]) #=>
  {:enabled            => true,
   :caller_reference   => "200809102100536497863003",
   :e_tag              => "E39OHHU1ON65SI",
   :status             => "Deployed",
   :domain_name        => "d3dxv71tbbt6cd.6hops.net",
   :cnames             => ["web1.my-awesome-site.net", "web2.my-awesome-site.net"]
   :aws_id             => "E2REJM3VUN5RSI",
   :comment            => "Woo-Hoo!",
   :origin             => "my-bucket.s3.amazonaws.com",
   :last_modified_time => Wed Sep 10 17:00:54 UTC 2008 }

config = acf.get_distribution_config(distibution[:aws_id]) #=>
  {:enabled          => true,
   :caller_reference => "200809102100536497863003",
   :e_tag            => "E39OHHU1ON65SI",
   :cnames           => ["web1.my-awesome-site.net", "web2.my-awesome-site.net"]
   :comment          => "Woo-Hoo!",
   :origin           => "my-bucket.s3.amazonaws.com"}

config[:comment] = 'Olah-lah!'
config[:enabled] = false
config[:cnames] << "web3.my-awesome-site.net"

acf.set_distribution_config(distibution[:aws_id], config) #=> true

Defined Under Namespace

Classes: AcfDistributionListParser

Constant Summary collapse

API_VERSION =
"2009-04-02"
DEFAULT_HOST =
'cloudfront.amazonaws.com'
DEFAULT_PORT =
443
DEFAULT_PROTOCOL =
'https'
DEFAULT_PATH =
'/'
@@bench =
AwsBenchmarkingBlock.new

Constants included from RightAwsBaseInterface

RightAwsBaseInterface::DEFAULT_SIGNATURE_VERSION

Constants inherited from RightAwsBase

RightAwsBase::AMAZON_PROBLEMS

Instance Attribute Summary

Attributes included from RightAwsBaseInterface

#aws_access_key_id, #cache, #connection, #last_errors, #last_request, #last_request_id, #last_response, #logger, #params, #signature_version

Class Method Summary collapse

Instance Method Summary collapse

Methods included from RightAwsBaseInterface

#amazonize_list, #cache_hits?, caching, caching=, #caching?, #generate_request_impl, #get_connection, #init, #on_exception, #request_cache_or_info, #request_info_impl, #signed_service_params, #update_cache

Methods inherited from RightAwsBase

amazon_problems, amazon_problems=

Constructor Details

#initialize(aws_access_key_id = nil, aws_secret_access_key = nil, params = {}) ⇒ AcfInterface

Create a new handle to a CloudFront account. All handles share the same per process or per thread HTTP connection to CloudFront. Each handle is for a specific account. The params have the following options:

  • :endpoint_url a fully qualified url to Amazon API endpoint (this overwrites: :server, :port, :service, :protocol). Example: ‘cloudfront.amazonaws.com

  • :server: CloudFront service host, default: DEFAULT_HOST

  • :port: CloudFront service port, default: DEFAULT_PORT

  • :protocol: ‘http’ or ‘https’, default: DEFAULT_PROTOCOL

  • :multi_thread: true=HTTP connection per thread, false=per process

  • :logger: for log messages, default: RAILS_DEFAULT_LOGGER else STDOUT

acf = RightAws::AcfInterface.new('1E3GDYEOGFJPIT7XXXXXX','hgTHt68JY07JKUY08ftHYtERkjgtfERn57XXXXXX',
  {:logger => Logger.new('/tmp/x.log')}) #=>  #<RightAws::AcfInterface::0xb7b3c30c>


106
107
108
109
110
111
112
113
114
115
116
# File 'lib/acf/right_acf_interface.rb', line 106

def initialize(aws_access_key_id=nil, aws_secret_access_key=nil, params={})
  init({ :name                => 'ACF',
         :default_host        => ENV['ACF_URL'] ? URI.parse(ENV['ACF_URL']).host   : DEFAULT_HOST,
         :default_port        => ENV['ACF_URL'] ? URI.parse(ENV['ACF_URL']).port   : DEFAULT_PORT,
         :default_service     => ENV['ACF_URL'] ? URI.parse(ENV['ACF_URL']).path   : DEFAULT_PATH,
         :default_protocol    => ENV['ACF_URL'] ? URI.parse(ENV['ACF_URL']).scheme : DEFAULT_PROTOCOL,
         :default_api_version => ENV['ACF_API_VERSION'] || API_VERSION },
       aws_access_key_id     || ENV['AWS_ACCESS_KEY_ID'], 
       aws_secret_access_key || ENV['AWS_SECRET_ACCESS_KEY'], 
       params)
end

Class Method Details

.bench_serviceObject



89
90
91
# File 'lib/acf/right_acf_interface.rb', line 89

def self.bench_service
  @@bench.service
end

.bench_xmlObject



86
87
88
# File 'lib/acf/right_acf_interface.rb', line 86

def self.bench_xml
  @@bench.xml
end

.escape(text) ⇒ Object


Helpers:



158
159
160
# File 'lib/acf/right_acf_interface.rb', line 158

def self.escape(text) # :nodoc:
  REXML::Text::normalize(text)
end

.unescape(text) ⇒ Object

:nodoc:



162
163
164
# File 'lib/acf/right_acf_interface.rb', line 162

def self.unescape(text) # :nodoc:
  REXML::Text::unnormalize(text)
end

Instance Method Details

#config_to_xml(config) ⇒ Object

:nodoc:



178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
# File 'lib/acf/right_acf_interface.rb', line 178

def config_to_xml(config) # :nodoc:
  cnames = ''
  unless config[:cnames].blank?
    config[:cnames].to_a.each { |cname| cnames += "  <CNAME>#{cname}</CNAME>\n" }
  end
  # logging
  logging = ''
  unless config[:logging].blank?
    logging = "  <Logging>\n" +
              "    <Bucket>#{config[:logging][:bucket]}</Bucket>\n" +
              "    <Prefix>#{config[:logging][:prefix]}</Prefix>\n" +
              "  </Logging>\n"
  end
  # xml
  "<?xml version=\"1.0\" encoding=\"UTF-8\"?>\n" +
  "<DistributionConfig xmlns=\"http://#{@params[:server]}/doc/#{API_VERSION}/\">\n" +
  "  <Origin>#{config[:origin]}</Origin>\n" +
  "  <CallerReference>#{config[:caller_reference]}</CallerReference>\n" +
  "  <Comment>#{AcfInterface::escape(config[:comment].to_s)}</Comment>\n" +
  "  <Enabled>#{config[:enabled]}</Enabled>\n" +
  cnames  +
  logging +
  "</DistributionConfig>"
end

#create_distribution(origin, comment = '', enabled = true, cnames = [], caller_reference = nil, logging = {}) ⇒ Object

Create a new distribution. Returns the just created distribution or RightAws::AwsError exception.

acf.create_distribution('my-bucket.s3.amazonaws.com', 'Woo-Hoo!', true, ['web1.my-awesome-site.net'],
                        { :prefix=>"log/", :bucket=>"my-logs.s3.amazonaws.com" } ) #=>
  {:comment            => "Woo-Hoo!",
   :enabled            => true,
   :location           => "https://cloudfront.amazonaws.com/2008-06-30/distribution/E2REJM3VUN5RSI",
   :status             => "InProgress",
   :aws_id             => "E2REJM3VUN5RSI",
   :domain_name        => "d3dxv71tbbt6cd.6hops.net",
   :origin             => "my-bucket.s3.amazonaws.com",
   :cnames             => ["web1.my-awesome-site.net"],
   :logging            => { :prefix => "log/",
                            :bucket => "my-logs.s3.amazonaws.com"},
   :last_modified_time => Wed Sep 10 17:00:54 UTC 2008,
   :caller_reference   => "200809102100536497863003"}


290
291
292
293
294
295
296
297
298
# File 'lib/acf/right_acf_interface.rb', line 290

def create_distribution(origin, comment='', enabled=true, cnames=[], caller_reference=nil, logging={})
  config = { :origin  => origin,
             :comment => comment,
             :enabled => enabled,
             :cnames  => cnames.to_a,
             :caller_reference => caller_reference }
  config[:logging] = logging unless logging.blank?
  create_distribution_by_config(config)
end

#create_distribution_by_config(config) ⇒ Object



300
301
302
303
304
# File 'lib/acf/right_acf_interface.rb', line 300

def create_distribution_by_config(config)
  config[:caller_reference] ||= generate_call_reference
  link = generate_request('POST', 'distribution', {}, config_to_xml(config))
  merge_headers(request_info(link, AcfDistributionListParser.new(:logger => @logger))[:distributions].first)
end

#delete_distribution(aws_id, e_tag) ⇒ Object

Delete a distribution. The enabled distribution cannot be deleted. Returns true on success or RightAws::AwsError exception.

acf.delete_distribution('E2REJM3VUN5RSI', 'E39OHHU1ON65SI') #=> true


368
369
370
371
372
# File 'lib/acf/right_acf_interface.rb', line 368

def delete_distribution(aws_id, e_tag)
  link = generate_request('DELETE', "distribution/#{aws_id}", {}, nil,
                                    'If-Match' => e_tag)
  request_info(link, RightHttp2xxParser.new(:logger => @logger))
end

#generate_call_referenceObject

:nodoc:



166
167
168
169
170
# File 'lib/acf/right_acf_interface.rb', line 166

def generate_call_reference # :nodoc:
  result = Time.now.strftime('%Y%m%d%H%M%S')
  10.times{ result << rand(10).to_s }
  result
end

#generate_request(method, path, params = {}, body = nil, headers = {}) ⇒ Object

Generates request hash for REST API.



123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
# File 'lib/acf/right_acf_interface.rb', line 123

def generate_request(method, path, params={}, body=nil, headers={})  # :nodoc:
# Params
params.delete_if{ |key, val| val.blank? }
unless params.blank?
  path += "?" + params.to_a.collect{ |key,val| "#{AwsUtils::amz_escape(key)}=#{AwsUtils::amz_escape(val.to_s)}" }.join("&")
end
# Headers
headers['content-type'] ||= 'text/xml' if body
headers['date'] = Time.now.httpdate
# Auth
signature = AwsUtils::sign(@aws_secret_access_key, headers['date'])
headers['Authorization'] = "AWS #{@aws_access_key_id}:#{signature}"
# Request
path    = "#{@params[:service]}#{@params[:api_version]}/#{path}"
request = "Net::HTTP::#{method.capitalize}".constantize.new(path)
request.body = body if body
# Set request headers
headers.each { |key, value| request[key.to_s] = value }
# prepare output hash
{ :request  => request, 
  :server   => @params[:server],
  :port     => @params[:port],
  :protocol => @params[:protocol] }
end

#get_distribution(aws_id) ⇒ Object

Get a distribution’s information. Returns a distribution’s information or RightAws::AwsError exception.

acf.get_distribution('E2REJM3VUN5RSI') #=>
  {:enabled            => true,
   :caller_reference   => "200809102100536497863003",
   :e_tag              => "E39OHHU1ON65SI",
   :status             => "Deployed",
   :domain_name        => "d3dxv71tbbt6cd.6hops.net",
   :cnames             => ["web1.my-awesome-site.net", "web2.my-awesome-site.net"]
   :aws_id             => "E2REJM3VUN5RSI",
   :comment            => "Woo-Hoo!",
   :origin             => "my-bucket.s3.amazonaws.com",
   :last_modified_time => Wed Sep 10 17:00:54 UTC 2008 }


321
322
323
324
# File 'lib/acf/right_acf_interface.rb', line 321

def get_distribution(aws_id)
  link = generate_request('GET', "distribution/#{aws_id}")
  merge_headers(request_info(link, AcfDistributionListParser.new(:logger => @logger))[:distributions].first)
end

#get_distribution_config(aws_id) ⇒ Object

Get a distribution’s configuration. Returns a distribution’s configuration or RightAws::AwsError exception.

acf.get_distribution_config('E2REJM3VUN5RSI') #=>
  {:enabled          => true,
   :caller_reference => "200809102100536497863003",
   :e_tag            => "E39OHHU1ON65SI",
   :cnames           => ["web1.my-awesome-site.net", "web2.my-awesome-site.net"]
   :comment          => "Woo-Hoo!",
   :origin           => "my-bucket.s3.amazonaws.com"}


337
338
339
340
# File 'lib/acf/right_acf_interface.rb', line 337

def get_distribution_config(aws_id)
  link = generate_request('GET', "distribution/#{aws_id}/config")
  merge_headers(request_info(link, AcfDistributionListParser.new(:logger => @logger))[:distributions].first)
end

#incrementally_list_distributions(params = {}, &block) ⇒ Object

Incrementally list distributions.

Optional params: :marker and :max_items.

# get first distribution
incrementally_list_distributions(:max_items => 1) #=>
   {:distributions=>
     [{:status=>"Deployed",
       :aws_id=>"E2Q0AOOMFNPSYL",
       :logging=>{},
       :origin=>"my-bucket.s3.amazonaws.com",
       :domain_name=>"d1s5gmdtmafnre.6hops.net",
       :comment=>"ONE LINE OF COMMENT",
       :last_modified_time=>Wed Oct 22 19:31:23 UTC 2008,
       :enabled=>true,
       :cnames=>[]}],
    :is_truncated=>true,
    :max_items=>1,
    :marker=>"",
    :next_marker=>"E2Q0AOOMFNPSYL"}

# get max 100 distributions (the list will be restricted by a default MaxItems value ==100 )
incrementally_list_distributions

# list distributions by 10
incrementally_list_distributions(:max_items => 10) do |response|
  puts response.inspect # a list of 10 distributions
  false # return false if the listing should be broken otherwise use true
end


258
259
260
261
262
263
264
265
266
267
268
269
270
# File 'lib/acf/right_acf_interface.rb', line 258

def incrementally_list_distributions(params={}, &block)
  opts = {}
  opts['MaxItems'] = params[:max_items] if params[:max_items]
  opts['Marker']   = params[:marker]    if params[:marker]
  last_response = nil
  loop do
    link = generate_request('GET', 'distribution', opts)
    last_response = request_info(link,  AcfDistributionListParser.new(:logger => @logger))
    opts['Marker'] = last_response[:next_marker]
    break unless block && block.call(last_response) && !last_response[:next_marker].blank?
  end 
  last_response 
end

#list_distributionsObject

List all distributions. Returns an array of distributions or RightAws::AwsError exception.

acf.list_distributions #=>
  [{:status             => "Deployed",
    :domain_name        => "d74zzrxmpmygb.6hops.net",
    :aws_id             => "E4U91HCJHGXVC",
    :cnames             => ["web1.my-awesome-site.net", "web2.my-awesome-site.net"]
    :origin             => "my-bucket.s3.amazonaws.com",
    :comment            => "My comments",
    :last_modified_time => Wed Sep 10 17:00:04 UTC 2008 }, ..., {...} ]


219
220
221
222
223
224
225
226
# File 'lib/acf/right_acf_interface.rb', line 219

def list_distributions
  result = []
  incrementally_list_distributions do |response|
    result += response[:distributions]
    true
  end
  result
end

#merge_headers(hash) ⇒ Object

:nodoc:



172
173
174
175
176
# File 'lib/acf/right_acf_interface.rb', line 172

def merge_headers(hash) # :nodoc:
  hash[:location] = @last_response['Location'] if @last_response['Location']
  hash[:e_tag]    = @last_response['ETag']     if @last_response['ETag']
  hash
end

#request_info(request, parser, &block) ⇒ Object

Sends request to Amazon and parses the response. Raises AwsError if any banana happened.



150
151
152
# File 'lib/acf/right_acf_interface.rb', line 150

def request_info(request, parser, &block) # :nodoc:
  request_info_impl(:acf_connection, @@bench, request, parser, &block)
end

#set_distribution_config(aws_id, config) ⇒ Object

Set a distribution’s configuration (the :origin and the :caller_reference cannot be changed). Returns true on success or RightAws::AwsError exception.

config = acf.get_distribution_config('E2REJM3VUN5RSI') #=>
  {:enabled          => true,
   :caller_reference => "200809102100536497863003",
   :e_tag            => "E39OHHU1ON65SI",
   :cnames           => ["web1.my-awesome-site.net", "web2.my-awesome-site.net"]
   :comment          => "Woo-Hoo!",
   :origin           => "my-bucket.s3.amazonaws.com"}
config[:comment] = 'Olah-lah!'
config[:enabled] = false
acf.set_distribution_config('E2REJM3VUN5RSI', config) #=> true


357
358
359
360
361
# File 'lib/acf/right_acf_interface.rb', line 357

def set_distribution_config(aws_id, config)
  link = generate_request('PUT', "distribution/#{aws_id}/config", {}, config_to_xml(config),
                                 'If-Match' => config[:e_tag])
  request_info(link, RightHttp2xxParser.new(:logger => @logger))
end