Class: RightAws::Ec2

Inherits:
Object
  • Object
show all
Defined in:
lib/ec2/right_ec2.rb

Overview

RightAWS::EC2 – RightScale Amazon EC2 interface

The RightAws::EC2 class provides a complete interface to Amazon’s Elastic Compute Cloud service. For explanations of the semantics of each call, please refer to Amazon’s documentation at developer.amazonwebservices.com/connect/kbcategory.jspa?categoryID=87

Examples:

Create an EC2 interface handle:

@ec2   = RightAws::Ec2.new(aws_access_key_id,
                            aws_secret_access_key)

Create a new SSH key pair:

@key   = 'right_ec2_awesome_test_key'
new_key = @ec2.create_key_pair(@key)
keys = @ec2.describe_key_pairs

Create a security group:

@group = 'right_ec2_awesome_test_security_group'
@ec2.create_security_group(@group,'My awesome test group')
group = @ec2.describe_security_groups([@group])[0]

Configure a security group:

@ec2.authorize_security_group_named_ingress(@group, , 'default')
@ec2.authorize_security_group_IP_ingress(@group, 80,80,'udp','192.168.1.0/8')

Describe the available images:

images = @ec2.describe_images

Launch an instance:

ec2.run_instances('ami-9a9e7bf3', 1, 1, ['default'], @key, 'SomeImportantUserData', 'public')

Describe running instances:

@ec2.describe_instances

Error handling: all operations raise an RightAws::AwsError in case of problems. Note that transient errors are automatically retried.

Defined Under Namespace

Classes: QEc2ConfirmProductInstanceParser, QEc2CreateKeyPairParser, QEc2CreateKeyPairType, QEc2DescribeImageAttributeParser, QEc2DescribeImageAttributeType, QEc2DescribeImagesParser, QEc2DescribeImagesResponseItemType, QEc2DescribeInstancesParser, QEc2DescribeInstancesType, QEc2DescribeKeyPairParser, QEc2DescribeKeyPairType, QEc2DescribeSecurityGroupsParser, QEc2GetConsoleOutputParser, QEc2GetConsoleOutputResponseType, QEc2InstanceStateType, QEc2IpPermissionType, QEc2LaunchPermissionItemType, QEc2RegisterImageParser, QEc2RunInstancesParser, QEc2RunningInstancesItemType, QEc2SecurityGroupItemType, QEc2TerminateInstancesParser, QEc2TerminateInstancesResponseInfoType, QEc2UserIdGroupPairType, RightBoolResponseParser

Constant Summary collapse

SIGNATURE_VERSION =
"1"
API_VERSION =

Amazon EC2 API version being used

"2007-03-01"
DEFAULT_HOST =
"ec2.amazonaws.com"
DEFAULT_PROTOCOL =
'https'
DEFAULT_PORT =
443
DEFAULT_ADDRESSING_TYPE =

Default addressing type (public=NAT, direct=no-NAT) used when launching instances.

'public'
DNS_ADDRESSING_SET =
['public','direct']
@@amazon_problems =

A list of Amazon problems we can handle by AWSErrorHandler.

RightAws::AMAZON_PROBLEMS
@@bench_ec2 =
Benchmark::Tms.new()
@@bench_xml =
Benchmark::Tms.new()

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

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

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

  • :server: EC2 service host, default: DEFAULT_HOST

  • :port: EC2 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

Raises:



126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
# File 'lib/ec2/right_ec2.rb', line 126

def initialize(aws_access_key_id, aws_secret_access_key, params={})
  @params = params
  raise AwsError.new("AWS access keys are required to operate on EC2") \
    if aws_access_key_id.blank? || aws_secret_access_key.blank?
  @aws_access_key_id     = aws_access_key_id
  @aws_secret_access_key = aws_secret_access_key
    # params
  @params[:server]       ||= DEFAULT_HOST
  @params[:port]         ||= DEFAULT_PORT
  @params[:protocol]     ||= DEFAULT_PROTOCOL
  @params[:multi_thread] ||= defined?(AWS_DAEMON)
    # set logger
  @logger = @params[:logger]
  @logger = RAILS_DEFAULT_LOGGER if !@logger && defined?(RAILS_DEFAULT_LOGGER)
  @logger = Logger.new(STDOUT)   if !@logger
  @logger.info "New #{self.class.name} using #{@params[:multi_thread] ? 'multi' : 'single'}-threaded mode"
end

Instance Attribute Details

#aws_access_key_idObject (readonly)

Current aws_access_key_id



83
84
85
# File 'lib/ec2/right_ec2.rb', line 83

