6
6
from boto import ses
7
7
import boto .ec2
8
8
from boto .ec2 .address import Address
9
+ from boto .ec2 .blockdevicemapping import BlockDeviceMapping , BlockDeviceType
9
10
from exc import InstanceNameNotAvailable
10
11
11
12
13
+ SIMPLEAWS_SECTION_TITLE = 'simple-aws'
14
+
15
+
12
16
class AwsManager (object ):
13
17
"""
14
- :param str conf_path: Path to the configuration file. See *simple-aws.conf.TEMPLATE* for structure .
18
+ :param str conf_path: See :class:`saws.manager.AwsManagerConfiguration` .
15
19
:param bool filtered: If ``True``, only consider instances attached to ``key_name`` in the configuration file.
16
20
:param bool only_running: If ``True``, only consider running instances.
17
- :param str section_title: The title of the section in the configuration file to read values from.
21
+ :param str section_title: See :class:`saws.manager.AwsManagerConfiguration`.
22
+ :param conf: Configuration object used in place of configuration file.
23
+ :type conf: :class:`saws.manager.AwsManagerConfiguration`
18
24
"""
19
25
20
- def __init__ (self , conf_path = None , filtered = True , only_running = True , section_title = 'simple-aws' ):
21
- if conf_path is None :
22
- msg = 'Path to configuration file required.'
23
- raise ValueError (msg )
24
-
25
- self .conf_path = conf_path or os .path .expanduser (os .getenv ('SIMPLEAWS_CONF_PATH' ))
26
+ def __init__ (self , conf_path = None , filtered = True , only_running = True , section_title = SIMPLEAWS_SECTION_TITLE ,
27
+ conf = None ):
28
+ if conf is None :
29
+ conf = AwsManagerConfiguration (conf_path = conf_path , section_title = section_title )
30
+ self .conf = conf
26
31
self .filtered = filtered
27
32
self .only_running = only_running
28
33
self ._conn = None
29
- self ._parser = SafeConfigParser ()
30
- self ._parser .read (self .conf_path )
31
- self ._cfg = dict (self ._parser .items (section_title ))
32
34
33
35
@property
34
36
def conn (self ):
@@ -50,7 +52,7 @@ def _get_key_(instance):
50
52
raise NotImplementedError (key )
51
53
return ret
52
54
53
- reservations = self .conn .get_all_reservations ()
55
+ reservations = self .conn .get_all_instances ()
54
56
instances = [i for r in reservations for i in r .instances ]
55
57
instances = {i .id : i for i in instances }
56
58
if self .only_running :
@@ -69,18 +71,28 @@ def get_instance_by_name(self, name):
69
71
else :
70
72
return ret
71
73
72
- def launch_new_instance (self , name , image_id = None , instance_type = None , placement = None , elastic_ip = None , wait = True ):
73
- image_id = image_id or self ._cfg ['image_id' ]
74
- instance_type = instance_type or self ._cfg ['instance_type' ]
75
- security_group = self ._cfg ['security_group' ]
76
- key_name = self ._cfg ['key_name' ]
74
+ def launch_new_instance (self , name , image_id = None , instance_type = None , placement = None , elastic_ip = None , wait = True ,
75
+ ebs_snapshot_id = None , ebs_mount_name = '/dev/xvdg' ):
76
+ image_id = image_id or self .conf .aws_image_id
77
+ instance_type = instance_type or self .conf .aws_instance_type
78
+ security_group = self .conf .aws_security_group
79
+ key_name = self .conf .aws_key_name
77
80
78
81
if not self ._get_is_unique_tag_ (name , 'Name' ):
79
82
msg = 'The assigned instance name "{0}" is not unique.' .format (name )
80
83
raise ValueError (msg )
81
84
85
+ block_device_map = None
86
+ if ebs_snapshot_id is not None :
87
+ block_device_map = BlockDeviceMapping ()
88
+ block_dev_type = BlockDeviceType ()
89
+ block_dev_type .delete_on_termination = True
90
+ block_dev_type .snapshot_id = ebs_snapshot_id
91
+ block_device_map [ebs_mount_name ] = block_dev_type
92
+
82
93
reservation = self .conn .run_instances (image_id , key_name = key_name , instance_type = instance_type ,
83
- security_groups = [security_group ], placement = placement )
94
+ security_groups = [security_group ], placement = placement ,
95
+ block_device_map = block_device_map )
84
96
instance = reservation .instances [0 ]
85
97
86
98
if wait :
@@ -101,10 +113,10 @@ def send_email(self, fromaddr, recipient, subject, body):
101
113
msg ['From' ] = fromaddr
102
114
msg ['To' ] = recipient
103
115
104
- aws_access_key_id = self ._cfg [ 'aws_access_key_id' ]
105
- aws_secret_access_key = self ._cfg [ 'aws_secret_access_key' ]
106
- conn = ses .connect_to_region (self ._cfg [ 'region' ] , aws_access_key_id = aws_access_key_id ,
107
- aws_secret_access_key = aws_secret_access_key )
116
+ aws_access_key = self .conf . aws_access_key
117
+ aws_secret_key = self .conf . aws_secret_key
118
+ conn = ses .connect_to_region (self .conf . aws_region , aws_access_key_id = aws_access_key ,
119
+ aws_secret_access_key = aws_secret_key )
108
120
conn .send_raw_email (msg .as_string ())
109
121
110
122
def start_instance_by_name (self , name , wait = True ):
@@ -123,31 +135,25 @@ def start_instance_by_name(self, name, wait=True):
123
135
self .only_running = prev_only_running
124
136
125
137
@staticmethod
126
- def wait_for_status (target , status_target , sleep = 1 , pad = None ):
138
+ def wait_for_status (instance , status_target , sleep = 1 , pad = 3 ):
127
139
time .sleep (sleep )
128
- while target .update () != status_target :
140
+ while instance .update () != status_target :
129
141
time .sleep (sleep )
130
142
if pad is not None :
131
143
time .sleep (pad )
132
144
133
145
def _filter_ (self , instance ):
134
- if instance .key_name == self ._cfg [ 'key_name' ] :
146
+ if instance .key_name == self .conf . aws_key_name :
135
147
ret = True
136
148
else :
137
149
ret = False
138
150
return ret
139
151
140
152
def _get_aws_connection_ (self ):
141
- region = self ._cfg ['region' ]
142
-
143
- aws_access_key_id = self ._cfg ['aws_access_key_id' ]
144
- aws_secret_access_key = self ._cfg ['aws_secret_access_key' ]
145
-
146
- conn = boto .ec2 .connect_to_region (region , aws_access_key_id = aws_access_key_id , aws_secret_access_key = aws_secret_access_key )
147
-
153
+ conn = boto .ec2 .connect_to_region (self .conf .aws_region , aws_access_key_id = self .conf .aws_access_key ,
154
+ aws_secret_access_key = self .conf .aws_secret_key )
148
155
if conn is None :
149
156
raise RuntimeError ('Unable to launch instance.' )
150
-
151
157
return conn
152
158
153
159
def _get_is_unique_tag_ (self , tag_value , tag_key ):
@@ -157,3 +163,55 @@ def _get_is_unique_tag_(self, tag_value, tag_key):
157
163
if i .tags .get (tag_key ) == tag_value :
158
164
ret = False
159
165
return ret
166
+
167
+
168
+ class AwsManagerConfiguration (object ):
169
+ """
170
+ :class:`saws.AwsManager` configuration object. Any of the keywords arguments found in
171
+ :attr:`saws.AwsManagerConfiguration._kwargs` may be set in the following ways (in order of precedence):
172
+ * Passed as keyword arguments to the constructor.
173
+ * Set as uppercase environment variables.
174
+ * Set in the configuration file.
175
+
176
+ :keyword str conf_path: (``=None``) Path to the configuration file. The environment variable
177
+ ``'SIMPLEAWS_CONF_PATH'`` may also be used.
178
+ :keyword str section_title: (``='simple-aws'``) Name of the section in the configuration file to look for values.
179
+ :keyword kwargs: Any keyword from :attr:`saws.AwsManagerConfiguration._kwargs`.
180
+ :raises: ValueError
181
+ """
182
+
183
+ _kwargs = {'aws_access_key' : False , 'aws_secret_key' : False , 'aws_image_id' : True , 'aws_instance_type' : True ,
184
+ 'aws_region' : False , 'aws_security_group' : True , 'aws_key_name' : True , 'aws_key_path' : False }
185
+
186
+ def __init__ (self , ** kwargs ):
187
+ self .conf_path = kwargs .pop ('conf_path' , None )
188
+ if self .conf_path is None :
189
+ self .conf_path = os .environ .get ('SIMPLEAWS_CONF_PATH' )
190
+ self .section_title = kwargs .pop ('section_title' , SIMPLEAWS_SECTION_TITLE )
191
+
192
+ cfg_kwargs = {}
193
+ for kwarg in self ._kwargs .iterkeys ():
194
+ value = kwargs .get (kwarg )
195
+ if value is None :
196
+ value = os .environ .get (kwarg )
197
+ if value is None :
198
+ value = os .environ .get (kwarg .upper ())
199
+ cfg_kwargs [kwarg ] = value
200
+
201
+ cfg_conf = {}
202
+ if self .conf_path is not None :
203
+ self .conf_path = os .path .expanduser (self .conf_path )
204
+ parser = SafeConfigParser ()
205
+ parser .read (self .conf_path )
206
+ cfg_conf = dict (parser .items (self .section_title ))
207
+
208
+ for k , v in cfg_conf .iteritems ():
209
+ if cfg_kwargs .get (k ) is None :
210
+ cfg_kwargs [k ] = v
211
+
212
+ for k , v in cfg_kwargs .iteritems ():
213
+ if v is None and not self ._kwargs [k ]:
214
+ msg = 'The configuration key "{0}" may not be None.' .format (k )
215
+ raise ValueError (msg )
216
+ else :
217
+ setattr (self , k , v )
0 commit comments