Search in sources :

Example 1 with ProvQuoteDatabase

use of org.ligoj.app.plugin.prov.model.ProvQuoteDatabase in project plugin-prov by ligoj.

the class ProvQuoteDatabaseResourceTest method lookupLicenseIncluded.

/**
 * Basic case, almost no requirements but license.
 */
@Test
void lookupLicenseIncluded() {
    final var lookup = qbResource.lookup(subscription, builder().usage("Full Time 12 month").license("INCLUDED").engine("MYSQL").build());
    // Check the instance result
    final var pi = lookup.getPrice();
    Assertions.assertEquals("database2", pi.getType().getName());
    Assertions.assertEquals("MYSQL3", pi.getCode());
    Assertions.assertEquals("MYSQL", pi.getEngine());
    Assertions.assertNull(pi.getStorageEngine());
    Assertions.assertNull(pi.getEdition());
    Assertions.assertNull(pi.getLicense());
    // Coverage only
    Assertions.assertTrue(pi.toString().contains("engine=MYSQL, edition=null"));
    Assertions.assertTrue(lookup.toString().contains("engine=MYSQL, edition=null"));
    new ProvQuoteDatabase().setStorages(null);
    Assertions.assertNotNull(qbResource.getItRepository());
}
Also used : ProvQuoteDatabase(org.ligoj.app.plugin.prov.model.ProvQuoteDatabase) AbstractProvResourceTest(org.ligoj.app.plugin.prov.AbstractProvResourceTest) Test(org.junit.jupiter.api.Test)

Example 2 with ProvQuoteDatabase

use of org.ligoj.app.plugin.prov.model.ProvQuoteDatabase in project plugin-prov by ligoj.

the class ProvQuoteUploadResource method upload.

/**
 * Upload a file of quote.
 *
 * @param subscription    The subscription identifier, will be used to filter the locations from the associated
 *                        provider.
 * @param uploadedFile    Instance entries files to import. Currently support only CSV format.
 * @param headers         the CSV header names. When <code>null</code> or empty, the default headers are used.
 * @param headersIncluded When <code>true</code>, the first line is the headers and the given <code>headers</code>
 *                        parameter is ignored. Otherwise the <code>headers</code> parameter is used.
 * @param defaultUsage    The optional usage name. When not <code>null</code>, each quote instance without defined
 *                        usage will be associated to this usage.
 * @param mode            The merge option indicates how the entries are inserted.
 * @param ramMultiplier   The multiplier for imported RAM values. Default is 1.
 * @param encoding        CSV encoding. Default is UTF-8.
 * @param errorContinue   When <code>true</code> errors do not block the upload.
 * @param createUsage     When <code>true</code>, missing usage are automatically created.
 * @param separator       CSV separator. Default is ";".
 * @throws IOException When the CSV stream cannot be written.
 */