def aws_access_key_id
  @aws_access_key_id
end

#last_errorsObject

Last AWS errors list (used by AWSErrorHandler)



89
90
91
# File 'lib/ec2/right_ec2.rb', line 89

def last_errors
  @last_errors
end

#last_requestObject (readonly)

Last HTTP request object



85
86
87
# File 'lib/ec2/right_ec2.rb', line 85

def last_request
  @last_request
end

#last_request_idObject

Last AWS request id (used by AWSErrorHandler)



91
92
93
# File 'lib/ec2/right_ec2.rb', line 91

def last_request_id
  @last_request_id
end

#last_responseObject (readonly)

Last HTTP response object



87
88
89
# File 'lib/ec2/right_ec2.rb', line 87

def last_response
  @last_response
end

#loggerObject

Logger object, used by this class to generate log messages



93
94
95
# File 'lib/ec2/right_ec2.rb', line 93

def logger
  @logger
end

#paramsObject

Option params passed into new



95
96
97
# File 'lib/ec2/right_ec2.rb', line 95

def params
  @params
end

Class Method Details

.amazon_problemsObject

Returns a list of Amazon service responses which are known to be transient errors. By default returns the same value as AMAZON_PROBLEMS const. See AWSErrorHandler.



108
109
110
# File 'lib/ec2/right_ec2.rb', line 108

def self.amazon_problems
  @@amazon_problems
end

.amazon_problems=(problems_list) ⇒ Object

Sets the list of Amazon problems that are automatically retried. See AWSErrorHandler.



113
114
115
# File 'lib/ec2/right_ec2.rb', line 113

def self.amazon_problems=(problems_list)
  @@amazon_problems = problems_list
end

.bench_ec2Object

Benchmark::Tms instance that accumulates time spent in requests to EC2.



101
# File 'lib/ec2/right_ec2.rb', line 101

def self.bench_ec2;  @@bench_ec2;  end

.bench_xmlObject

Benchmark::Tms instance that accumulates time spent in XML parsing.



104
# File 'lib/ec2/right_ec2.rb', line 104

def self.bench_xml; @@bench_xml; end

Instance Method Details

#authorize_security_group_IP_ingress(name, from_port, to_port, protocol = 'tcp', cidr_ip = '0.0.0.0/0') ⇒ Object

Add permission to a security group. Returns true or an exception. protocol is one of :‘tcp’|‘udp’|‘icmp’.

ec2.authorize_security_group_IP_ingress('my_awesome_group', 80, 82, 'udp', '192.168.1.0/8') #=> true
ec2.authorize_security_group_IP_ingress('my_awesome_group', -1, -1, 'icmp') #=> true


675
676
677
678
679
680
681
682
683
684
685
# File 'lib/ec2/right_ec2.rb', line 675

def authorize_security_group_IP_ingress(name, from_port, to_port, protocol='tcp', cidr_ip='0.0.0.0/0')
  link = generate_request("AuthorizeSecurityGroupIngress", 
                          'GroupName'  => name.to_s, 
                          'IpProtocol' => protocol.to_s, 
                          'FromPort'   => from_port.to_s, 
                          'ToPort'     => to_port.to_s, 
                          'CidrIp'     => cidr_ip.to_s)
  request_info(link, RightBoolResponseParser.new(:logger => @logger))
rescue Exception
  on_exception
end

#authorize_security_group_named_ingress(name, owner, group) ⇒ Object

Authorize named ingress for security group. Allows instances that are member of someone else’s security group to open connections to instances in my group.

ec2.authorize_security_group_named_ingress('my_awesome_group', '7011-0219-8268', 'their_group_name') #=> true


646
647
648
649
650
651
652
653
654
# File 'lib/ec2/right_ec2.rb', line 646

def authorize_security_group_named_ingress(name, owner, group)
  link = generate_request("AuthorizeSecurityGroupIngress", 
                          'GroupName'                  => name.to_s, 
                          'SourceSecurityGroupName'    => group.to_s, 
                          'SourceSecurityGroupOwnerId' => owner.to_s.gsub(/-/,''))
  request_info(link, RightBoolResponseParser.new(:logger => @logger))
rescue Exception
  on_exception
end

#confirm_product_instance(instance, product_code) ⇒ Object

Return the product code attached to instance or nil otherwise.

ec2.confirm_product_instance('ami-e444444d','12345678') #=> nil
ec2.confirm_product_instance('ami-e444444d','00001111') #=> "000000000888"


457
458
459
460
461
# File 'lib/ec2/right_ec2.rb', line 457

