def test_generate_aws_events_with_args_and_some_times(self): """Assert generation of InstanceEvents with all specified args.""" account = helper.generate_cloud_account() ec2_ami_id = util_helper.generate_dummy_image_id() image = helper.generate_image(ec2_ami_id=ec2_ami_id) instance = helper.generate_instance(account, image=image) powered_times = ( (None, util_helper.utc_dt(2017, 1, 1)), (util_helper.utc_dt(2017, 1, 2), util_helper.utc_dt(2017, 1, 3)), (util_helper.utc_dt(2017, 1, 4), None), ) instance_type = util_helper.get_random_instance_type() subnet = str(uuid.uuid4()) events = helper.generate_instance_events( instance, powered_times, instance_type=instance_type, subnet=subnet, ) self.assertEqual(len(events), 4) # We don't care to check *everything* in the events since that should # already be covered by ``test_generate_events_with_some_times``. # Here we only care that argument values were set correctly. for event in events: if event.event_type != event.TYPE.power_off: self.assertEqual( event.instance.machine_image.content_object.ec2_ami_id, ec2_ami_id ) self.assertEqual(event.content_object.instance_type, instance_type) self.assertEqual(event.content_object.subnet, subnet)
def generate_single_instance_event( instance, occurred_at, event_type=None, instance_type=None, subnet=None, no_instance_type=False, no_subnet=False, cloud_type=AWS_PROVIDER_STRING, ): """ Generate single AwsInstanceEvent for testing. The ``powered_time`` is a datetime.datetime that defines when the instance event (either powering on or powering off) occurred. Args: instance (Instance): instance that owns the events. occurred_at (datetime.datetime): Time that the instance occurred. event_type (str): AWS event type instance_type (str): Optional AWS instance type. subnet (str): Optional subnet ID where instance runs. no_instance_type (bool): If true, don't assign an instance type. no_subnet (bool): If true, don't create and assign a subnet. Returns: AwsInstanceEvent: The created AwsInstanceEvent. """ if no_instance_type: instance_type = None elif instance_type is None: instance_type = helper.get_random_instance_type(cloud_type=cloud_type) if event_type is None: event_type = InstanceEvent.TYPE.power_off if cloud_type == AZURE_PROVIDER_STRING: cloud_provider_event = AzureInstanceEvent.objects.create( instance_type=instance_type, ) else: if no_subnet: subnet = None elif subnet is None: subnet = helper.generate_dummy_subnet_id() cloud_provider_event = AwsInstanceEvent.objects.create( subnet=subnet, instance_type=instance_type, ) event = InstanceEvent.objects.create( instance=instance, event_type=event_type, occurred_at=occurred_at, content_object=cloud_provider_event, ) return event
def create_random_definition(self): """Create and save a random definition.""" InstanceDefinition.objects.create( instance_type=helper.get_random_instance_type(), memory=random.randrange(4), vcpu=random.randrange(4), json_definition='{"test": "data"}', cloud_type="aws", )
def generate_cloudtrail_instance_event( instance, occurred_at, event_type=None, instance_type=None, subnet=None, no_instance_type=False, no_subnet=False, ): """ Generate a single CloudTrailInstanceEvent for testing. Any optional arguments not provided will be randomly generated. Args: instance (Instance): instance that owns the events. occurred_at (datetime): Time periods the instance is powered on. instance_type (str): Optional AWS instance type. subnet (str): Optional subnet ID where instance runs. no_instance_type (bool): If true, instance_type is not set Returns: CloudTrailInstanceEvent: The created CloudTrailInstanceEvent. """ if no_instance_type: instance_type = None elif instance_type is None: instance_type = helper.get_random_instance_type() if no_subnet: subnet = None elif subnet is None: subnet = helper.generate_dummy_subnet_id() if event_type is None: event_type = InstanceEvent.TYPE.power_off event = CloudTrailInstanceEvent( occurred_at=occurred_at, event_type=event_type, instance_type=instance_type, aws_account_id=instance.cloud_account.id, region=instance.machine_image.content_object.region, ec2_instance_id=instance.content_object.ec2_instance_id, ec2_ami_id=instance.machine_image.content_object.ec2_ami_id, subnet_id=subnet, ) return event
def test_generate_dummy_describe_instance_with_values(self): """Assert generated instance contains given values.""" image_id = helper.generate_dummy_image_id() instance_id = helper.generate_dummy_instance_id() subnet_id = helper.generate_dummy_subnet_id() state = aws.InstanceState.shutting_down instance_type = helper.get_random_instance_type() device_mapping = helper.generate_dummy_block_device_mapping() instance = helper.generate_dummy_describe_instance( instance_id=instance_id, image_id=image_id, subnet_id=subnet_id, state=state, instance_type=instance_type, device_mappings=[device_mapping], ) self.assertEqual(instance["ImageId"], image_id) self.assertEqual(instance["InstanceId"], instance_id) self.assertEqual(instance["InstanceType"], instance_type) self.assertEqual(instance["SubnetId"], subnet_id) self.assertEqual(instance["State"]["Code"], state.value) self.assertEqual(instance["State"]["Name"], state.name) self.assertEqual(instance["State"]["Name"], state.name) self.assertEqual(instance["BlockDeviceMappings"], [device_mapping])
def test_new_run_deletes_concurrent_usage(self): """ Test that creating a new run deletes the right ConcurrentUsage. When a run is saved that is related to ConcurrentUsage through the potentially_related_runs field, ensure those ConcurrentUsages are deleted. Creating a new Run should not remove ConcurrentUsages with no related runs. """ user = util_helper.generate_test_user() aws_account_id = util_helper.generate_dummy_aws_account_id() account = api_helper.generate_cloud_account( aws_account_id=aws_account_id, user=user, ) image = api_helper.generate_image( owner_aws_account_id=aws_account_id, rhel_detected=True, ) instance = api_helper.generate_instance(account, image=image) instance_type = util_helper.get_random_instance_type() start_time = util_helper.utc_dt(2019, 5, 1, 1, 0, 0) end_time = util_helper.utc_dt(2019, 5, 1, 2, 0, 0) request_date = datetime.date(2019, 5, 1) # Calculating maximum usage for no runs generates one concurrent usage # with empty counts calculate_max_concurrent_usage(request_date, user_id=user.id) self.assertEqual(1, ConcurrentUsage.objects.all().count()) self.assertEqual("[]", ConcurrentUsage.objects.all()[0]._maximum_counts) # Create a run run = Run.objects.create( start_time=start_time, end_time=end_time, instance=instance, machineimage=image, instance_type=instance_type, vcpu=util_helper.SOME_EC2_INSTANCE_TYPES[instance_type]["vcpu"], memory=util_helper.SOME_EC2_INSTANCE_TYPES[instance_type] ["memory"], ) # Creating a run should not delete the empty concurrent usage # since that concurrent usage isn't related to this run self.assertEqual(1, ConcurrentUsage.objects.all().count()) self.assertEqual("[]", ConcurrentUsage.objects.all()[0]._maximum_counts) # recalculating the maximum concurrent usage results in a nonempty # ConcurrentUsage maximum_counts calculate_max_concurrent_usage(request_date, user_id=user.id) self.assertNotEqual("[]", ConcurrentUsage.objects.all()[0]._maximum_counts) # Re-saving the run should remove the related the concurrent usage. run.save() self.assertEqual(0, ConcurrentUsage.objects.all().count())
def generate_single_run( instance, runtime, image=None, no_image=False, instance_type=None, no_instance_type=False, calculate_concurrent_usage=True, ): """ Generate a single Run (and related events) for testing. Args: instance (Instance): instance that was ran. runtime (tuple(datetime.datetime, datetime.datetime)): time the run occured. image (Image): image that was ran. no_image (bool): If true, don't create and assign an image. instance_type (str): Optional AWS instance type. no_instance_type (bool): Optional indication that instance has no type. calculate_concurrent_usage (bool): Optional indicated if after creating the run we should run calculate_max_concurrent_usage_from_runs. Returns: Run: The created Run. """ if no_instance_type: instance_type = None elif instance_type is None: instance_type = helper.get_random_instance_type() if not no_image and image is None: image = generate_image() run = Run.objects.create( start_time=runtime[0], end_time=runtime[1], instance=instance, machineimage=image, instance_type=instance_type, vcpu=helper.SOME_EC2_INSTANCE_TYPES[instance_type]["vcpu"] if instance_type in helper.SOME_EC2_INSTANCE_TYPES else None, memory=helper.SOME_EC2_INSTANCE_TYPES[instance_type]["memory"] if instance_type in helper.SOME_EC2_INSTANCE_TYPES else None, ) generate_single_instance_event( instance=instance, occurred_at=runtime[0], event_type=InstanceEvent.TYPE.power_on, instance_type=instance_type, no_instance_type=no_instance_type, ) if runtime[1]: generate_single_instance_event( instance=instance, occurred_at=runtime[1], event_type=InstanceEvent.TYPE.power_off, instance_type=instance_type, no_instance_type=no_instance_type, ) if calculate_concurrent_usage: # Calculate the runs directly instead of scheduling a task for testing purposes with patch("api.util.schedule_concurrent_calculation_task" ) as mock_schedule_concurrent_task: mock_schedule_concurrent_task.side_effect = calculate_max_concurrent_usage calculate_max_concurrent_usage_from_runs([run]) return run
def generate_instance_events( instance, powered_times, instance_type=None, subnet=None, no_instance_type=False, cloud_type=AWS_PROVIDER_STRING, ): """ Generate list of InstanceEvents for the Instance for testing. Any optional arguments not provided will be randomly generated. The ``powered_times`` defines when the instance should be considered running for sake of the event types. The first element of the tuple is a datetime.datetime of when a "power on" event occurs, and the second element is a datetime.datetime of when a "power off" event occurs. Power-off events will never be created with an image defined in this helper function because in most real-world cases they do not have one. Args: instance (Instance): instance that owns the events. powered_times (list[tuple]): Time periods the instance is powered on. instance_type (str): Optional AWS instance type. subnet (str): Optional subnet ID where instance runs. no_instance_type (bool): If true, instance_type is not set Returns: list(InstanceEvent): The list of created AwsInstanceEvents. """ if no_instance_type: instance_type = None elif instance_type is None: instance_type = helper.get_random_instance_type(cloud_type=cloud_type) if subnet is None: subnet = helper.generate_dummy_subnet_id() events = [] for power_on_time, power_off_time in powered_times: if power_on_time is not None: event = generate_single_instance_event( instance=instance, occurred_at=power_on_time, event_type=InstanceEvent.TYPE.power_on, instance_type=instance_type, subnet=subnet, no_instance_type=no_instance_type, cloud_type=cloud_type, ) events.append(event) if power_off_time is not None: # power_off events typically do *not* have an image defined. # So, ignore inputs and *always* set ec2_ami_id=None. event = generate_single_instance_event( instance=instance, occurred_at=power_off_time, event_type=InstanceEvent.TYPE.power_off, instance_type=instance_type, subnet=subnet, no_instance_type=no_instance_type, cloud_type=cloud_type, ) events.append(event) return events