Cleaned up code in main cloud controller.

This commit is contained in:
Enis Afgan
2009-11-12 14:24:43 -05:00
parent b335c62c72
commit 3cab97ba8e
14 changed files with 366 additions and 352 deletions
+8 -8
View File
@@ -48,7 +48,7 @@ instance_states = Bunch(
ERROR = "error"
)
store_states = Bunch(
store_status = Bunch(
IN_USE = "in-use",
CREATING = "creating",
DELETED = 'deleted',
@@ -105,14 +105,14 @@ class EC2CloudProvider( object ):
elif uci_state==uci_states.SNAPSHOT:
self.snapshotUCI( uci_wrapper )
except:
log.exception( "Uncaught exception executing request." )
log.exception( "Uncaught exception executing cloud request." )
cnt += 1
def get_connection( self, uci_wrapper ):
"""
Establishes EC2 cloud connection using user's credentials associated with given UCI
"""
log.debug( 'Establishing %s cloud connection' % self.type )
log.debug( 'Establishing %s cloud connection.' % self.type )
provider = uci_wrapper.get_provider()
try:
region = RegionInfo( None, provider.region_name, provider.region_endpoint )
@@ -127,8 +127,8 @@ class EC2CloudProvider( object ):
is_secure=provider.is_secure,
region=region,
path=provider.path )
except Exception, ex:
err = "Establishing connection with cloud failed: " + str( ex )
except boto.exception.EC2ResponseError, e:
err = "Establishing connection with cloud failed: " + str( e )
log.error( err )
uci_wrapper.set_error( err, True )
return None
@@ -545,8 +545,8 @@ class EC2CloudProvider( object ):
self.updateInstance( inst )
# Update storage volume(s)
stores = model.CloudStore.filter( or_( model.CloudStore.c.status==store_states.IN_USE,
model.CloudStore.c.status==store_states.CREATING,
stores = model.CloudStore.filter( or_( model.CloudStore.c.status==store_status.IN_USE,
model.CloudStore.c.status==store_status.CREATING,
model.CloudStore.c.status==None ) ).all()
for store in stores:
if self.type == store.uci.credentials.provider.type: # and store.volume_id != None:
@@ -558,7 +558,7 @@ class EC2CloudProvider( object ):
# store.uci.error = "There exists an entry in local database for a storage volume without an ID. Storage volume might have been created " \
# "with cloud provider though. Manual check is recommended. After understanding what happened, local database entry for given " \
# "storage volume should be updated."
# store.status = store_states.ERROR
# store.status = store_status.ERROR
# store.uci.state = uci_states.ERROR
# store.uci.flush()
# store.flush()
+6 -6
View File
@@ -114,9 +114,9 @@ class EucalyptusCloudProvider( object ):
log.debug( 'Establishing %s cloud connection.' % self.type )
provider = uci_wrapper.get_provider()
try:
euca_region = RegionInfo( None, provider.region_name, provider.region_endpoint )
except Exception, e:
err = "Selecting region with cloud provider failed: " + str( e )
region = RegionInfo( None, provider.region_name, provider.region_endpoint )
except Exception, ex:
err = "Selecting region with cloud provider failed: " + str( ex )
log.error( err )
uci_wrapper.set_error( err, True )
return None
@@ -125,7 +125,7 @@ class EucalyptusCloudProvider( object ):
aws_secret_access_key=uci_wrapper.get_secret_key(),
is_secure=provider.is_secure,
port=provider.port,
region=euca_region,
region=region,
path=provider.path )
except boto.exception.EC2ResponseError, e:
err = "Establishing connection with cloud failed: " + str( e )
@@ -853,12 +853,12 @@ class EucalyptusCloudProvider( object ):
s_key = uci.credentials.secret_key
# Get connection
try:
euca_region = RegionInfo( None, uci.credentials.provider.region_name, uci.credentials.provider.region_endpoint )
region = RegionInfo( None, uci.credentials.provider.region_name, uci.credentials.provider.region_endpoint )
conn = EC2Connection( aws_access_key_id=a_key,
aws_secret_access_key=s_key,
is_secure=uci.credentials.provider.is_secure,
port=uci.credentials.provider.port,
region=euca_region,
region=region,
path=uci.credentials.provider.path )
except boto.exception.EC2ResponseError, e:
err = "Establishing connection with cloud failed: " + str( e )
+323 -309
View File
@@ -59,7 +59,7 @@ instance_states = Bunch(
ERROR = "error"
)
store_states = Bunch(
store_status = Bunch(
IN_USE = "in-use",
CREATING = "creating",
DELETED = 'deleted',
@@ -135,9 +135,9 @@ class CloudController( BaseController ):
model.UCI.c.state==uci_states.SUBMITTED_UCI ) ) \
.all()
if pendingInstances:
trans.set_message( "Galaxy instance started. Note that it will take several minutes for the instance to start "
"(typically, 3-5 minutes). Once the instance is running and Galaxy is available, "
"a button to connect to the instance will then appear alongside instance description." )
trans.set_message( "Galaxy instance started. NOTE: Please wait about 5 minutes for the instance to "
"start up. A button to connect to the instance will appear alongside "
"instance description once cloud instance of Galaxy is ready." )
# log.debug( "provider.is_secure: '%s'" % trans.sa_session.query( model.CloudProvider).filter_by(id=1).first().is_secure )
# trans.sa_session.query( model.CloudProvider).filter_by(id=1).first().is_secure=False
@@ -152,200 +152,11 @@ class CloudController( BaseController ):
prevInstances = prevInstances,
cloudProviders = cloudProviders )
@web.expose
@web.require_login( "start Galaxy cloud instance" )
def start( self, trans, id, type='m1.small' ):
"""
Start a new cloud resource instance
"""
user = trans.get_user()
uci = get_uci( trans, id )
stores = get_stores( trans, uci )
# Ensure instance is available and then store relevant data
# into DB to initiate instance startup by cloud manager
if ( len(stores) is not 0 ) and ( uci.state == uci_states.AVAILABLE ):
instance = model.CloudInstance()
instance.user = user
instance.uci = uci
instance.state = instance_states.SUBMITTED
instance.availability_zone = stores[0].availability_zone # Bc. all EBS volumes need to be in the same avail. zone, just check 1st
instance.type = type
uci.state = uci_states.SUBMITTED_UCI
# Persist
session = trans.sa_session
session.save_or_update( instance )
session.save_or_update( uci )
session.flush()
# Log
trans.log_event ("User initiated starting of UCI '%s'." % uci.name )
trans.set_message( "Galaxy instance started. NOTE: Please wait about 5 minutes for the instance to "
"start up. A button to connect to the instance will appear alongside "
"instance description once cloud instance of Galaxy is ready." )
return self.list( trans )
if len(stores) == 0:
error( "This instance does not have any storage volumes associated it and thus cannot be started." )
else:
error( "Cannot start instance that is in state '%s'." % uci.state )
return self.list( trans )
@web.expose
@web.require_login( "stop Galaxy cloud instance" )
def stop( self, trans, id ):
"""
Stop a cloud UCI instance.
"""
uci = get_uci( trans, id )
if ( uci.state != uci_states.DELETING ) and \
( uci.state != uci_states.DELETING_UCI ) and \
( uci.state != uci_states.ERROR ) and \
( uci.state != uci_states.SHUTTING_DOWN_UCI ) and \
( uci.state != uci_states.SHUTTING_DOWN ) and \
( uci.state != uci_states.AVAILABLE ):
uci.state = uci_states.SHUTTING_DOWN_UCI
session = trans.sa_session
session.save_or_update( uci )
session.flush()
trans.log_event( "User stopped cloud instance '%s' (id: %s)" % ( uci.name, uci.id ) )
trans.set_message( "Stopping of Galaxy instance '%s' initiated." % uci.name )
return self.list( trans )
trans.show_error_message( "Cannot stop instance that is in state '%s'." % uci.state )
return self.list( trans )
@web.expose
@web.require_login( "delete user configured Galaxy cloud instance" )
def deleteInstance( self, trans, id ):
"""
Deletes User Configured Instance (UCI) from the cloud and local database. NOTE that this implies deletion of
any and all storage associated with this UCI!
"""
uci = get_uci( trans, id )
if ( uci.state != uci_states.DELETING_UCI ) and ( uci.state != uci_states.DELETING ) and ( uci.state != uci_states.ERROR ):
name = uci.name
uci.state = uci_states.DELETING_UCI
session = trans.sa_session
session.save_or_update( uci )
session.flush()
trans.log_event( "User marked cloud instance '%s' for deletion." % name )
trans.set_message( "Galaxy instance '%s' marked for deletion." % name )
return self.list( trans )
if uci.state != uci_states.ERROR:
trans.set_message( "Cannot delete instance in state ERROR." )
else:
trans.set_message( "Instance '%s' is already marked for deletion." % uci.name )
return self.list( trans )
# ----- UCI methods -----
@web.expose
@web.require_login( "use Galaxy cloud" )
def create_snapshot( self, trans, id ):
user = trans.get_user()
id = trans.security.decode_id( id )
uci = get_uci( trans, id )
stores = trans.sa_session.query( model.CloudStore ) \
.filter_by( user=user, deleted=False, uci_id=id ) \
.all()
if ( len( stores ) > 0 ) and ( uci.state == uci_states.AVAILABLE ):
for store in stores:
snapshot = model.CloudSnapshot()
snapshot.user = user
snapshot.uci = uci
snapshot.store = store
snapshot.status = snapshot_status.SUBMITTED
uci.state = uci_states.SNAPSHOT_UCI
# Persist
session = trans.sa_session
session.save_or_update( snapshot )
session.save_or_update( uci )
session.flush()
elif len( stores ) == 0:
error( "No storage volumes found that are associated with this instance." )
else:
error( "Snapshot can be created only for an instance that is in 'available' state." )
# Log and display the management page
trans.log_event( "User initiated creation of new snapshot." )
trans.set_message( "Creation of new snapshot initiated. " )
return self.list( trans )
@web.expose
@web.require_login( "use Galaxy cloud" )
def view_snapshots( self, trans, id=None ):
"""
View details about any snapshots associated with given UCI
"""
user = trans.get_user()
id = trans.security.decode_id( id )
snaps = trans.sa_session.query( model.CloudSnapshot ) \
.filter_by( user=user, uci_id=id, deleted=False ) \
.order_by( desc( model.CloudSnapshot.c.update_time ) ) \
.all()
return trans.fill_template( "cloud/view_snapshots.mako",
snaps = snaps )
@web.expose
@web.require_login( "use Galaxy cloud" )
def delete_snapshot( self, trans, uci_id=None, snap_id=None ):
"""
Initiates deletion of a snapshot
"""
user = trans.get_user()
snap_id = trans.security.decode_id( snap_id )
# Set snapshot as 'ready for deletion' to be picked up by general updater
snap = trans.sa_session.query( model.CloudSnapshot ).get( snap_id )
if snap.status == snapshot_status.COMPLETED:
snap.status = snapshot_status.DELETE
snap.flush()
trans.set_message( "Snapshot '%s' is marked for deletion. Once the deletion is complete, it will no longer be visible in this list. "
"Please note that this process may take up to a minute." % snap.snapshot_id )
else:
error( "Only snapshots in state 'completed' can be deleted. See the cloud provider directly "
"if you believe the snapshot is available and can be deleted." )
# Display new list of snapshots
uci_id = trans.security.decode_id( uci_id )
snaps = trans.sa_session.query( model.CloudSnapshot ) \
.filter_by( user=user, uci_id=uci_id, deleted=False ) \
.order_by( desc( model.CloudSnapshot.c.update_time ) ) \
.all()
return trans.fill_template( "cloud/view_snapshots.mako",
snaps = snaps )
@web.expose
@web.require_login( "add instance storage" )
def addStorage( self, trans, id ):
instance = get_uci( trans, id )
error( "Adding storage to instance '%s' is not supported yet." % instance.name )
return self.list( trans )
@web.expose
@web.require_login( "use Galaxy cloud" )
def usageReport( self, trans, id ):
user = trans.get_user()
id = trans.security.decode_id( id )
prevInstances = trans.sa_session.query( model.CloudInstance ) \
.filter_by( user=user, state=instance_states.TERMINATED, uci_id=id ) \
.order_by( desc( model.CloudInstance.c.update_time ) ) \
.all()
return trans.fill_template( "cloud/view_usage.mako", prevInstances = prevInstances )
@web.expose
@web.require_login( "use Galaxy cloud" )
def configureNew( self, trans, instanceName='', credName='', volSize='', zone='' ):
def configure_new_uci( self, trans, instanceName='', credName='', volSize='', zone='' ):
"""
Configure and add new cloud instance to user's instance pool
"""
@@ -446,9 +257,256 @@ class CloudController( BaseController ):
error = error,
providersToZones = providersToZones )
@web.expose
@web.require_login( "start Galaxy cloud instance" )
def start( self, trans, id, type='m1.small' ):
"""
Start a new cloud resource instance
"""
user = trans.get_user()
uci = get_uci( trans, id )
stores = get_stores( trans, uci )
# Ensure instance is available and then store relevant data
# into DB to initiate instance startup by cloud manager
if ( len(stores) is not 0 ) and ( uci.state == uci_states.AVAILABLE ):
instance = model.CloudInstance()
instance.user = user
instance.uci = uci
instance.state = instance_states.SUBMITTED
instance.availability_zone = stores[0].availability_zone # Bc. all EBS volumes need to be in the same avail. zone, just check 1st
instance.type = type
uci.state = uci_states.SUBMITTED_UCI
# Persist
session = trans.sa_session
session.save_or_update( instance )
session.save_or_update( uci )
session.flush()
# Log
trans.log_event ("User initiated starting of UCI '%s'." % uci.name )
trans.set_message( "Galaxy instance started. NOTE: Please wait about 5 minutes for the instance to "
"start up. A button to connect to the instance will appear alongside "
"instance description once cloud instance of Galaxy is ready." )
return self.list( trans )
if len(stores) == 0:
error( "This instance does not have any storage volumes associated it and thus cannot be started." )
else:
error( "Cannot start instance that is in state '%s'." % uci.state )
return self.list( trans )
@web.expose
@web.require_login( "stop Galaxy cloud instance" )
def stop( self, trans, id ):
"""
Stop a cloud UCI instance.
"""
uci = get_uci( trans, id )
if ( uci.state != uci_states.DELETING ) and \
( uci.state != uci_states.DELETING_UCI ) and \
( uci.state != uci_states.ERROR ) and \
( uci.state != uci_states.SHUTTING_DOWN_UCI ) and \
( uci.state != uci_states.SHUTTING_DOWN ) and \
( uci.state != uci_states.AVAILABLE ):
uci.state = uci_states.SHUTTING_DOWN_UCI
session = trans.sa_session
session.save_or_update( uci )
session.flush()
trans.log_event( "User stopped cloud instance '%s' (id: %s)" % ( uci.name, uci.id ) )
trans.set_message( "Stopping of Galaxy instance '%s' initiated." % uci.name )
return self.list( trans )
trans.show_error_message( "Cannot stop instance that is in state '%s'." % uci.state )
return self.list( trans )
@web.expose
@web.require_login( "use Galaxy cloud" )
def set_uci_state( self, trans, id, state='available', clear_error=True ):
"""
Sets state of UCI to given state, optionally resets error field, and resets UCI's launch time field to 'None'.
"""
uci = get_uci( trans, id )
uci.state = state
if clear_error:
uci.error = None
uci.launch_time = None
trans.sa_session.flush()
trans.set_message( "Instance '%s' state reset." % uci.name )
return self.list( trans )
@web.expose
@web.require_login( "view instance details" )
def view_uci_details( self, trans, id=None ):
"""
View details about running instance
"""
uci = get_uci( trans, id )
instances = get_instances( trans, uci ) # TODO: Handle list (will probably need to be done in mako template)
return trans.fill_template( "cloud/view_instance.mako",
liveInstance = instances )
@web.expose
@web.require_login( "use Galaxy cloud" )
def rename_uci( self, trans, id, new_name=None ):
instance = get_uci( trans, id )
if new_name is not None:
if len(new_name) > 255:
error( "Instance name must be less than 255 characters long." )
user = trans.get_user()
name_exists = trans.sa_session.query( model.UCI ) \
.filter_by( user=user, name=new_name ) \
.first()
if name_exists:
error( "Specified name ('%s') is already used by an existing instance. Please choose an alternative name." % new_name )
# Update name in local DB
instance.name = new_name
trans.sa_session.flush()
trans.set_message( "Instance renamed to '%s'." % new_name )
return self.list( trans )
else:
return trans.show_form(
web.FormBuilder( url_for( id=trans.security.encode_id(instance.id) ), "Rename instance", submit_text="Rename" )
.add_text( "new_name", "Instance name", value=instance.name ) )
@web.expose
@web.require_login( "use Galaxy cloud" )
def uci_usage_report( self, trans, id ):
user = trans.get_user()
id = trans.security.decode_id( id )
prevInstances = trans.sa_session.query( model.CloudInstance ) \
.filter_by( user=user, state=instance_states.TERMINATED, uci_id=id ) \
.order_by( desc( model.CloudInstance.c.update_time ) ) \
.all()
return trans.fill_template( "cloud/view_usage.mako", prevInstances = prevInstances )
@web.expose
@web.require_login( "delete user configured Galaxy cloud instance" )
def delete_uci( self, trans, id ):
"""
Deletes User Configured Instance (UCI) from the cloud and local database. NOTE that this implies deletion of
any and all storage associated with this UCI!
"""
uci = get_uci( trans, id )
if ( uci.state != uci_states.DELETING_UCI ) and ( uci.state != uci_states.DELETING ) and ( uci.state != uci_states.ERROR ):
name = uci.name
uci.state = uci_states.DELETING_UCI
session = trans.sa_session
session.save_or_update( uci )
session.flush()
trans.log_event( "User marked cloud instance '%s' for deletion." % name )
trans.set_message( "Galaxy instance '%s' marked for deletion." % name )
return self.list( trans )
if uci.state != uci_states.ERROR:
trans.set_message( "Cannot delete instance in state ERROR." )
else:
trans.set_message( "Instance '%s' is already marked for deletion." % uci.name )
return self.list( trans )
# ----- Snapshot methods -----
@web.expose
@web.require_login( "use Galaxy cloud" )
def create_snapshot( self, trans, id ):
user = trans.get_user()
id = trans.security.decode_id( id )
uci = get_uci( trans, id )
stores = trans.sa_session.query( model.CloudStore ) \
.filter_by( user=user, deleted=False, uci_id=id ) \
.all()
if ( len( stores ) > 0 ) and ( uci.state == uci_states.AVAILABLE ):
for store in stores:
snapshot = model.CloudSnapshot()
snapshot.user = user
snapshot.uci = uci
snapshot.store = store
snapshot.status = snapshot_status.SUBMITTED
uci.state = uci_states.SNAPSHOT_UCI
# Persist
session = trans.sa_session
session.save_or_update( snapshot )
session.save_or_update( uci )
session.flush()
elif len( stores ) == 0:
error( "No storage volumes found that are associated with this instance." )
else:
error( "Snapshot can be created only for an instance that is in 'available' state." )
# Log and display the management page
trans.log_event( "User initiated creation of new snapshot." )
trans.set_message( "Creation of new snapshot initiated. " )
return self.list( trans )
@web.expose
@web.require_login( "use Galaxy cloud" )
def view_snapshots( self, trans, id=None ):
"""
View details about any snapshots associated with given UCI
"""
user = trans.get_user()
id = trans.security.decode_id( id )
snaps = trans.sa_session.query( model.CloudSnapshot ) \
.filter_by( user=user, uci_id=id, deleted=False ) \
.order_by( desc( model.CloudSnapshot.c.update_time ) ) \
.all()
return trans.fill_template( "cloud/view_snapshots.mako",
snaps = snaps )
@web.expose
@web.require_login( "use Galaxy cloud" )
def delete_snapshot( self, trans, uci_id=None, snap_id=None ):
"""
Initiates deletion of a snapshot
"""
user = trans.get_user()
snap_id = trans.security.decode_id( snap_id )
# Set snapshot as 'ready for deletion' to be picked up by general updater
snap = trans.sa_session.query( model.CloudSnapshot ).get( snap_id )
if snap.status == snapshot_status.COMPLETED:
snap.status = snapshot_status.DELETE
snap.flush()
trans.set_message( "Snapshot '%s' is marked for deletion. Once the deletion is complete, it will no longer be visible in this list. "
"Please note that this process may take up to a minute." % snap.snapshot_id )
else:
error( "Only snapshots in state 'completed' can be deleted. See the cloud provider directly "
"if you believe the snapshot is available and can be deleted." )
# Display new list of snapshots
uci_id = trans.security.decode_id( uci_id )
snaps = trans.sa_session.query( model.CloudSnapshot ) \
.filter_by( user=user, uci_id=uci_id, deleted=False ) \
.order_by( desc( model.CloudSnapshot.c.update_time ) ) \
.all()
return trans.fill_template( "cloud/view_snapshots.mako",
snaps = snaps )
# ----- Storage methods -----
@web.expose
@web.require_login( "add instance storage" )
def add_storage( self, trans, id ):
instance = get_uci( trans, id )
error( "Adding storage to instance '%s' is not supported yet." % instance.name )
return self.list( trans )
# ----- Image methods -----
@web.expose
@web.require_admin
def addNewImage( self, trans, provider_type='', image_id='', manifest='', architecture='', state=None ):
def add_new_image( self, trans, provider_type='', image_id='', manifest='', architecture='', state=None ):
#id_error = arch_error = provider_error = manifest_error = None
error = {}
if provider_type or image_id or manifest or architecture:
@@ -498,24 +556,24 @@ class CloudController( BaseController ):
@web.expose
@web.require_login( "use Galaxy cloud" )
def listMachineImages( self, trans ):
def list_machine_images( self, trans ):
images = trans.sa_session.query( model.CloudImage ).filter( trans.app.model.CloudImage.table.c.deleted != True ).all()
return trans.fill_template( '/cloud/list_images.mako', images=images )
@web.expose
@web.require_admin
def deleteImage( self, trans, id=None ):
def delete_image( self, trans, id=None ):
if not isinstance( id, int ):
id = trans.security.decode_id( id )
image = trans.sa_session.query( model.CloudImage ).get( id )
image.deleted = True
image.flush()
return self.listMachineImages( trans )
return self.list_machine_images( trans )
@web.expose
@web.require_admin
def editImage( self, trans, provider_type='', image_id='', manifest='', architecture='', id='', edited=False ):
def edit_image( self, trans, provider_type='', image_id='', manifest='', architecture='', id='', edited=False ):
error = {}
if not isinstance( id, int ):
id = trans.security.decode_id( id )
@@ -552,93 +610,13 @@ class CloudController( BaseController ):
session.flush()
# Log and display the management page
trans.set_message( "Machine image '%s' edited." % image.image_id )
return self.listMachineImages( trans )
@web.expose
@web.require_login( "use Galaxy cloud" )
def edit( self, trans, id, credName=None, accessKey=None, secretKey=None, edited=False ):
error = {}
if not edited:
credentials = get_stored_credentials( trans, id )
return trans.fill_template( "cloud/edit_credentials.mako",
credential = credentials,
error = error
)
else:
user = trans.get_user()
credentials = get_stored_credentials( trans, id )
if credName=='' or len( credName ) > 255:
error['cred_error'] = "Credentials name must be between 1 and 255 characters in length."
elif trans.app.model.CloudUserCredentials \
.filter_by( user=user ) \
.filter( and_( trans.app.model.CloudUserCredentials.table.c.id != credentials.id, trans.app.model.CloudUserCredentials.table.c.name==credName ) ) \
.first():
error['cred_error'] = "Credentials with name '" + credName + "' already exist. Please choose an alternative name."
elif accessKey=='' or len( accessKey ) > 255:
error['access_key_error'] = "Access key must be between 1 and 255 characters long."
elif secretKey=='' or len( secretKey ) > 255:
error['secret_key_error'] = "Secret key must be between 1 and 255 characters long."
return self.list_machine_images( trans )
if error:
return trans.fill_template( "cloud/edit_credentials.mako",
credential = credentials,
error = error
)
else:
# Edit user stored credentials
credentials.name = credName
credentials.access_key = accessKey
credentials.secret_key = secretKey
# Persist
session = trans.sa_session
session.save_or_update( credentials )
session.flush()
# Log and display the management page
trans.set_message( "Credential '%s' edited." % credentials.name )
return self.list( trans )
@web.expose
@web.require_login( "use Galaxy cloud" )
def renameInstance( self, trans, id, new_name=None ):
instance = get_uci( trans, id )
if new_name is not None:
if len(new_name) > 255:
error( "Instance name must be less than 255 characters long." )
user = trans.get_user()
name_exists = trans.sa_session.query( model.UCI ) \
.filter_by( user=user, name=new_name ) \
.first()
if name_exists:
error( "Specified name ('%s') is already used by an existing instance. Please choose an alternative name." % new_name )
# Update name in local DB
instance.name = new_name
trans.sa_session.flush()
trans.set_message( "Instance renamed to '%s'." % new_name )
return self.list( trans )
else:
return trans.show_form(
web.FormBuilder( url_for( id=trans.security.encode_id(instance.id) ), "Rename instance", submit_text="Rename" )
.add_text( "new_name", "Instance name", value=instance.name ) )
@web.expose
@web.require_login( "use Galaxy cloud" )
def set_uci_state( self, trans, id, state='available', clear_error=True ):
"""
Sets state of UCI to given state, optionally resets error field, and resets UCI's launch time field to 'None'.
"""
uci = get_uci( trans, id )
uci.state = state
if clear_error:
uci.error = None
uci.launch_time = None
trans.sa_session.flush()
trans.set_message( "Instance '%s' state reset." % uci.name )
return self.list( trans )
# ----- Credentials methods -----
@web.expose
@web.require_login( "add credentials" )
def add( self, trans, credName='', accessKey='', secretKey='', providerName='' ):
def add_credentials( self, trans, credName='', accessKey='', secretKey='', providerName='' ):
"""
Add user's cloud credentials stored under name `credName`.
"""
@@ -687,16 +665,59 @@ class CloudController( BaseController ):
providers = providers
)
@web.expose
@web.require_login( "use Galaxy cloud" )
def edit_credentials( self, trans, id, credName=None, accessKey=None, secretKey=None, edited=False ):
error = {}
if not edited:
credentials = get_stored_credentials( trans, id )
return trans.fill_template( "cloud/edit_credentials.mako",
credential = credentials,
error = error
)
else:
user = trans.get_user()
credentials = get_stored_credentials( trans, id )
if credName=='' or len( credName ) > 255:
error['cred_error'] = "Credentials name must be between 1 and 255 characters in length."
elif trans.app.model.CloudUserCredentials \
.filter_by( user=user ) \
.filter( and_( trans.app.model.CloudUserCredentials.table.c.id != credentials.id, trans.app.model.CloudUserCredentials.table.c.name==credName ) ) \
.first():
error['cred_error'] = "Credentials with name '" + credName + "' already exist. Please choose an alternative name."
elif accessKey=='' or len( accessKey ) > 255:
error['access_key_error'] = "Access key must be between 1 and 255 characters long."
elif secretKey=='' or len( secretKey ) > 255:
error['secret_key_error'] = "Secret key must be between 1 and 255 characters long."
if error:
return trans.fill_template( "cloud/edit_credentials.mako",
credential = credentials,
error = error
)
else:
# Edit user stored credentials
credentials.name = credName
credentials.access_key = accessKey
credentials.secret_key = secretKey
# Persist
session = trans.sa_session
session.save_or_update( credentials )
session.flush()
# Log and display the management page
trans.set_message( "Credential '%s' edited." % credentials.name )
return self.list( trans )
@web.expose
@web.require_login( "view credentials" )
def view( self, trans, id=None ):
def view_credentials( self, trans, id=None ):
"""
View details for user credentials
"""
# Load credentials from database
stored = get_stored_credentials( trans, id )
return trans.fill_template( "cloud/view.mako",
return trans.fill_template( "cloud/view_credentials.mako",
credDetails = stored )
@web.expose
@@ -706,43 +727,34 @@ class CloudController( BaseController ):
Tests credentials provided by user with selected cloud provider
"""
@web.expose
@web.require_login( "view instance details" )
def viewInstance( self, trans, id=None ):
"""
View details about running instance
"""
uci = get_uci( trans, id )
instances = get_instances( trans, uci ) # TODO: Handle list (will probably need to be done in mako template)
return trans.fill_template( "cloud/viewInstance.mako",
liveInstance = instances )
@web.expose
@web.require_login( "delete credentials" )
def delete( self, trans, id=None ):
def delete_credentials( self, trans, id=None ):
"""
Delete user's cloud credentials checking that no registered instances are tied to given credentials.
"""
# Load credentials from database
user = trans.get_user()
stored = get_stored_credentials( trans, id )
UCIs = trans.sa_session.query( model.UCI ) \
.filter_by( user=user, credentials_id=stored.id ) \
.filter( model.UCI.c.deleted != True ) \
.all()
# Check if there are any UCIs that depend on these credentials
UCI = None
UCI = trans.sa_session.query( model.UCI ) \
.filter_by( user=user, credentials_id=stored.id, deleted=False ) \
.first()
if len(UCIs) == 0:
if UCI == None:
# Delete and save
stored.deleted = True
stored.flush()
# Display the management page
trans.set_message( "Credentials '%s' deleted." % stored.name )
return self.list( trans )
error( "Existing instance(s) depend on credentials '%s'. You must delete those instances before being able \
to delete these credentials." % stored.name )
return self.list( trans )
else:
error( "Existing instance(s) depend on credentials '%s'. You must delete those instances before being able \
to delete these credentials." % stored.name )
return self.list( trans )
# ----- Provider methods -----
@web.expose
@web.require_login( "add provider" )
@@ -1007,6 +1019,8 @@ class CloudController( BaseController ):
to delete this cloud provider." % provider.name )
return self.list( trans )
# ----- AJAX methods -----
@web.json
def json_update( self, trans ):
user = trans.get_user()
@@ -1132,7 +1146,7 @@ def get_stores( trans, uci ):
user = trans.get_user()
stores = trans.sa_session.query( model.CloudStore ) \
.filter_by( user=user, uci_id=uci.id ) \
.filter( model.CloudStore.c.status != store_states.ERROR ) \
.filter( model.CloudStore.c.status != store_status.ERROR ) \
.all()
return stores
+2 -2
View File
@@ -127,8 +127,8 @@
</div>
<div class="toolSectionBody">
<div class="toolSectionBg">
<div class="toolTitle"><a href="${h.url_for( controller='cloud', action='listMachineImages' )}" target="galaxy_main">List machine images</a></div>
<div class="toolTitle"><a href="${h.url_for( controller='cloud', action='addNewImage' )}" target="galaxy_main">Add machine image</a></div>
<div class="toolTitle"><a href="${h.url_for( controller='cloud', action='list_machine_images' )}" target="galaxy_main">List machine images</a></div>
<div class="toolTitle"><a href="${h.url_for( controller='cloud', action='add_new_image' )}" target="galaxy_main">Add machine image</a></div>
</div>
</div>
</div>
+1 -1
View File
@@ -20,7 +20,7 @@ $(function(){
<div class="form">
<div class="form-title">Add credentials</div>
<div class="form-body">
<form name="Add credentials" action="${h.url_for( action='add' )}" method="post" >
<form name="add_credentials" action="${h.url_for( action='add_credentials' )}" method="post" >
<%
cls = "form-row"
+1 -1
View File
@@ -18,7 +18,7 @@ $(function(){
<div class="form">
<div class="form-title">Add machine image</div>
<div class="form-body">
<form name="add_image" action="${h.url_for( action='addNewImage' )}" method="post" >
<form name="add_image" action="${h.url_for( action='add_new_image' )}" method="post" >
<%
cls = "form-row"
if error.has_key('provider_error'):
+15 -15
View File
@@ -156,7 +156,7 @@ function trim19(str){
%if cloudCredentials:
<ul class="manage-table-actions">
<li>
<a class="action-button" href="${h.url_for( action='add' )}">
<a class="action-button" href="${h.url_for( action='add_credentials' )}">
<img src="${h.url_for('/static/images/silk/add.png')}" />
<span>Add credentials</span>
</a>
@@ -181,9 +181,9 @@ function trim19(str){
</td>
<td>
<div popupmenu="cr-${i}-popup">
<a class="action-button" href="${h.url_for( action='view', id=trans.security.encode_id(cloudCredential.id) )}">View</a>
<a class="action-button" href="${h.url_for( action='edit', id=trans.security.encode_id(cloudCredential.id) )}">Edit</a>
<a class="action-button" confirm="Are you sure you want to delete credentials '${cloudCredential.name}'?" href="${h.url_for( action='delete', id=trans.security.encode_id(cloudCredential.id) )}">Delete</a>
<a class="action-button" href="${h.url_for( action='view_credentials', id=trans.security.encode_id(cloudCredential.id) )}">View</a>
<a class="action-button" href="${h.url_for( action='edit_credentials', id=trans.security.encode_id(cloudCredential.id) )}">Edit</a>
<a class="action-button" confirm="Are you sure you want to delete credentials '${cloudCredential.name}'?" href="${h.url_for( action='delete_credentials', id=trans.security.encode_id(cloudCredential.id) )}">Delete</a>
</div>
</td>
</tr>
@@ -196,7 +196,7 @@ function trim19(str){
<h3>Manage your cloud instances</h3>
<ul class="manage-table-actions">
<li>
<a class="action-button" href="${h.url_for( action='configureNew' )}">
<a class="action-button" href="${h.url_for( action='configure_new_uci' )}">
<img src="${h.url_for('/static/images/silk/add.png')}" />
<span>Configure new instance</span>
</a>
@@ -253,10 +253,10 @@ function trim19(str){
<td id="${ liveInstance.id }-link"></td>
<td>
<div popupmenu="li-${i}-popup">
<a class="action-button" confirm="Are you sure you want to stop instance '${liveInstance.name}'? Please note that this may take up to 1 minute during which time the page will not refresh." href="${h.url_for( action='stop', id=trans.security.encode_id(liveInstance.id) )}">Stop</a>
<a class="action-button" href="${h.url_for( action='renameInstance', id=trans.security.encode_id(liveInstance.id) )}">Rename</a>
<a class="action-button" href="${h.url_for( action='viewInstance', id=trans.security.encode_id(liveInstance.id) )}">View details</a>
<a class="action-button" href="${h.url_for( action='usageReport', id=trans.security.encode_id(liveInstance.id) )}">Usage report</a>
<a class="action-button" confirm="Are you sure you want to stop instance '${liveInstance.name}'?" href="${h.url_for( action='stop', id=trans.security.encode_id(liveInstance.id) )}">Stop</a>
<a class="action-button" href="${h.url_for( action='rename_uci', id=trans.security.encode_id(liveInstance.id) )}">Rename</a>
<a class="action-button" href="${h.url_for( action='view_uci_details', id=trans.security.encode_id(liveInstance.id) )}">View details</a>
<a class="action-button" href="${h.url_for( action='uci_usage_report', id=trans.security.encode_id(liveInstance.id) )}">Usage report</a>
</div>
</td>
</tr>
@@ -322,12 +322,12 @@ function trim19(str){
<div popupmenu="pi-${i}-popup">
<a class="action-button" href="${h.url_for( action='start', id=trans.security.encode_id(prevInstance.id), type='m1.small' )}"> Start m1.small</a>
<a class="action-button" href="${h.url_for( action='start', id=trans.security.encode_id(prevInstance.id), type='c1.medium' )}"> Start c1.medium</a>
<a class="action-button" href="${h.url_for( action='renameInstance', id=trans.security.encode_id(prevInstance.id) )}">Rename</a>
<a class="action-button" href="${h.url_for( action='create_snapshot', id=trans.security.encode_id(prevInstance.id) )}">Create snapshot</a>
<a class="action-button" href="${h.url_for( action='rename_uci', id=trans.security.encode_id(prevInstance.id) )}">Rename</a>
<a class="action-button" href="${h.url_for( action='uci_usage_report', id=trans.security.encode_id(prevInstance.id) )}">Usage report</a>
<a class="action-button" href="${h.url_for( action='create_snapshot', id=trans.security.encode_id(prevInstance.id) )}">Create snapshot</a>
<a class="action-button" href="${h.url_for( action='view_snapshots', id=trans.security.encode_id(prevInstance.id) )}">View snapshots</a>
<a class="action-button" href="${h.url_for( action='addStorage', id=trans.security.encode_id(prevInstance.id) )}" target="_parent">Add storage</a>
<a class="action-button" href="${h.url_for( action='usageReport', id=trans.security.encode_id(prevInstance.id) )}">Usage report</a>
<a class="action-button" confirm="Are you sure you want to delete instance '${prevInstance.name}'? This will delete all of your data assocaiated with this instance!" href="${h.url_for( action='deleteInstance', id=trans.security.encode_id(prevInstance.id) )}">Delete</a>
<a class="action-button" href="${h.url_for( action='add_storage', id=trans.security.encode_id(prevInstance.id) )}" target="_parent">Add storage</a>
<a class="action-button" confirm="Are you sure you want to delete instance '${prevInstance.name}'? This will delete all of your data assocaiated with this instance!" href="${h.url_for( action='delete_uci', id=trans.security.encode_id(prevInstance.id) )}">Delete</a>
</div>
</td>
</tr>
@@ -341,7 +341,7 @@ function trim19(str){
%else:
You have no credentials associated with your Galaxy account:
<a class="action-button" href="${h.url_for( action='add' )}">
<a class="action-button" href="${h.url_for( action='add_credentials' )}">
<img src="${h.url_for('/static/images/silk/add.png')}" />
<span>add credentials</span>
</a>
+1 -1
View File
@@ -35,7 +35,7 @@ $(function(){
<div class="form">
<div class="form-title">Configure new Galaxy instance</div>
<div class="form-body">
<form name="Configure new UCI" action="${h.url_for( action='configureNew' )}" method="post" >
<form name="Configure new UCI" action="${h.url_for( action='configure_new_uci' )}" method="post" >
<%
cls = "form-row"
+1 -1
View File
@@ -20,7 +20,7 @@ $(function(){
<div class="form">
<div class="form-title">Edit credentials</div>
<div class="form-body">
<form name="edit_credentials" action="${h.url_for( action='edit', id=trans.security.encode_id(credential.id), edited="true" )}" method="post" >
<form name="edit_credentials" action="${h.url_for( action='edit_credentials', id=trans.security.encode_id(credential.id), edited="true" )}" method="post" >
<%
cls = "form-row"
+1 -1
View File
@@ -20,7 +20,7 @@ $(function(){
<div class="form">
<div class="form-title">Edit image</div>
<div class="form-body">
<form name="edit_image" action="${h.url_for( action='editImage', id=trans.security.encode_id(image.id), edited="true" )}" method="post" >
<form name="edit_image" action="${h.url_for( action='edit_image', id=trans.security.encode_id(image.id), edited="true" )}" method="post" >
<%
cls = "form-row"
if error.has_key('provider_error'):
+3 -3
View File
@@ -69,18 +69,18 @@
%endif
</td>
<td>
<a href="${h.url_for( controller='cloud', action='editImage', image_id=image.image_id, manifest=image.manifest, id=trans.security.encode_id(image.id) )}">e</a>
<a href="${h.url_for( controller='cloud', action='edit_image', image_id=image.image_id, manifest=image.manifest, id=trans.security.encode_id(image.id) )}">e</a>
</td>
<td>
<a confirm="Are you sure you want to delete machine image '${image.image_id}'? Note that this may result in users' UCI's not to work any more!"
href="${h.url_for( controller='cloud', action='deleteImage', id=trans.security.encode_id(image.id) )}">x</a>
href="${h.url_for( controller='cloud', action='delete_image', id=trans.security.encode_id(image.id) )}">x</a>
</td>
</tr>
%endfor
</table>
%else:
<h3>There are no registered machine images.</h3><br />
<a href="${h.url_for( controller='cloud', action='addNewImage' )}" target="galaxy_main">Add machine image now?</a>
<a href="${h.url_for( controller='cloud', action='add_new_image' )}" target="galaxy_main">Add machine image now?</a>
%endif
@@ -32,8 +32,8 @@
</td>
<td>
<div popupmenu="wf-popup">
<a class="action-button" href="${h.url_for( action='rename', id=trans.security.encode_id(credDetails.id) )}">Rename</a>
<a class="action-button" confirm="Are you sure you want to delete credentials '${credDetails.name}'?" href="${h.url_for( action='delete', id=trans.security.encode_id(credDetails.id) )}">Delete</a>
<a class="action-button" href="${h.url_for( action='edit_credentials', id=trans.security.encode_id(credDetails.id) )}">Edit</a>
<a class="action-button" confirm="Are you sure you want to delete credentials '${credDetails.name}'?" href="${h.url_for( action='delete_credentials', id=trans.security.encode_id(credDetails.id) )}">Delete</a>
</div>
</td>
</tr>
@@ -30,7 +30,7 @@
</td>
<td>
<div popupmenu="li-popup">
<a class="action-button" href="${h.url_for( action='renameInstance', id=trans.security.encode_id(liveInstance.uci.id) )}">Rename</a>
<a class="action-button" href="${h.url_for( action='rename_uci', id=trans.security.encode_id(liveInstance.uci.id) )}">Rename</a>
<a class="action-button" confirm="Are you sure you want to stop instance '${liveInstance.uci.name}'?" href="${h.url_for( action='stop', id=trans.security.encode_id(liveInstance.uci.id) )}">Stop</a>
</div>
</td>
+1 -1
View File
@@ -88,7 +88,7 @@
</table>
<br/>Total number of hours instance was alive: ${total_hours} <br />
Note that these are just best effort estimates - true usage should be obtained from respective cloud provider. <br />
<%namespace name="view_cred" file="view.mako" />
<%namespace name="view_cred" file="view_credentials.mako" />
<div id="hide_cred_details">
This instance uses credentials: