zaws 0.0.1

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 (89) hide show
  1. data/.gitignore +35 -0
  2. data/.travis.yml +20 -0
  3. data/Gemfile +5 -0
  4. data/Gemfile.lock +78 -0
  5. data/LICENSE +204 -0
  6. data/README.md +17 -0
  7. data/Rakefile +26 -0
  8. data/bin/zaws +20 -0
  9. data/feature/compute/assoc_security_group.feature +55 -0
  10. data/feature/compute/compute.feature +138 -0
  11. data/feature/compute/secondary_ip.feature +107 -0
  12. data/feature/compute/view.feature +23 -0
  13. data/feature/compute/view_images.feature +24 -0
  14. data/feature/elasticip/elasticip.feature +138 -0
  15. data/feature/elasticip/view.feature +18 -0
  16. data/feature/hosted_zone/view.feature +17 -0
  17. data/feature/hosted_zone/view_record.feature +29 -0
  18. data/feature/load_balancer/instance_registration.feature +120 -0
  19. data/feature/load_balancer/listener.feature +86 -0
  20. data/feature/load_balancer/load_balancer.feature +101 -0
  21. data/feature/load_balancer/view.feature +18 -0
  22. data/feature/route_table/assoc_subnet.feature +128 -0
  23. data/feature/route_table/route_propagation.feature +93 -0
  24. data/feature/route_table/route_table.feature +91 -0
  25. data/feature/route_table/route_to_gateway.feature +69 -0
  26. data/feature/route_table/route_to_instance.feature +115 -0
  27. data/feature/route_table/view.feature +25 -0
  28. data/feature/security_group/ingress.feature +184 -0
  29. data/feature/security_group/security_group.feature +107 -0
  30. data/feature/security_group/view.feature +23 -0
  31. data/feature/subnet/subnet.feature +92 -0
  32. data/feature/subnet/view.feature +24 -0
  33. data/feature/support/env.rb +14 -0
  34. data/feature/version.feature +6 -0
  35. data/lib/zaws/aws.rb +26 -0
  36. data/lib/zaws/command/compute.rb +100 -0
  37. data/lib/zaws/command/elasticip.rb +47 -0
  38. data/lib/zaws/command/hosted_zone.rb +26 -0
  39. data/lib/zaws/command/load_balancer.rb +113 -0
  40. data/lib/zaws/command/route_table.rb +134 -0
  41. data/lib/zaws/command/security_group.rb +69 -0
  42. data/lib/zaws/command/subnet.rb +65 -0
  43. data/lib/zaws/ec2/compute.rb +247 -0
  44. data/lib/zaws/ec2/elasticip.rb +85 -0
  45. data/lib/zaws/ec2/route_table.rb +202 -0
  46. data/lib/zaws/ec2/security_group.rb +116 -0
  47. data/lib/zaws/ec2/subnet.rb +108 -0
  48. data/lib/zaws/ec2.rb +40 -0
  49. data/lib/zaws/elb/load_balancer.rb +157 -0
  50. data/lib/zaws/elb.rb +20 -0
  51. data/lib/zaws/helper/file.rb +23 -0
  52. data/lib/zaws/helper/option.rb +24 -0
  53. data/lib/zaws/helper/output.rb +46 -0
  54. data/lib/zaws/helper/shell.rb +25 -0
  55. data/lib/zaws/route53/hosted_zone.rb +36 -0
  56. data/lib/zaws/route53.rb +20 -0
  57. data/lib/zaws/version.rb +3 -0
  58. data/lib/zaws.rb +57 -0
  59. data/spec/spec_helper.rb +4 -0
  60. data/spec/zaws/ec2/compute/add_volume_spec.rb +39 -0
  61. data/spec/zaws/ec2/compute/block_device_mapping_spec.rb +31 -0
  62. data/spec/zaws/ec2/compute/instance_id_by_external_id_spec.rb +23 -0
  63. data/spec/zaws/ec2/compute/instance_ping_spec.rb +34 -0
  64. data/spec/zaws/ec2/compute/instance_running_spec.rb +47 -0
  65. data/spec/zaws/ec2/compute/network_interface_json_spec.rb +57 -0
  66. data/spec/zaws/ec2/compute/nosdcheck_spec.rb +17 -0
  67. data/spec/zaws/ec2/compute/tag_instance_spec.rb +21 -0
  68. data/spec/zaws/ec2/security_group/id_by_name_spec.rb +32 -0
  69. data/spec/zaws/ec2/subnet/available_spec.rb +22 -0
  70. data/spec/zaws/ec2/subnet/declare_spec.rb +31 -0
  71. data/spec/zaws/ec2/subnet/exists_spec.rb +33 -0
  72. data/spec/zaws/ec2/subnet/id_array_by_cidrblock_array_spec.rb +48 -0
  73. data/spec/zaws/ec2/subnet/id_by_cidrblock_spec.rb +35 -0
  74. data/spec/zaws/ec2/subnet/id_by_ip_spec.rb +42 -0
  75. data/spec/zaws/ec2/subnet/view_spec.rb +34 -0
  76. data/spec/zaws/elb/load_balancer/calculated_listener_spec.rb +18 -0
  77. data/spec/zaws/helper/option/absent_spec.rb +14 -0
  78. data/spec/zaws/helper/option/exclusive_spec.rb +14 -0
  79. data/spec/zaws/helper/option/exists_spec.rb +18 -0
  80. data/spec/zaws/helper/option/minimum_spec.rb +14 -0
  81. data/spec/zaws/helper/output/binary_nagios_check_spec.rb +19 -0
  82. data/spec/zaws/helper/output/colorize_spec.rb +30 -0
  83. data/spec/zaws/helper/output/opt_exclusive_spec.rb +14 -0
  84. data/spec/zaws/helper/output/opt_minimum_spec.rb +15 -0
  85. data/spec/zaws/helper/output/opt_required_spec.rb +12 -0
  86. data/spec/zaws/helper/shell/cli_spec.rb +33 -0
  87. data/spec/zaws/helper/shell/if_then_spec.rb +24 -0
  88. data/zaws.gemspec +34 -0
  89. metadata +350 -0