def confirm_product_instance(instance, product_code)
  link = generate_request("ConfirmProductInstance", { 'ProductCode' => product_code,
                                                      'InstanceId'  => instance })
  request_info(link, QEc2ConfirmProductInstanceParser.new(:logger => @logger))
end

#create_key_pair(name) ⇒ Object

Create new SSH key. Returns a hash of the key’s data or an exception.

ec2.create_key_pair('my_awesome_key') #=>
  {:aws_key_name    => "my_awesome_key",
   :aws_fingerprint => "01:02:03:f4:25:e6:97:e8:9b:02:1a:26:32:4e:58:6b:7a:8c:9f:03",
   :aws_material    => "-----BEGIN RSA PRIVATE KEY-----\nMIIEpQIBAAK...Q8MDrCbuQ=\n-----END RSA PRIVATE KEY-----"}


730
731
732
733
734
735
736
737
738
739
# File 'lib/ec2/right_ec2.rb', line 730

def create_key_pair(name)
  link = generate_request("CreateKeyPair", 
                          'KeyName' => name.to_s)
  key  = request_info(link, QEc2CreateKeyPairParser.new(:logger => @logger))
  { :aws_key_name    => key.keyName,
    :aws_fingerprint => key.keyFingerprint,
    :aws_material    => key.keyMaterial}
rescue Exception
  on_exception
end

#create_security_group(name, description) ⇒ Object

Create new Security Group. Returns true or an exception.

ec2.create_security_group('default-1',"Default allowing SSH, HTTP, and HTTPS ingress") #=> true


618
619
620
621
622
623
624
625
626
627
# File 'lib/ec2/right_ec2.rb', line 618

def create_security_group(name, description)
  # EC2 doesn't like an empty description...
  description = " " if description.blank?
  link = generate_request("CreateSecurityGroup", 
                          'GroupName'        => name.to_s, 
                          'GroupDescription' => description.to_s)
  request_info(link, RightBoolResponseParser.new(:logger => @logger))
rescue Exception
  on_exception
end

#delete_key_pair(name) ⇒ Object

Delete a key pair. Returns true or an exception.

ec2.delete_key_pair('my_awesome_key') #=> true


745
746
747
748
749
750
751
# File 'lib/ec2/right_ec2.rb', line 745

def delete_key_pair(name)
  link = generate_request("DeleteKeyPair", 
                          'KeyName' => name.to_s)
  request_info(link, RightBoolResponseParser.new(:logger => @logger))
rescue Exception
  on_exception
end

#delete_security_group(name) ⇒ Object

Remove Security Group. Returns true or an exception.

ec2.delete_security_group('default-1') #=> true


633
634
635
636
637
638
639
# File 'lib/ec2/right_ec2.rb', line 633

def delete_security_group(name)
  link = generate_request("DeleteSecurityGroup", 
                          'GroupName' => name.to_s)
  request_info(link, RightBoolResponseParser.new(:logger => @logger))
rescue Exception
  on_exception
end

#deregister_image(image_id) ⇒ Object

Deregister image at Amazon. Returns true or an exception.

ec2.deregister_image('ami-e444444d') #=> true


292
293
294
295
296
297
298
# File 'lib/ec2/right_ec2.rb', line 292

def deregister_image(image_id)
  link = generate_request("DeregisterImage", 
                          'ImageId' => image_id.to_s)
  request_info(link, RightBoolResponseParser.new(:logger => @logger))
rescue Exception
  on_exception
end

#describe_image_attribute(image_id, attribute = 'launchPermission') ⇒ Object

Describe image attributes. Currently ‘launchPermission’ and ‘productCodes’ are supported.

ec2.describe_image_attribute('ami-e444444d') #=> {:groups=>["all"], :users=>["000000000777"]}


305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
# File 'lib/ec2/right_ec2.rb', line 305

def describe_image_attribute(image_id, attribute='launchPermission')
  link = generate_request("DescribeImageAttribute", 
                          'ImageId'   => image_id,
                          'Attribute' => attribute)
  image_attr = request_info(link, QEc2DescribeImageAttributeParser.new(:logger => @logger))
  result = {}
  if image_attr.launchPermission
    result = { :users  => image_attr.launchPermission.userIds,
               :groups => image_attr.launchPermission.groups }
  elsif image_attr.productCodes
    result = { :aws_product_codes => image_attr.productCodes}
  end
  result
rescue Exception
  on_exception
end

#describe_images(list = []) ⇒ Object

Retrieve a list of images. Returns array of hashes describing the images or an exception:

ec2.describe_images #=>
  [{:aws_owner => "522821470517",
    :aws_id => "ami-e4b6538d",
    :aws_state => "available",
    :aws_location => "marcins_cool_public_images/ubuntu-6.10.manifest.xml",
    :aws_is_public => true},
   {...},
   {...} ]

