awscli 0.0.4 → 0.0.5

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (51) hide show
  1. checksums.yaml +8 -8
  2. data/README.rdoc +5 -0
  3. data/Rakefile +44 -0
  4. data/bin/awscli +32 -0
  5. data/features/awscli.feature +8 -0
  6. data/features/step_definitions/awscli_steps.rb +6 -0
  7. data/features/support/env.rb +15 -0
  8. data/lib/awscli.rb +51 -0
  9. data/lib/awscli/as.rb +289 -0
  10. data/lib/awscli/cli.rb +21 -0
  11. data/lib/awscli/cli/as.rb +12 -0
  12. data/lib/awscli/cli/as/activities.rb +28 -0
  13. data/lib/awscli/cli/as/configurations.rb +50 -0
  14. data/lib/awscli/cli/as/groups.rb +97 -0
  15. data/lib/awscli/cli/as/instances.rb +34 -0
  16. data/lib/awscli/cli/as/policies.rb +45 -0
  17. data/lib/awscli/cli/ec2.rb +23 -0
  18. data/lib/awscli/cli/ec2/ami.rb +46 -0
  19. data/lib/awscli/cli/ec2/ebs.rb +85 -0
  20. data/lib/awscli/cli/ec2/eip.rb +56 -0
  21. data/lib/awscli/cli/ec2/instances.rb +216 -0
  22. data/lib/awscli/cli/ec2/keypairs.rb +60 -0
  23. data/lib/awscli/cli/ec2/monitoring.rb +35 -0
  24. data/lib/awscli/cli/ec2/placement.rb +42 -0
  25. data/lib/awscli/cli/ec2/reservedinstmng.rb +45 -0
  26. data/lib/awscli/cli/ec2/secgroups.rb +66 -0
  27. data/lib/awscli/cli/ec2/spot.rb +81 -0
  28. data/lib/awscli/cli/ec2/subnet.rb +43 -0
  29. data/lib/awscli/cli/ec2/tags.rb +45 -0
  30. data/lib/awscli/cli/ec2/vmmng.rb +17 -0
  31. data/lib/awscli/cli/ec2/vpc.rb +42 -0
  32. data/lib/awscli/cli/ec2/vpc/connections.rb +0 -0
  33. data/lib/awscli/cli/ec2/vpc/cust_gateways.rb +0 -0
  34. data/lib/awscli/cli/ec2/vpc/dhcp.rb +51 -0
  35. data/lib/awscli/cli/ec2/vpc/internet_gateways.rb +58 -0
  36. data/lib/awscli/cli/ec2/vpc/net_interfaces.rb +75 -0
  37. data/lib/awscli/cli/ec2/vpc/network_acls.rb +29 -0
  38. data/lib/awscli/cli/ec2/vpc/priv_gatewats.rb +0 -0
  39. data/lib/awscli/cli/ec2/vpc/route_tables.rb +0 -0
  40. data/lib/awscli/cli/s3.rb +12 -0
  41. data/lib/awscli/cli/s3/directories.rb +82 -0
  42. data/lib/awscli/cli/s3/files.rb +77 -0
  43. data/lib/awscli/connection.rb +55 -0
  44. data/lib/awscli/ec2.rb +821 -0
  45. data/lib/awscli/errors.rb +64 -0
  46. data/lib/awscli/helper.rb +8 -0
  47. data/lib/awscli/s3.rb +108 -0
  48. data/lib/awscli/version.rb +3 -0
  49. data/test/default_test.rb +14 -0
  50. data/test/test_helper.rb +9 -0
  51. metadata +59 -4
