1 # Copyright (c) 2006,2007 Mitch Garnaat http://garnaat.org/ 2 # 3 # Permission is hereby granted, free of charge, to any person obtaining a 4 # copy of this software and associated documentation files (the 5 # "Software"), to deal in the Software without restriction, including 6 # without limitation the rights to use, copy, modify, merge, publish, dis- 7 # tribute, sublicense, and/or sell copies of the Software, and to permit 8 # persons to whom the Software is furnished to do so, subject to the fol- 9 # lowing conditions: 10 # 11 # The above copyright notice and this permission notice shall be included 12 # in all copies or substantial portions of the Software. 13 # 14 # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 15 # OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABIL- 16 # ITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT 17 # SHALL THE AUTHOR BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, 18 # WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 20 # IN THE SOFTWARE. 21 """ 22 High-level abstraction of an EC2 order for servers 23 """ 24 25 import boto 26 import boto.ec2 27 from boto.mashups.server import Server, ServerSet 28 from boto.mashups.iobject import IObject 29 from boto.pyami.config import Config 30 from boto.sdb.persist import get_domain, set_domain 31 import time 32 from boto.compat import StringIO 33 34 InstanceTypes = ['m1.small', 'm1.large', 'm1.xlarge', 'c1.medium', 'c1.xlarge'] 35 36 class Item(IObject): 37 38 def __init__(self): 39 self.region = None 40 self.name = None 41 self.instance_type = None 42 self.quantity = 0 43 self.zone = None 44 self.ami = None 45 self.groups = [] 46 self.key = None 47 self.ec2 = None 48 self.config = None 49 50 def set_userdata(self, key, value): 51 self.userdata[key] = value 52 53 def get_userdata(self, key): 54 return self.userdata[key] 55 56 def set_region(self, region=None): 57 if region: 58 self.region = region 59 else: 60 l = [(r, r.name, r.endpoint) for r in boto.ec2.regions()] 61 self.region = self.choose_from_list(l, prompt='Choose Region') 62 63 def set_name(self, name=None): 64 if name: 65 self.name = name 66 else: 67 self.name = self.get_string('Name') 68 69 def set_instance_type(self, instance_type=None): 70 if instance_type: 71 self.instance_type = instance_type 72 else: 73 self.instance_type = self.choose_from_list(InstanceTypes, 'Instance Type') 74 75 def set_quantity(self, n=0): 76 if n > 0: 77 self.quantity = n 78 else: 79 self.quantity = self.get_int('Quantity') 80 81 def set_zone(self, zone=None): 82 if zone: 83 self.zone = zone 84 else: 85 l = [(z, z.name, z.state) for z in self.ec2.get_all_zones()] 86 self.zone = self.choose_from_list(l, prompt='Choose Availability Zone') 87 88 def set_ami(self, ami=None): 89 if ami: 90 self.ami = ami 91 else: 92 l = [(a, a.id, a.location) for a in self.ec2.get_all_images()] 93 self.ami = self.choose_from_list(l, prompt='Choose AMI') 94 95 def add_group(self, group=None): 96 if group: 97 self.groups.append(group) 98 else: 99 l = [(s, s.name, s.description) for s in self.ec2.get_all_security_groups()] 100 self.groups.append(self.choose_from_list(l, prompt='Choose Security Group')) 101 102 def set_key(self, key=None): 103 if key: 104 self.key = key 105 else: 106 l = [(k, k.name, '') for k in self.ec2.get_all_key_pairs()] 107 self.key = self.choose_from_list(l, prompt='Choose Keypair') 108 109 def update_config(self): 110 if not self.config.has_section('Credentials'): 111 self.config.add_section('Credentials') 112 self.config.set('Credentials', 'aws_access_key_id', self.ec2.aws_access_key_id) 113 self.config.set('Credentials', 'aws_secret_access_key', self.ec2.aws_secret_access_key) 114 if not self.config.has_section('Pyami'): 115 self.config.add_section('Pyami') 116 sdb_domain = get_domain() 117 if sdb_domain: 118 self.config.set('Pyami', 'server_sdb_domain', sdb_domain) 119 self.config.set('Pyami', 'server_sdb_name', self.name) 120 121 def set_config(self, config_path=None): 122 if not config_path: 123 config_path = self.get_filename('Specify Config file') 124 self.config = Config(path=config_path) 125 126 def get_userdata_string(self): 127 s = StringIO() 128 self.config.write(s) 129 return s.getvalue() 130 131 def enter(self, **params): 132 self.region = params.get('region', self.region) 133 if not self.region: 134 self.set_region() 135 self.ec2 = self.region.connect() 136 self.name = params.get('name', self.name) 137 if not self.name: 138 self.set_name() 139 self.instance_type = params.get('instance_type', self.instance_type) 140 if not self.instance_type: 141 self.set_instance_type() 142 self.zone = params.get('zone', self.zone) 143 if not self.zone: 144 self.set_zone() 145 self.quantity = params.get('quantity', self.quantity) 146 if not self.quantity: 147 self.set_quantity() 148 self.ami = params.get('ami', self.ami) 149 if not self.ami: 150 self.set_ami() 151 self.groups = params.get('groups', self.groups) 152 if not self.groups: 153 self.add_group() 154 self.key = params.get('key', self.key) 155 if not self.key: 156 self.set_key() 157 self.config = params.get('config', self.config) 158 if not self.config: 159 self.set_config() 160 self.update_config() 161 162 class Order(IObject): 163 164 def __init__(self): 165 self.items = [] 166 self.reservation = None 167 168 def add_item(self, **params): 169 item = Item() 170 item.enter(**params) 171 self.items.append(item) 172 173 def display(self): 174 print('This Order consists of the following items') 175 print() 176 print('QTY\tNAME\tTYPE\nAMI\t\tGroups\t\t\tKeyPair') 177 for item in self.items: 178 print('%s\t%s\t%s\t%s\t%s\t%s' % (item.quantity, item.name, item.instance_type, 179 item.ami.id, item.groups, item.key.name)) 180 181 def place(self, block=True): 182 if get_domain() is None: 183 print('SDB Persistence Domain not set') 184 domain_name = self.get_string('Specify SDB Domain') 185 set_domain(domain_name) 186 s = ServerSet() 187 for item in self.items: 188 r = item.ami.run(min_count=1, max_count=item.quantity, 189 key_name=item.key.name, user_data=item.get_userdata_string(), 190 security_groups=item.groups, instance_type=item.instance_type, 191 placement=item.zone.name) 192 if block: 193 states = [i.state for i in r.instances] 194 if states.count('running') != len(states): 195 print(states) 196 time.sleep(15) 197 states = [i.update() for i in r.instances] 198 for i in r.instances: 199 server = Server() 200 server.name = item.name 201 server.instance_id = i.id 202 server.reservation = r 203 server.save() 204 s.append(server) 205 if len(s) == 1: 206 return s[0] 207 else: 208 return s 209 210 211 212