If list param is set, then retrieve information about the listed images only:

ec2.describe_images(['ami-e4b6538d']) #=>
  [{:aws_owner => "522821470517",
    :aws_id => "ami-e4b6538d",
    :aws_state => "available",
    :aws_location => "marcins_cool_public_images/ubuntu-6.10.manifest.xml",
    :aws_is_public => true}]


250
251
252
# File 'lib/ec2/right_ec2.rb', line 250

def describe_images(list=[])
  ec2_describe_images('ImageId', list)
end

#describe_images_by_executable_by(list) ⇒ Object

Example:

ec2.describe_images_by_executable_by('522821470517')
ec2.describe_images_by_executable_by('self')


270
271
272
# File 'lib/ec2/right_ec2.rb', line 270

def describe_images_by_executable_by(list)
  ec2_describe_images('ExecutableBy', list)
end

#describe_images_by_owner(list) ⇒ Object

Example:

ec2.describe_images_by_owner('522821470517')
ec2.describe_images_by_owner('self')


260
261
262
# File 'lib/ec2/right_ec2.rb', line 260

def describe_images_by_owner(list)
  ec2_describe_images('Owner', list)
end

#describe_instances(list = []) ⇒ Object

Retrieve information about EC2 instances. If list is omitted then returns the list of all instances.

ec2.describe_instances #=> 
  [{:aws_image_id       => "ami-e444444d",
    :aws_reason         => "",
    :aws_state_code     => "16",
    :aws_owner          => "000000000888",
    :aws_instance_id    => "i-123f1234",
    :aws_reservation_id => "r-aabbccdd",
    :aws_state          => "running",
    :dns_name           => "domU-12-34-67-89-01-C9.usma2.compute.amazonaws.com",
    :ssh_key_name       => "staging",
    :aws_groups         => ["default"],
    :private_dns_name   => "domU-12-34-67-89-01-C9.usma2.compute.amazonaws.com"},
     ..., {...}]


444
445
446
447
448
449
450
# File 'lib/ec2/right_ec2.rb', line 444

def describe_instances(list=[])
  link      = generate_request("DescribeInstances", hash_params('InstanceId',list.to_a))
  instances = request_info(link, QEc2DescribeInstancesParser.new(:logger => @logger))
  get_desc_instances(instances)
rescue Exception
  on_exception
end

#describe_key_pairs(list = []) ⇒ Object

Retrieve a list of SSH keys. Returns an array of keys or an exception. Each key is represented as a two-element hash.

ec2.describe_key_pairs #=>
  [{:aws_fingerprint=> "01:02:03:f4:25:e6:97:e8:9b:02:1a:26:32:4e:58:6b:7a:8c:9f:03", :aws_key_name=>"key-1"},
   {:aws_fingerprint=> "1e:29:30:47:58:6d:7b:8c:9f:08:11:20:3c:44:52:69:74:80:97:08", :aws_key_name=>"key-2"},
    ..., {...} ]


711
712
713
714
715
716
717
718
719
720
721
# File 'lib/ec2/right_ec2.rb', line 711

def describe_key_pairs(list=[])
  link   = generate_request("DescribeKeyPairs", hash_params('KeyName',list.to_a))
  result = request_info(link, QEc2DescribeKeyPairParser.new(:logger => @logger))
  result.collect! do |key|
      {:aws_key_name    => key.keyName,
       :aws_fingerprint => key.keyFingerprint }
  end
  result   
rescue Exception
  on_exception
end

#describe_security_groups(list = []) ⇒ Object

Retrieve Security Group information. If list is omitted the returns the whole list of groups.

ec2.describe_security_groups #=>
  [{:aws_group_name  => "default-1",
    :aws_owner       => "000000000888",
    :aws_description => "Default allowing SSH, HTTP, and HTTPS ingress",
    :aws_perms       =>
      [{:owner => "000000000888", :group => "default"},
       {:owner => "000000000888", :group => "default-1"},
       {:to_port => "-1",  :protocol => "icmp", :from_port => "-1",  :cidr_ips => "0.0.0.0/0"},
       {:to_port => "22",  :protocol => "tcp",  :from_port => "22",  :cidr_ips => "0.0.0.0/0"},
       {:to_port => "80",  :protocol => "tcp",  :from_port => "80",  :cidr_ips => "0.0.0.0/0"},
       {:to_port => "443", :protocol => "tcp",  :from_port => "443", :cidr_ips => "0.0.0.0/0"}]},
  ..., {...}]