@@ -0,0 +1,29 @@
1
+ module AwsCli
2
+ module CLI
3
+ module EC2
4
+ module VPC
5
+ require 'awscli/cli/ec2/vpc'
6
+ class NetworkAcl < Thor
7
+
8
+ desc "list", "List NACLs"
9
+ def list
10
+ create_ec2_object
11
+ @ec2.list
12
+ end
13
+
14
+ private
15
+
16
+ def create_ec2_object
17
+ puts "ec2 Establishing Connetion..."
18
+ $ec2_conn = Awscli::Connection.new.request_ec2
19
+ puts "ec2 Establishing Connetion... OK"
20
+ @ec2 = Awscli::EC2::NetworkAcl.new($ec2_conn)
21
+ end
22
+
23
+ AwsCli::CLI::EC2::Vpc.register AwsCli::CLI::EC2::VPC::NetworkAcl, :networkacl, 'networkacl [COMMAND]', 'VPC Network Acl Management'
24
+
25
+ end
26
+ end
27
+ end
28
+ end
29
+ end
File without changes
@@ -0,0 +1,12 @@
1
+ module AwsCli
2
+ module CLI
3
+ require 'awscli/cli'
4
+ require 'awscli/connection'
5
+ require 'awscli/s3'
6
+ class S3 < Thor
7
+ class_option :region, :type => :string, :desc => "region to connect to"
8
+
9
+ AwsCli::Cli.register AwsCli::CLI::S3, :s3, 's3 [COMMAND]', 'Simple Storage Service Interface'
10
+ end
11
+ end
12
+ end
@@ -0,0 +1,82 @@
1
+ module AwsCli
2
+ module CLI
3
+ module Sss
4
+ require 'awscli/cli/s3'
5
+ class Directories < Thor
6
+
7
+ desc "list", "List S3 buckets"
8
+ def list
9
+ create_s3_object
10
+ @s3.list
11
+ end
12
+
13
+ desc "create", "Create an new S3 bucket"
14
+ method_option :key, :aliases => "-k", :type => :string, :required => true, :desc => "name of the bucket to create(name should be globally unique)"
15
+ method_option :public, :aliases => "-p", :type => :boolean, :default => false, :desc => "makes the bucket publicly availble"
16
+ # method_option :x_amz_acl, :aliases => "-x", :type => :string, :desc => "Permissions, must be in ['private', 'public-read', 'public-read-write', 'authenticated-read']"
17
+ def create
18
+ create_s3_object
19
+ @s3.create options
20
+ end
21
+
22
+ desc "delete", "Delete existing S3 bucket"
23
+ method_option :key, :aliases => "-k", :type => :string, :required => true, :desc => "name of the bucket to delete"
24
+ def delete
25
+ create_s3_object
26
+ @s3.delete options[:key]
27
+ end
28
+
29
+ desc "set_acl", "Change access control list for an S3 bucket"
30
+ method_option :key, :aliases => "-k", :type => :string, :required => true, :desc => "name of the bucket to change acl"
31
+ method_option :acl, :aliases => "-a", :type => :string, :required => true, :desc => "Permissions, must be in ['private', 'public-read', 'public-read-write', 'authenticated-read']"
32
+ def set_acl
33
+ create_s3_object
34
+ @s3.set_acl options[:key], options[:acl]
35
+ end
36
+
37
+ desc "get_acl", "Get access control list for an S3 bucket"
38
+ method_option :key, :aliases => "-k", :type => :string, :required => true, :desc => "name of the bucket to get acl"
39
+ def get_acl
40
+ create_s3_object
41
+ @s3.get_acl options[:key]
42
+ end
43
+
44
+ desc "get_logging_status", "Get logging status for an S3 bucket"
45
+ method_option :key, :aliases => "-k", :type => :string, :required => true, :desc => "name of the bucket"
46
+ def get_logging_status
47
+ create_s3_object
48
+ @s3.get_logging_status options[:key]
49
+ end
50
+
51
+ # desc "set_logging_status", "Change logging status for an S3 bucket"
52
+ # method_option :key, :aliases => "-k", :type => :string, :required => true, :desc => "name of the bucket"
53
+ # method_option :owner, :aliases => "-o", :type => :hash, :banner => "ID:NAME", :desc => "set id and displayname of the owner"
54
+ # method_option :grantee, :aliases => "-g", :type => :hash, :banner => "NAME:ID|EMAIL|URI", :desc => "Grantee hash containing, <Display name of the grantee>: <ID of the grantee (or) Email of the grantee (or) Uri of the group to grant access>"
55
+ # method_option :permission, :aliases => "-p", :type => :string, :desc => "Permission, in [FULL_CONTROL, WRITE, WRITE_ACP, READ, READ_ACP]"
56
+ # def set_logging_status
57
+ # create_s3_object
58
+ # (acl ||= []) << options[:grantee] if options[:grantee]
59
+ # acl << options[:permission] if options[:permission]
60
+ # logging_status = Hash.new
61
+ # logging_status['Owner'] = options[:owner] if options[:owner]
62
+ # logging_status['AccessControlList'] = acl if acl
63
+ # puts "Empty logging_status will disable logging" if logging_status.nil?
64
+ # puts "#{logging_status}"
65
+ # @s3.set_logging_status options[:key], logging_status
66
+ # end
67
+
68
+ private
69
+
70
+ def create_s3_object
71
+ puts "S3 Establishing Connetion..."
72
+ $s3_conn = Awscli::Connection.new.request_s3
73
+ puts "S3 Establishing Connetion... OK"
74
+ @s3 = Awscli::S3::Directories.new($s3_conn)
75
+ end
76
+
77
+ AwsCli::CLI::S3.register AwsCli::CLI::Sss::Directories, :dirs, 'dirs [COMMAND]', 'S3 Directories Management'
78
+
79
+ end
80
+ end
81
+ end
82
+ end
@@ -0,0 +1,77 @@
1
+ module AwsCli
2
+ module CLI
3
+ module Sss
4
+ require 'awscli/cli/s3'
5
+ class Files < Thor
6
+
7
+ desc "list", "list objects(files) in a bucket"
8
+ method_option :bucket_name, :aliases => "-b", :required => true, :desc => "bucket name to print the contents from"
9
+ def list
10
+ create_s3_object
11
+ @s3.list options[:bucket_name]
12
+ end
13
+
14
+ desc "put", "put a file into a bucket"
15
+ method_option :bucket_name, :aliases => "-b", :required => true, :desc => "name of the bucket to upload the file to"
16
+ method_option :file_path, :aliases => "-p", :required => true, :desc => "local file path"
17
+ def put
18
+ create_s3_object
19
+ @s3.upload_file options[:bucket_name], options[:file_path]
20
+ end
21
+
22
+ desc "get", "get a file from a bucket"
23
+ method_option :bucket_name, :aliases => "-b", :required => true, :desc => "name of the bucket to download the file from"
24
+ method_option :file_name, :aliases => "-f", :required => true, :desc => "name of file to download"
25
+ method_option :local_path, :aliases => "-p", :required => true, :desc => "local fs path, where to download the file to"
26
+ def get
27
+ create_s3_object
28
+ @s3.download_file options[:bucket_name], options[:file_name], options[:local_path]
29
+ end
30
+
31
+ desc "delete", "delete a file from a bucket"
32
+ method_option :bucket_name, :aliases => "-b", :required => true, :desc => "name of the bucket to download the file from"
33
+ method_option :file_name, :aliases => "-f", :required => true, :desc => "name of file to download"
34
+ def delete
35
+ create_s3_object
36
+ @s3.delete_file options[:bucket_name], options[:file_name]
37
+ end
38
+
39
+ # s3.directories.get('arun123').files.get('block_9091299035346850259').copy('ashrithtst', 'testfile')
40
+ desc "copy", "copy object from one bucket to another"
41
+ method_option :source_bucket, :aliases => "-s", :required => true, :desc => "source bucket name from where to copy the file"
42
+ method_option :source_file, :aliases => "-f", :required => true, :desc => "source file name to copy"
43
+ method_option :dest_bucket, :aliases => "-d", :required => true, :desc => "destination bucket name to copy the file to"
44
+ method_option :dest_file, :alises => "-r", :required => true, :desc => "destination file name"
45
+ def copy
46
+ create_s3_object
47
+ @s3.copy_file options[:source_bucket], options[:source_file], options[:dest_bucket], options[:dest_file]
48
+ end
49
+
50
+ desc "public_url", "show the public url of a file"
51
+ method_option :bucket_name, :aliases => "-b", :required => true, :desc => "name of the bucket to download the file from"
52
+ method_option :file_name, :aliases => "-f", :required => true, :desc => "name of file to download"
53
+ def public_url
54
+ create_s3_object
55
+ @s3.get_public_url options[:bucket_name], options[:file_name]
56
+ end
57
+
58
+
59
+ private
60
+
61
+ def create_s3_object
62
+ puts "S3 Establishing Connetion..."
63
+ $s3_conn = if parent_options[:region]
64
+ Awscli::Connection.new.request_s3(parent_options[:region])
65
+ else
66
+ Awscli::Connection.new.request_s3
67
+ end
68
+ puts "S3 Establishing Connetion... OK"
69
+ @s3 = Awscli::S3::Files.new($s3_conn)
70
+ end
71
+
72
+ AwsCli::CLI::S3.register AwsCli::CLI::Sss::Files, :files, 'files [COMMAND]', 'S3 Files Management'
73
+
74
+ end
75
+ end
76
+ end
77
+ end
@@ -0,0 +1,55 @@
1
+ module Awscli
2
+ class Connection
3
+ require 'awscli/errors'
4
+ require 'awscli/helper'
5
+
6
+ def initialize
7
+ #load env variable AWSCLI_CONFIG_FILE
8
+ @@aws_config_file = ENV['AWSCLI_CONFIG_FILE']
9
+ unless !@@aws_config_file.nil?
10
+ puts "Cannot find config file environment variable"
11
+ Awscli::Errors.missing_environment_variable
12
+ end
13
+ @@aws_config_file_path = File.expand_path(@@aws_config_file)
14
+ unless File.exist?(@@aws_config_file_path)
15
+ puts "Cannot locate file #{@@aws_config_file}"
16
+ Awscli::Errors.missing_config_file
17
+ end
18
+ @@config = YAML.load(File.read(@@aws_config_file_path))
19
+ unless @@config.kind_of?(Hash)
20
+ puts "Parse Error"
21
+ Awscli::Errors.missing_credentials
22
+ end
23
+ end
24
+
25
+ def request_ec2
26
+ # => returns AWS Compute connection object
27
+ @@config.merge!(:provider => 'AWS')
28
+ if @@config['region']
29
+ Awscli::Errors.invalid_region unless Awscli::Instances::REGIONS.include?(@@config['region'])
30
+ end
31
+ Fog::Compute.new(@@config)
32
+ end
33
+
34
+ def request_s3 region=nil
35
+ # => returns S3 connection object
36
+ @@config.merge!(:provider => 'AWS')
37
+ if @@config['region']
38
+ #remove region
39
+ @@config.reject!{ |k| k == "region" }
40
+ end
41
+ #parse optionally passing region
42
+ if region
43
+ Awscli::Errors.invalid_region unless Awscli::Instances::REGIONS.include?(region)
44
+ @@config.merge!(:region => region)
45
+ end
46
+ Fog::Storage.new(@@config)
47
+ end
48
+
49
+ def request_as
50
+ # => returns AWS Auto Scaling connection object
51
+ Fog::AWS::AutoScaling.new(@@config)
52
+ end
53
+
54
+ end
55
+ end
@@ -0,0 +1,821 @@
1
+ module Awscli
2
+ module EC2
3
+
4
+ class EC2
5
+
6
+ # initialize ec2 class object
7
+ # params:
8
+ # connection: Awscli::Connection.new.request_ec2
9
+ # extra options hash
10
+ def initialize connection, options = {}
11
+ @@conn = connection
12
+ end
13
+
14
+ # list instances from a specified region in a tabular format
15
+ def list_instances
16
+ @@conn.servers.table([:id, :dns_name, :flavor_id, :groups, :image_id, :key_name, :private_ip_address,
17
+ :public_ip_address, :root_device_type, :security_group_ids, :state, :tags])
18
+ end
19
+
20
+ # list available instance types
21
+ def list_flavors
22
+ @@conn.flavors.table
23
+ end
24
+
25
+ # describe instance attributes - returns information about an attribute of an instance. You can get information
26
+ # only one attribute per call.
27
+ # Avaliable attributes to request: instanceType, kernel, ramdisk, userData, disableApiTermination, instanceInitiatedShutdownBehavior,
28
+ # rootDeviceName, blockDeviceMapping, sourceDestCheck, groupSet
29
+ def describe_instance_attribute instance_id, request
30
+ valid_requests = %w(architecture ami_launch_index availability_zone block_device_mapping network_interfaces client_token
31
+ dns_name ebs_optimized groups flavor_id iam_instance_profile image_id instance_initiated_shutdown_behavior
32
+ kernel_id key_name created_at monitoring placement_group platform private_dns_name private_ip_address
33
+ public_ip_address ramdisk_id root_device_name root_device_type security_group_ids state state_reason subnet_id
34
+ tenancy tags user_data vpc_id volumes username)
35
+ #more options
36
+ #:monitor=, :username=, :private_key=, :private_key_path=, :public_key=, :public_key_path=, :username, :private_key_path, :private_key, :public_key_path, :public_key, :scp, :scp_upload, :scp_download, :ssh, :ssh_port, :sshable?
37
+ response = @@conn.servers.get(instance_id)
38
+ abort "Invalid Attribute, available attributes to request: #{valid_requests}" unless valid_requests.include?(request)
39
+ abort "InstanceId Not found :#{instance_id}, Available instnaces #{@@conn.servers.map { |x| x.id }}" unless response
40
+ puts "#{request}: #{response.send(request)}"
41
+ end
42
+
43
+ # modifies an attribute of an instance
44
+ def modify_instance_attribute instance_id, attributename, attributevalue
45
+ attrs_lookup = {
46
+ 'isize' => 'InstanceType',
47
+ 'kernel' => 'Kernel',
48
+ 'ramdisk' => 'Ramdisk',
49
+ 'userdata' => 'UserData',
50
+ 'disable_api_term' => 'DisableApiTermination',
51
+ 'inst_shutdown_beh' => 'InstanceInitiatedShutdownBehavior',
52
+ 'source_dest_check' => 'SourceDestCheck',
53
+ 'group_id' => 'GroupId'
54
+ }
55
+ valid_attributes = %w(InstanceType Kernel Ramdisk UserData DisableApiTermination InstanceInitiatedShutdownBehavior SourceDestCheck GroupId)
56
+ response = @@conn.servers.get(instance_id)
57
+ abort "InstanceId Not found :#{instance_id}, Available instnaces #{@@conn.servers.map { |x| x.id }}" unless response
58
+ abort "Instance should be in stopped state to modify its attributes" if response.state != 'stopped'
59
+ puts "#{instance_id}, #{attributename}, #{attributevalue}"
60
+ if attrs_lookup[attributename] == 'GroupId' #handle groupid which is array
61
+ puts "#{instance_id}, #{attrs_lookup[attributename]} => #{attributevalue}"
62
+ @@conn.modify_instance_attribute(instance_id, attrs_lookup[attributename] => attributevalue)
63
+ else
64
+ puts "#{instance_id}, #{attrs_lookup[attributename]}.Value => #{attributevalue}"
65
+ @@conn.modify_instance_attribute(instance_id, "#{attrs_lookup[attributename]}.Value" => attributevalue)
66
+ end
67
+ end
68
+
69
+ # reset instance attribute
70
+ def reset_instance_attribute instance_id, attribute
71
+ end
72
+
73
+ #create a single instance with options passed
74
+ def create_instance options
75
+ #validate required options
76
+ puts "Validating Options ..."
77
+ abort "Invalid Key: #{options[:key_name]}" unless @@conn.key_pairs.get(options[:key_name])
78
+ options[:groups].each do |sg|
79
+ abort "Invalid Group: #{sg}" unless @@conn.security_groups.get(sg)
80
+ end
81
+ abort "Invalid AMI: #{options[:image_id]}" unless @@conn.images.get(options[:image_id])
82
+ abort "Invalid Instance Flavor: #{options[:flavor_id]}" unless @@conn.flavors.get(options[:flavor_id])
83
+ #validate optional options
84
+ if options[:availability_zone]
85
+ available_zones = @@conn.describe_availability_zones.body['availabilityZoneInfo'].map { |az| az['zoneName'] }
86
+ abort "Invalid AvailabilityZone: #{options[:availability_zone]}" unless available_zones.include?(options[:availability_zone])
87
+ end
88
+ opts = Marshal.load(Marshal.dump(options))
89
+ block_device_mapping = Array.new
90
+ #validate block device mapping and parse it to a hash understandable by fog
91
+ if options[:block_device_mapping]
92
+ options[:block_device_mapping].each do |group|
93
+ mapping = Hash.new
94
+ #parse options
95
+ abort "Invalid block device mapping format, expecting 'devicename=blockdevice' format" unless group =~ /\S=\S/
96
+ device_name, block_device = group.split("=")
97
+ abort "Invalid device name, expectiing '/dev/sd[a-z]'" unless device_name =~ /^\/dev\/sd[a-z]$/
98
+ abort "Invalud block device format, expecting 'ephemeral[0..3]|none|[snapshot-id]:[volume-size]:[true|false]:[standard|io1[:iops]]'" unless block_device =~ /^(snap-.*|ephemeral\w{1,3}|none|:.*)$/
99
+ mapping['DeviceName'] = device_name
100
+ case block_device
101
+ when 'none'
102
+ mapping['Ebs.NoDevice'] = 'true'
103
+ when /ephemeral/
104
+ mapping['VirtualName'] = block_device
105
+ when /snap-.*|:.*/
106
+ snapshot_id, volume_size, delete_on_termination, volume_type, iops = block_device.split(":")
107
+
108
+ mapping['Ebs.SnapshotId'] = snapshot_id if !snapshot_id.nil? && !snapshot_id.empty?
109
+ mapping['Ebs.VolumeSize'] = volume_size if !volume_size.nil? && !volume_size.empty?
110
+ mapping['Ebs.DeleteOnTermination'] = delete_on_termination if !delete_on_termination.nil? && !delete_on_termination.empty?
111
+ else
112
+ abort "Cannot validate block_device"
113
+ end
114
+ block_device_mapping << mapping
115
+ end
116
+ end
117
+ if block_devices = opts.delete(:block_device_mapping)
118
+ opts.merge!(:block_device_mapping => block_device_mapping)
119
+ end
120
+ wait_for_server = options[:wait_for] && opts.reject! { |k| k == 'wait_for' }
121
+ puts "Validating Options ... OK"
122
+ puts "Creating Server"
123
+ server = @@conn.servers.create(opts)
124
+ #wait for server to get created and return public_dns
125
+ if wait_for_server
126
+ print "Waiting for server to get created "
127
+ server.wait_for { print "."; ready? }
128
+ puts
129
+ puts "Server dns_name: #{server.dns_name}"
130
+ end
131
+ end
132
+
133
+ # create a new instnace(s)
134
+ def run_instances options
135
+ end
136
+
137
+ # describe instnace status
138
+ def describe_instance_status instnace_id
139
+ response = @@conn.servers.get(instance_id)
140
+ abort "InstanceId Not found :#{instance_id}" unless response
141
+ puts "Instance #{instance_id} State: #{response.state}"
142
+ end
143
+
144
+ # import instance as vm
145
+ def import_instance
146
+ end
147
+
148
+ #@@conn.server.get(instanceid).(:reboot, :save, :setup, :start, :stop)
149
+ # reboot an instance
150
+ def reboot_instance instance_id
151
+ response = @@conn.servers.get(instance_id)
152
+ abort "InstanceId Not found :#{instance_id}" unless response
153
+ response.reboot
154
+ puts "Rebooting Instance: #{instance_id}"
155
+ end
156
+
157
+ # start a stopped instance
158
+ def stop_instance instance_id
159
+ response = @@conn.servers.get(instance_id)
160
+ abort "InstanceId Not found :#{instance_id}" unless response
161
+ abort "Instance should be in running to stop it" if response.state != 'running'
162
+ response.stop
163
+ puts "Stopped Instance: #{instance_id}"
164
+ end
165
+
166
+ # stop a running isntance
167
+ def start_instance instance_id
168
+ response = @@conn.servers.get(instance_id)
169
+ abort "InstanceId Not found :#{instance_id}" unless response
170
+ abort "Instance should be stopped to start it" if response.state != 'stopped'
171
+ response.start
172
+ puts "Starting Instance: #{instance_id}"
173
+ end
174
+
175
+ # terminates an instance
176
+ def terminate_instance instance_id
177
+ response = @@conn.servers.get(instance_id)
178
+ abort "InstanceId Not found :#{instance_id}" unless response
179
+ response.destroy
180
+ puts "Terminsted Instance: #{instance_id}"
181
+ end
182
+
183
+ def get_console_output instance_id
184
+ response = @@conn.get_console_output(instance_id)
185
+ puts response
186
+ end
187
+
188
+ end # => EC2
189
+
190
+ class KeyPairs
191
+ def initialize connection, options = {}
192
+ @@conn = connection
193
+ end
194
+
195
+ def list_keypairs
196
+ @@conn.key_pairs.table
197
+ end
198
+
199
+ def create_keypair options
200
+ #validate keypair
201
+ Fog.credential = 'awscli'
202
+ abort "KeyPair '#{options[:name]}' already exists" if @@conn.key_pairs.get(options[:name])
203
+ kp = @@conn.key_pairs.create(options)
204
+ puts "Created keypair: #{options[:name]}"
205
+ p kp.write #save the key to disk
206
+ end
207
+
208
+ def delete_keypair keypair
209
+ abort "KeyPair '#{keypair}' does not exist" unless @@conn.key_pairs.get(keypair)
210
+ @@conn.key_pairs.get(keypair).destroy
211
+ puts "Deleted Keypair: #{keypair}"
212
+ end
213
+
214
+ def fingerprint keypair
215
+ response = @@conn.key_pairs.get(keypair)
216
+ abort "Cannot find key pair: #{keypair}" unless response
217
+ puts "Fingerprint for the key (#{keypair}): #{response.fingerprint}"
218
+ end
219
+
220
+ def import_keypair options
221
+ #validate if the file exists
222
+ private_key_path = if options[:private_key_path]
223
+ File.expand_path(options[:private_key_path])
224
+ else
225
+ File.expand_path("~/.ssh/#{options[:name]}")
226
+ end
227
+ public_key_path = if options[:public_key_path]
228
+ File.expand_path(options[:public_key_path])
229
+ else
230
+ File.expand_path("~/.ssh/#{options[:name]}.pub")
231
+ end
232
+ abort "Cannot find private_key_path: #{private_key_path}" unless File.exist?(private_key_path)
233
+ abort "Cannot find public_key_path: #{public_key_path}" unless File.exist?(public_key_path)
234
+ #validate if the key pair name exists
235
+ Fog.credentials = Fog.credentials.merge({ :private_key_path => private_key_path, :public_key_path => public_key_path })
236
+ @@conn.import_key_pair(options[:name], IO.read(public_key_path)) if @@conn.key_pairs.get(options[:name]).nil?
237
+ puts "Imported KeyPair with name: #{options[:name]} sucessfully, using public_key: #{public_key_path} and private_key: #{private_key_path}"
238
+ end
239
+ end # => KP
240
+
241
+ class SecGroups
242
+
243
+ #Limitations: Ec2-Classic: user can have upto 500 groups
244
+ # Ec2-VPC: user can have 50 group per VPC
245
+
246
+ def initialize connection, options = {}
247
+ @@conn = connection
248
+ end
249
+
250
+ def list_secgroups options
251
+ if options[:show_ip_permissions]
252
+ # @@conn.security_groups.table([:name, :group_id, :ip_permissions])
253
+ @@conn.security_groups.each do |sg|
254
+ id = sg.group_id
255
+ ip_permissions = sg.ip_permissions.to_yaml
256
+ Formatador.display_line("[green]#{id}[/]")
257
+ puts "#{ip_permissions}"
258
+ puts "================="
259
+ end
260
+ else
261
+ @@conn.security_groups.table([:name, :group_id, :description])
262
+ end
263
+ end
264
+
265
+ def authorize_securitygroup options
266
+ # => Ingress regular traffic -> this action applies to both EC2 and VPC Security Groups
267
+ # Each rule consists of the protocol, plus cidr range or a source group,
268
+ #for TCP/UDP protocols you must also specify the dest port or port range
269
+ #for ICMP, you must specify the icmp type and code (-1 means all types/codes)
270
+ abort "Expecting Security group id(s) of the form: 'sg-xxxxxx'" unless options[:group_id] =~ /sg-\S{8}/
271
+ abort "Invalid CIDR format" unless options[:cidr] =~ /^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])(\/(\d|[1-2]\d|3[0-2]))$/
272
+ sg = @@conn.security_groups.get_by_id(options[:group_id])
273
+ abort "Cannot find Security Group with Id: #{sg}" unless sg
274
+ begin
275
+ @@conn.authorize_security_group_ingress(
276
+ "GroupId" => options[:group_id],
277
+ "IpProtocol" => options[:protocol_type],
278
+ "FromPort" => options[:start_port],
279
+ "ToPort" => options[:end_port],
280
+ "CidrIp" => options[:cidr]
281
+ )
282
+ puts "Authorized rule"
283
+ rescue Fog::Compute::AWS::Error #=> e
284
+ abort "Error: #{$!}"
285
+ #puts $@ #backtrace
286
+ end
287
+ end
288
+
289
+ def revoke_securitygroup options
290
+ abort "Expecting Security group id(s) of the form: 'sg-xxxxxx'" unless options[:group_id] =~ /sg-\S{8}/
291
+ sg = @@conn.security_groups.get_by_id(options[:group_id])
292
+ abort "Cannot find Security Group with Id: #{sg}" unless sg
293
+ begin
294
+ response = @@conn.revoke_security_group_ingress(
295
+ "GroupId" => options[:group_id],
296
+ "IpProtocol" => options[:protocol_type],
297
+ "FromPort" => options[:start_port],
298
+ "ToPort" => options[:end_port],
299
+ "CidrIp" => options[:cidr]
300
+ )
301
+ puts "Revoked rule: #{response.body['return']}"
302
+ rescue Fog::Compute::AWS::Error #=> e
303
+ abort "Error: #{$!}"
304
+ end
305
+ end
306
+
307
+ def create_securitygroup options
308
+ abort "Error: Security Group => #{options[:name]} already exists" if @@conn.security_groups.get(options[:name])
309
+ @@conn.security_groups.create(options)
310
+ puts "Created Security Group: #{options[:name]}"
311
+ end
312
+
313
+ def delete_securitygroup options
314
+ sg = @@conn.security_groups.get_by_id(options[:group_id])
315
+ abort "Error: Cannot find Security Group with Id: #{sg}" unless sg
316
+ begin
317
+ sg.destroy
318
+ puts "Deleted Security Group with id: #{options[:group_id]}"
319
+ rescue Fog::Compute::AWS::Error #=> e
320
+ abort "Error: #{$!}"
321
+ end
322
+ end
323
+
324
+ end # => SG
325
+
326
+ class Eip
327
+ def initialize connection, options = {}
328
+ @@conn = connection
329
+ end
330
+
331
+ def list
332
+ @@conn.addresses.table
333
+ end
334
+
335
+ def create
336
+ eip = @@conn.addresses.create
337
+ puts "Created EIP: #{eip.public_ip}"
338
+ end
339
+
340
+ def delete options
341
+ abort "Invalid IP Format" unless options[:eip] =~ /^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$/
342
+ eip = @@conn.addresses.get(options[:eip])
343
+ abort "Cannot find IP: #{options[:eip]}" unless eip
344
+ eip.destroy
345
+ puts "Deleted EIP: #{eip.public_ip}"
346
+ end
347
+
348
+ def associate options
349
+ abort "Invalid IP Format" unless options[:eip] =~ /^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$/
350
+ eip = @@conn.addresses.get(options[:eip])
351
+ abort "Cannot find eip: #{options[:eip]}" unless eip
352
+ server = @@conn.servers.get(options[:instance_id])
353
+ abort "Cannot find server with id: #{options[:instance_id]}" unless server
354
+ begin
355
+ eip.server = server
356
+ puts "Associated EIP: #{options[:eip]} with Instance: #{options[:instance_id]}"
357
+ rescue Fog::Compute::AWS::Error
358
+ abort "Error: #{$!}"
359
+ end
360
+ end
361
+
362
+ def disassociate options
363
+ abort "Invalid IP Format" unless options[:eip] =~ /^(([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])\.){3}([0-9]|[1-9][0-9]|1[0-9]{2}|2[0-4][0-9]|25[0-5])$/
364
+ abort "Cannot find EIP: #{options[:eip]}" unless @@conn.addresses.get(options[:eip])
365
+ @@conn.disassociate_address(options[:eip])
366
+ puts "Disassociated EIP: #{options[:eip]}"
367
+ end
368
+ end # => Eip
369
+
370
+ class Ami
371
+ def initialize connection, options = {}
372
+ @@conn = connection
373
+ end
374
+
375
+ def list filter
376
+ puts filter
377
+ if filter.nil?
378
+ @@conn.images.all.table([:architecture, :id, :is_public, :platform, :root_device_type, :state])
379
+ else
380
+ @@conn.images.all(filter).table([:architecture, :id, :is_public, :platform, :root_device_type, :state])
381
+ end
382
+ end
383
+
384
+ def show_filters
385
+ filters =
386
+ [
387
+ {:filter_name => "architecture", :desc => "Image Architecture"},
388
+ {:filter_name => "block-device-mapping.delete-on-termination", :desc => "Whether the Amazon EBS volume is deleted on instance termination"},
389
+ {:filter_name => "block-device-mapping.device-name", :desc => "Device name (e.g., /dev/sdh) for an Amazon EBS volume mapped to the image"},
390
+ {:filter_name => "block-device-mapping.snapshot-id", :desc => "Snapshot ID for an Amazon EBS volume mapped to the image"},
391
+ {:filter_name => "block-device-mapping.volume-size", :desc => "Volume size for an Amazon EBS volume mapped to the image"},
392
+ {:filter_name => "description", :desc => "Description of the AMI (provided during image creation)"},
393
+ {:filter_name => "image-id", :desc => "ID of the image" },
394
+ {:filter_name => "imgae-type", :desc => "Type of image" },
395
+ {:filter_name => "is-public", :desc => "Whether the image is public" },
396
+ {:filter_name => "kernel-id", :desc => "Kernel ID" },
397
+ {:filter_name => "manifest-location", :desc => "Location of the image manifest" },
398
+ {:filter_name => "name", :desc => "Name of the AMI (provided during image creation)" },
399
+ {:filter_name => "owner-alias", :desc => "AWS account alias (e.g., amazon or self) or AWS account ID that owns the AMI" },
400
+ {:filter_name => "owner-id", :desc => "AWS account ID of the image owner" },
401
+ {:filter_name => "platform", :desc => "Use windows if you have Windows based AMIs; otherwise leave blank" },
402
+ {:filter_name => "product-code", :desc => "Product code associated with the AMI" },
403
+ {:filter_name => "ramdisk-id", :desc => "RAM disk ID" },
404
+ {:filter_name => "root-device-name", :desc => "Root device name of the AMI (e.g., /dev/sda1)" },
405
+ {:filter_name => "root-device-type", :desc => "Root device type the AMI uses" },
406
+ {:filter_name => "state", :desc => "State of the image" },
407
+ {:filter_name => "state-reason-code", :desc => "Reason code for the state change" },
408
+ {:filter_name => "state-reason-message", :desc => "Message for the state change" },
409
+ {:filter_name => "tag-key", :desc => "Key of a tag assigned to the resource. This filter is independent of the tag-value filter" },
410
+ {:filter_name => "tag-value", :desc => "Value of a tag assigned to the resource. This filter is independent of the tag-key filter." },
411
+ {:filter_name => "virtualization-type", :desc => "Virtualization type of the image" },
412
+ {:filter_name => "hypervisor", :desc => "Hypervisor type of the image" }
413
+ ]
414
+ Formatador.display_table(filters, [:filter_name, :desc])
415
+ end
416
+
417
+ def list_amazon
418
+ @@conn.images.all('owner-alias' => 'amazon').table([:architecture, :id, :is_public, :platform, :root_device_type, :state])
419
+ end
420
+
421
+ def create_image_from_instance options
422
+ abort "Invalid Instace: #{options[:instance_id]}" unless @@conn.servers.get(options[:instance_id])
423
+ @@conn.create_image(
424
+ options[:instance_id],
425
+ options[:name],
426
+ options[:desc],
427
+ options[:no_reboot]
428
+ )
429
+ puts "Created image from instance: #{options[:instance_id]}"
430
+ end
431
+
432
+ end # => AMI
433
+
434
+ class Ebs
435
+ def initialize connection, options = {}
436
+ @@conn = connection
437
+ end
438
+
439
+ def list options
440
+ unless options[:snapshots]
441
+ @@conn.volumes.table([:availability_zone, :delete_on_termination, :device, :id, :server_id, :size, :snapshot_id, :state, :tags, :type])
442
+ else
443
+ @@conn.snapshots.table([:id, :owner_id, :volume_id, :state, :progress, :tags, :description])
444
+ end
445
+ end
446
+
447
+ def create options
448
+ @@conn.volumes.create(options)
449
+ end
450
+
451
+ def attach_volume options
452
+ #The volume and instance must be in the same Availability Zone.
453
+ volume = @@conn.volumes.get(options[:volume_id])
454
+ volume.merge_attributes(:device => options[:device])
455
+ server = @@conn.servers.get(options[:instance_id])
456
+ abort "Cannot find volume: #{options[:volume_id]}" unless volume
457
+ abort "Cannot find instance: #{options[:instance_id]}" unless server
458
+ volume.server = server
459
+ puts "Attached volume: #{options[:volume_id]} to instance: #{options[:instance_id]}"
460
+ end
461
+
462
+ def detach_volume options
463
+ #Check if the volume is mounted and show warning regarding data loss
464
+ volume = @@conn.volumes.get(options[:volume_id])
465
+ abort "Cannot find volume: #{options[:volume_id]}" unless volume
466
+ if options[:force]
467
+ volume.force_detach
468
+ else
469
+ @@conn.detach_volume(options[:volume_id])
470
+ end
471
+ puts "Detached volume: #{options[:volume_id]}"
472
+ end
473
+
474
+ def delete_volume options
475
+ vol = @@conn.volumes.get(options[:volume_id])
476
+ abort "Cannot find volume #{options[:volume_id]}" unless vol
477
+ vol.destroy
478
+ puts "Deleted volume: #{options[:volume_id]}"
479
+ end
480
+
481
+ def create_snapshot options
482
+ abort "Cannot find volume: #{options[:volume_id]}" unless @@conn.volumes.get(options[:volume_id])
483
+ @@conn.snapshots.create(options)
484
+ puts "Created snapshot"
485
+ end
486
+
487
+ def copy_snapshot options
488
+ abort "Cannot find snapshot: #{options[:snapshot_id]}" unless @@conn.snapshots.get(options[:snapshot_id])
489
+ @@conn.copy_snapshot(options[:snapshot_id], options[:source_region])
490
+ puts "Copied snapshot"
491
+ end
492
+
493
+ def delete_snapshot options
494
+ snap = @@conn.snapshots.get(options[:snapshot_id])
495
+ abort "Cannot find snapshot: #{options[:snapshot_id]}" unless snap
496
+ snap.destroy
497
+ puts "Destroyed snapshot"
498
+ end
499
+ end # => EBS
500
+
501
+ class Monitor
502
+ def initialize connection, options = {}
503
+ @@conn = connection
504
+ end
505
+
506
+ def monitor options
507
+ options[:instance_ids].each do |instance|
508
+ abort "Invalid InstanceId: #{instance}" unless @@conn.servers.get(instance)
509
+ end
510
+ @@conn.monitor_instances(options[:instance_ids])
511
+ puts "Enabled monitoring for instnaces: #{options[:instance_ids].join(",")}"
512
+ end
513
+
514
+ def unmonitor options
515
+ options[:instance_ids].each do |instance|
516
+ abort "Invalid InstanceId: #{instance}" unless @@conn.servers.get(instance)
517
+ end
518
+ @@conn.unmonitor_instances(options[:instance_ids])
519
+ puts "Disabled monitoring for instnaces: #{options[:instance_ids].join(",")}"
520
+ end
521
+ end # => Monitor
522
+
523
+ class Tags
524
+ def initialize connection, options = {}
525
+ @@conn = connection
526
+ end
527
+
528
+ def list
529
+ @@conn.tags.table
530
+ end
531
+
532
+ def create options
533
+ @@conn.tags.create(options)
534
+ puts "Created Tag"
535
+ end
536
+
537
+ def delete options
538
+ @@conn.tags.destroy(options)
539
+ puts "Deleted Tag"
540
+ end
541
+ end # => Tags
542
+
543
+ class Placement
544
+ def initialize connection, options = {}
545
+ @@conn = connection
546
+ end
547
+
548
+ def list
549
+ @@conn.describe_placement_groups
550
+ end
551
+
552
+ def create options
553
+ @@conn.create_placement_group(options[:name], options[:strategy])
554
+ puts "Created a new placement group: #{options[:name]}"
555
+ end
556
+
557
+ def delete options
558
+ @@conn.delete_placement_group(options[:name])
559
+ puts "Deleted placement group: #{options[:name]}"
560
+ end
561
+ end # => Placement
562
+
563
+ class ReservedInstances
564
+ def initialize connection, options = {}
565
+ @@conn = connection
566
+ end
567
+
568
+ def list filters
569
+ puts filters
570
+ if filters.nil?
571
+ @@conn.describe_reserved_instances.body['reservedInstancesSet']
572
+ else
573
+ @@conn.describe_reserved_instances(filters).body['reservedInstancesSet']
574
+ end
575
+ end
576
+
577
+ def list_offerings filters
578
+ puts filters
579
+ response = if filters.nil?
580
+ @@conn.describe_reserved_instances_offerings.body['reservedInstancesOfferingsSet']
581
+ else
582
+ @@conn.describe_reserved_instances_offerings(filters).body['reservedInstancesOfferingsSet']
583
+ end
584
+ Formatador.display_table(response)
585
+ end
586
+
587
+ def list_filters
588
+ filters = [
589
+ {:filter_name => "availability-zone", :desc => "Availability Zone where the Reserved Instance can be used", :availability => "Both"},
590
+ {:filter_name => "duration", :desc => "Duration of the Reserved Instance (e.g., one year or three years), in seconds", :availability => "Both"},
591
+ {:filter_name => "fixed-price", :desc => "Purchase price of the Reserved Instance", :availability => "Both"},
592
+ {:filter_name => "instance-type", :desc => "Instance type on which the Reserved Instance can be used", :availability => "Both"},
593
+ {:filter_name => "product-description", :desc => "Reserved Instance description", :availability => "Both"},
594
+ {:filter_name => "reserved-instances-id", :desc => "Reserved Instance's ID", :availability => "Only ReservedInstances"},
595
+ {:filter_name => "reserved-instances-offering-id", :desc => "Reserved Instances offering ID", :availability => "Only reservedInstancesOfferingsSet"},
596
+ {:filter_name => "start", :desc => "Time the Reserved Instance purchase request was placed", :availability => "Only ReservedInstances"},
597
+ {:filter_name => "state", :desc => "State of the Reserved Instance", :availability => "Only ReservedInstances"},
598
+ {:filter_name => "tag-key", :desc => "Key of a tag assigned to the resource", :availability => "Only ReservedInstances"}, #This filter is independent of the tag-value filter. For example, if you use both the filter tag-key=Purpose and the filter tag-value=X, you get any resources assigned both the tag key Purpose and the tag value X
599
+ {:filter_name => "tag-value", :desc => "Value of a tag assigned to the resource", :availability => "Only ReservedInstances"}, #This filter is independent of the tag-key filter.
600
+ {:filter_name => "usage-price", :desc => "Usage price of the Reserved Instance, per hour", :availability => "Both"},
601
+ ]
602
+ Formatador.display_table(filters, [:filter_name, :desc, :availability])
603
+ end
604
+
605
+ def purchase options
606
+ @@conn.purchase_reserved_instances_offering(options[:reserved_instances_offering_id], options[:instance_count])
607
+ end
608
+ end # => ReservedInstances
609
+
610
+ class Spot
611
+ def initialize connection, options = {}
612
+ @@conn = connection
613
+ end
614
+
615
+ def describe_spot_requests
616
+ @@conn.spot_requests.table
617
+ end
618
+
619
+ def describe_spot_datafeed_subscription
620
+ @@conn.describe_spot_datafeed_subscription
621
+ end
622
+
623
+ def describe_spot_price_history filters
624
+ puts filters
625
+ response = if filters.nil?
626
+ @@conn.describe_spot_price_history.body['spotPriceHistorySet']
627
+ else
628
+ @@conn.describe_spot_price_history(filters).body['spotPriceHistorySet']
629
+ end
630
+ Formatador.display_table(response)
631
+ end
632
+
633
+ def list_filters
634
+ filters = [
635
+ {:filter_name => "instance-type", :desc => "Type of instance"},
636
+ {:filter_name => "product-description", :desc => "Product description for the Spot Price"},
637
+ {:filter_name => "spot-price", :desc => "Spot Price. The value must match exactly (or use wildcards; greater than or less than comparison is not supported)"},
638
+ {:filter_name => "timestamp", :desc => "Timestamp of the Spot Price history, e.g., 2010-08-16T05:06:11.000Z. You can use wildcards (* and ?)"},
639
+ ]
640
+ Formatador.display_table(filters, [:filter_name, :desc])
641
+ end
642
+
643
+ def create_spot_datafeed_subsription bucket, prefix
644
+ @@conn.create_spot_datafeed_subscription(bucket, prefix)
645
+ end
646
+
647
+ def delete_spot_datafeed_subsription
648
+ @@conn.delete_spot_datafeed_subscription
649
+ end
650
+
651
+ def request_spot_instances options
652
+ sr = @@conn.spot_requests.create(options)
653
+ puts "Created spot request: #{sr.id}"
654
+ end
655
+
656
+ def cancel_spot_instance_requests sid
657
+ sr = @@conn.spot_requests.get(sid)
658
+ abort "Cannot find spot request with id: #{sid}" unless sr
659
+ sr.destroy
660
+ puts "Deleted spot request: #{sid}"
661
+ end
662
+ end # => Spot
663
+
664
+ class Vpc
665
+ def initialize connection, options = {}
666
+ @@conn = connection
667
+ end
668
+
669
+ def list
670
+ @@conn.vpcs.table
671
+ end
672
+
673
+ def create options
674
+ vpc = @@conn.vpcs.create(options)
675
+ puts "Created VPC: #{vpc.id}"
676
+ end
677
+
678
+ def delete vpc_id
679
+ vpc = @@conn.vpcs.get(vpc_id)
680
+ abort "cannot find vpc: #{vpc_id}" unless vpc
681
+ vpc.destroy
682
+ puts "Deleted VPC : #{vpc_id}"
683
+ end
684
+ end # => Vpc
685
+
686
+ class Subnet
687
+ def initialize connection, options = {}
688
+ @@conn = connection
689
+ end
690
+
691
+ def list
692
+ @@conn.subnets.table
693
+ end
694
+
695
+ def create options
696
+ subnet = @@conn.subnets.create(options)
697
+ puts "Created Subnet: #{subnet.id}"
698
+ end
699
+
700
+ def delete subnet_id
701
+ subnet = @@conn.subnets.get(subnet_id)
702
+ abort "Cannot find subnet: #{subnet_id}" unless subnet
703
+ subnet.destroy
704
+ puts "Deleted subnet: #{subnet_id}"
705
+ end
706
+ end # => Subnet
707
+
708
+ class NetworkAcl
709
+ def initialize connection, options = {}
710
+ @@conn = connection
711
+ end
712
+
713
+ def list
714
+ puts "Listing Network Acls"
715
+ end
716
+
717
+ end # => NetworkAcl
718
+
719
+ class NetworkInterfaces
720
+ def initialize connection, options = {}
721
+ @@conn = connection
722
+ end
723
+
724
+ def list
725
+ @@conn.network_interfaces.table
726
+ end
727
+
728
+ def create options
729
+ nic = @@conn.network_interfaces.create(options)
730
+ puts "Create network interface #{nic.network_interface_id}"
731
+ end
732
+
733
+ def delete nic_id
734
+ nic = @@conn.network_interfaces.get(nic_id)
735
+ abort "Cannot find nic with id: #{nic_id}" unless nic
736
+ nic.destroy
737
+ puts "Deleted network interface #{nic_id}"
738
+ end
739
+
740
+ def attach nic_id, instance_id, device_index
741
+ @@conn.attach_network_interface(nic_id, instance_id, device_index)
742
+ puts "Attached Network Interface: #{nic_id} to instance: #{instance_id}"
743
+ end
744
+
745
+ def deattach attachement_id, force
746
+ @@conn.detach_network_interface attachement_id, force
747
+ puts "Deattached Network Interface with attachement_id: #{attachement_id}"
748
+ end
749
+
750
+ def modify_attribute options
751
+ case options[:attribute]
752
+ when 'description'
753
+ @@conn.modify_network_interface_attribute(options[:network_interface_id], 'description', options[:description])
754
+ when 'groupSet'
755
+ @@conn.modify_network_interface_attribute(options[:network_interface_id], 'groupSet', options[:group_set])
756
+ when 'sourceDestCheck'
757
+ @@conn.modify_network_interface_attribute(options[:network_interface_id], 'sourceDestCheck', options[:source_dest_check])
758
+ when 'attachment'
759
+ @@conn.modify_network_interface_attribute(options[:network_interface_id], 'attachment', options[:attachment])
760
+ else
761
+ abort "Invalid attribute: #{options[:attribute]}"
762
+ end
763
+ end
764
+ end # => NetworkInterfaces
765
+
766
+ class InternetGateways
767
+ def initialize connection, options = {}
768
+ @@conn = connection
769
+ end
770
+
771
+ def list
772
+ @@conn.internet_gateways.table
773
+ end
774
+
775
+ def create
776
+ gw = @@conn.internet_gateways.create
777
+ puts "Created Internet Gateway: #{gw.id}"
778
+ end
779
+
780
+ def delete gwid
781
+ gw = @@conn.internet_gateways.get(gwid)
782
+ gw.destroy
783
+ puts "Deleted Internet Gateway: #{gwid}"
784
+ end
785
+
786
+ def attach gwid, vpcid
787
+ @@conn.internet_gateways.attach(gwid, vpcid)
788
+ puts "Attached InternetGateway: #{gwid} to VPC: #{vpcid}"
789
+ end
790
+
791
+ def deattach gwid, vpcid
792
+ @@conn.internet_gateways.deattach(gwid, vpcid)
793
+ puts "Deattached InternetGateway: #{gwid} from VPC: #{vpcid}"
794
+ end
795
+ end # => InternetGateways
796
+
797
+ class Dhcp
798
+ def initialize connection, options = {}
799
+ @@conn = connection
800
+ end
801
+
802
+ def list
803
+ @@conn.dhcp_options.table
804
+ end
805
+
806
+ def create options
807
+ @@conn.dhcp_options.create(options)
808
+ end
809
+
810
+ def delete dhcp_id
811
+ dhcp = @@conn.dhcp_options(dhcp_id)
812
+ dhcp.destroy
813
+ end
814
+
815
+ def associate dhcp_ic, vpc_id
816
+ @@conn.dhcp_options.attach(dhcp_id, vpc_id)
817
+ end
818
+ end # => Dhcp
819
+
820
+ end
821
+ end