OLD | NEW |
(Empty) | |
| 1 #!/usr/bin/env python |
| 2 # Copyright (c) 2009 Chris Moyer http://coredumped.org/ |
| 3 # |
| 4 # Permission is hereby granted, free of charge, to any person obtaining a |
| 5 # copy of this software and associated documentation files (the |
| 6 # "Software"), to deal in the Software without restriction, including |
| 7 # without limitation the rights to use, copy, modify, merge, publish, dis- |
| 8 # tribute, sublicense, and/or sell copies of the Software, and to permit |
| 9 # persons to whom the Software is furnished to do so, subject to the fol- |
| 10 # lowing conditions: |
| 11 # |
| 12 # The above copyright notice and this permission notice shall be included |
| 13 # in all copies or substantial portions of the Software. |
| 14 # |
| 15 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS |
| 16 # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL- |
| 17 # ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT |
| 18 # SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, |
| 19 # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, |
| 20 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS |
| 21 |
| 22 # |
| 23 # Elastic Load Balancer Tool |
| 24 # |
| 25 VERSION = "0.2" |
| 26 usage = """%prog [options] [command] |
| 27 Commands: |
| 28 list|ls List all Elastic Load Balancers |
| 29 delete <name> Delete ELB <name> |
| 30 get <name> Get all instances associated with <name> |
| 31 create <name> Create an ELB; -z and -l are required |
| 32 add <name> <instance> Add <instance> in ELB <name> |
| 33 remove|rm <name> <instance> Remove <instance> from ELB <name> |
| 34 reap <name> Remove terminated instances from ELB <name> |
| 35 enable|en <name> <zone> Enable Zone <zone> for ELB <name> |
| 36 disable <name> <zone> Disable Zone <zone> for ELB <name> |
| 37 addl <name> Add listeners (specified by -l) to the ELB |
| 38 <name> |
| 39 rml <name> <port> Remove Listener(s) specified by the port on |
| 40 the ELB <name> |
| 41 """ |
| 42 |
| 43 |
| 44 def find_elb(elb, name): |
| 45 try: |
| 46 elbs = elb.get_all_load_balancers(name) |
| 47 except boto.exception.BotoServerError as se: |
| 48 if se.code == 'LoadBalancerNotFound': |
| 49 elbs = [] |
| 50 else: |
| 51 raise |
| 52 |
| 53 if len(elbs) < 1: |
| 54 print "No load balancer by the name of %s found" % name |
| 55 return None |
| 56 elif len(elbs) > 1: |
| 57 print "More than one elb matches %s?" % name |
| 58 return None |
| 59 |
| 60 # Should not happen |
| 61 if name not in elbs[0].name: |
| 62 print "No load balancer by the name of %s found" % name |
| 63 return None |
| 64 |
| 65 return elbs[0] |
| 66 |
| 67 |
| 68 def list(elb): |
| 69 """List all ELBs""" |
| 70 print "%-20s %s" % ("Name", "DNS Name") |
| 71 print "-" * 80 |
| 72 for b in elb.get_all_load_balancers(): |
| 73 print "%-20s %s" % (b.name, b.dns_name) |
| 74 |
| 75 |
| 76 def get(elb, name): |
| 77 """Get details about ELB <name>""" |
| 78 |
| 79 b = find_elb(elb, name) |
| 80 if b: |
| 81 print "=" * 80 |
| 82 print "Name: %s" % b.name |
| 83 print "DNS Name: %s" % b.dns_name |
| 84 if b.canonical_hosted_zone_name: |
| 85 chzn = b.canonical_hosted_zone_name |
| 86 print "Canonical hosted zone name: %s" % chzn |
| 87 if b.canonical_hosted_zone_name_id: |
| 88 chznid = b.canonical_hosted_zone_name_id |
| 89 print "Canonical hosted zone name id: %s" % chznid |
| 90 print |
| 91 |
| 92 print "Health Check: %s" % b.health_check |
| 93 print |
| 94 |
| 95 print "Listeners" |
| 96 print "---------" |
| 97 print "%-8s %-8s %s" % ("IN", "OUT", "PROTO") |
| 98 for l in b.listeners: |
| 99 print "%-8s %-8s %s" % (l[0], l[1], l[2]) |
| 100 |
| 101 print |
| 102 |
| 103 print " Zones " |
| 104 print "---------" |
| 105 for z in b.availability_zones: |
| 106 print z |
| 107 |
| 108 print |
| 109 |
| 110 # Make map of all instance Id's to Name tags |
| 111 ec2 = boto.connect_ec2() |
| 112 |
| 113 instance_health = b.get_instance_health() |
| 114 instances = [state.instance_id for state in instance_health] |
| 115 |
| 116 names = {} |
| 117 for r in ec2.get_all_instances(instances): |
| 118 for i in r.instances: |
| 119 names[i.id] = i.tags.get('Name', '') |
| 120 |
| 121 name_column_width = max([4] + [len(v) for k,v in names.iteritems()]) + 2 |
| 122 |
| 123 print "Instances" |
| 124 print "---------" |
| 125 print "%-12s %-15s %-*s %s" % ("ID", |
| 126 "STATE", |
| 127 name_column_width, "NAME", |
| 128 "DESCRIPTION") |
| 129 for state in instance_health: |
| 130 print "%-12s %-15s %-*s %s" % (state.instance_id, |
| 131 state.state, |
| 132 name_column_width, names[state.instan
ce_id], |
| 133 state.description) |
| 134 |
| 135 print |
| 136 |
| 137 |
| 138 def create(elb, name, zones, listeners): |
| 139 """Create an ELB named <name>""" |
| 140 l_list = [] |
| 141 for l in listeners: |
| 142 l = l.split(",") |
| 143 if l[2] == 'HTTPS': |
| 144 l_list.append((int(l[0]), int(l[1]), l[2], l[3])) |
| 145 else: |
| 146 l_list.append((int(l[0]), int(l[1]), l[2])) |
| 147 |
| 148 b = elb.create_load_balancer(name, zones, l_list) |
| 149 return get(elb, name) |
| 150 |
| 151 |
| 152 def delete(elb, name): |
| 153 """Delete this ELB""" |
| 154 b = find_elb(elb, name) |
| 155 if b: |
| 156 b.delete() |
| 157 print "Load Balancer %s deleted" % name |
| 158 |
| 159 |
| 160 def add_instance(elb, name, instance): |
| 161 """Add <instance> to ELB <name>""" |
| 162 b = find_elb(elb, name) |
| 163 if b: |
| 164 b.register_instances([instance]) |
| 165 return get(elb, name) |
| 166 |
| 167 |
| 168 def remove_instance(elb, name, instance): |
| 169 """Remove instance from elb <name>""" |
| 170 b = find_elb(elb, name) |
| 171 if b: |
| 172 b.deregister_instances([instance]) |
| 173 return get(elb, name) |
| 174 |
| 175 |
| 176 def reap_instances(elb, name): |
| 177 """Remove terminated instances from elb <name>""" |
| 178 b = find_elb(elb, name) |
| 179 if b: |
| 180 for state in b.get_instance_health(): |
| 181 if (state.state == 'OutOfService' and |
| 182 state.description == 'Instance is in terminated state.'): |
| 183 b.deregister_instances([state.instance_id]) |
| 184 return get(elb, name) |
| 185 |
| 186 |
| 187 def enable_zone(elb, name, zone): |
| 188 """Enable <zone> for elb""" |
| 189 b = find_elb(elb, name) |
| 190 if b: |
| 191 b.enable_zones([zone]) |
| 192 return get(elb, name) |
| 193 |
| 194 |
| 195 def disable_zone(elb, name, zone): |
| 196 """Disable <zone> for elb""" |
| 197 b = find_elb(elb, name) |
| 198 if b: |
| 199 b.disable_zones([zone]) |
| 200 return get(elb, name) |
| 201 |
| 202 |
| 203 def add_listener(elb, name, listeners): |
| 204 """Add listeners to a given load balancer""" |
| 205 l_list = [] |
| 206 for l in listeners: |
| 207 l = l.split(",") |
| 208 l_list.append((int(l[0]), int(l[1]), l[2])) |
| 209 b = find_elb(elb, name) |
| 210 if b: |
| 211 b.create_listeners(l_list) |
| 212 return get(elb, name) |
| 213 |
| 214 |
| 215 def rm_listener(elb, name, ports): |
| 216 """Remove listeners from a given load balancer""" |
| 217 b = find_elb(elb, name) |
| 218 if b: |
| 219 b.delete_listeners(ports) |
| 220 return get(elb, name) |
| 221 |
| 222 |
| 223 if __name__ == "__main__": |
| 224 try: |
| 225 import readline |
| 226 except ImportError: |
| 227 pass |
| 228 import boto |
| 229 import sys |
| 230 from optparse import OptionParser |
| 231 from boto.mashups.iobject import IObject |
| 232 parser = OptionParser(version=VERSION, usage=usage) |
| 233 parser.add_option("-z", "--zone", |
| 234 help="Operate on zone", |
| 235 action="append", default=[], dest="zones") |
| 236 parser.add_option("-l", "--listener", |
| 237 help="Specify Listener in,out,proto", |
| 238 action="append", default=[], dest="listeners") |
| 239 |
| 240 (options, args) = parser.parse_args() |
| 241 |
| 242 if len(args) < 1: |
| 243 parser.print_help() |
| 244 sys.exit(1) |
| 245 |
| 246 elb = boto.connect_elb() |
| 247 |
| 248 print "%s" % (elb.region.endpoint) |
| 249 |
| 250 command = args[0].lower() |
| 251 if command in ("ls", "list"): |
| 252 list(elb) |
| 253 elif command == "get": |
| 254 get(elb, args[1]) |
| 255 elif command == "create": |
| 256 if not options.listeners: |
| 257 print "-l option required for command create" |
| 258 sys.exit(1) |
| 259 if not options.zones: |
| 260 print "-z option required for command create" |
| 261 sys.exit(1) |
| 262 create(elb, args[1], options.zones, options.listeners) |
| 263 elif command == "delete": |
| 264 delete(elb, args[1]) |
| 265 elif command in ("add", "put"): |
| 266 add_instance(elb, args[1], args[2]) |
| 267 elif command in ("rm", "remove"): |
| 268 remove_instance(elb, args[1], args[2]) |
| 269 elif command == "reap": |
| 270 reap_instances(elb, args[1]) |
| 271 elif command in ("en", "enable"): |
| 272 enable_zone(elb, args[1], args[2]) |
| 273 elif command == "disable": |
| 274 disable_zone(elb, args[1], args[2]) |
| 275 elif command == "addl": |
| 276 if not options.listeners: |
| 277 print "-l option required for command addl" |
| 278 sys.exit(1) |
| 279 add_listener(elb, args[1], options.listeners) |
| 280 elif command == "rml": |
| 281 if not args[2:]: |
| 282 print "port required" |
| 283 sys.exit(2) |
| 284 rm_listener(elb, args[1], args[2:]) |
OLD | NEW |