576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
# File 'lib/ec2/right_ec2.rb', line 576

def describe_security_groups(list=[])
  link   = generate_request("DescribeSecurityGroups", hash_params('GroupName',list.to_a))
  groups = request_info(link, QEc2DescribeSecurityGroupsParser.new(:logger => @logger))
  
  result = []     
  groups.each do |item|
    perms = []
    item.ipPermissions.each do |perm|
      perm.groups.each do |ngroup|
        perms << {:group => ngroup.groupName,
                  :owner => ngroup.userId}
      end
      perm.ipRanges.each do |cidr_ip|
        perms << {:from_port => perm.fromPort, 
                  :to_port   => perm.toPort, 
                  :protocol  => perm.ipProtocol,
                  :cidr_ips  => cidr_ip}
      end
    end
    
       # delete duplication
    perms.each_index do |i|
      (0...i).each do |j|
        if perms[i] == perms[j] then perms[i] = nil; break; end
      end
    end
    perms.compact!

    result << {:aws_owner       => item.ownerId, 
               :aws_group_name  => item.groupName, 
               :aws_description => item.groupDescription,
               :aws_perms       => perms}
  end  
  result
rescue Exception
  on_exception
end

#ec2_describe_images(type, list) ⇒ Object






214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
# File 'lib/ec2/right_ec2.rb', line 214

def ec2_describe_images(type, list) #:nodoc:
  link   = generate_request("DescribeImages", hash_params(type,list.to_a))
  images = request_info(link, QEc2DescribeImagesParser.new(:logger => @logger))
  images.collect! do |image|
                {:aws_id            => image.imageId,
                 :aws_location      => image.imageLocation,
                 :aws_owner         => image.imageOwnerId,
                 :aws_state         => image.imageState.downcase,
                 :aws_is_public     => image.isPublic,
                 :aws_product_codes => image.productCodes}
  end
  images
rescue Exception
  on_exception
end

#generate_request(action, param = {}) ⇒ Object

:nodoc:



153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
# File 'lib/ec2/right_ec2.rb', line 153

def generate_request(action, param={}) #:nodoc:
  timestamp    = ( Time::now ).utc.strftime("%Y-%m-%dT%H:%M:%S.000Z")
  request_hash = {"Action"            => action,
                  "AWSAccessKeyId"    => @aws_access_key_id,
                  "Version"           => API_VERSION,
                  "Timestamp"         => timestamp,
                  "SignatureVersion"  => SIGNATURE_VERSION }
  request_hash.update(param)
  request_data   = request_hash.sort{|a,b| (a[0].to_s.downcase)<=>(b[0].to_s.downcase)}.to_s
  request_hash.update('Signature' => Base64.encode64( OpenSSL::HMAC.digest( OpenSSL::Digest::Digest.new( "sha1" ), @aws_secret_access_key, request_data)).strip)
  request_params = request_hash.to_a.collect{|key,val| key + "=" + CGI::escape(val) }.join("&")
  request        = Net::HTTP::Get.new("/?#{request_params}")
    # prepare output hash
  { :request  => request, 
    :server   => @params[:server],
    :port     => @params[:port],
    :protocol => @params[:protocol] }
end

#get_console_output(instance_id) ⇒ Object

Retreive EC2 instance OS logs. Returns a hash of data or an exception.

ec2.get_console_output('i-f222222d') =>
  {:aws_instance_id => 'i-f222222d',
   :aws_timestamp   => "2007-05-23T14:36:07.000-07:00",
   :timestamp       => Wed May 23 21:36:07 UTC 2007,          # Time instance
   :aws_output      => "Linux version 2.6.16-xenU ([email protected]) (gcc version 4.0.1 20050727 ..."


539
540
541
542
543
544
545
546
547
548
# File 'lib/ec2/right_ec2.rb', line 539

def get_console_output(instance_id)
  link   = generate_request("GetConsoleOutput", { 'InstanceId.1' => instance_id })
  result = request_info(link, QEc2GetConsoleOutputParser.new(:logger => @logger))
  { :aws_instance_id => result.instanceId,
    :aws_timestamp   => result.timestamp,
    :timestamp       => (Time.parse(result.timestamp)).utc,
    :aws_output      => result.output }
rescue Exception
  on_exception
end

#get_desc_instances(instances) ⇒ Object

:nodoc:



401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
# File 'lib/ec2/right_ec2.rb', line 401

def get_desc_instances(instances)  # :nodoc:
  result = []
  instances.each do |item|
    item.instancesSet.each do |instance|
      # Parse and remove timestamp from the reason string. The timestamp is of
      # the request, not when EC2 took action, thus confusing & useless...
      reason = instance.reason.sub(/\(\d[^)]*GMT\) */, '')
      result << {:aws_owner          => item.ownerId,
                 :aws_reservation_id => item.reservationId,
                 :aws_groups         => item.groupSet,
                 :aws_state_code     => instance.instanceState.code,
                 :dns_name           => instance.dnsName,
                 :private_dns_name   => instance.privateDnsName,
                 :aws_instance_id    => instance.instanceId,
                 :aws_state          => instance.instanceState.name,
                 :ssh_key_name       => instance.keyName,
                 :aws_image_id       => instance.imageId,
                 :aws_reason         => reason,
                 :aws_product_codes  => instance.productCodes}
    end
  end
  result
rescue Exception
  on_exception
end

#hash_params(prefix, list) ⇒ Object

:nodoc:



203
204
205
206
207
# File 'lib/ec2/right_ec2.rb', line 203

def hash_params(prefix, list) #:nodoc:
  groups = {}
  list.each_index{|i| groups.update("#{prefix}.#{i+1}"=>list[i])} if list
  return groups
end

#modify_image_attribute(image_id, attribute, operation_type = nil, vars = {}) ⇒ Object

Modify an image’s attributes. It is recommended that you use modify_image_launch_perm_add_users, modify_image_launch_perm_remove_users, etc. instead of modify_image_attribute because the signature of modify_image_attribute may change with EC2 service changes.

attribute      : currently, only 'launchPermission' is supported.
operation_type : currently, only 'add' & 'remove' are supported.
vars: 
  :user_group  : currently, only 'all' is supported.  
  :user_id
  :product_code


346
347
348
349
350
351
352
353
354
355
356
357
# File 'lib/ec2/right_ec2.rb', line 346

def modify_image_attribute(image_id, attribute, operation_type = nil, vars = {})
  params =  {'ImageId'   => image_id,
             'Attribute' => attribute}
  params['OperationType'] = operation_type if operation_type
  params.update(hash_params('UserId',      vars[:user_id].to_a))    if vars[:user_id]
  params.update(hash_params('UserGroup',   vars[:user_group].to_a)) if vars[:user_group]
  params.update(hash_params('ProductCode', vars[:product_code]))    if vars[:product_code]
  link = generate_request("ModifyImageAttribute", params)
  request_info(link, RightBoolResponseParser.new(:logger => @logger))
rescue Exception
  on_exception
end

#modify_image_launch_perm_add_groups(image_id, userGroup = ['all']) ⇒ Object

Add image launch permissions for users groups (currently only ‘all’ is supported, which gives public launch permissions). Returns true or an exception.

ec2.modify_image_launch_perm_add_groups('ami-e444444d') #=> true


381
382
383
# File 'lib/ec2/right_ec2.rb', line 381

def modify_image_launch_perm_add_groups(image_id, userGroup=['all'])
  modify_image_attribute(image_id, 'launchPermission', 'add', :user_group => userGroup.to_a)
end

#modify_image_launch_perm_add_users(image_id, user_id = []) ⇒ Object

Grant image launch permissions to users. Parameter userId is a list of user AWS account ids. Returns true or an exception.

ec2.modify_image_launch_perm_add_users('ami-e444444d',['000000000777','000000000778']) #=> true


364
365
366
# File 'lib/ec2/right_ec2.rb', line 364

def modify_image_launch_perm_add_users(image_id, user_id=[])
  modify_image_attribute(image_id, 'launchPermission', 'add', :user_id => user_id.to_a)
end

#modify_image_launch_perm_remove_groups(image_id, userGroup = ['all']) ⇒ Object

Remove image launch permissions for users groups (currently only ‘all’ is supported, which gives public launch permissions).

ec2.modify_image_launch_perm_remove_groups('ami-e444444d') #=> true


389
390
391
# File 'lib/ec2/right_ec2.rb', line 389

def modify_image_launch_perm_remove_groups(image_id, userGroup=['all'])
  modify_image_attribute(image_id, 'launchPermission', 'remove', :user_group => userGroup.to_a)
end

#modify_image_launch_perm_remove_users(image_id, user_id = []) ⇒ Object

Revokes image launch permissions for users. userId is a list of users AWS accounts ids. Returns true or an exception.

ec2.modify_image_launch_perm_remove_users('ami-e444444d',['000000000777','000000000778']) #=> true


372
373
374
# File 'lib/ec2/right_ec2.rb', line 372

def modify_image_launch_perm_remove_users(image_id, user_id=[])
  modify_image_attribute(image_id, 'launchPermission', 'remove', :user_id => user_id.to_a)
