Home | History | Annotate | Download | only in mashups
      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