@POST
@Consumes(MediaType.MULTIPART_FORM_DATA)
@Path("{subscription:\\d+}/upload")
public void upload(@PathParam("subscription") final int subscription, @Multipart(value = CSV_FILE) final InputStream uploadedFile, @Multipart(value = "headers", required = false) final String[] headers, @Multipart(value = "headers-included", required = false) final boolean headersIncluded, @Multipart(value = "usage", required = false) final String defaultUsage, @Multipart(value = "mergeUpload", required = false) final MergeMode mode, @Multipart(value = "memoryUnit", required = false) final Integer ramMultiplier, @Multipart(value = "errorContinue", required = false) final boolean errorContinue, @Multipart(value = "encoding", required = false) final String encoding, @Multipart(value = "createMissingUsage", required = false) final boolean createUsage, @Multipart(value = "separator", required = false) final String separator) throws IOException {
    log.info("Upload provisioning requested...");
    subscriptionResource.checkVisible(subscription);
    final var quote = resource.getRepository().findBy("subscription.id", subscription);
    final var safeEncoding = ObjectUtils.defaultIfNull(encoding, DEFAULT_ENCODING);
    // Check headers validity
    final String[] headersArray;
    final InputStream fileNoHeader;
    if (headersIncluded) {
        // Header at first line
        final var br = new BufferedReader(new StringReader(IOUtils.toString(uploadedFile, safeEncoding)));
        headersArray = StringUtils.defaultString(br.readLine()).split(separator);
        fileNoHeader = new ByteArrayInputStream(IOUtils.toByteArray(br, safeEncoding));
    } else {
        // Headers are provided separately
        headersArray = ArrayUtils.isEmpty(headers) ? DEFAULT_HEADERS : headers;
        fileNoHeader = uploadedFile;
    }
    final var headersArray2 = checkHeaders(headersArray);
    final var headersString = StringUtils.chop(ArrayUtils.toString(headersArray2)).substring(1).replace(",", separator) + "\n";
    final var reader = new InputStreamReader(new SequenceInputStream(new ByteArrayInputStream(headersString.getBytes(safeEncoding)), fileNoHeader), safeEncoding);
    // Build entries
    log.info("Upload provisioning : reading, using header {}", headersString);
    final var list = csvForBean.toBean(VmUpload.class, reader);
    log.info("Upload provisioning : importing {} entries", list.size());
    final var cursor = new AtomicInteger(0);
    final var previousQi = qiRepository.findAll(quote).stream().collect(Collectors.toConcurrentMap(ProvQuoteInstance::getName, Function.identity()));
    final var previousQb = qbRepository.findAll(quote).stream().collect(Collectors.toConcurrentMap(ProvQuoteDatabase::getName, Function.identity()));
    // Initialization for parallel process
    Hibernate.initialize(quote.getUsages());
    Hibernate.initialize(quote.getBudgets());
    final var context = new UploadContext();
    context.quote = quote;
    context.previousQi = previousQi;
    context.previousQb = previousQb;
    list.stream().filter(Objects::nonNull).filter(i -> i.getName() != null).forEach(i -> {
        try {
            persist(subscription, defaultUsage, mode, ramMultiplier, list.size(), cursor, context, createUsage, i);
        } catch (final ValidationJsonException e) {
            handleUploadError(errorContinue, handleValidationError(i, e));
        } catch (final ConstraintViolationException e) {
            handleUploadError(errorContinue, handleValidationError(i, new ValidationJsonException(e)));
        } catch (final RuntimeException e) {
            log.error("Unmanaged error during import of " + i.getName(), e);
            handleUploadError(errorContinue, e);
        }
    });
    log.info("Upload provisioning : flushing");
}
Also used : CsvForBean(org.ligoj.bootstrap.core.csv.CsvForBean) Arrays(java.util.Arrays) Produces(javax.ws.rs.Produces) BiFunction(java.util.function.BiFunction) Path(javax.ws.rs.Path) ProvUsageRepository(org.ligoj.app.plugin.prov.dao.ProvUsageRepository) Autowired(org.springframework.beans.factory.annotation.Autowired) ProvQuoteStorage(org.ligoj.app.plugin.prov.model.ProvQuoteStorage) StringUtils(org.apache.commons.lang3.StringUtils) ValidationJsonException(org.ligoj.bootstrap.core.validation.ValidationJsonException) MediaType(javax.ws.rs.core.MediaType) ByteArrayInputStream(java.io.ByteArrayInputStream) Consumes(javax.ws.rs.Consumes) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) Map(java.util.Map) Multipart(org.apache.cxf.jaxrs.ext.multipart.Multipart) ProvQuoteDatabase(org.ligoj.app.plugin.prov.model.ProvQuoteDatabase) ProvQuoteStorageResource(org.ligoj.app.plugin.prov.quote.storage.ProvQuoteStorageResource) Transactional(javax.transaction.Transactional) ResourceType(org.ligoj.app.plugin.prov.model.ResourceType) Collectors(java.util.stream.Collectors) AbstractProvQuoteVmResource(org.ligoj.app.plugin.prov.AbstractProvQuoteVmResource) StandardCharsets(java.nio.charset.StandardCharsets) Serializable(java.io.Serializable) Objects(java.util.Objects) IOUtils(org.apache.commons.io.IOUtils) List(java.util.List) QuoteStorageEditionVo(org.ligoj.app.plugin.prov.quote.storage.QuoteStorageEditionVo) Slf4j(lombok.extern.slf4j.Slf4j) QuoteDatabaseEditionVo(org.ligoj.app.plugin.prov.quote.database.QuoteDatabaseEditionVo) Optional(java.util.Optional) Pattern(java.util.regex.Pattern) ProvQuoteDatabaseResource(org.ligoj.app.plugin.prov.quote.database.ProvQuoteDatabaseResource) IntStream(java.util.stream.IntStream) PathParam(javax.ws.rs.PathParam) QuoteInstanceEditionVo(org.ligoj.app.plugin.prov.quote.instance.QuoteInstanceEditionVo) HashMap(java.util.HashMap) ArrayUtils(org.apache.commons.lang3.ArrayUtils) ObjIntConsumer(java.util.function.ObjIntConsumer) ProvQuoteInstance(org.ligoj.app.plugin.prov.model.ProvQuoteInstance) Function(java.util.function.Function) CollectionUtils(org.apache.commons.collections4.CollectionUtils) ArrayList(java.util.ArrayList) HashSet(java.util.HashSet) ObjectUtils(org.apache.commons.lang3.ObjectUtils) Service(org.springframework.stereotype.Service) EntityNotFoundException(javax.persistence.EntityNotFoundException) AbstractQuoteVmEditionVo(org.ligoj.app.plugin.prov.AbstractQuoteVmEditionVo) ProvUsage(org.ligoj.app.plugin.prov.model.ProvUsage) ProvQuoteInstanceResource(org.ligoj.app.plugin.prov.quote.instance.ProvQuoteInstanceResource) MapUtils(org.apache.commons.collections4.MapUtils) POST(javax.ws.rs.POST) SequenceInputStream(java.io.SequenceInputStream) ProvQuoteInstanceRepository(org.ligoj.app.plugin.prov.dao.ProvQuoteInstanceRepository) IOException(java.io.IOException) SubscriptionResource(org.ligoj.app.resource.subscription.SubscriptionResource) InputStreamReader(java.io.InputStreamReader) ProvTagResource(org.ligoj.app.plugin.prov.ProvTagResource) TagEditionVo(org.ligoj.app.plugin.prov.TagEditionVo) StringReader(java.io.StringReader) ConstraintViolationException(javax.validation.ConstraintViolationException) ProvQuoteDatabaseRepository(org.ligoj.app.plugin.prov.dao.ProvQuoteDatabaseRepository) ProvResource(org.ligoj.app.plugin.prov.ProvResource) ProvQuote(org.ligoj.app.plugin.prov.model.ProvQuote) BufferedReader(java.io.BufferedReader) Hibernate(org.hibernate.Hibernate) InputStream(java.io.InputStream) InputStreamReader(java.io.InputStreamReader) ByteArrayInputStream(java.io.ByteArrayInputStream) SequenceInputStream(java.io.SequenceInputStream) InputStream(java.io.InputStream) SequenceInputStream(java.io.SequenceInputStream) ByteArrayInputStream(java.io.ByteArrayInputStream) AtomicInteger(java.util.concurrent.atomic.AtomicInteger) BufferedReader(java.io.BufferedReader) StringReader(java.io.StringReader) Objects(java.util.Objects) ValidationJsonException(org.ligoj.bootstrap.core.validation.ValidationJsonException) ConstraintViolationException(javax.validation.ConstraintViolationException) Path(javax.ws.rs.Path) POST(javax.ws.rs.POST) Consumes(javax.ws.rs.Consumes)