end

#modify_image_product_code(image_id, productCode = []) ⇒ Object

Add product code to image

ec2.modify_image_product_code('ami-e444444d','0ABCDEF') #=> true


397
398
399
# File 'lib/ec2/right_ec2.rb', line 397

def modify_image_product_code(image_id, productCode=[])
  modify_image_attribute(image_id, 'productCodes', nil, :product_code => productCode.to_a)
end

#multi_threadObject

Return true if this RightEc2NativeQuery instance works in multi_thread mode and false otherwise.



149
150
151
# File 'lib/ec2/right_ec2.rb', line 149

def multi_thread
  @params[:multi_thread]
end

#on_exception(options = {:raise=>true, :log=>true}) ⇒ Object

:nodoc:



144
145
146
# File 'lib/ec2/right_ec2.rb', line 144

def on_exception(options={:raise=>true, :log=>true}) # :nodoc:
  AwsError::on_aws_exception(self, options)
end

#reboot_instances(list) ⇒ Object

Reboot an EC2 instance. Returns true or an exception.

ec2.reboot_instances(['i-f222222d','i-f222222e']) #=> true


554
555
556
557
558
559
# File 'lib/ec2/right_ec2.rb', line 554

def reboot_instances(list)
  link = generate_request("RebootInstances", hash_params('InstanceId', list.to_a))
  request_info(link, RightBoolResponseParser.new(:logger => @logger))
rescue Exception
  on_exception
end

#register_image(image_location) ⇒ Object

Register new image at Amazon. Returns new image id or an exception.

ec2.register_image('bucket/key/manifest') #=> 'ami-e444444d'


280
281
282
283
284
285
286
# File 'lib/ec2/right_ec2.rb', line 280

def register_image(image_location)
  link = generate_request("RegisterImage", 
                          'ImageLocation' => image_location.to_s)
  request_info(link, QEc2RegisterImageParser.new(:logger => @logger))
rescue Exception
  on_exception
end

#request_info(request, parser) ⇒ Object

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



174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
# File 'lib/ec2/right_ec2.rb', line 174

def request_info(request, parser)  #:nodoc:
  thread = @params[:multi_thread] ? Thread.current : Thread.main
  thread[:ec2_connection] ||= Rightscale::HttpConnection.new(:exception => AwsError)
  @last_request  = request[:request]
  @last_response = nil
  response=nil
  
  @@bench_ec2.add!{ response = thread[:ec2_connection].request(request) }
    # check response for errors...
  @last_response = response
  if response.is_a?(Net::HTTPSuccess)
    @error_handler = nil
    @@bench_xml.add! { parser.parse(response) }
    return parser.result
  else
    @error_handler = AWSErrorHandler.new(self, parser, @@amazon_problems) unless @error_handler
    check_result   = @error_handler.check(request)
    if check_result
      @error_handler = nil
      return check_result 
    end
    raise AwsError.new(@last_errors, @last_response.code, @last_request_id)
  end
rescue
  @error_handler = nil
  raise
end

#reset_image_attribute(image_id, attribute = 'launchPermission') ⇒ Object

Reset image attribute. Currently, only ‘launchPermission’ is supported. Returns true or an exception.

ec2.reset_image_attribute('ami-e444444d') #=> true


326
327
328
329
330
331
332
333
# File 'lib/ec2/right_ec2.rb', line 326

def reset_image_attribute(image_id, attribute='launchPermission')
  link = generate_request("ResetImageAttribute", 
                          'ImageId'   => image_id,
                          'Attribute' => attribute)
  request_info(link, RightBoolResponseParser.new(:logger => @logger))
rescue Exception
  on_exception
end

#revoke_security_group_IP_ingress(name, from_port, to_port, protocol = 'tcp', cidr_ip = '0.0.0.0/0') ⇒ Object

Remove permission from a security group. Returns true or an exception. protocol is one of :‘tcp’|‘udp’|‘icmp’ (‘tcp’ is default).

ec2.revoke_security_group_IP_ingress('my_awesome_group', 80, 82, 'udp', '192.168.1.0/8') #=> true


691
692
693
694
695
696
697
698
699
700
701
# File 'lib/ec2/right_ec2.rb', line 691

def revoke_security_group_IP_ingress(name, from_port, to_port, protocol='tcp', cidr_ip='0.0.0.0/0')
  link = generate_request("RevokeSecurityGroupIngress", 
                          'GroupName'  => name.to_s, 
                          'IpProtocol' => protocol.to_s, 
                          'FromPort'   => from_port.to_s, 
                          'ToPort'     => to_port.to_s, 
                          'CidrIp'     => cidr_ip.to_s)
  request_info(link, RightBoolResponseParser.new(:logger => @logger))
