def provider_over_allocation_enforcement(identity, user): provider = identity.provider action = provider.over_allocation_action if not action: logger.debug("No 'over_allocation_action' provided for %s" % provider) return False driver = get_cached_driver(identity=identity) esh_instances = driver.list_instances() #TODO: Parallelize this operation so you don't wait for larger instances to finish 'wait_for' task below.. for instance in esh_instances: try: if driver._is_active_instance(instance): # Suspend active instances, update the task in the DB # NOTE: identity.created_by COULD BE the Admin User, indicating that this action/InstanceHistory was # executed by the administrator.. Future Release Idea. _execute_provider_action(identity, identity.created_by, instance, action.name) # NOTE: Intentionally added to allow time for # the Cloud to begin 'suspend' operation # before querying for the instance again. #TODO: Instead: Add "wait_for" change from active to any terminal, non-active state? wait_time = random.uniform(2, 6) time.sleep(wait_time) updated_esh = driver.get_instance(instance.id) convert_esh_instance( driver, updated_esh, identity.provider.uuid, identity.uuid, user) except Exception, e: # Raise ANY exception that doesn't say # 'This instance is already in the requested VM state' #NOTE: This is OpenStack specific if 'in vm_state' not in e.message: raise
def get(self, request, provider_uuid, identity_uuid, instance_id): """ Authentication Required, get instance details. """ user = request.user # NOTE: This 'Scheme' should be used across # the ENTIRE API v1 (Machines, Volumes, Sizes) # NOTE: Especially the part below, where you end date # all the things that are 'inactive' try: provider = Provider.objects.get(uuid=provider_uuid) if not provider.is_current(): raise ProviderNotActive(provider) except Provider.DoesNotExist: return invalid_creds(provider_uuid, identity_uuid) except ProviderNotActive as pna: return inactive_provider(pna) # Cleared provider testing -- ready for driver prep. try: esh_driver = prepare_driver(request, provider_uuid, identity_uuid) if not esh_driver: return invalid_creds(provider_uuid, identity_uuid) logger.info("InstanceQuery Looking for %s" % instance_id) esh_instance = esh_driver.get_instance(instance_id) logger.info("InstanceQuery Found instance %s" % esh_instance) except (socket_error, ConnectionFailure): logger.exception("Connection failure prevented InstanceQuery") return connection_failure(provider_uuid, identity_uuid) except LibcloudInvalidCredsError: logger.exception("Invalid credentialsprevented InstanceQuery") return invalid_creds(provider_uuid, identity_uuid) except Exception as exc: logger.exception("Encountered a generic exception. " "Returning 409-CONFLICT") return failure_response(status.HTTP_409_CONFLICT, str(exc.message)) # NOTE: Especially THIS part below, where you end date all the # things that are 'inactive' if not esh_instance: try: core_inst = CoreInstance.objects.get( provider_alias=instance_id, source__provider__uuid=provider_uuid, created_by_identity__uuid=identity_uuid) core_inst.end_date_all() except CoreInstance.DoesNotExist: pass return instance_not_found(instance_id) core_instance = convert_esh_instance(esh_driver, esh_instance, provider_uuid, identity_uuid, user) serialized_data = InstanceSerializer( core_instance, context={"request": request}).data response = Response(serialized_data) response['Cache-Control'] = 'no-cache' return response
def update_status(esh_driver, instance_id, provider_id, identity_id, user): #Grab a new copy of the instance instance_list_method = esh_driver.list_instances if AccountProvider.objects.filter(identity__id=identity_id): # Instance list method changes when using the OPENSTACK provider instance_list_method = esh_driver.list_all_instances try: esh_instance_list = instance_list_method() except InvalidCredsError: return invalid_creds(provider_id, identity_id) esh_instance = [instance for instance in esh_instance_list if instance.id == instance_id] esh_instance = esh_instance[0] #Convert & Update based on new status change core_instance = convert_esh_instance(esh_driver, esh_instance, provider_id, identity_id, user) core_instance.update_history( core_instance.esh.extra['status'], core_instance.esh.extra.get('task'))
def get(self, request, provider_uuid, identity_uuid): """ Returns a list of all instances """ user = request.user esh_driver = prepare_driver(request, provider_uuid, identity_uuid) if not esh_driver: return invalid_creds(provider_uuid, identity_uuid) identity = Identity.objects.get(uuid=identity_uuid) try: esh_instance_list = get_cached_instances(identity=identity) except MalformedResponseError: return malformed_response(provider_uuid, identity_uuid) except (socket_error, ConnectionFailure): return connection_failure(provider_uuid, identity_uuid) except InvalidCredsError: return invalid_creds(provider_uuid, identity_uuid) core_instance_list = [convert_esh_instance(esh_driver, inst, provider_uuid, identity_uuid, user) for inst in esh_instance_list] # TODO: Core/Auth checks for shared instances serialized_data = InstanceSerializer(core_instance_list, context={"request": request}, many=True).data response = Response(serialized_data) response['Cache-Control'] = 'no-cache' return response
def delete(self, request, provider_id, identity_id, instance_id): user = request.user esh_driver = prepare_driver(request, identity_id) try: esh_instance = esh_driver.get_instance(instance_id) if not esh_instance: return instance_not_found(instance_id) task.destroy_instance_task(esh_instance, identity_id) existing_instance = esh_driver.get_instance(instance_id) if existing_instance: #Instance will be deleted soon... esh_instance = existing_instance if esh_instance.extra\ and 'task' not in esh_instance.extra: esh_instance.extra['task'] = 'queueing delete' core_instance = convert_esh_instance(esh_driver, esh_instance, provider_id, identity_id, user) if core_instance: core_instance.end_date_all() serialized_data = InstanceSerializer(core_instance).data response = Response(serialized_data, status=status.HTTP_200_OK) response['Cache-Control'] = 'no-cache' return response except InvalidCredsError: return invalid_creds(provider_id, identity_id)
def put(self, request, provider_id, identity_id, instance_id): """ TODO: Options for put - Instance status change (suspend,resume,etc.) - DB changes (Name, tags) """ user = request.user data = request.DATA #Ensure item exists on the server first esh_driver = prepare_driver(request, identity_id) try: esh_instance = esh_driver.get_instance(instance_id) except InvalidCredsError: return invalid_creds(provider_id, identity_id) if not esh_instance: return instance_not_found(instance_id) #Gather the DB related item and update core_instance = convert_esh_instance(esh_driver, esh_instance, provider_id, identity_id, user) serializer = InstanceSerializer(core_instance, data=data) if serializer.is_valid(): logger.info('metadata = %s' % data) update_instance_metadata(esh_driver, esh_instance, data) serializer.save() response = Response(serializer.data) logger.info('data = %s' % serializer.data) response['Cache-Control'] = 'no-cache' return response else: return Response(serializer.errors, status=status.HTTP_400)
def patch(self, request, provider_id, identity_id, instance_id): """ """ user = request.user data = request.DATA #Ensure item exists on the server first esh_driver = prepare_driver(request, identity_id) try: esh_instance = esh_driver.get_instance(instance_id) except InvalidCredsError: return invalid_creds(provider_id, identity_id) if not esh_instance: return instance_not_found(instance_id) #Gather the DB related item and update core_instance = convert_esh_instance(esh_driver, esh_instance, provider_id, identity_id, user) serializer = InstanceSerializer(core_instance, data=data, partial=True) if serializer.is_valid(): logger.info('metadata = %s' % data) update_instance_metadata(esh_driver, esh_instance, data) serializer.save() response = Response(serializer.data) logger.info('data = %s' % serializer.data) response['Cache-Control'] = 'no-cache' return response else: return Response( serializer.errors, status=status.HTTP_400_BAD_REQUEST)
def over_allocation_test(identity, esh_instances): from api import get_esh_driver from core.models.instance import convert_esh_instance from atmosphere import settings over_allocated, time_diff = check_over_allocation( identity.created_by.username, identity.id, time_period=relativedelta(day=1, months=1)) logger.info("Overallocation Test: %s - %s - %s\tInstances:%s" % (identity.created_by.username, over_allocated, time_diff, esh_instances)) if not over_allocated: # Nothing changed, bail. return False if settings.DEBUG: logger.info('Do not enforce allocations in DEBUG mode') return False driver = get_esh_driver(identity) running_instances = [] for instance in esh_instances: #Suspend active instances, update the task in the DB try: if driver._is_active_instance(instance): driver.suspend_instance(instance) except Exception, e: if 'in vm_state suspended' not in e.message: raise updated_esh = driver.get_instance(instance.id) updated_core = convert_esh_instance(driver, updated_esh, identity.provider.id, identity.id, identity.created_by) running_instances.append(updated_core)
def monitor_instances_for_user(provider, username, instances): from core.models.instance import convert_esh_instance from api import get_esh_driver try: user = AtmosphereUser.objects.get(username=username) #TODO: When user->group is no longer true, # we will need to modify this.. group = Group.objects.get(name=user.username) ident = user.identity_set.get(provider=provider) im = ident.identitymembership_set.get(member=group) #NOTE: Couples with API, probably want this in # service/driver driver = get_esh_driver(ident) core_instances = [] #NOTE: We are converting them so they will # be picked up as core models for the 'over_allocation_test' for instance in instances: c_inst = convert_esh_instance( driver, instance, ident.provider.id, ident.id, ident.created_by) core_instances.append(c_inst) over_allocation = over_allocation_test(im.identity, instances) core_instances = user.instance_set.filter( provider_machine__provider=provider, end_date=None) core_instances_ident = ident.instance_set.filter(end_date=None) update_instances(driver, im.identity, instances, core_instances) except: logger.exception("Unable to monitor User:%s on Provider:%s" % (username,provider))
def delete(self, request, provider_id, identity_id, instance_id): """Authentication Required, TERMINATE the instance. Be careful, there is no going back once you've deleted an instance. """ user = request.user esh_driver = prepare_driver(request, provider_id, identity_id) if not esh_driver: return invalid_creds(provider_id, identity_id) try: esh_instance = esh_driver.get_instance(instance_id) if not esh_instance: return instance_not_found(instance_id) task.destroy_instance_task(esh_instance, identity_id) existing_instance = esh_driver.get_instance(instance_id) if existing_instance: #Instance will be deleted soon... esh_instance = existing_instance if esh_instance.extra\ and 'task' not in esh_instance.extra: esh_instance.extra['task'] = 'queueing delete' core_instance = convert_esh_instance(esh_driver, esh_instance, provider_id, identity_id, user) if core_instance: core_instance.end_date_all() else: logger.warn("Unable to find core instance %s." % (instance_id)) serialized_data = InstanceSerializer(core_instance, context={"request":request}).data response = Response(serialized_data, status=status.HTTP_200_OK) response['Cache-Control'] = 'no-cache' return response except InvalidCredsError: return invalid_creds(provider_id, identity_id)
def get(self, request, provider_id, identity_id): """ Returns a list of all instances """ user = request.user esh_driver = prepare_driver(request, provider_id, identity_id) if not esh_driver: return invalid_creds(provider_id, identity_id) instance_list_method = esh_driver.list_instances if AccountProvider.objects.filter(identity__id=identity_id): # Instance list method changes when using the OPENSTACK provider instance_list_method = esh_driver.list_all_instances try: esh_instance_list = instance_list_method() except InvalidCredsError: return invalid_creds(provider_id, identity_id) core_instance_list = [convert_esh_instance(esh_driver, inst, provider_id, identity_id, user) for inst in esh_instance_list] #TODO: Core/Auth checks for shared instances serialized_data = InstanceSerializer(core_instance_list, context={"request":request}, many=True).data response = Response(serialized_data) response['Cache-Control'] = 'no-cache' return response
def get(self, request, provider_id, identity_id, instance_id): """ Authentication Required, get instance details. """ user = request.user esh_driver = prepare_driver(request, provider_id, identity_id) if not esh_driver: return invalid_creds(provider_id, identity_id) esh_instance = esh_driver.get_instance(instance_id) if not esh_instance: try: core_inst = CoreInstance.objects.get( provider_alias=instance_id, provider_machine__provider__id=provider_id, created_by_identity__id=identity_id) core_inst.end_date_all() except CoreInstance.DoesNotExist: pass return instance_not_found(instance_id) core_instance = convert_esh_instance(esh_driver, esh_instance, provider_id, identity_id, user) serialized_data = InstanceSerializer(core_instance, context={"request":request}).data response = Response(serialized_data) response['Cache-Control'] = 'no-cache' return response
def get_core_instance(request, provider_id, identity_id, instance_id): user = request.user esh_driver = prepare_driver(request, provider_id, identity_id) esh_instance = get_esh_instance(request, provider_id, identity_id, instance_id) core_instance = convert_esh_instance(esh_driver, esh_instance, provider_id, identity_id, user) return core_instance
def put(self, request, provider_id, identity_id, instance_id): """Authentication Required, update metadata about the instance""" user = request.user data = request.DATA #Ensure item exists on the server first esh_driver = prepare_driver(request, provider_id, identity_id) if not esh_driver: return invalid_creds(provider_id, identity_id) esh_instance = esh_driver.get_instance(instance_id) if not esh_instance: return instance_not_found(instance_id) #Gather the DB related item and update core_instance = convert_esh_instance(esh_driver, esh_instance, provider_id, identity_id, user) serializer = InstanceSerializer(core_instance, data=data, context={"request":request}) if serializer.is_valid(): logger.info('metadata = %s' % data) update_instance_metadata(esh_driver, esh_instance, data) serializer.save() response = Response(serializer.data) logger.info('data = %s' % serializer.data) response['Cache-Control'] = 'no-cache' return response else: return Response(serializer.errors, status=status.HTTP_400)
def monitor_instances_for(provider_id, users=None, print_logs=False, check_allocations=False, start_date=None, end_date=None): """ Run the set of tasks related to monitoring instances for a provider. Optionally, provide a list of usernames to monitor While debugging, print_logs=True can be very helpful. start_date and end_date allow you to search a 'non-standard' window of time. """ provider = Provider.objects.get(id=provider_id) # For now, lets just ignore everything that isn't openstack. if 'openstack' not in provider.type.name.lower(): return instance_map = _get_instance_owner_map(provider, users=users) if print_logs: import logging import sys consolehandler = logging.StreamHandler(sys.stdout) consolehandler.setLevel(logging.DEBUG) celery_logger.addHandler(consolehandler) # DEVNOTE: Potential slowdown running multiple functions # Break this out when instance-caching is enabled running_total = 0 for username in sorted(instance_map.keys()): running_instances = instance_map[username] running_total += len(running_instances) identity = _get_identity_from_tenant_name(provider, username) if identity and running_instances: try: driver = get_cached_driver(identity=identity) core_running_instances = [ convert_esh_instance( driver, inst, identity.provider.uuid, identity.uuid, identity.created_by) for inst in running_instances] except Exception as exc: celery_logger.exception( "Could not convert running instances for %s" % username) continue else: # No running instances. core_running_instances = [] # Using the 'known' list of running instances, cleanup the DB core_instances = _cleanup_missing_instances( identity, core_running_instances) if check_allocations: allocation_result = user_over_allocation_enforcement( provider, username, print_logs, start_date, end_date) if print_logs: celery_logger.removeHandler(consolehandler) return running_total
def delete(self, request, provider_uuid, identity_uuid, instance_id): """Authentication Required, TERMINATE the instance. Be careful, there is no going back once you've deleted an instance. """ user = request.user esh_driver = prepare_driver(request, provider_uuid, identity_uuid) if not esh_driver: return invalid_creds(provider_uuid, identity_uuid) try: esh_instance = esh_driver.get_instance(instance_id) except (socket_error, ConnectionFailure): return connection_failure(provider_uuid, identity_uuid) except InvalidCredsError: return invalid_creds(provider_uuid, identity_uuid) except Exception as exc: logger.exception("Encountered a generic exception. " "Returning 409-CONFLICT") return failure_response(status.HTTP_409_CONFLICT, str(exc.message)) try: # Test that there is not an attached volume BEFORE we destroy task.destroy_instance_task(user, esh_instance, identity_uuid) invalidate_cached_instances(identity=Identity.objects.get(uuid=identity_uuid)) existing_instance = esh_driver.get_instance(instance_id) if existing_instance: # Instance will be deleted soon... esh_instance = existing_instance if esh_instance.extra and "task" not in esh_instance.extra: esh_instance.extra["task"] = "queueing delete" except VolumeAttachConflict as exc: message = exc.message return failure_response(status.HTTP_409_CONFLICT, message) except (socket_error, ConnectionFailure): return connection_failure(provider_uuid, identity_uuid) except InvalidCredsError: return invalid_creds(provider_uuid, identity_uuid) except Exception as exc: logger.exception("Encountered a generic exception. " "Returning 409-CONFLICT") return failure_response(status.HTTP_409_CONFLICT, str(exc.message)) try: core_instance = convert_esh_instance(esh_driver, esh_instance, provider_uuid, identity_uuid, user) if core_instance: core_instance.end_date_all() else: logger.warn("Unable to find core instance %s." % (instance_id)) serialized_data = InstanceSerializer(core_instance, context={"request": request}).data response = Response(serialized_data, status=status.HTTP_200_OK) response["Cache-Control"] = "no-cache" return response except (Identity.DoesNotExist) as exc: return failure_response(status.HTTP_400_BAD_REQUEST, "Invalid provider_uuid or identity_uuid.") except (socket_error, ConnectionFailure): return connection_failure(provider_uuid, identity_uuid) except InvalidCredsError: return invalid_creds(provider_uuid, identity_uuid)
def get_core_instances(identity_id): identity = CoreIdentity.objects.get(id=identity_id) driver = get_esh_driver(identity) instances = driver.list_instances() core_instances = [ convert_esh_instance(driver, esh_instance, identity.provider.id, identity.id, identity.created_by) for esh_instance in instances ] return core_instances
def monitor_instances_for(provider_id, users=None, print_logs=False, start_date=None, end_date=None): """ Run the set of tasks related to monitoring instances for a provider. Optionally, provide a list of usernames to monitor While debugging, print_logs=True can be very helpful. start_date and end_date allow you to search a 'non-standard' window of time. """ provider = Provider.objects.get(id=provider_id) # For now, lets just ignore everything that isn't openstack. if 'openstack' not in provider.type.name.lower(): return instance_map = _get_instance_owner_map(provider, users=users) if print_logs: console_handler = _init_stdout_logging() seen_instances = [] # DEVNOTE: Potential slowdown running multiple functions # Break this out when instance-caching is enabled if not settings.ENFORCING: celery_logger.debug('Settings dictate allocations are NOT enforced') for tenant_name in sorted(instance_map.keys()): running_instances = instance_map[tenant_name] identity = _get_identity_from_tenant_name(provider, tenant_name) if identity and running_instances: try: driver = get_cached_driver(identity=identity) core_running_instances = [ convert_esh_instance( driver, inst, identity.provider.uuid, identity.uuid, identity.created_by) for inst in running_instances] seen_instances.extend(core_running_instances) except Exception as exc: celery_logger.exception( "Could not convert running instances for %s" % tenant_name) continue else: # No running instances. core_running_instances = [] # Using the 'known' list of running instances, cleanup the DB core_instances = _cleanup_missing_instances( identity, core_running_instances) if print_logs: _exit_stdout_logging(console_handler) # return seen_instances NOTE: this has been commented out to avoid PicklingError! # TODO: Uncomment the above, Determine what _we can return_ and return that instead.... return
def put(self, request, provider_uuid, identity_uuid, instance_id): """Authentication Required, update metadata about the instance""" user = request.user data = request.data # Ensure item exists on the server first esh_driver = prepare_driver(request, provider_uuid, identity_uuid) if not esh_driver: return invalid_creds(provider_uuid, identity_uuid) if not can_use_instance(user, instance_id, leader_required=True): return member_action_forbidden(user.username, instance_id) try: esh_instance = esh_driver.get_instance(instance_id) except (socket_error, ConnectionFailure): return connection_failure(provider_uuid, identity_uuid) except LibcloudInvalidCredsError: return invalid_creds(provider_uuid, identity_uuid) except Exception as exc: logger.exception("Encountered a generic exception. " "Returning 409-CONFLICT") return failure_response(status.HTTP_409_CONFLICT, str(exc.message)) if not esh_instance: return instance_not_found(instance_id) # Gather the DB related item and update core_instance = convert_esh_instance(esh_driver, esh_instance, provider_uuid, identity_uuid, user) serializer = InstanceSerializer(core_instance, data=data, context={"request": request}) identity = Identity.objects.get(uuid=identity_uuid) if serializer.is_valid(): logger.info('metadata = %s' % data) #NOTE: We shouldn't allow 'full replacement' of metadata.. # We should also validate against potentional updating of 'atmo-used metadata' update_metadata.s(esh_driver.__class__, esh_driver.provider, esh_driver.identity, esh_instance.id, data, replace_metadata=False).apply() new_instance = serializer.save() boot_scripts = data.pop('boot_scripts', []) if boot_scripts: new_instance = _save_scripts_to_instance(new_instance, boot_scripts) serializer = InstanceSerializer( new_instance, context={"request": request}) invalidate_cached_instances(identity=identity) response = Response(serializer.data) logger.info('data = %s' % serializer.data) response['Cache-Control'] = 'no-cache' return response else: return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
def launch_instance(user, provider_id, identity_id, size_alias, machine_alias, **kwargs): """ Required arguments will launch the instance, extras will do provider-specific modifications. Test the quota, Launch the instance, creates a core repr and updates status. returns a core_instance object after updating core DB. """ now_time = datetime.now().strftime("%Y-%m-%d %H:%M:%S") if machine_alias: alias = "machine,%s" % machine_alias elif 'volume_alias' in kwargs: alias = "boot_volume,%s" % kwargs['volume_alias'] else: raise Exception("Not enough data to launch: " "volume_alias/machine_alias is missing") status_logger.debug("%s,%s,%s,%s,%s,%s" % (now_time, user, "No Instance", alias, size_alias, "Request Received")) core_identity = CoreIdentity.objects.get(id=identity_id) esh_driver = get_esh_driver(core_identity, user) size = esh_driver.get_size(size_alias) #May raise SizeNotAvailable check_size(size, provider_id) #May raise OverQuotaError or OverAllocationError check_quota(user.username, identity_id, size) #May raise InvalidCredsError (esh_instance, token, password) = launch_esh_instance(esh_driver, machine_alias, size_alias, core_identity, **kwargs) #Convert esh --> core core_instance = convert_esh_instance( esh_driver, esh_instance, provider_id, identity_id, user, token, password) esh_size = esh_driver.get_size(esh_instance.size.id) core_size = convert_esh_size(esh_size, provider_id) core_instance.update_history( core_instance.esh.extra['status'], core_size, #3rd arg is task OR tmp_status core_instance.esh.extra.get('task') or core_instance.esh.extra.get('metadata', {}).get('tmp_status'), first_update=True) return core_instance
def _complete_launch_instance(driver, identity, instance, user, token, password, deploy=True): from service import task #Create the Core/DB for instance core_instance = convert_esh_instance( driver, instance, identity.provider.uuid, identity.uuid, user, token, password) # call async task to deploy to instance. task.deploy_init_task(driver, instance, identity, user.username, password, token, deploy=deploy) #Update InstanceStatusHistory _first_update(driver, identity, core_instance, instance) #Invalidate and return invalidate_cached_instances(identity=identity) return core_instance
def patch(self, request, provider_uuid, identity_uuid, instance_id): """Authentication Required, update metadata about the instance""" user = request.user data = request.data esh_driver = prepare_driver(request, provider_uuid, identity_uuid) if not esh_driver: return invalid_creds(provider_uuid, identity_uuid) try: esh_instance = esh_driver.get_instance(instance_id) except (socket_error, ConnectionFailure): return connection_failure(provider_uuid, identity_uuid) except InvalidCredsError: return invalid_creds(provider_uuid, identity_uuid) except Exception as exc: logger.exception("Encountered a generic exception. " "Returning 409-CONFLICT") return failure_response(status.HTTP_409_CONFLICT, str(exc.message)) if not esh_instance: return instance_not_found(instance_id) # Gather the DB related item and update core_instance = convert_esh_instance(esh_driver, esh_instance, provider_uuid, identity_uuid, user) serializer = InstanceSerializer( core_instance, data=data, context={"request": request}, partial=True) identity = Identity.objects.get(uuid=identity_uuid) provider = identity.provider if serializer.is_valid(): logger.info('metadata = %s' % data) driver_class = esh_driver.__class__ update_metadata.s(driver_class, provider, identity, esh_instance.id, data, replace_metadata=False).apply() instance = serializer.save() boot_scripts = data.pop('boot_scripts', []) if boot_scripts: _save_scripts_to_instance(instance, boot_scripts) invalidate_cached_instances(identity=identity) response = Response(serializer.data) logger.info('data = %s' % serializer.data) response['Cache-Control'] = 'no-cache' return response else: return Response( serializer.errors, status=status.HTTP_400_BAD_REQUEST)
def put(self, request, provider_uuid, identity_uuid, instance_id): """Authentication Required, update metadata about the instance""" user = request.user data = request.DATA # Ensure item exists on the server first esh_driver = prepare_driver(request, provider_uuid, identity_uuid) if not esh_driver: return invalid_creds(provider_uuid, identity_uuid) try: esh_instance = esh_driver.get_instance(instance_id) except ConnectionFailure: return connection_failure(provider_uuid, identity_uuid) except InvalidCredsError: return invalid_creds(provider_uuid, identity_uuid) except Exception as exc: logger.exception("Encountered a generic exception. " "Returning 409-CONFLICT") return failure_response(status.HTTP_409_CONFLICT, str(exc.message)) if not esh_instance: return instance_not_found(instance_id) # Gather the DB related item and update core_instance = convert_esh_instance(esh_driver, esh_instance, provider_uuid, identity_uuid, user) serializer = InstanceSerializer(core_instance, data=data, context={"request": request}) if serializer.is_valid(): logger.info('metadata = %s' % data) update_instance_metadata(esh_driver, esh_instance, data) serializer.save() new_instance = serializer.object boot_scripts = data.pop('boot_scripts', []) if boot_scripts: new_instance = _save_scripts_to_instance(new_instance, boot_scripts) serializer = InstanceSerializer( new_instance, context={"request": request}) invalidate_cached_instances( identity=Identity.objects.get( uuid=identity_uuid)) response = Response(serializer.data) logger.info('data = %s' % serializer.data) response['Cache-Control'] = 'no-cache' return response else: return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
def current_instance_time(user, instances, identity_id, delta_time): """ Add all running instances to core, so that the database is up to date before calling 'core_instance_time' """ from api import get_esh_driver ident = Identity.objects.get(id=identity_id) driver = get_esh_driver(ident) core_instance_list = [ convert_esh_instance(driver, inst, ident.provider.id, ident.id, user) for inst in instances] #All instances that don't have an end-date should be #included, even if all of their time is not. time_used = core_instance_time(user, ident.id, delta_time, running=core_instance_list) return time_used
def get(self, request, provider_uuid, identity_uuid, instance_id): """ Authentication Required, get instance details. """ user = request.user # NOTE: This 'Scheme' should be used across # the ENTIRE API v1 (Machines, Volumes, Sizes) # NOTE: Especially the part below, where you end date # all the things that are 'inactive' try: provider = Provider.objects.get(uuid=provider_uuid) except Provider.DoesNotExist: return invalid_creds(provider_uuid, identity_uuid) if provider.is_active(): esh_driver = prepare_driver(request, provider_uuid, identity_uuid) try: esh_instance = esh_driver.get_instance(instance_id) except (socket_error, ConnectionFailure): return connection_failure(provider_uuid, identity_uuid) except InvalidCredsError: return invalid_creds(provider_uuid, identity_uuid) except Exception as exc: logger.exception("Encountered a generic exception. " "Returning 409-CONFLICT") return failure_response(status.HTTP_409_CONFLICT, str(exc.message)) else: esh_instance = None # NOTE: Especially THIS part below, where you end date all the # things that are 'inactive' if not esh_instance: try: core_inst = CoreInstance.objects.get( provider_alias=instance_id, source__provider__uuid=provider_uuid, created_by_identity__uuid=identity_uuid, ) core_inst.end_date_all() except CoreInstance.DoesNotExist: pass return instance_not_found(instance_id) core_instance = convert_esh_instance(esh_driver, esh_instance, provider_uuid, identity_uuid, user) serialized_data = InstanceSerializer(core_instance, context={"request": request}).data response = Response(serialized_data) response["Cache-Control"] = "no-cache" return response
def get(self, request, provider_id, identity_id, instance_id): """ Return the object belonging to this instance ID TODO: Filter out instances you shouldnt see (permissions..) """ user = request.user esh_driver = prepare_driver(request, provider_id, identity_id) if not esh_driver: return invalid_creds(provider_id, identity_id) esh_instance = esh_driver.get_instance(instance_id) if not esh_instance: return instance_not_found(instance_id) core_instance = convert_esh_instance(esh_driver, esh_instance, provider_id, identity_id, user) serialized_data = InstanceSerializer(core_instance).data response = Response(serialized_data) response['Cache-Control'] = 'no-cache' return response
def get(self, request, provider_id, identity_id, instance_id): """ Authentication Required, get instance details. """ user = request.user esh_driver = prepare_driver(request, provider_id, identity_id) if not esh_driver: return invalid_creds(provider_id, identity_id) esh_instance = esh_driver.get_instance(instance_id) if not esh_instance: return instance_not_found(instance_id) core_instance = convert_esh_instance(esh_driver, esh_instance, provider_id, identity_id, user) serialized_data = InstanceSerializer(core_instance, context={"request":request}).data response = Response(serialized_data) response['Cache-Control'] = 'no-cache' return response
def update_status(esh_driver, instance_id, provider_id, identity_id, user): """ All that this method really does is: * Query for the instance * call 'convert_esh_instance' Converting the instance internally updates the status history.. But it makes more sense to call this function in the code.. """ # Grab a new copy of the instance if AccountProvider.objects.filter(identity__id=identity_id): esh_instance = admin_get_instance(esh_driver, instance_id) else: esh_instance = esh_driver.get_instance(instance_id) if not esh_instance: return None # Convert & Update based on new status change core_instance = convert_esh_instance(esh_driver, esh_instance, provider_id, identity_id, user)
def post(self, request, provider_id, identity_id, volume_id=None): user = request.user data = request.DATA missing_keys = valid_launch_data(data) if missing_keys: return keys_not_found(missing_keys) esh_driver = prepare_driver(request, provider_id, identity_id) if not esh_driver: return invalid_creds(provider_id, identity_id) source = None name = data.pop('name') size_id = data.pop('size') (source_type, get_source, source_id) = self._select_source(esh_driver, data) if not get_source: return failure_response( status.HTTP_400_BAD_REQUEST, 'Source could not be acquired. Did you send: [' 'snapshot_id/volume_id/image_id] ?') source = get_source(source_id) if not source: return failure_response( status.HTTP_404_NOT_FOUND, "%s %s does not exist" % (source_type.title(), source_id)) size = esh_driver.get_size(size_id) if not size: return failure_response( status.HTTP_404_NOT_FOUND, "Size %s does not exist" % (size_id,)) esh_instance = boot_volume(esh_driver, identity_id, name, size, source, source_type, **data) core_instance = convert_esh_instance(esh_driver, esh_instance, provider_id, identity_id, user) serialized_data = InstanceSerializer(core_instance, context={'request': request}).data response = Response(serialized_data) return response
def get(self, request, provider_uuid, identity_uuid): """ Returns a list of all instances """ user = request.user try: esh_driver = prepare_driver(request, provider_uuid, identity_uuid) except ProviderNotActive as pna: return inactive_provider(pna) except Exception as e: return failure_response( status.HTTP_409_CONFLICT, e.message) if not esh_driver: return invalid_creds(provider_uuid, identity_uuid) identity = Identity.objects.get(uuid=identity_uuid) # Probably redundant if not user.can_use_identity(identity.id): return invalid_creds(provider_uuid, identity_uuid) try: esh_instance_list = get_cached_instances(identity=identity) except MalformedResponseError: return malformed_response(provider_uuid, identity_uuid) except (socket_error, ConnectionFailure): return connection_failure(provider_uuid, identity_uuid) except InvalidCredsError: return invalid_creds(provider_uuid, identity_uuid) core_instance_list = [convert_esh_instance(esh_driver, inst, provider_uuid, identity_uuid, user) for inst in esh_instance_list] # TODO: Core/Auth checks for shared instances serialized_data = InstanceSerializer(core_instance_list, context={"request": request}, many=True).data response = Response(serialized_data) response['Cache-Control'] = 'no-cache' return response
def launch_instance(user, provider_id, identity_id, size_alias, machine_alias, **kwargs): """ Required arguments will launch the instance, extras will do provider-specific modifications. Test the quota, Launch the instance, creates a core repr and updates status. returns a core_instance object after updating core DB. """ core_identity = CoreIdentity.objects.get(id=identity_id) esh_driver = get_esh_driver(core_identity, user) size = esh_driver.get_size(size_alias) #May raise SizeNotAvailable check_size(size, provider_id) #May raise OverQuotaError or OverAllocationError check_quota(user.username, identity_id, size) #May raise InvalidCredsError (esh_instance, token, password) = launch_esh_instance(esh_driver, machine_alias, size_alias, core_identity, **kwargs) #Convert esh --> core core_instance = convert_esh_instance( esh_driver, esh_instance, provider_id, identity_id, user, token, password) core_instance.update_history( core_instance.esh.extra['status'], #2nd arg is task OR tmp_status core_instance.esh.extra.get('task') or core_instance.esh.extra.get('metadata', {}).get('tmp_status'), first_update=True) return core_instance
def get(self, request, provider_uuid, identity_uuid): """ Returns a list of all instances """ user = request.user try: esh_driver = prepare_driver(request, provider_uuid, identity_uuid) except ProviderNotActive as pna: return inactive_provider(pna) except Exception as e: return failure_response(status.HTTP_409_CONFLICT, e.message) if not esh_driver: return invalid_creds(provider_uuid, identity_uuid) identity = Identity.objects.get(uuid=identity_uuid) # Probably redundant if not user.can_use_identity(identity.id): return invalid_creds(provider_uuid, identity_uuid) try: esh_instance_list = get_cached_instances(identity=identity) except LibcloudBadResponseError: return malformed_response(provider_uuid, identity_uuid) except (socket_error, ConnectionFailure): return connection_failure(provider_uuid, identity_uuid) except LibcloudInvalidCredsError: return invalid_creds(provider_uuid, identity_uuid) core_instance_list = [ convert_esh_instance(esh_driver, inst, provider_uuid, identity_uuid, user) for inst in esh_instance_list ] # TODO: Core/Auth checks for shared instances serialized_data = InstanceSerializer(core_instance_list, context={ "request": request }, many=True).data response = Response(serialized_data) response['Cache-Control'] = 'no-cache' return response
def update_status(esh_driver, instance_id, provider_uuid, identity_uuid, user): """ All that this method really does is: * Query for the instance * call 'convert_esh_instance' Converting the instance internally updates the status history.. But it makes more sense to call this function in the code.. """ #Grab a new copy of the instance if AccountProvider.objects.filter(identity__uuid=identity_uuid): esh_instance = admin_get_instance(esh_driver, instance_id) else: esh_instance = esh_driver.get_instance(instance_id) if not esh_instance: return None #Convert & Update based on new status change core_instance = convert_esh_instance(esh_driver, esh_instance, provider_uuid, identity_uuid, user)
def get(self, request, provider_uuid, identity_uuid, instance_id): """ Authentication Required, get instance details. """ user = request.user esh_driver = prepare_driver(request, provider_uuid, identity_uuid) if not esh_driver: return invalid_creds(provider_uuid, identity_uuid) try: esh_instance = esh_driver.get_instance(instance_id) except (socket_error, ConnectionFailure): return connection_failure(provider_uuid, identity_uuid) except InvalidCredsError: return invalid_creds(provider_uuid, identity_uuid) except Exception as exc: logger.exception("Encountered a generic exception. " "Returning 409-CONFLICT") return failure_response(status.HTTP_409_CONFLICT, str(exc.message)) if not esh_instance: try: core_inst = CoreInstance.objects.get( provider_alias=instance_id, source__provider__uuid=provider_uuid, created_by_identity__uuid=identity_uuid) core_inst.end_date_all() except CoreInstance.DoesNotExist: pass return instance_not_found(instance_id) core_instance = convert_esh_instance(esh_driver, esh_instance, provider_uuid, identity_uuid, user) serialized_data = InstanceSerializer( core_instance, context={"request": request}).data response = Response(serialized_data) response['Cache-Control'] = 'no-cache' return response
def get(self, request, provider_id, identity_id): """ Returns a list of all instances """ user = request.user esh_driver = prepare_driver(request, provider_id, identity_id) if not esh_driver: return invalid_creds(provider_id, identity_id) identity = Identity.objects.get(id=identity_id) esh_instance_list = get_cached_instances(identity=identity) core_instance_list = [ convert_esh_instance(esh_driver, inst, provider_id, identity_id, user) for inst in esh_instance_list ] #TODO: Core/Auth checks for shared instances serialized_data = InstanceSerializer(core_instance_list, context={ "request": request }, many=True).data response = Response(serialized_data) response['Cache-Control'] = 'no-cache' return response
def suspend_all_instances_for(identity, user): driver = get_cached_driver(identity=identity) esh_instances = driver.list_instances() for instance in esh_instances: try: if driver._is_active_instance(instance): #Suspend active instances, update the task in the DB driver.suspend_instance(instance) #NOTE: Intentionally added to allow time for # the Cloud to begin 'suspend' operation # before querying for the instance again. time = random.uniform(2,6) time.sleep(time) updated_esh = driver.get_instance(instance.id) updated_core = convert_esh_instance( driver, updated_esh, identity.provider.uuid, identity.uuid, user) except Exception, e: #Raise ANY exception that doesn't say #'This instance is already suspended' if 'in vm_state suspended' not in e.message: raise
def put(self, request, provider_uuid, identity_uuid, instance_id): """Authentication Required, update metadata about the instance""" user = request.user data = request.DATA #Ensure item exists on the server first esh_driver = prepare_driver(request, provider_uuid, identity_uuid) if not esh_driver: return invalid_creds(provider_uuid, identity_uuid) esh_instance = esh_driver.get_instance(instance_id) if not esh_instance: return instance_not_found(instance_id) #Gather the DB related item and update core_instance = convert_esh_instance(esh_driver, esh_instance, provider_uuid, identity_uuid, user) serializer = InstanceSerializer(core_instance, data=data, context={"request":request}) if serializer.is_valid(): logger.info('metadata = %s' % data) update_instance_metadata(esh_driver, esh_instance, data) serializer.save() new_instance = serializer.object boot_scripts = data.pop('boot_scripts', []) if boot_scripts: new_instance = _save_scripts_to_instance(new_instance, boot_scripts) serializer = InstanceSerializer(new_instance, context={"request":request}) invalidate_cached_instances( identity=Identity.objects.get( uuid=identity_uuid)) response = Response(serializer.data) logger.info('data = %s' % serializer.data) response['Cache-Control'] = 'no-cache' return response else: return Response(serializer.errors, status=status.HTTP_400_BAD_REQUEST)
def delete(self, request, provider_uuid, identity_uuid, instance_id): """Authentication Required, TERMINATE the instance. Be careful, there is no going back once you've deleted an instance. """ user = request.user esh_driver = prepare_driver(request, provider_uuid, identity_uuid) if not esh_driver: return invalid_creds(provider_uuid, identity_uuid) try: esh_instance = esh_driver.get_instance(instance_id) except (socket_error, ConnectionFailure): return connection_failure(provider_uuid, identity_uuid) except LibcloudInvalidCredsError: return invalid_creds(provider_uuid, identity_uuid) except Exception as exc: logger.exception("Encountered a generic exception. " "Returning 409-CONFLICT") return failure_response(status.HTTP_409_CONFLICT, str(exc.message)) try: # Test that there is not an attached volume BEFORE we destroy task.destroy_instance_task(user, esh_instance, identity_uuid) invalidate_cached_instances(identity=Identity.objects.get( uuid=identity_uuid)) existing_instance = esh_driver.get_instance(instance_id) if existing_instance: # Instance will be deleted soon... esh_instance = existing_instance if esh_instance.extra\ and 'task' not in esh_instance.extra: esh_instance.extra['task'] = 'queueing delete' except VolumeAttachConflict as exc: message = exc.message return failure_response(status.HTTP_409_CONFLICT, message) except (socket_error, ConnectionFailure): return connection_failure(provider_uuid, identity_uuid) except LibcloudInvalidCredsError: return invalid_creds(provider_uuid, identity_uuid) except InstanceDoesNotExist as dne: return failure_response( status.HTTP_404_NOT_FOUND, 'Instance %s no longer exists' % (dne.message, )) except Exception as exc: logger.exception("Encountered a generic exception. " "Returning 409-CONFLICT") return failure_response(status.HTTP_409_CONFLICT, str(exc.message)) try: core_instance = convert_esh_instance(esh_driver, esh_instance, provider_uuid, identity_uuid, user) if core_instance: core_instance.end_date_all() else: logger.warn("Unable to find core instance %s." % (instance_id)) serialized_data = InstanceSerializer(core_instance, context={ "request": request }).data response = Response(serialized_data, status=status.HTTP_200_OK) response['Cache-Control'] = 'no-cache' return response except (Identity.DoesNotExist) as exc: return failure_response(status.HTTP_400_BAD_REQUEST, "Invalid provider_uuid or identity_uuid.") except (socket_error, ConnectionFailure): return connection_failure(provider_uuid, identity_uuid) except LibcloudInvalidCredsError: return invalid_creds(provider_uuid, identity_uuid)