Example 3 with ProvQuoteDatabase

use of org.ligoj.app.plugin.prov.model.ProvQuoteDatabase in project plugin-prov by ligoj.

the class ProvBudgetResource method pack.

private double pack(final ProvBudget budget, final Map<Double, AbstractQuoteVm<?>> packToQr, final Map<AbstractQuoteVm<?>, FloatingPrice<?>> prices, final List<ProvQuoteInstance> validatedQi, final List<ProvQuoteDatabase> validatedQb, final List<ProvQuoteContainer> validatedQc, final List<ProvQuoteFunction> validatedQf, final Map<ResourceType, Map<Integer, FloatingCost>> costs) {
    if (packToQr.isEmpty()) {
        return 0d;
    }
    // At least one initial cost is implied, use bin packing strategy
    final var packStart = System.currentTimeMillis();
    final var packer = new LinearBinPacker();
    final var bins = packer.packAll(packToQr.entrySet().stream().sorted(priceOrder(prices)).map(Entry::getKey).collect(Collectors.toList()), new ArrayList<>(List.of(new LinearBin(budget.getRemainingBudget()))), new ArrayList<>(List.of(Double.MAX_VALUE)));
    final var bin = bins.get(0);
    bin.getPieces().stream().map(packToQr::get).forEach(i -> {
        if (i.getResourceType() == ResourceType.INSTANCE) {
            validatedQi.add((ProvQuoteInstance) i);
        } else if (i.getResourceType() == ResourceType.DATABASE) {
            validatedQb.add((ProvQuoteDatabase) i);
        } else if (i.getResourceType() == ResourceType.CONTAINER) {
            validatedQc.add((ProvQuoteContainer) i);
        } else {
            validatedQf.add((ProvQuoteFunction) i);
        }
    });
    logLean(b -> {
        log.info("Packing result: {}", b.get(0).getPieces().stream().map(packToQr::get).map(i -> i.getName() + CODE + i.getPrice().getCode() + ")").collect(Collectors.toList()));
        log.info("Packing result: {}", b);
    }, bins);
    logPack(packStart, packToQr, budget);
    var init = bin.getTotal();
    if (bins.size() > 1) {
        // Extra bin needs to make a new pass
        budget.setRemainingBudget(FloatingCost.round(budget.getRemainingBudget() - bin.getTotal()));
        final List<ProvQuoteInstance> subQi = newSubPack(packToQr, bins, ResourceType.INSTANCE);
        final List<ProvQuoteDatabase> subQb = newSubPack(packToQr, bins, ResourceType.DATABASE);
        final List<ProvQuoteContainer> subQc = newSubPack(packToQr, bins, ResourceType.CONTAINER);
        final List<ProvQuoteFunction> subQf = newSubPack(packToQr, bins, ResourceType.FUNCTION);
        init += leanRecursive(budget, subQi, subQb, subQc, subQf, costs);
    } else {
    // Pack is completed
    }
    return init;
}
Also used : ProvQuoteFunction(org.ligoj.app.plugin.prov.model.ProvQuoteFunction) ProvQuoteInstance(org.ligoj.app.plugin.prov.model.ProvQuoteInstance) ProvQuoteDatabase(org.ligoj.app.plugin.prov.model.ProvQuoteDatabase) ProvQuoteContainer(org.ligoj.app.plugin.prov.model.ProvQuoteContainer) Entry(java.util.Map.Entry) LinearBinPacker(net.jnellis.binpack.LinearBinPacker) LinearBin(net.jnellis.binpack.LinearBin)

Aggregations

ProvQuoteDatabase (org.ligoj.app.plugin.prov.model.ProvQuoteDatabase)3 ProvQuoteInstance (org.ligoj.app.plugin.prov.model.ProvQuoteInstance)2 BufferedReader (java.io.BufferedReader)1 ByteArrayInputStream (java.io.ByteArrayInputStream)1 IOException (java.io.IOException)1 InputStream (java.io.InputStream)1 InputStreamReader (java.io.InputStreamReader)1 SequenceInputStream (java.io.SequenceInputStream)1 Serializable (java.io.Serializable)1 StringReader (java.io.StringReader)1 StandardCharsets (java.nio.charset.StandardCharsets)1 ArrayList (java.util.ArrayList)1 Arrays (java.util.Arrays)1 HashMap (java.util.HashMap)1 HashSet (java.util.HashSet)1 List (java.util.List)1 Map (java.util.Map)1 Entry (java.util.Map.Entry)1 Objects (java.util.Objects)1 Optional (java.util.Optional)1