rescue Exception
  on_exception
end

#revoke_security_group_named_ingress(name, owner, group) ⇒ Object

Revoke named ingress for security group.

ec2.revoke_security_group_named_ingress('my_awesome_group', aws_user_id, 'another_group_name') #=> true


660
661
662
663
664
665
666
667
668
# File 'lib/ec2/right_ec2.rb', line 660

def revoke_security_group_named_ingress(name, owner, group)
  link = generate_request("RevokeSecurityGroupIngress", 
                          'GroupName'                  => name.to_s, 
                          'SourceSecurityGroupName'    => group.to_s, 
                          'SourceSecurityGroupOwnerId' => owner.to_s.gsub(/-/,''))
  request_info(link, RightBoolResponseParser.new(:logger => @logger))
rescue Exception
  on_exception
end

#run_instances(image_id, min_count, max_count, group_ids, key_name, user_data = '', addressing_type = DEFAULT_ADDRESSING_TYPE) ⇒ Object

Launch new EC2 instances. Returns a list of launched instances or an exception.

ec2.run_instances('ami-e444444d',1,1,['my_awesome_group'],'my_awesome_key', 'Woohoo!!!', 'public') #=>
 [{:aws_image_id       => "ami-e444444d",
   :aws_reason         => "",
   :aws_state_code     => "0",
   :aws_owner          => "000000000888",
   :aws_instance_id    => "i-123f1234",
   :aws_reservation_id => "r-aabbccdd",
   :aws_state          => "pending",
   :dns_name           => "",
   :ssh_key_name       => "my_awesome_key",
   :aws_groups         => ["my_awesome_group"],
   :private_dns_name   => ""}]


478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
# File 'lib/ec2/right_ec2.rb', line 478

def run_instances(image_id, min_count, max_count, group_ids, key_name, user_data='', addressing_type=DEFAULT_ADDRESSING_TYPE)
  @logger.info("Launching instance of image #{image_id} for #{@aws_access_key_id}, key: #{key_name}, groups: #{(group_ids||[]).to_a.join(',')}")
    # careful: keyName and securityGroups may be nil
  params = hash_params('SecurityGroup', group_ids.to_a)
  params.update( {'ImageId'        => image_id,
                  'MinCount'       => min_count.to_s,
                  'MaxCount'       => max_count.to_s,
                  'AddressingType' => addressing_type })
  params['KeyName']  = key_name unless key_name.blank?
  unless user_data.blank?
    user_data.strip!
      # Do not use CGI::escape(encode64(...)) as it is done in Amazons EC2 library.
      # Amazon 169.254.169.254 does not like escaped symbols!
      # And it doesn't like "\n" inside of encoded string! Grrr....
      # Otherwise, some of UserData symbols will be lost...
    params['UserData'] = Base64.encode64(user_data).delete("\n") unless user_data.blank?
  end
  link = generate_request("RunInstances", params)
    #debugger
  instances = request_info(link, QEc2RunInstancesParser.new(:logger => @logger))
  get_desc_instances(instances)
rescue Exception
  on_exception
end

#terminate_instances(list = []) ⇒ Object

Terminates EC2 instances. Returns a list of termination params or an exception.

ec2.terminate_instances(['i-f222222d','i-f222222e']) #=>
  [{:aws_shutdown_state      => "shutting-down", 
    :aws_instance_id         => "i-f222222d", 
    :aws_shutdown_state_code => 32, 
    :aws_prev_state          => "running", 
    :aws_prev_state_code     => 16}, 
   {:aws_shutdown_state      => "shutting-down", 
    :aws_instance_id         => "i-f222222e", 
    :aws_shutdown_state_code => 32, 
    :aws_prev_state          => "running", 
    :aws_prev_state_code     => 16}]


517
518
519
520
521
522
523
524
525
526
527
528
529
530
# File 'lib/ec2/right_ec2.rb', line 517

def terminate_instances(list=[])
  link      = generate_request("TerminateInstances", hash_params('InstanceId',list.to_a))
  instances = request_info(link, QEc2TerminateInstancesParser.new(:logger => @logger))
  instances.collect! do |instance|
          { :aws_instance_id         => instance.instanceId,
            :aws_shutdown_state      => instance.shutdownState.name,
            :aws_shutdown_state_code => instance.shutdownState.code.to_i,
            :aws_prev_state          => instance.previousState.name,
            :aws_prev_state_code     => instance.previousState.code.to_i }
  end 
  instances
rescue Exception
  on_exception
end