Search in sources :

Example 16 with InstanceDefinition

use of org.finra.herd.model.api.xml.InstanceDefinition in project herd by FINRAOS.

the class EmrPricingHelper method updateEmrClusterDefinitionWithBestPrice.

/**
 * Finds the best price for each master and core instances based on the subnets and master and core instance search parameters given in the definition.
 * <p/>
 * The results of the findings are used to update the given definition.
 * <p/>
 * If the instance's instanceSpotPrice is set, the instance definition will keep that value. If the instance's instanceMaxSearchPrice is set, the best price
 * will be found. If the found price is spot, the instanceSpotPrice will be set to the value of instanceMaxSearchPrice. If the found price is on-demand, the
 * instanceSpotPrice will be removed. The definition's subnetId will be set to the particular subnet which the best price is found. The value will always be
 * replaced by a single subnet ID.
 * <p/>
 * The definition's instanceMaxSearchPrice and instanceOnDemandThreshold will be removed by this operation.
 *
 * @param emrClusterAlternateKeyDto EMR cluster alternate key
 * @param emrClusterDefinition The EMR cluster definition with search criteria, and the definition that will be updated
 * @param awsParamsDto the AWS related parameters for access/secret keys and proxy details
 */
public void updateEmrClusterDefinitionWithBestPrice(EmrClusterAlternateKeyDto emrClusterAlternateKeyDto, EmrClusterDefinition emrClusterDefinition, AwsParamsDto awsParamsDto) {
    EmrVpcPricingState emrVpcPricingState = new EmrVpcPricingState();
    // Get total count of instances this definition will attempt to create
    int totalInstanceCount = getTotalInstanceCount(emrClusterDefinition);
    // Get the subnet information
    List<Subnet> subnets = getSubnets(emrClusterDefinition, awsParamsDto);
    for (Subnet subnet : subnets) {
        emrVpcPricingState.getSubnetAvailableIpAddressCounts().put(subnet.getSubnetId(), subnet.getAvailableIpAddressCount());
    }
    // Filter out subnets with not enough available IPs
    removeSubnetsWithAvailableIpsLessThan(subnets, totalInstanceCount);
    if (subnets.isEmpty()) {
        LOGGER.info(String.format("Insufficient IP availability. namespace=\"%s\" emrClusterDefinitionName=\"%s\" emrClusterName=\"%s\" " + "totalRequestedInstanceCount=%s emrVpcPricingState=%s", emrClusterAlternateKeyDto.getNamespace(), emrClusterAlternateKeyDto.getEmrClusterDefinitionName(), emrClusterAlternateKeyDto.getEmrClusterName(), totalInstanceCount, jsonHelper.objectToJson(emrVpcPricingState)));
        throw new ObjectNotFoundException(String.format("There are no subnets in the current VPC which have sufficient IP addresses available to run your " + "clusters. Try expanding the list of subnets or try again later. requestedInstanceCount=%s%n%s", totalInstanceCount, emrVpcPricingStateFormatter.format(emrVpcPricingState)));
    }
    // Best prices are accumulated in this list
    List<EmrClusterPriceDto> emrClusterPrices = new ArrayList<>();
    InstanceDefinition masterInstanceDefinition = getMasterInstanceDefinition(emrClusterDefinition);
    InstanceDefinition coreInstanceDefinition = getCoreInstanceDefinition(emrClusterDefinition);
    InstanceDefinition taskInstanceDefinition = getTaskInstanceDefinition(emrClusterDefinition);
    Set<String> requestedInstanceTypes = new HashSet<>();
    String masterInstanceType = masterInstanceDefinition.getInstanceType();
    requestedInstanceTypes.add(masterInstanceType);
    if (coreInstanceDefinition != null) {
        String coreInstanceType = coreInstanceDefinition.getInstanceType();
        requestedInstanceTypes.add(coreInstanceType);
    }
    if (taskInstanceDefinition != null) {
        String taskInstanceType = taskInstanceDefinition.getInstanceType();
        requestedInstanceTypes.add(taskInstanceType);
    }
    // Get AZs for the subnets
    for (AvailabilityZone availabilityZone : getAvailabilityZones(subnets, awsParamsDto)) {
        // Create a mapping of instance types to prices for more efficient, in-memory lookup
        // This method also validates that the given instance types are real instance types supported by AWS.
        Map<String, BigDecimal> instanceTypeOnDemandPrices = getInstanceTypeOnDemandPrices(availabilityZone, requestedInstanceTypes);
        // Create a mapping of instance types to prices for more efficient, in-memory lookup
        // When AWS does not return any spot price history for an instance type in an availability zone, the algorithm will not use that availability zone
        // when selecting the lowest price.
        Map<String, BigDecimal> instanceTypeSpotPrices = getInstanceTypeSpotPrices(availabilityZone, requestedInstanceTypes, awsParamsDto);
        emrVpcPricingState.getSpotPricesPerAvailabilityZone().put(availabilityZone.getZoneName(), instanceTypeSpotPrices);
        emrVpcPricingState.getOnDemandPricesPerAvailabilityZone().put(availabilityZone.getZoneName(), instanceTypeOnDemandPrices);
        // Get and compare master price
        BigDecimal masterSpotPrice = instanceTypeSpotPrices.get(masterInstanceType);
        BigDecimal masterOnDemandPrice = instanceTypeOnDemandPrices.get(masterInstanceType);
        Ec2PriceDto masterPrice = getBestInstancePrice(masterSpotPrice, masterOnDemandPrice, masterInstanceDefinition);
        // Get and compare core price
        Ec2PriceDto corePrice = null;
        if (coreInstanceDefinition != null) {
            String coreInstanceType = coreInstanceDefinition.getInstanceType();
            BigDecimal coreSpotPrice = instanceTypeSpotPrices.get(coreInstanceType);
            BigDecimal coreOnDemandPrice = instanceTypeOnDemandPrices.get(coreInstanceType);
            corePrice = getBestInstancePrice(coreSpotPrice, coreOnDemandPrice, coreInstanceDefinition);
        }
        // Get and compare task price
        Ec2PriceDto taskPrice = null;
        if (taskInstanceDefinition != null) {
            String taskInstanceType = taskInstanceDefinition.getInstanceType();
            BigDecimal taskSpotPrice = instanceTypeSpotPrices.get(taskInstanceType);
            BigDecimal taskOnDemandPrice = instanceTypeOnDemandPrices.get(taskInstanceType);
            taskPrice = getBestInstancePrice(taskSpotPrice, taskOnDemandPrice, taskInstanceDefinition);
        }
        // If prices were found
        if (masterPrice != null && (coreInstanceDefinition == null || corePrice != null) && (taskInstanceDefinition == null || taskPrice != null)) {
            // Add the pricing result to the result list
            emrClusterPrices.add(createEmrClusterPrice(availabilityZone, masterPrice, corePrice, taskPrice));
        }
    // If prices were not found for either master or core, this AZ cannot satisfy the search criteria. Ignore this AZ.
    }
    if (emrClusterPrices.isEmpty()) {
        LOGGER.info(String.format("No subnets which satisfied the best price search criteria. namespace=\"%s\" emrClusterDefinitionName=\"%s\" " + "emrClusterName=\"%s\" emrVpcPricingState=%s", emrClusterAlternateKeyDto.getNamespace(), emrClusterAlternateKeyDto.getEmrClusterDefinitionName(), emrClusterAlternateKeyDto.getEmrClusterName(), jsonHelper.objectToJson(emrVpcPricingState)));
        throw new ObjectNotFoundException(String.format("There were no subnets which satisfied your best price search criteria. If you explicitly opted to use spot EC2 instances, please confirm " + "that your instance types support spot pricing. Otherwise, try setting the max price or the on-demand threshold to a higher value.%n%s", emrVpcPricingStateFormatter.format(emrVpcPricingState)));
    }
    // Find the best prices from the result list
    EmrClusterPriceDto bestEmrClusterPrice = getEmrClusterPriceWithLowestCoreInstancePrice(emrClusterPrices);
    // Find the best subnet among the best AZ's
    Subnet bestEmrClusterSubnet = getBestSubnetForAvailabilityZone(bestEmrClusterPrice.getAvailabilityZone(), subnets);
    // Update the definition with the new calculated values
    updateInstanceDefinitionsWithBestPrice(emrClusterDefinition, bestEmrClusterSubnet, bestEmrClusterPrice);
}
Also used : InstanceDefinition(org.finra.herd.model.api.xml.InstanceDefinition) MasterInstanceDefinition(org.finra.herd.model.api.xml.MasterInstanceDefinition) EmrVpcPricingState(org.finra.herd.model.dto.EmrVpcPricingState) EmrClusterPriceDto(org.finra.herd.model.dto.EmrClusterPriceDto) ArrayList(java.util.ArrayList) AvailabilityZone(com.amazonaws.services.ec2.model.AvailabilityZone) BigDecimal(java.math.BigDecimal) Ec2PriceDto(org.finra.herd.model.dto.Ec2PriceDto) ObjectNotFoundException(org.finra.herd.model.ObjectNotFoundException) Subnet(com.amazonaws.services.ec2.model.Subnet) HashSet(java.util.HashSet)

Example 17 with InstanceDefinition

use of org.finra.herd.model.api.xml.InstanceDefinition in project herd by FINRAOS.

the class EmrClusterDefinitionServiceTest method testCreateEmrClusterDefinitionCoreInstanceCountNegativeAssertException.

/**
 * Asserts that when a negative number is specified for core instance count, a validation exception is thrown.
 */
@Test
public void testCreateEmrClusterDefinitionCoreInstanceCountNegativeAssertException() throws Exception {
    // Create and persist the namespace entity.
    namespaceDaoTestHelper.createNamespaceEntity(NAMESPACE);
    // Create an EMR cluster definition create request.
    EmrClusterDefinitionCreateRequest request = createEmrClusterDefinitionCreateRequest(NAMESPACE, EMR_CLUSTER_DEFINITION_NAME, getTestEmrClusterDefinitionConfiguration(EMR_CLUSTER_DEFINITION_XML_FILE_WITH_CLASSPATH));
    InstanceDefinition coreInstanceDefinition = new InstanceDefinition(-1, "m1.medium", NO_EMR_CLUSTER_DEFINITION_EBS_CONFIGURATION, NO_INSTANCE_SPOT_PRICE, NO_INSTANCE_MAX_SEARCH_PRICE, NO_INSTANCE_ON_DEMAND_THRESHOLD);
    request.getEmrClusterDefinition().getInstanceDefinitions().setCoreInstances(coreInstanceDefinition);
    // Create an EMR cluster definition.
    try {
        emrClusterDefinitionService.createEmrClusterDefinition(request);
        fail();
    } catch (IllegalArgumentException e) {
        assertEquals("At least 0 core instance must be specified.", e.getMessage());
    }
}
Also used : InstanceDefinition(org.finra.herd.model.api.xml.InstanceDefinition) EmrClusterDefinitionCreateRequest(org.finra.herd.model.api.xml.EmrClusterDefinitionCreateRequest) Test(org.junit.Test)

