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

Source Code for Module starcluster.exception

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