@@ -0,0 +1,247 @@
1
+ require 'json'
2
+ require 'netaddr'
3
+ require 'timeout'
4
+
5
+ module ZAWS
6
+ module EC2Services
7
+ class Compute
8
+
9
+ def initialize(shellout,aws)
10
+ @shellout=shellout
11
+ @aws=aws
12
+ end
13
+
14
+ def view(region,viewtype,textout=nil,verbose=nil,vpcid=nil,externalid=nil)
15
+ comline="aws --output #{viewtype} --region #{region} ec2 describe-instances"
16
+ if vpcid || externalid
17
+ comline = comline + " --filter"
18
+ end
19
+ comline = comline + " 'Name=vpc-id,Values=#{vpcid}'" if vpcid
20
+ comline = comline + " 'Name=tag:externalid,Values=#{externalid}'" if externalid
21
+ instances=@shellout.cli(comline,verbose)
22
+ textout.puts(instances) if textout
23
+ return instances
24
+ end
25
+
26
+ def view_images(region,viewtype,owner,imageid,textout=nil,verbose=nil)
27
+ comline="aws --output #{viewtype} --region #{region} ec2 describe-images"
28
+ comline = "#{comline} --owner #{owner}" if owner
29
+ comline = "#{comline} --image-ids #{imageid}" if imageid
30
+ verbose.puts comline if verbose
31
+ images=@shellout.cli(comline,verbose)
32
+ textout.puts(images) if textout
33
+ return images
34
+ end
35
+
36
+ def exists(region,textout=nil,verbose=nil,vpcid,externalid)
37
+ instances=JSON.parse(view(region,'json',nil,verbose,vpcid,externalid))
38
+ val = (instances["Reservations"].count == 1) && (instances["Reservations"][0]["Instances"].count == 1)
39
+ instance_id = val ? instances["Reservations"][0]["Instances"][0]["InstanceId"] : nil
40
+ sgroups = val ? instances["Reservations"][0]["Instances"][0]["SecurityGroups"] : nil
41
+ textout.puts val.to_s if textout
42
+ return val, instance_id, sgroups
43
+ end
44
+
45
+ def instance_id_by_external_id(region,externalid,vpcid=nil,textout=nil,verbose=nil)
46
+ val,instance_id,sgroups=exists(region,nil,verbose,vpcid,externalid)
47
+ return instance_id
48
+ end
49
+
50
+ def network_interface_json(region,verbose,vpcid,ip,groupname)
51
+ ec2_dir = File.dirname(__FILE__)
52
+ ip_to_subnet_id = @aws.ec2.subnet.id_by_ip(region,nil,verbose,vpcid,ip)
53
+ subnet_id=ip_to_subnet_id
54
+ security_group_id= @aws.ec2.security_group.id_by_name(region,nil,verbose,vpcid,groupname)
55
+ new_hash= [{ "Groups"=> [security_group_id], "PrivateIpAddress"=>"#{ip}","DeviceIndex"=>"0","SubnetId"=> ip_to_subnet_id }]
56
+ return new_hash.to_json
57
+ end
58
+
59
+ def block_device_mapping(region,owner,verbose,rootsize,imageid)
60
+ image_descriptions=JSON.parse(view_images(region,'json',owner,imageid,nil,verbose))
61
+ image_mappings=image_descriptions['Images'][0]["BlockDeviceMappings"]
62
+ image_root=image_descriptions['Images'][0]["RootDeviceName"]
63
+ image_mappings.each do |x|
64
+ if x["DeviceName"]==image_root
65
+ if x["Ebs"]["VolumeSize"].to_i > rootsize.to_i
66
+ raiseerror "The image root size is greater than the specified root size. image=#{x["Ebs"]["VolumeSize"]} > rootsize=#{rootsize}"
67
+ exit 1
68
+ end
69
+ x["Ebs"]["VolumeSize"]=rootsize.to_i
70
+ end
71
+ end
72
+ return image_mappings.to_json
73
+ end
74
+
75
+ def random_clienttoken
76
+ (0...8).map { (65 + rand(26)).chr }.join
77
+ end
78
+
79
+ def declare(externalid,image,owner,nodetype,root,zone,key,sgroup,privateip,optimized,apiterminate,clienttoken,region,textout,verbose,vpcid,nagios,ufile,no_sdcheck,skip_running_check,volsize,volume)
80
+ if ufile
81
+ ZAWS::Helper::File.prepend("zaws compute delete #{externalid} --region #{region} --vpcid #{vpcid} $XTRA_OPTS",'#Delete instance',ufile)
82
+ end
83
+ compute_exists,instance_id,sgroups = exists(region,nil,verbose,vpcid,externalid)
84
+ return ZAWS::Helper::Output.binary_nagios_check(compute_exists,"OK: Instance already exists.","CRITICAL: Instance does not exist.",textout) if nagios
85
+ if not compute_exists
86
+ clienttoken=random_clienttoken if not clienttoken
87
+ comline = "aws --region #{region} ec2 run-instances --image-id #{image} --key-name #{key} --instance-type #{nodetype}"
88
+ #comline = comline + " --user-data 'file://#{options[:userdata]}'" if options[:userdata]
89
+ comline = comline + " --placement AvailabilityZone=#{zone}" if zone
90
+ comline = comline + " --block-device-mappings '#{block_device_mapping(region,owner,verbose,root,image)}'" if root
91
+ comline = apiterminate ? comline + " --enable-api-termination" : comline + " --disable-api-termination"
92
+ comline = comline + " --client-token #{clienttoken}"
93
+ comline = comline + " --network-interfaces '#{network_interface_json(region,verbose,vpcid,privateip[0],sgroup)}'" if privateip # Difference between vpc and classic
94
+ #comline = comline + " --security-groups '#{options[:securitygroup]}'" if not options[:privateip]
95
+ #comline = comline + " --iam-instance-profile Name='#{options[:profilename]}'" if options[:profilename]
96
+ comline = optimized ? comline + " --ebs-optimized" : comline + " --no-ebs-optimized"
97
+ newinstance=JSON.parse(@shellout.cli(comline,verbose))
98
+ textout.puts "Instance created." if (newinstance["Instances"] and newinstance["Instances"][0]["InstanceId"])
99
+ new_instanceid=newinstance["Instances"][0]["InstanceId"]
100
+ tag_resource(region,new_instanceid,externalid,verbose)
101
+ instance_running?(region,vpcid,externalid,60,5,verbose) if not skip_running_check
102
+ add_volume(region,new_instanceid,externalid,privateip,volume,zone,volsize,verbose) if volume
103
+ nosdcheck(region,new_instanceid,verbose) if no_sdcheck # Needed for NAT instances.
104
+ else
105
+ textout.puts "Instance already exists. Creation skipped."
106
+ end
107
+
108
+ end
109
+
110
+ def delete(region,textout=nil,verbose=nil,vpcid,externalid)
111
+ compute_exists,instance_id,sgroups = exists(region,nil,verbose,vpcid,externalid)
112
+ if compute_exists
113
+ comline = "aws --region #{region} ec2 terminate-instances --instance-ids #{instance_id}"
114
+ delinstance=JSON.parse(@shellout.cli(comline,verbose))
115
+ textout.puts "Instance deleted." if delinstance["TerimatingInstances"]
116
+ else
117
+ textout.puts "Instance does not exist. Skipping deletion."
118
+ end
119
+ end
120
+
121
+ def exists_security_group_assoc(region,textout,verbose,vpcid,externalid,sgroup)
122
+ compute_exists,instance_id,sgroups = exists(region,nil,verbose,vpcid,externalid)
123
+ sgroup_exists,sgroupid = @aws.ec2.security_group.exists(region,nil,verbose,vpcid,sgroup)
124
+ verbose.puts "compute_exists=#{compute_exists}" if verbose
125
+ verbose.puts "sgroup_exists=#{sgroup_exists}" if verbose
126
+ verbose.puts "sgroups=#{sgroups}" if verbose
127
+ if compute_exists and sgroup_exists
128
+ assoc_exists = sgroups.any? { |z| z["GroupId"] == "#{sgroupid}" }
129
+ textout.puts assoc_exists if textout
130
+ return assoc_exists, instance_id, sgroupid
131
+ else
132
+ textout.puts false if textout
133
+ return false, instance_id, sgroupid
134
+ end
135
+ end
136
+
137
+ def assoc_security_group(region,textout,verbose,vpcid,externalid,sgroup)
138
+ assoc_exists,instance_id,sgroupid=exists_security_group_assoc(region,nil,verbose,vpcid,externalid,sgroup)
139
+ if not assoc_exists
140
+ comline = "aws --region #{region} ec2 modify-instance-attribute --instance-id #{instance_id} --groups #{sgroupid}"
141
+ verbose.puts "comline=#{comline}" if verbose
142
+ assocsgroup=JSON.parse(@shellout.cli(comline,verbose))
143
+ textout.puts "Security Group Association Changed." if assocsgroup["return"]=="true"
144
+ else
145
+ textout.puts "Security Group Association Not Changed."
146
+ end
147
+ end
148
+
149
+ def tag_resource(region,resourceid,externalid,verbose=nil)
150
+ comline="aws --output json --region #{region} ec2 create-tags --resources #{resourceid} --tags Key=externalid,Value=#{externalid}"
151
+ tag_creation=JSON.parse(@shellout.cli(comline,verbose))
152
+ comline="aws --output json --region #{region} ec2 create-tags --resources #{resourceid} --tags Key=Name,Value=#{externalid}"
153
+ tag_creation=JSON.parse(@shellout.cli(comline,verbose))
154
+ end
155
+
156
+ def nosdcheck(region,instanceid,verbose=nil)
157
+ comline = "aws --output json --region #{region} ec2 modify-instance-attribute --instance-id=#{instanceid} --no-source-dest-check"
158
+ nosdcheck_result=JSON.parse(@shellout.cli(comline,verbose))
159
+ end
160
+
161
+ def instance_ping?(ip,statetimeout,sleeptime,verbose=nil)
162
+ begin
163
+ Timeout.timeout(statetimeout) do
164
+ begin
165
+ comline ="ping -q -c 2 #{ip}"
166
+ @shellout.cli(comline,verbose)
167
+ rescue Mixlib::ShellOut::ShellCommandFailed
168
+ sleep(sleeptime)
169
+ retry
170
+ end
171
+ end
172
+ rescue Timeout::Error
173
+ raise StandardError.new('Timeout before instance responded to ping.')
174
+ end
175
+ return true
176
+ end
177
+
178
+ def instance_running?(region,vpcid,externalid,statetimeout,sleeptime,verbose=nil)
179
+ begin
180
+ Timeout.timeout(statetimeout) do
181
+ begin
182
+ sleep(sleeptime)
183
+ query_instance=JSON.parse(view(region,'json',nil,verbose,vpcid,externalid))
184
+ end while query_instance["Reservations"][0]["Instances"][0]["State"]["Code"]!=16
185
+ end
186
+ rescue Timeout::Error
187
+ raise StandardError.new('Timeout before instance state code set to running(16).')
188
+ end
189
+ end
190
+
191
+ def add_volume(region,instanceid,externalid,ip,volume,zone,volsize,verbose=nil)
192
+ comline = "aws --output json --region #{region} ec2 create-volume --availability-zone #{zone} --size #{volsize}"
193
+ new_volume=JSON.parse(@shellout.cli(comline,verbose))
194
+ new_volumeid=new_volume["VolumeId"]
195
+ tag_resource(region,new_volumeid,externalid,verbose)
196
+ if instance_ping?(ip,10,1)
197
+ comline = "aws --output json ec2 attach-volume --region #{region} --volume-id #{new_volumeid} --instance-id #{instanceid} --device #{volume}"
198
+ volattach=JSON.parse(@shellout.cli(comline,verbose))
199
+ end
200
+ end
201
+
202
+ def exists_secondary_ip(region,ip,textout,verbose,vpcid,externalid)
203
+ compute_exists,instance_id,sgroups = exists(region,nil,verbose,vpcid,externalid)
204
+ if compute_exists
205
+ query_instance=JSON.parse(view(region,'json',nil,verbose,vpcid,externalid))
206
+ val = query_instance["Reservations"][0]["Instances"][0]["NetworkInterfaces"][0]["PrivateIpAddresses"].any? { |x| x["PrivateIpAddress"] == "#{ip}" }
207
+ netid = query_instance["Reservations"][0]["Instances"][0]["NetworkInterfaces"][0]["NetworkInterfaceId"]
208
+ textout.puts val if textout
209
+ return val,true,netid
210
+ else
211
+ return false,false,nil
212
+ end
213
+ end
214
+
215
+ def declare_secondary_ip(region,ip,textout,verbose,vpcid,externalid,nagios,ufile)
216
+ if ufile
217
+ ZAWS::Helper::File.prepend("zaws compute delete_secondary_ip #{externalid} #{ip} --region #{region} --vpcid #{vpcid} $XTRA_OPTS",'#Delete secondary ip',ufile)
218
+ end
219
+ compute_exists,instance_id,sgroups = exists(region,nil,verbose,vpcid,externalid)
220
+ secondary_ip_exists,compute_exists,network_interface = exists_secondary_ip(region,ip,nil,verbose,vpcid,externalid)
221
+ return ZAWS::Helper::Output.binary_nagios_check(secondary_ip_exists,"OK: Secondary ip exists.","CRITICAL: Secondary ip does not exist.",textout) if nagios
222
+ if not secondary_ip_exists and compute_exists
223
+ comline = "aws --output json --region #{region} ec2 assign-private-ip-addresses --network-interface-id '#{network_interface}' --private-ip-addresses '#{ip}'"
224
+ $stdout.puts comline
225
+ assignreturn = JSON.parse(@shellout.cli(comline,verbose))
226
+ textout.puts "Secondary ip assigned." if assignreturn["return"] == "true"
227
+ else
228
+ textout.puts "Secondary ip already exists. Skipping assignment."
229
+ end
230
+ end
231
+
232
+ def delete_secondary_ip(region,ip,textout,verbose,vpcid,externalid)
233
+ secondary_ip_exists,compute_exists,network_interface = exists_secondary_ip(region,ip,nil,verbose,vpcid,externalid)
234
+ if secondary_ip_exists and compute_exists
235
+ comline = "aws --output json --region #{region} ec2 unassign-private-ip-addresses --network-interface-id '#{network_interface}' --private-ip-addresses '#{ip}'"
236
+ assignreturn = JSON.parse(@shellout.cli(comline,verbose))
237
+ textout.puts "Secondary ip deleted." if assignreturn["return"] == "true"
238
+ else
239
+ textout.puts "Secondary IP does not exists, skipping deletion."
240
+ end
241
+ end
242
+
243
+
244
+ end
245
+ end
246
+ end
247
+
@@ -0,0 +1,85 @@
1
+ require 'json'
2
+ require 'netaddr'
3
+ require 'timeout'
4
+
5
+ module ZAWS
6
+ module EC2Services
7
+ class Elasticip
8
+
9
+ def initialize(shellout,aws)
10
+ @shellout=shellout
11
+ @aws=aws
12
+ end
13
+
14
+ def view(region,view,textout=nil,verbose=nil,vpcid=nil,instanceid=nil)
15
+ comline="aws --output #{view} --region #{region} ec2 describe-addresses"
16
+ if vpcid
17
+ comline = comline + " --filter"
18
+ end
19
+ comline = comline + " 'Name=domain,Values=vpc'" if vpcid
20
+ comline = comline + " 'Name=instance-id,Values=#{instanceid}'" if instanceid
21
+ rtables=@shellout.cli(comline,verbose)
22
+ textout.puts(rtables) if textout
23
+ return rtables
24
+ end
25
+
26
+ def assoc_exists(region,externalid,textout=nil,verbose=nil,vpcid=nil)
27
+ val,instance_id,sgroups=@aws.ec2.compute.exists(region,nil,verbose,vpcid,externalid)
28
+ if val
29
+ addresses=JSON.parse(view(region,'json',nil,verbose,vpcid,instance_id))
30
+ verbose.puts addresses if verbose
31
+ addressassoc=(addresses["Addresses"] and (addresses["Addresses"].count == 1))
32
+ associationid= (addressassoc and addresses["Addresses"][0]["AssociationId"]) ? addresses["Addresses"][0]["AssociationId"]:nil
33
+ allocationid= (addressassoc and addresses["Addresses"][0]["AllocationId"]) ? addresses["Addresses"][0]["AllocationId"]:nil
34
+ ip= (addressassoc and addresses["Addresses"][0]["PublicIp"]) ? addresses["Addresses"][0]["PublicIp"]:nil
35
+ verbose.puts "addressassoc=#{addressassoc}" if verbose
36
+ verbose.puts "associationid=#{associationid}" if verbose
37
+ verbose.puts "allocationid=#{allocationid}" if verbose
38
+ textout.puts addressassoc if textout
39
+ return addressassoc,instance_id,associationid,allocationid,ip
40
+ else
41
+ textout.puts addressassoc if textout
42
+ return false,nil,nil,nil,nil
43
+ end
44
+ end
45
+
46
+ def declare(region,externalid,textout=nil,verbose=nil,vpcid=nil,nagios=nil,ufile=nil)
47
+ if ufile
48
+ ZAWS::Helper::File.prepend("zaws elasticip release #{externalid} --region #{region} --vpcid #{vpcid} $XTRA_OPTS",'#Release elastic ip.',ufile)
49
+ end
50
+ elasticip_exists,instance_id,association_id,allocation_id,ip=assoc_exists(region,externalid,nil,verbose,vpcid)
51
+ return ZAWS::Helper::Output.binary_nagios_check(elasticip_exists,"OK: Elastic Ip exists.","CRITICAL: Elastic Ip DOES NOT EXIST.",textout) if nagios
52
+ if not elasticip_exists and instance_id
53
+ comline="aws --region #{region} ec2 allocate-address --domain vpc"
54
+ allocation=JSON.parse(@shellout.cli(comline,verbose))
55
+ if allocation["AllocationId"]
56
+ comline="aws --region #{region} ec2 associate-address --instance-id #{instance_id} --public-ip #{allocation["PublicIp"]} --allocation-id #{allocation["AllocationId"]}"
57
+ association=JSON.parse(@shellout.cli(comline,verbose))
58
+ textout.puts "New elastic ip associated to instance." if association["return"] == "true"
59
+ end
60
+ else
61
+ textout.puts "instance already has an elastic ip. Skipping creation."
62
+ end
63
+ end
64
+
65
+ def release(region,externalid,textout=nil,verbose=nil,vpcid=nil)
66
+ elasticip_exists,instance_id,association_id,allocation_id,ip=assoc_exists(region,externalid,nil,verbose,vpcid)
67
+ if elasticip_exists and association_id and allocation_id
68
+ verbose = $stdout
69
+ comline="aws --region #{region} ec2 disassociate-address --public-ip #{ip} --association-id #{association_id}"
70
+ verbose.puts comline if verbose
71
+ disassociation=JSON.parse(@shellout.cli(comline,verbose))
72
+ if disassociation["return"]=="true"
73
+ comline="aws --region #{region} ec2 release-address --public-ip #{ip} --allocation-id #{allocation_id}"
74
+ release=JSON.parse(@shellout.cli(comline,verbose))
75
+ textout.puts "Deleted elasticip." if release["return"] == "true"
76
+ end
77
+ else
78
+ textout.puts "Elasticip does not exist. Skipping deletion."
79
+ end
80
+ end
81
+
82
+ end
83
+ end
84
+ end
85
+
@@ -0,0 +1,202 @@
1
+ require 'json'
2
+ require 'netaddr'
3
+ require 'timeout'
4
+
5
+ module ZAWS
6
+ module EC2Services
7
+ class RouteTable
8
+
9
+ def initialize(shellout,aws)
10
+ @shellout=shellout
11
+ @aws=aws
12
+ end
13
+
14
+ def view(region,view,textout=nil,verbose=nil,vpcid=nil,externalid=nil)
15
+ comline="aws --output #{view} --region #{region} ec2 describe-route-tables"
16
+ if vpcid || externalid
17
+ comline = comline + " --filter"
18
+ end
19
+ comline = comline + " 'Name=vpc-id,Values=#{vpcid}'" if vpcid
20
+ comline = comline + " 'Name=tag:externalid,Values=#{externalid}'" if externalid
21
+ rtables=@shellout.cli(comline,verbose)
22
+ textout.puts(rtables) if textout
23
+ return rtables
24
+ end
25
+
26
+ def exists(region,textout=nil,verbose=nil,vpcid,externalid)
27
+ rtable=JSON.parse(view(region,'json',nil,verbose,vpcid,externalid))
28
+ val = (rtable["RouteTables"].count == 1)
29
+ rtable_id = val ? rtable["RouteTables"][0]["RouteTableId"] : nil
30
+ textout.puts val.to_s if textout
31
+ return val, rtable_id
32
+ end
33
+
34
+ def declare(region,vpcid,externalid,nagios,textout=nil,verbose=nil,ufile=nil)
35
+ if ufile
36
+ ZAWS::Helper::File.prepend("zaws route_table delete #{externalid} --region #{region} --vpcid #{vpcid} $XTRA_OPTS",'#Delete route table',ufile)
37
+ end
38
+ rtable_exists, rtable_id = exists(region,nil,verbose,vpcid,externalid)
39
+ return ZAWS::Helper::Output.binary_nagios_check(rtable_exists,"OK: Route table exists.","CRITICAL: Route table does not exist.",textout) if nagios
40
+ if not rtable_exists
41
+ comline="aws --region #{region} ec2 create-route-table --vpc-id #{vpcid}"
42
+ rtable=JSON.parse(@shellout.cli(comline,verbose))
43
+ rtableid=rtable["RouteTable"]["RouteTableId"]
44
+ tagline="aws --region #{region} ec2 create-tags --resources #{rtableid} --tags Key=externalid,Value=#{externalid}"
45
+ tagresult=JSON.parse(@shellout.cli(tagline,verbose))
46
+ textout.puts "Route table created with external id: my_route_table." if tagresult["return"] == "true"
47
+ else
48
+ textout.puts "Route table exists already. Skipping Creation."
49
+ end
50
+ end
51
+
52
+ def delete(region,textout=nil,verbose=nil,vpcid,externalid)
53
+ rtable_exists, rtable_id = exists(region,nil,verbose,vpcid,externalid)
54
+ if rtable_exists
55
+ comline="aws --region #{region} ec2 delete-route-table --route-table-id #{rtable_id}"
56
+ deletion=JSON.parse(@shellout.cli(comline,verbose))
57
+ textout.puts "Route table deleted." if deletion["return"] == "true"
58
+ else
59
+ textout.puts "Route table does not exist. Skipping deletion."
60
+ end
61
+ end
62
+
63
+ def route_exists_by_instance(region,textout=nil,verbose=nil,vpcid,routetable,cidrblock,externalid)
64
+ # Returns the answer, instance_id, route_table_id
65
+ instance_id=@aws.ec2.compute.instance_id_by_external_id(region,externalid,vpcid,nil,verbose)
66
+ return false, nil, nil if not instance_id
67
+ rtable=JSON.parse(view(region,'json',nil,verbose,vpcid,routetable))
68
+ val = (rtable["RouteTables"].count == 1) && rtable["RouteTables"][0]["Routes"].any? { |x| x["DestinationCidrBlock"]=="#{cidrblock}" && x["InstanceId"]=="#{instance_id}" }
69
+ rtable_id = (rtable["RouteTables"].count == 1) ? rtable["RouteTables"][0]["RouteTableId"] : nil
70
+ textout.puts val.to_s if textout
71
+ return val, instance_id, rtable_id
72
+ end
73
+
74
+ def declare_route(region,textout=nil,verbose=nil,vpcid,routetable,cidrblock,externalid,nagios,ufile)
75
+ if ufile
76
+ ZAWS::Helper::File.prepend("zaws route_table delete_route #{routetable} #{cidrblock} --region #{region} --vpcid #{vpcid} $XTRA_OPTS",'#Delete route',ufile)
77
+ end
78
+ # TODO: Route exists already of a different type?
79
+ route_exists, instance_id, rtable_id = route_exists_by_instance(region,nil,verbose,vpcid,routetable,cidrblock,externalid)
80
+ return ZAWS::Helper::Output.binary_nagios_check(route_exists,"OK: Route to instance exists.","CRITICAL: Route to instance does not exist.",textout) if nagios
81
+ if not route_exists
82
+ comline="aws --region #{region} ec2 create-route --route-table-id #{rtable_id} --destination-cidr-block #{cidrblock} --instance-id #{instance_id}"
83
+ routereturn=JSON.parse(@shellout.cli(comline,verbose))
84
+ textout.puts "Route created to instance." if routereturn["return"] == "true"
85
+ else
86
+ textout.puts "Route not created to instance. Skip creation."
87
+ end
88
+ end
89
+
90
+ def delete_route(region,textout=nil,verbose=nil,vpcid,routetable,cidrblock)
91
+ rtable=JSON.parse(view(region,'json',nil,verbose,vpcid,routetable))
92
+ val = (rtable["RouteTables"].count == 1) && rtable["RouteTables"][0]["Routes"].any? { |x| x["DestinationCidrBlock"]=="#{cidrblock}" }
93
+ rtable_id = (rtable["RouteTables"].count == 1) ? rtable["RouteTables"][0]["RouteTableId"] : nil
94
+ if val
95
+ comline="aws --region #{region} ec2 delete-route --route-table-id #{rtable_id} --destination-cidr-block #{cidrblock}"
96
+ deletion=JSON.parse(@shellout.cli(comline,verbose))
97
+ textout.puts "Route deleted." if deletion["return"] == "true"
98
+ else
99
+ textout.puts "Route does not exist. Skipping deletion."
100
+ end
101
+ end
102
+
103
+ def route_exists_by_gatewayid(region,textout=nil,verbose=nil,vpcid,routetable,cidrblock,gatewayid)
104
+ # Returns the answer, route_table_id
105
+ rtable=JSON.parse(view(region,'json',nil,verbose,vpcid,routetable))
106
+ val = (rtable["RouteTables"].count == 1) && rtable["RouteTables"][0]["Routes"].any? { |x| x["DestinationCidrBlock"]=="#{cidrblock}" && x["GatewayId"]=="#{gatewayid}" }
107
+ rtable_id = (rtable["RouteTables"].count == 1) ? rtable["RouteTables"][0]["RouteTableId"] : nil
108
+ textout.puts val.to_s if textout
109
+ return val, rtable_id
110
+ end
111
+
112
+
113
+ def declare_route_to_gateway(region,textout=nil,verbose=nil,vpcid,routetable,cidrblock,gatewayid,nagios,ufile)
114
+ if ufile
115
+ ZAWS::Helper::File.prepend("zaws route_table delete_route #{routetable} #{cidrblock} --region #{region} --vpcid #{vpcid} $XTRA_OPTS",'#Delete route',ufile)
116
+ end
117
+ # TODO: Route exists already of a different type?
118
+ route_exists, rtable_id = route_exists_by_gatewayid(region,nil,verbose,vpcid,routetable,cidrblock,gatewayid)
119
+ return ZAWS::Helper::Output.binary_nagios_check(route_exists,"OK: Route to gateway exists.","CRITICAL: Route to gateway does not exist.",textout) if nagios
120
+ if not route_exists
121
+ comline="aws --region #{region} ec2 create-route --route-table-id #{rtable_id} --destination-cidr-block #{cidrblock} --gateway-id #{gatewayid}"
122
+ routereturn=JSON.parse(@shellout.cli(comline,verbose))
123
+ textout.puts "Route created to gateway." if routereturn["return"] == "true"
124
+ else
125
+ textout.puts "Route to gateway exists. Skipping creation."
126
+ end
127
+ end
128
+
129
+ def subnet_assoc_exists(region,textout=nil,verbose=nil,vpcid,rtable_externalid,cidrblock)
130
+ rtable=JSON.parse(view(region,'json',nil,verbose,vpcid,rtable_externalid))
131
+ subnetid=@aws.ec2.subnet.id_by_cidrblock(region,nil,verbose,vpcid,cidrblock)
132
+ val = ((not subnetid.nil?) and (rtable["RouteTables"].count == 1) and (rtable["RouteTables"][0]["Associations"].any? { |x| x["SubnetId"]=="#{subnetid}"}))
133
+ rtassocid= (val and rtable["RouteTables"].count == 1) ? (rtable["RouteTables"][0]["Associations"].select { |x| x["SubnetId"]=="#{subnetid}"})[0]["RouteTableAssociationId"] : nil
134
+ rtableid = (rtable["RouteTables"].count == 1) ? rtable["RouteTables"][0]["RouteTableId"] : nil
135
+ textout.puts val.to_s if textout
136
+ return val, subnetid, rtableid, rtassocid
137
+ end
138
+
139
+ def assoc_subnet(region,textout=nil,verbose=nil,vpcid,routetable,cidrblock,nagios,ufile)
140
+ if ufile
141
+ ZAWS::Helper::File.prepend("zaws route_table delete_assoc_subnet #{routetable} #{cidrblock} --region #{region} --vpcid #{vpcid} $XTRA_OPTS",'#Delete route table association to subnet',ufile)
142
+ end
143
+ assoc_exists, subnetid, rtableid, rtassocid = subnet_assoc_exists(region,nil,verbose,vpcid,routetable,cidrblock)
144
+ return ZAWS::Helper::Output.binary_nagios_check(assoc_exists,"OK: Route table association to subnet exists.","CRITICAL: Route table association to subnet does not exist.",textout) if nagios
145
+ if not assoc_exists
146
+ comline="aws --region #{region} ec2 associate-route-table --subnet-id #{subnetid} --route-table-id #{rtableid}"
147
+ assocreturn=JSON.parse(@shellout.cli(comline,verbose))
148
+ textout.puts "Route table associated to subnet." if assocreturn["AssociationId"]
149
+ else
150
+ textout.puts "Route table already associated to subnet. Skipping association."
151
+ end
152
+ end
153
+
154
+ def delete_assoc_subnet(region,textout=nil,verbose=nil,vpcid,rtable_externalid,cidrblock)
155
+ assoc_exists, subnetid, rtableid, rtassocid = subnet_assoc_exists(region,nil,verbose,vpcid,rtable_externalid,cidrblock)
156
+ if assoc_exists
157
+ comline="aws --region #{region} ec2 disassociate-route-table --association-id #{rtassocid}"
158
+ assocreturn=JSON.parse(@shellout.cli(comline,verbose))
159
+ textout.puts "Route table association to subnet deleted." if assocreturn["return"] == "true"
160
+ else
161
+ textout.puts "Route table association to subnet not deleted because it does not exist."
162
+ end
163
+ end
164
+
165
+ def propagation_exists_from_gateway(region,textout=nil,verbose=nil,vpcid,rtable_externalid,vgatewayid)
166
+ rtable=JSON.parse(view(region,'json',nil,verbose,vpcid,rtable_externalid))
167
+ val = ((rtable["RouteTables"].count == 1) and (rtable["RouteTables"][0]["PropagatingVgws"].any? { |x| x["GatewayId"]=="#{vgatewayid}"}))
168
+ rtableid = (rtable["RouteTables"].count == 1) ? rtable["RouteTables"][0]["RouteTableId"] : nil
169
+ textout.puts val.to_s if textout
170
+ return val, rtableid
171
+ end
172
+
173
+ def declare_propagation_from_gateway(region,textout=nil,verbose=nil,vpcid,routetable,vgatewayid,nagios,ufile)
174
+ if ufile
175
+ ZAWS::Helper::File.prepend("zaws route_table delete_propagation_from_gateway my_route_table vgw-???????? --region us-west-1 --vpcid my_vpc_id $XTRA_OPTS",'#Delete route propagation',ufile)
176
+ end
177
+ propagation_exists,rtableid = propagation_exists_from_gateway(region,nil,verbose,vpcid,routetable,vgatewayid)
178
+ return ZAWS::Helper::Output.binary_nagios_check(propagation_exists,"OK: Route propagation from gateway enabled.","CRITICAL: Route propagation from gateway not enabled.",textout) if nagios
179
+ if not propagation_exists
180
+ comline="aws --region #{region} ec2 enable-vgw-route-propagation --route-table-id #{rtableid} --gateway-id #{vgatewayid}"
181
+ propreturn=JSON.parse(@shellout.cli(comline,verbose))
182
+ textout.puts "Route propagation from gateway enabled." if propreturn["return"] == "true"
183
+ else
184
+ textout.puts "Route propagation from gateway already enabled. Skipping propagation."
185
+ end
186
+ end
187
+
188
+ def delete_propagation_from_gateway(region,textout=nil,verbose=nil,vpcid,rtable_externalid,vgatewayid)
189
+ propagation_exists,rtableid = propagation_exists_from_gateway(region,nil,verbose,vpcid,rtable_externalid,vgatewayid)
190
+ if propagation_exists
191
+ comline="aws --region #{region} ec2 disable-vgw-route-propagation --route-table-id #{rtableid} --gateway-id #{vgatewayid}"
192
+ assocreturn=JSON.parse(@shellout.cli(comline,verbose))
193
+ textout.puts "Deleted route propagation from gateway." if assocreturn["return"] == "true"
194
+ else
195
+ textout.puts "Route propagation from gateway does not exist, skipping deletion."
196
+ end
197
+ end
198
+
199
+ end
200
+ end
201
+ end
202
+
@@ -0,0 +1,116 @@
1
+ require 'json'
2
+ require 'netaddr'
3
+ require 'timeout'
4
+
5
+ module ZAWS
6
+ module EC2Services
7
+ class SecurityGroup
8
+
9
+ def initialize(shellout,aws)
10
+ @shellout=shellout
11
+ @aws=aws
12
+ end
13
+
14
+ def view(region,view,textout=nil,verbose=nil,vpcid=nil,groupname=nil,groupid=nil,perm_groupid=nil,perm_protocol=nil,perm_toport=nil)
15
+ comline="aws --output #{view} --region #{region} ec2 describe-security-groups"
16
+ if vpcid || groupname
17
+ comline = comline + " --filter"
18
+ end
19
+ comline = comline + " 'Name=vpc-id,Values=#{vpcid}'" if vpcid
20
+ comline = comline + " 'Name=group-name,Values=#{groupname}'" if groupname
21
+ comline = comline + " 'Name=group-id,Values=#{groupid}'" if groupid
22
+ comline = comline + " 'Name=ip-permission.group-id,Values=#{perm_groupid}'" if perm_groupid
23
+ comline = comline + " 'Name=ip-permission.protocol,Values=#{perm_protocol}'" if perm_protocol
24
+ comline = comline + " 'Name=ip-permission.to-port,Values=#{perm_toport}'" if perm_toport
25
+ sgroups=@shellout.cli(comline,verbose)
26
+ textout.puts(sgroups) if textout
27
+ return sgroups
28
+ end
29
+
30
+ def exists(region,textout=nil,verbose=nil,vpcid,groupname)
31
+ sgroups=JSON.parse(view(region,'json',nil,verbose,vpcid,groupname))
32
+ val = (sgroups["SecurityGroups"].count == 1)
33
+ sgroupid = val ? sgroups["SecurityGroups"][0]["GroupId"] : nil
34
+ textout.puts val.to_s if textout
35
+ return val, sgroupid
36
+ end
37
+
38
+ def declare(region,vpcid,groupname,description,nagios,textout=nil,verbose=nil,ufile=nil)
39
+ if ufile
40
+ ZAWS::Helper::File.prepend("zaws security_group delete #{groupname} --region #{region} --vpcid #{vpcid} $XTRA_OPTS",'#Delete security group',ufile)
41
+ end
42
+ sgroup_exists,sgroupid = exists(region,nil,verbose,vpcid,groupname)
43
+ return ZAWS::Helper::Output.binary_nagios_check(sgroup_exists,"OK: Security Group Exists.","CRITICAL: Security Group Does Not Exist.",textout) if nagios
44
+ if not sgroup_exists
45
+ comline="aws --output json --region #{region} ec2 create-security-group --vpc-id #{vpcid} --group-name #{groupname} --description '#{description}'"
46
+ sgroup=JSON.parse(@shellout.cli(comline,verbose))
47
+ textout.puts "Security Group Created." if sgroup["return"] == "true"
48
+ else
49
+ textout.puts "Security Group Exists Already. Skipping Creation."
50
+ end
51
+ end
52
+
53
+ def id_by_name(region,textout=nil,verbose=nil,vpcid,groupname)
54
+ sgroups=JSON.parse(view(region,'json',nil,verbose,vpcid,groupname))
55
+ group_id= sgroups["SecurityGroups"].count == 1 ? sgroups["SecurityGroups"][0]["GroupId"] : nil
56
+ raise "More than one security group found when looking up id by name." if sgroups["SecurityGroups"].count > 1
57
+ textout.puts group_id if textout
58
+ return group_id
59
+ end
60
+
61
+
62
+ def delete(region,textout=nil,verbose=nil,vpcid,groupname)
63
+ groupid=id_by_name(region,nil,nil,vpcid,groupname)
64
+ if groupid
65
+ comline="aws --region #{region} ec2 delete-security-group --group-ids #{groupid}"
66
+ sgroup=JSON.parse(@shellout.cli(comline,verbose))
67
+ textout.puts "Security Group deleted." if sgroup["return"] == "true"
68
+ else
69
+ textout.puts "Security Group does not exist. Skipping deletion."
70
+ end
71
+ end
72
+
73
+ def ingress_group_exists(region,vpcid,target,source,protocol,port,textout=nil,verbose=nil)
74
+ targetid=id_by_name(region,nil,nil,vpcid,target)
75
+ sourceid=id_by_name(region,nil,nil,vpcid,source)
76
+ if targetid && sourceid
77
+ sgroups=JSON.parse(view(region,'json',nil,verbose,vpcid,nil,targetid,sourceid,protocol,port))
78
+ val = (sgroups["SecurityGroups"].count > 0)
79
+ textout.puts val.to_s if textout
80
+ return val, targetid, sourceid
81
+ end
82
+ end
83
+
84
+ def declare_ingress_group(region,vpcid,target,source,protocol,port,nagios,textout=nil,verbose=nil,ufile=nil)
85
+ if ufile
86
+ ZAWS::Helper::File.prepend("zaws security_group delete_ingress_group #{target} #{source} #{protocol} #{port} --region #{region} --vpcid #{vpcid} $XTRA_OPTS",'#Delete security group ingress group rule',ufile)
87
+ end
88
+
89
+ ingress_exists,targetid,sourceid = ingress_group_exists(region,vpcid,target,source,protocol,port,nil,verbose)
90
+
91
+ return ZAWS::Helper::Output.binary_nagios_check(ingress_exists,"OK: Security group ingress group rule exists.","CRITICAL: Security group ingress group rule does not exist.",textout) if nagios
92
+
93
+ if not ingress_exists
94
+ comline="aws --region #{region} ec2 authorize-security-group-ingress --group-id #{targetid} --source-security-group-owner-id #{sourceid} --protocol #{protocol} --port #{port}"
95
+ ingressrule=JSON.parse(@shellout.cli(comline,verbose))
96
+ textout.puts "Ingress group rule created." if ingressrule["return"] == "true"
97
+ else
98
+ textout.puts "Ingress group rule not created. Exists already."
99
+ end
100
+ end
101
+
102
+ def delete_ingress_group(region,vpcid,target,source,protocol,port,textout=nil,verbose=nil)
103
+ ingress_exists,targetid,sourceid = ingress_group_exists(region,vpcid,target,source,protocol,port,nil,verbose)
104
+ if ingress_exists
105
+ comline="aws --region #{region} ec2 revoke-security-group-ingress --group-id #{targetid} --source-security-group-owner-id #{sourceid} --protocol #{protocol} --port #{port}"
106
+ val=JSON.parse(@shellout.cli(comline,verbose))
107
+ textout.puts "Security group ingress group rule deleted." if val["return"] == "true"
108
+ else
109
+ textout.puts "Security group ingress group rule does not exist. Skipping deletion."
110
+ end
111
+ end
112
+
113
+ end
114
+ end
115
+ end
116
+