Example 18 with InstanceDefinition

use of org.finra.herd.model.api.xml.InstanceDefinition in project herd by FINRAOS.

the class EmrServiceTest method testCreateEmrClusterWithTaskInstances.

/**
 * This method tests the scenario where task instances are there
 */
@Test
public void testCreateEmrClusterWithTaskInstances() throws Exception {
    // Create the namespace entity.
    NamespaceEntity namespaceEntity = namespaceDaoTestHelper.createNamespaceEntity(NAMESPACE);
    String configXml = IOUtils.toString(resourceLoader.getResource(EMR_CLUSTER_DEFINITION_XML_FILE_WITH_CLASSPATH).getInputStream());
    EmrClusterDefinition emrClusterDefinition = xmlHelper.unmarshallXmlToObject(EmrClusterDefinition.class, configXml);
    InstanceDefinition taskDef = new InstanceDefinition();
    taskDef.setInstanceCount(1);
    // This could be any EC2 instance type supported in EMR.
    taskDef.setInstanceType(MockEc2OperationsImpl.INSTANCE_TYPE_1);
    emrClusterDefinition.getInstanceDefinitions().setTaskInstances(taskDef);
    configXml = xmlHelper.objectToXml(emrClusterDefinition);
    emrClusterDefinitionDaoTestHelper.createEmrClusterDefinitionEntity(namespaceEntity, EMR_CLUSTER_DEFINITION_NAME, configXml);
    // Create a new EMR cluster create request.
    EmrClusterCreateRequest request = getNewEmrClusterCreateRequest();
    EmrCluster emrCluster = emrService.createCluster(request);
    // Validate the returned object against the input.
    assertNotNull(emrCluster);
    assertTrue(emrCluster.getNamespace().equals(request.getNamespace()));
    assertTrue(emrCluster.getEmrClusterDefinitionName().equals(request.getEmrClusterDefinitionName()));
    assertTrue(emrCluster.getEmrClusterName().equals(request.getEmrClusterName()));
}
Also used : InstanceDefinition(org.finra.herd.model.api.xml.InstanceDefinition) NamespaceEntity(org.finra.herd.model.jpa.NamespaceEntity) EmrClusterDefinition(org.finra.herd.model.api.xml.EmrClusterDefinition) EmrClusterCreateRequest(org.finra.herd.model.api.xml.EmrClusterCreateRequest) EmrCluster(org.finra.herd.model.api.xml.EmrCluster) Test(org.junit.Test)

