Package starcluster :: Module exception
[hide private]
[frames] | no frames]

Source Code for Module starcluster.exception

  1  #!/usr/bin/env python 
  2  """ 
  3  StarCluster Exception Classes 
  4  """ 
  5   
  6  import os 
  7   
  8  from starcluster import static 
  9  from starcluster.logger import log 
 10  from starcluster.templates import config, user_msgs 
 11   
 12   
13 -class BaseException(Exception):
14 - def __init__(self, *args):
15 self.msg = args[0]
16
17 - def __str__(self):
18 return self.msg
19
20 - def explain(self):
21 return "%s: %s" % (self.__class__.__name__, self.msg)
22 23
24 -class CommandNotFound(BaseException):
25 """Raised when command is not found on the system's PATH """
26 - def __init__(self, cmd):
27 self.msg = "command not found: '%s'" % cmd
28 29
30 -class RemoteCommandNotFound(CommandNotFound):
31 """Raised when command is not found on a *remote* system's PATH """
32 - def __init__(self, cmd):
33 self.msg = "command not found on remote system: '%s'" % cmd
34 35
36 -class SSHError(BaseException):
37 """Base class for all SSH related errors"""
38 39
40 -class SSHConnectionError(SSHError):
41 """Raised when ssh fails to to connect to a host (socket error)"""
42 - def __init__(self, host, port):
43 self.msg = "failed to connect to host %s on port %s" % (host, port)
44 45
46 -class SSHAuthException(SSHError):
47 """Raised when an ssh connection fails to authenticate"""
48 - def __init__(self, user, host):
49 self.msg = "failed to authenticate to host %s as user %s" % (host, 50 user)
51 52
53 -class SSHNoCredentialsError(SSHError):
54 - def __init__(self):
55 self.msg = "No password or key specified"
56 57
58 -class AWSError(BaseException):
59 """Base exception for all AWS related errors"""
60 61
62 -class RegionDoesNotExist(AWSError):
63 - def __init__(self, region_name):
64 self.msg = "region %s does not exist" % region_name
65 66
67 -class AMIDoesNotExist(AWSError):
68 - def __init__(self, image_id):
69 self.msg = "AMI %s does not exist" % image_id
70 71
72 -class InstanceDoesNotExist(AWSError):
73 - def __init__(self, instance_id, label='instance'):
74 self.msg = "%s '%s' does not exist" % (label, instance_id)
75 76
77 -class InstanceNotRunning(AWSError):
78 - def __init__(self, instance_id, state, label='instance'):
79 self.msg = "%s %s is not running (%s)" % (label, instance_id, state)
80 81
82 -class SecurityGroupDoesNotExist(AWSError):
83 - def __init__(self, sg_name):
84 self.msg = "security group %s does not exist" % sg_name
85 86
87 -class KeyPairDoesNotExist(AWSError):
88 - def __init__(self, keyname):
89 self.msg = "keypair %s does not exist" % keyname
90 91
92 -class ZoneDoesNotExist(AWSError):
93 - def __init__(self, zone, region):
94 self.msg = "zone %s does not exist in region %s" % (zone, region)
95 96
97 -class VolumeDoesNotExist(AWSError):
98 - def __init__(self, vol_id):
99 self.msg = "volume %s does not exist" % vol_id
100 101
102 -class SnapshotDoesNotExist(AWSError):
103 - def __init__(self, snap_id):
104 self.msg = "snapshot %s does not exist" % snap_id
105 106
107 -class BucketAlreadyExists(AWSError):
108 - def __init__(self, bucket_name):
109 self.msg = "bucket with name '%s' already exists on S3\n" % bucket_name 110 self.msg += "(NOTE: S3's bucket namepsace is shared by all AWS users)"
111 112
113 -class BucketDoesNotExist(AWSError):
114 - def __init__(self, bucket_name):
115 self.msg = "bucket '%s' does not exist" % bucket_name
116 117
118 -class InvalidOperation(AWSError):
119 pass
120 121
122 -class InvalidBucketName(AWSError):
123 - def __init__(self, bucket_name):
124 self.msg = "bucket name %s is not valid" % bucket_name
125 126
127 -class InvalidImageName(AWSError):
128 - def __init__(self, image_name):
129 self.msg = "image name %s is not valid" % image_name
130 131
132 -class AWSUserIdRequired(AWSError):
133 - def __init__(self):
134 self.msg = "No Amazon user id specified in config (AWS_USER_ID)"
135 136
137 -class EC2CertRequired(AWSError):
138 - def __init__(self):
139 self.msg = "No certificate file (pem) specified in config (EC2_CERT)"
140 141
142 -class EC2PrivateKeyRequired(AWSError):
143 - def __init__(self):
144 self.msg = "No private certificate file (pem) file specified in " + \ 145 "config (EC2_PRIVATE_KEY)"
146 147
148 -class EC2CertDoesNotExist(AWSError):
149 - def __init__(self, key):
150 self.msg = "EC2 certificate file %s does not exist" % key
151 152
153 -class EC2PrivateKeyDoesNotExist(AWSError):
154 - def __init__(self, key):
155 self.msg = "EC2 private key file %s does not exist" % key
156 157
158 -class SpotHistoryError(AWSError):
159 - def __init__(self, start, end):
160 self.msg = "no spot price history for the dates specified: " + \ 161 "%s - %s" % (start, end)
162 163
164 -class InvalidIsoDate(BaseException):
165 - def __init__(self, date):
166 self.msg = "Invalid date specified: %s" % date
167 168
169 -class ConfigError(BaseException):
170 """Base class for all config related errors"""
171 172
173 -class ConfigSectionMissing(ConfigError):
174 pass
175 176
177 -class ConfigHasNoSections(ConfigError):
178 - def __init__(self, cfg_file):
179 self.msg = "No valid sections defined in config file %s" % cfg_file
180 181
182 -class PluginNotFound(ConfigError):
183 - def __init__(self, plugin):
184 self.msg = 'Plugin "%s" not found in config' % plugin
185 186
187 -class NoDefaultTemplateFound(ConfigError):
188 - def __init__(self, options=None):
189 msg = "No default cluster template specified. To set the default " 190 msg += "cluster template, set DEFAULT_TEMPLATE in the [global] section" 191 msg += " of the config to the name of one of your cluster templates " 192 if options: 193 msg += '(' + ', '.join(options) + ')' 194 self.msg = msg
195 196
197 -class ConfigNotFound(ConfigError):
198 - def __init__(self, *args):
199 self.msg = args[0] 200 self.cfg = args[1] 201 self.template = config.copy_paste_template
202
203 - def create_config(self):
204 cfg_parent_dir = os.path.dirname(self.cfg) 205 if not os.path.exists(cfg_parent_dir): 206 os.makedirs(cfg_parent_dir) 207 cfg_file = open(self.cfg, 'w') 208 cfg_file.write(config.config_template) 209 cfg_file.close() 210 log.info("Config template written to %s. Please customize this file." % 211 self.cfg)
212
213 - def display_options(self):
214 print 'Options:' 215 print '--------' 216 print '[1] Show the StarCluster config template' 217 print '[2] Write config template to %s' % self.cfg 218 print '[q] Quit' 219 resp = raw_input('\nPlease enter your selection: ') 220 if resp == '1': 221 print self.template 222 elif resp == '2': 223 print 224 self.create_config()
225 226
227 -class KeyNotFound(ConfigError):
228 - def __init__(self, keyname):
229 self.msg = "key %s not found in config" % keyname
230 231
232 -class InvalidDevice(BaseException):
233 - def __init__(self, device):
234 self.msg = "invalid device specified: %s" % device
235 236
237 -class InvalidPartition(BaseException):
238 - def __init__(self, part):
239 self.msg = "invalid partition specified: %s" % part
240 241
242 -class PluginError(BaseException):
243 """Base class for plugin errors"""
244 245
246 -class PluginLoadError(PluginError):
247 """Raised when an error is encountered while loading a plugin"""
248 249
250 -class PluginSyntaxError(PluginError):
251 """Raised when plugin contains syntax errors"""
252 253
254 -class ValidationError(BaseException):
255 """Base class for validation related errors"""
256 257
258 -class ClusterReceiptError(BaseException):
259 """Raised when creating/loading a cluster receipt fails"""
260 261
262 -class ClusterValidationError(ValidationError):
263 """Cluster validation related errors"""
264 265
266 -class IncompatibleSettings(ClusterValidationError):
267 """Raised when two or more settings conflict with each other"""
268 269
270 -class InvalidProtocol(ClusterValidationError):
271 """Raised when user specifies an invalid IP protocol for permission"""
272 - def __init__(self, protocol):
273 self.msg = "protocol %s is not a valid ip protocol. options: %s" % \ 274 (protocol, ', '.join(static.PROTOCOLS))
275 276
277 -class InvalidPortRange(ClusterValidationError):
278 """Raised when user specifies an invalid port range for permission"""
279 - def __init__(self, from_port, to_port, reason=None):
280 self.msg = '' 281 if reason: 282 self.msg += "%s\n" % reason 283 self.msg += "port range is invalid: from %s to %s" % (from_port, 284 to_port)
285 286
287 -class InvalidCIDRSpecified(ClusterValidationError):
288 """Raised when user specifies an invalid CIDR ip for permission"""
289 - def __init__(self, cidr):
290 self.msg = "cidr_ip is invalid: %s" % cidr
291 292
293 -class InvalidZone(ClusterValidationError):
294 """ 295 Raised when a zone has been specified that does not match the common 296 zone of the volumes being attached 297 """
298 - def __init__(self, zone, common_vol_zone):
299 cvz = common_vol_zone 300 self.msg = ("availability_zone setting '%s' does not " + 301 "match the common volume zone '%s'") % (zone, cvz)
302 303
304 -class VolumesZoneError(ClusterValidationError):
305 - def __init__(self, volumes):
306 vlist = ', '.join(volumes) 307 self.msg = 'Volumes %s are not in the same availability zone' % vlist
308 309
310 -class ClusterTemplateDoesNotExist(BaseException):
311 """ 312 Exception raised when user requests a cluster template that does not exist 313 """
314 - def __init__(self, cluster_name):
315 self.msg = "cluster template %s does not exist" % cluster_name
316 317
318 -class ClusterNotRunning(BaseException):
319 """ 320 Exception raised when user requests a running cluster that does not exist 321 """
322 - def __init__(self, cluster_name):
323 self.msg = "cluster %s is not running" % cluster_name
324 325
326 -class ClusterDoesNotExist(BaseException):
327 """ 328 Exception raised when user requests a running cluster that does not exist 329 """
330 - def __init__(self, cluster_name):
331 self.msg = "cluster %s does not exist" % cluster_name
332 333
334 -class ClusterExists(BaseException):
335 - def __init__(self, cluster_name, is_ebs=False, stopped_ebs=False):
336 ctx = dict(cluster_name=cluster_name) 337 if stopped_ebs: 338 self.msg = user_msgs.stopped_ebs_cluster % ctx 339 elif is_ebs: 340 self.msg = user_msgs.active_ebs_cluster % ctx 341 else: 342 self.msg = user_msgs.cluster_exists % ctx
343 344
345 -class CancelledStartRequest(BaseException):
346 - def __init__(self, tag):
347 self.msg = "Request to start cluster '%s' was cancelled" % tag 348 self.msg += "\n\nPlease be aware that instances may still be running." 349 self.msg += "\nYou can check this from the output of:" 350 self.msg += "\n\n $ starcluster listclusters" 351 self.msg += "\n\nIf you wish to destroy these instances please run:" 352 self.msg += "\n\n $ starcluster stop %s" % tag 353 self.msg += "\n\nYou can then use:\n\n $ starcluster listinstances" 354 self.msg += "\n\nto verify that the instances have been terminated." 355 self.msg += "\n\nAnother option is to use the AWS management console" 356 self.msg += "\nto terminate the instances manually." 357 self.msg += "\n\nIf you would like to re-use these instances, rerun" 358 self.msg += "\nthe same start command with the --no-create option"
359 360
361 -class CancelledCreateVolume(BaseException):
362 - def __init__(self):
363 self.msg = "Request to create volume was cancelled" 364 self.msg += "\n\nPlease be aware that the volume host instance" 365 self.msg += " may still be running. " 366 self.msg += "\n\nTo destroy this instance please run:" 367 self.msg += "\n\n $ starcluster terminate %s" % \ 368 static.VOLUME_GROUP_NAME 369 self.msg += "\n\nand then use\n\n $ starcluster listinstances" 370 self.msg += "\n\nto verify that this instance has been terminated." 371 self.msg += "\n\nAnother option is to use the AWS management console " 372 self.msg += "to terminate\nthis instance manually."
373 374
375 -class CancelledCreateImage(BaseException):
376 - def __init__(self, bucket, image_name):
377 self.msg = "Request to create an S3 AMI was cancelled" 378 self.msg += "\n\nDepending on how far along the process was before it " 379 self.msg += "was cancelled, \nsome intermediate files might still be " 380 self.msg += "around in /mnt on the instance." 381 self.msg += "\n\nAlso, some of these intermediate files might " 382 self.msg += "have been uploaded to \nS3 in the '%(bucket)s' bucket " 383 self.msg += "you specified. You can check this by running:" 384 self.msg += "\n\n $ starcluster showbucket %(bucket)s\n\n" 385 self.msg += "and looking for files like: " 386 self.msg += "'%(iname)s.manifest.xml' or '%(iname)s.part.*'" 387 self.msg += "\nRe-executing the same s3image command " 388 self.msg += "should take care of these \nintermediate files and " 389 self.msg += "will also automatically override any\npartially uploaded " 390 self.msg += "files in S3." 391 self.msg = self.msg % {'bucket': bucket, 'iname': image_name}
392 393 394 CancelledS3ImageCreation = CancelledCreateImage 395 396
397 -class CancelledEBSImageCreation(BaseException):
398 - def __init__(self, is_ebs_backed, image_name):
399 self.msg = "Request to create EBS image %s was cancelled" % image_name 400 if is_ebs_backed: 401 self.msg += "\n\nDepending on how far along the process was " 402 self.msg += "before it was cancelled, \na snapshot of the image " 403 self.msg += "host's root volume may have been created.\nPlease " 404 self.msg += "inspect the output of:\n\n" 405 self.msg += " $ starcluster listsnapshots\n\n" 406 self.msg += "and clean up any unwanted snapshots" 407 else: 408 self.msg += "\n\nDepending on how far along the process was " 409 self.msg += "before it was cancelled, \na new volume and a " 410 self.msg += "snapshot of that new volume may have been created.\n" 411 self.msg += "Please inspect the output of:\n\n" 412 self.msg += " $ starcluster listvolumes\n\n" 413 self.msg += " and\n\n" 414 self.msg += " $ starcluster listsnapshots\n\n" 415 self.msg += "and clean up any unwanted volumes or snapshots"
416 417
418 -class ExperimentalFeature(BaseException):
419 - def __init__(self, feature_name):
420 self.msg = "%s is an experimental feature for this " % feature_name 421 self.msg += "release. \nIf you wish to test this feature, set " 422 self.msg += "ENABLE_EXPERIMENTAL=True \nin the [global] section of the" 423 self.msg += " config. \nYou have officially been warned :D"
424 425
426 -class ThreadPoolException(BaseException):
427 - def __init__(self, msg, exceptions):
428 self.msg = msg 429 self.exceptions = exceptions
430
431 - def print_excs(self):
432 print self.format_excs()
433
434 - def format_excs(self):
435 excs = [] 436 for exception in self.exceptions: 437 e, tb_msg, jobid = exception 438 excs.append('error occured in job (id=%s): %s' % (jobid, str(e))) 439 excs.append(tb_msg) 440 return '\n'.join(excs)
441 442
443 -class IncompatibleCluster(BaseException):
444 main_msg = """\ 445 The cluster '%(tag)s' was either created by a previous stable or development \ 446 version of StarCluster or you manually created the '%(group)s' group. In any \ 447 case '%(tag)s' cannot be used with this version of StarCluster (%(version)s). 448 449 """ 450 451 insts_msg = """\ 452 The cluster '%(tag)s' currently has %(num_nodes)d active nodes. 453 454 """ 455 456 no_insts_msg = """\ 457 The cluster '%(tag)s' does not have any nodes and is safe to terminate. 458 459 """ 460 461 terminate_msg = """\ 462 Please terminate the cluster using: 463 464 $ starcluster terminate %(tag)s 465 """ 466
467 - def __init__(self, group):
468 tag = group.name.replace(static.SECURITY_GROUP_PREFIX + '-', '') 469 self.msg = "Incompatible Cluster: %(tag)s\n\n" % dict(tag=tag) 470 self.msg += self.main_msg % dict(group=group.name, tag=tag, 471 version=static.VERSION) 472 states = ['pending', 'running', 'stopping', 'stopped'] 473 insts = filter(lambda x: x.state in states, group.instances()) 474 ctx = dict(tag=tag, num_nodes=len(insts)) 475 if insts: 476 self.msg += self.insts_msg % ctx 477 else: 478 self.msg += self.no_insts_msg % ctx 479 self.msg += self.terminate_msg % ctx
480