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