Example 19 with InstanceDefinition

use of org.finra.herd.model.api.xml.InstanceDefinition in project herd by FINRAOS.

the class EmrClusterDefinitionHelperTest method createValidEmrClusterDefinition.

/**
 * Creates a EMR cluster definition which does not cause validateEmrClusterDefinitionConfiguration() to throw an exception.
 * <p/>
 * - One subnet is specified - Master, core, and task instances are specified - Instance count, and instance type are specified for each instance
 * definition. - One node tag is specified
 *
 * @return A new instance of {@link EmrClusterDefinition}
 */
private EmrClusterDefinition createValidEmrClusterDefinition() {
    EmrClusterDefinition emrClusterDefinition = new EmrClusterDefinition();
    emrClusterDefinition.setSubnetId(MockEc2OperationsImpl.SUBNET_1);
    InstanceDefinitions instanceDefinitions = new InstanceDefinitions();
    MasterInstanceDefinition masterInstanceDefinition = new MasterInstanceDefinition();
    masterInstanceDefinition.setInstanceCount(1);
    masterInstanceDefinition.setInstanceType(MockEc2OperationsImpl.INSTANCE_TYPE_1);
    instanceDefinitions.setMasterInstances(masterInstanceDefinition);
    InstanceDefinition coreInstanceDefinition = new InstanceDefinition();
    coreInstanceDefinition.setInstanceCount(1);
    coreInstanceDefinition.setInstanceType(MockEc2OperationsImpl.INSTANCE_TYPE_1);
    instanceDefinitions.setCoreInstances(coreInstanceDefinition);
    InstanceDefinition taskInstanceDefinition = new InstanceDefinition();
    taskInstanceDefinition.setInstanceCount(1);
    taskInstanceDefinition.setInstanceType(MockEc2OperationsImpl.INSTANCE_TYPE_1);
    instanceDefinitions.setTaskInstances(taskInstanceDefinition);
    emrClusterDefinition.setInstanceDefinitions(instanceDefinitions);
    List<NodeTag> nodeTags = new ArrayList<>();
    {
        nodeTags.add(new NodeTag("test_nodeTagName", "test_nodeTagValue"));
    }
    emrClusterDefinition.setNodeTags(nodeTags);
    return emrClusterDefinition;
}
Also used : InstanceDefinition(org.finra.herd.model.api.xml.InstanceDefinition) MasterInstanceDefinition(org.finra.herd.model.api.xml.MasterInstanceDefinition) EmrClusterDefinition(org.finra.herd.model.api.xml.EmrClusterDefinition) NodeTag(org.finra.herd.model.api.xml.NodeTag) ArrayList(java.util.ArrayList) MasterInstanceDefinition(org.finra.herd.model.api.xml.MasterInstanceDefinition) InstanceDefinitions(org.finra.herd.model.api.xml.InstanceDefinitions)

Example 20 with InstanceDefinition

use of org.finra.herd.model.api.xml.InstanceDefinition in project herd by FINRAOS.

the class EmrDaoImplTest method testGetInstanceGroupConfigs.

@Test
public void testGetInstanceGroupConfigs() {
    // Create objects required for testing.
    final Integer instanceCount = 0;
    final InstanceDefinitions instanceDefinitions = new InstanceDefinitions(new MasterInstanceDefinition(), new InstanceDefinition(), new InstanceDefinition());
    // Mock the external calls.
    when(emrHelper.isInstanceDefinitionsEmpty(instanceDefinitions)).thenReturn(false);
    // Call the method under test.
    List<InstanceGroupConfig> result = emrDaoImpl.getInstanceGroupConfigs(instanceDefinitions);
    // Verify the external calls.
    verify(emrHelper).isInstanceDefinitionsEmpty(instanceDefinitions);
    verifyNoMoreInteractionsHelper();
    // Validate the results.
    assertEquals(3, CollectionUtils.size(result));
    assertTrue(result.contains(new InstanceGroupConfig(InstanceRoleType.MASTER, null, instanceCount)));
    assertTrue(result.contains(new InstanceGroupConfig(InstanceRoleType.CORE, null, instanceCount)));
    assertTrue(result.contains(new InstanceGroupConfig(InstanceRoleType.TASK, null, instanceCount)));
}
Also used : MasterInstanceDefinition(org.finra.herd.model.api.xml.MasterInstanceDefinition) InstanceDefinition(org.finra.herd.model.api.xml.InstanceDefinition) MasterInstanceDefinition(org.finra.herd.model.api.xml.MasterInstanceDefinition) InstanceDefinitions(org.finra.herd.model.api.xml.InstanceDefinitions) InstanceGroupConfig(com.amazonaws.services.elasticmapreduce.model.InstanceGroupConfig) Test(org.junit.Test) AbstractDaoTest(org.finra.herd.dao.AbstractDaoTest)

Aggregations

InstanceDefinition (org.finra.herd.model.api.xml.InstanceDefinition)39 MasterInstanceDefinition (org.finra.herd.model.api.xml.MasterInstanceDefinition)36 Test (org.junit.Test)34 AbstractDaoTest (org.finra.herd.dao.AbstractDaoTest)27 EmrClusterDefinition (org.finra.herd.model.api.xml.EmrClusterDefinition)24 ObjectNotFoundException (org.finra.herd.model.ObjectNotFoundException)8 InstanceDefinitions (org.finra.herd.model.api.xml.InstanceDefinitions)7 AmazonServiceException (com.amazonaws.AmazonServiceException)5 NodeTag (org.finra.herd.model.api.xml.NodeTag)5 RunJobFlowRequest (com.amazonaws.services.elasticmapreduce.model.RunJobFlowRequest)4 AwsParamsDto (org.finra.herd.model.dto.AwsParamsDto)4 InvocationOnMock (org.mockito.invocation.InvocationOnMock)4 InstanceGroupConfig (com.amazonaws.services.elasticmapreduce.model.InstanceGroupConfig)3 BigDecimal (java.math.BigDecimal)3 ArrayList (java.util.ArrayList)3 EmrVpcPricingState (org.finra.herd.model.dto.EmrVpcPricingState)3 HashMap (java.util.HashMap)2 EmrClusterDefinitionCreateRequest (org.finra.herd.model.api.xml.EmrClusterDefinitionCreateRequest)2 ClientConfiguration (com.amazonaws.ClientConfiguration)1 AvailabilityZone (com.amazonaws.services.ec2.model.AvailabilityZone)1