From 09041ca1b5aeec64cde60a1865cacbb0ec66d2c3 Mon Sep 17 00:00:00 2001 From: Cedrick Lunven Date: Thu, 11 Jun 2026 15:11:12 +0200 Subject: [PATCH 1/4] feat: PCU groups implementation and related changes --- astra-db-java/pom.xml | 14 ++ .../astra/client/admin/AstraDBAdmin.java | 113 ++++++++++++++- .../admin/definition/DatabaseDefinition.java | 78 ++++++++++ .../admin/options/CreateDatabaseOptions.java | 21 +++ .../com/dtsx/astra/sdk/AstraOpsClient.java | 9 +- .../db/domain/DatabaseCreationBuilder.java | 32 +++++ .../db/domain/DatabaseCreationRequest.java | 37 ++++- .../dtsx/astra/sdk/pcu/PcuGroupOpsClient.java | 3 +- ...upsClient.java => PcuGroupsOpsClient.java} | 83 +++++++++-- .../pcu/domain/PcuCapacityWorkloadType.java | 34 +++++ .../dtsx/astra/sdk/pcu/domain/PcuGroup.java | 4 +- .../domain/PcuGroupCreateUpdateRequest.java | 34 ++++- .../pcu/domain/PcuGroupCreationRequest.java | 14 +- .../sdk/pcu/domain/PcuGroupUpdateRequest.java | 9 +- .../astra/sdk/pcu/domain/PcuInstanceType.java | 22 +++ .../sdk/pcu/domain/PcuProvisionType.java | 1 + .../dtsx/astra/sdk/pcu/domain/PcuType.java | 19 +++ .../sdk/pcu/domain/PcuTypeLocationFilter.java | 15 ++ .../astra/sdk/pcu/domain/PcuTypeResolver.java | 58 ++++++++ .../dtsx/astra/sdk/AbstractDevopsApiTest.java | 8 +- .../astra/sdk/pcu/PCUGroupClientTest.java | 135 ++++++++++++++++++ .../com/dtsx/astra/sdk/pcu/ParkingTest.java | 10 -- .../astra/sdk/pcu/PcuTypeResolverTest.java | 132 +++++++++++++++++ .../skills/spring-boot-data-api/README.md | 26 +++- .../{ => assets}/examples/basic/README.md | 0 .../templates/Controller.java.template | 0 .../templates/Document.java.template | 0 .../templates/Repository.java.template | 0 .../templates/Service.java.template | 0 .../templates/application.yml.template | 0 tools/data-api-tools/pom.xml | 9 ++ .../com/datastax/astra/tool/copy/README.md | 86 +++++++++++ .../src/test/resources/logback-test.xml | 15 ++ .../src/test/resources/test-config.properties | 49 +++++++ 34 files changed, 1019 insertions(+), 51 deletions(-) create mode 100644 astra-db-java/src/main/java/com/datastax/astra/client/admin/definition/DatabaseDefinition.java create mode 100644 astra-db-java/src/main/java/com/datastax/astra/client/admin/options/CreateDatabaseOptions.java rename astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/{PcuGroupsClient.java => PcuGroupsOpsClient.java} (68%) create mode 100644 astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PcuCapacityWorkloadType.java create mode 100644 astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PcuInstanceType.java create mode 100644 astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PcuType.java create mode 100644 astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PcuTypeLocationFilter.java create mode 100644 astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PcuTypeResolver.java create mode 100644 astra-sdk-devops/src/test/java/com/dtsx/astra/sdk/pcu/PCUGroupClientTest.java delete mode 100644 astra-sdk-devops/src/test/java/com/dtsx/astra/sdk/pcu/ParkingTest.java create mode 100644 astra-sdk-devops/src/test/java/com/dtsx/astra/sdk/pcu/PcuTypeResolverTest.java rename integrations/skills/spring-boot-data-api/{ => assets}/examples/basic/README.md (100%) rename integrations/skills/spring-boot-data-api/{ => assets}/templates/Controller.java.template (100%) rename integrations/skills/spring-boot-data-api/{ => assets}/templates/Document.java.template (100%) rename integrations/skills/spring-boot-data-api/{ => assets}/templates/Repository.java.template (100%) rename integrations/skills/spring-boot-data-api/{ => assets}/templates/Service.java.template (100%) rename integrations/skills/spring-boot-data-api/{ => assets}/templates/application.yml.template (100%) create mode 100644 tools/data-api-tools/src/test/java/com/datastax/astra/tool/copy/README.md create mode 100644 tools/data-api-tools/src/test/resources/logback-test.xml create mode 100644 tools/data-api-tools/src/test/resources/test-config.properties diff --git a/astra-db-java/pom.xml b/astra-db-java/pom.xml index b235a7d3..c1b9e290 100644 --- a/astra-db-java/pom.xml +++ b/astra-db-java/pom.xml @@ -158,6 +158,20 @@ + + + + org.apache.maven.plugins + maven-jar-plugin + 3.3.0 + + + + test-jar + + + + diff --git a/astra-db-java/src/main/java/com/datastax/astra/client/admin/AstraDBAdmin.java b/astra-db-java/src/main/java/com/datastax/astra/client/admin/AstraDBAdmin.java index 6c453237..0c66ae26 100644 --- a/astra-db-java/src/main/java/com/datastax/astra/client/admin/AstraDBAdmin.java +++ b/astra-db-java/src/main/java/com/datastax/astra/client/admin/AstraDBAdmin.java @@ -21,8 +21,10 @@ */ import com.datastax.astra.client.admin.commands.AstraAvailableRegionInfo; +import com.datastax.astra.client.admin.definition.DatabaseDefinition; import com.datastax.astra.client.admin.options.AdminOptions; import com.datastax.astra.client.admin.options.AstraFindAvailableRegionsOptions; +import com.datastax.astra.client.admin.options.CreateDatabaseOptions; import com.datastax.astra.client.core.options.DataAPIClientOptions; import com.datastax.astra.client.databases.definition.DatabaseInfo; import com.datastax.astra.client.databases.DatabaseOptions; @@ -38,6 +40,8 @@ import com.dtsx.astra.sdk.db.domain.FilterByOrgType; import com.dtsx.astra.sdk.db.domain.RegionType; import com.dtsx.astra.sdk.db.exception.DatabaseNotFoundException; +import com.dtsx.astra.sdk.pcu.PcuGroupsOpsClient; +import com.dtsx.astra.sdk.pcu.domain.PcuGroup; import com.dtsx.astra.sdk.utils.AstraRc; import com.dtsx.astra.sdk.utils.observability.ApiRequestObserver; import com.dtsx.astra.sdk.utils.observability.LoggingRequestObserver; @@ -46,7 +50,6 @@ import java.net.http.HttpClient; import java.time.Duration; -import java.util.ArrayList; import java.util.HashMap; import java.util.List; import java.util.Map; @@ -77,6 +80,9 @@ public class AstraDBAdmin { /** Client for Astra Devops Api. */ final AstraDBOpsClient devopsDbClient; + /** Client for Astra Devops Api PCU. */ + final PcuGroupsOpsClient devopsPcuClient; + /** Options to personalized http client other client options. */ final AdminOptions adminOptions; @@ -110,14 +116,17 @@ public AstraDBAdmin(AdminOptions options) { if (dataAPIClientOptions.getObservers() != null) { Map devopsObservers = new HashMap<>(); if (dataAPIClientOptions.getObservers().containsKey(LoggingCommandObserver.class.getSimpleName())) { - System.out.println("Logging enabled for AstraDBAdmin operations."); devopsObservers.put("logging", new LoggingRequestObserver(AstraDBAdmin.class)); } this.devopsDbClient = new AstraDBOpsClient(options.getToken(), dataAPIClientOptions.getAstraEnvironment(), devopsObservers); + this.devopsPcuClient = new PcuGroupsOpsClient(options.getToken(), + dataAPIClientOptions.getAstraEnvironment(), devopsObservers); } else { this.devopsDbClient = new AstraDBOpsClient(options.getToken(), dataAPIClientOptions.getAstraEnvironment()); + this.devopsPcuClient = new PcuGroupsOpsClient(options.getToken(), + dataAPIClientOptions.getAstraEnvironment()); } // Local Agent for Resume @@ -158,6 +167,83 @@ public List findAvailableRegions(AstraFindAvailableReg .toList(); } + // -------------------- + // -- PCU Support --- + // -------------------- + + /** + * Lists PCU (Processing Capacity Units) groups filtered by cloud provider and region. + * PCU groups manage compute resources for databases across cloud providers and regions. + * + * @param cloud + * cloud provider to filter by (AWS, GCP, AZURE), or null for all providers + * @param cloudRegion + * cloud region to filter by (e.g., "us-east-1"), or null for all regions + * @return + * list of PCU groups matching the specified filters + */ + public List listPcuGroups(CloudProviderType cloud, String cloudRegion) { + List pcus = devopsPcuClient.findAll().toList(); + // Filter by cloud provider if specified + if (cloud != null) { + pcus = pcus.stream() + .filter(pcu -> cloud.equals(pcu.getCloudProvider())) + .collect(Collectors.toList()); + } + + // Filter by region if specified + if (cloudRegion != null && !cloudRegion.isBlank()) { + pcus = pcus.stream() + .filter(pcu -> cloudRegion.equals(pcu.getRegion())) + .collect(Collectors.toList()); + } + + return pcus; + } + + /** + * Lists all PCU (Processing Capacity Units) groups in the organization. + * This is a convenience method that returns all PCU groups without filtering. + * + * @return + * list of all PCU groups + */ + public List listPcuGroups() { + return listPcuGroups(null, null); + } + + /** + * Checks if a PCU group exists by its identifier. + * This is a convenience method that checks existence without filtering by cloud or region. + * + * @param pcuGroupId + * PCU group UUID to check + * @return + * true if the PCU group exists, false otherwise + */ + public boolean pcuGroupExists(UUID pcuGroupId) { + return pcuGroupExists(pcuGroupId, null, null); + } + + /** + * Checks if a PCU group exists by its identifier, optionally filtered by cloud provider and region. + * + * @param pcuGroupId + * PCU group UUID to check + * @param cloud + * cloud provider to filter by (AWS, GCP, AZURE), or null for all providers + * @param cloudRegion + * cloud region to filter by (e.g., "us-east-1"), or null for all regions + * @return + * true if the PCU group exists and matches the filters, false otherwise + */ + public boolean pcuGroupExists(UUID pcuGroupId, CloudProviderType cloud, String cloudRegion) { + Assert.notNull(pcuGroupId, "pcuGroupId"); + return listPcuGroups(cloud, cloudRegion) + .stream() + .anyMatch(pcuGroup -> pcuGroupId.equals(pcuGroup.getId())); + } + // -------------------- // -- Databases --- // -------------------- @@ -298,6 +384,29 @@ public DatabaseAdmin createDatabase(String name, CloudProviderType cloud, String return createDatabase(name, cloud, cloudRegion, true); } + /** + * Create new database with a name on free tier. The database name should not exist in the tenant. + * + * @param name + * unique name for the database + * @param definition + * definition of the database + * @return + * database admin object + */ + public DatabaseAdmin createDatabase(String name, DatabaseDefinition definition, CreateDatabaseOptions options) { + Assert.notNull(definition, "definition"); + Assert.hasLength(name, "name"); + DatabaseCreationRequest req = definition.asRequest(); + req.setName(name); + UUID newDbId = UUID.fromString(devopsDbClient.create(req)); + log.info("Database {} is starting (id={}): it will take about a minute please wait...", name, newDbId); + if (options != null && options.isWaitForDb()) { + waitForDatabase(devopsDbClient.database(newDbId.toString())); + } + return getDatabaseAdmin(newDbId); + } + /** * Delete a Database if exists from its identifier. * diff --git a/astra-db-java/src/main/java/com/datastax/astra/client/admin/definition/DatabaseDefinition.java b/astra-db-java/src/main/java/com/datastax/astra/client/admin/definition/DatabaseDefinition.java new file mode 100644 index 00000000..b884dee3 --- /dev/null +++ b/astra-db-java/src/main/java/com/datastax/astra/client/admin/definition/DatabaseDefinition.java @@ -0,0 +1,78 @@ +package com.datastax.astra.client.admin.definition; + +import com.dtsx.astra.sdk.db.domain.CloudProviderType; +import com.dtsx.astra.sdk.db.domain.DatabaseCreationBuilder; +import com.dtsx.astra.sdk.db.domain.DatabaseCreationRequest; +import com.dtsx.astra.sdk.db.domain.DatabaseCreationType; +import lombok.Builder; +import lombok.Data; + +import java.util.UUID; + +@Data +@Builder +public class DatabaseDefinition { + + /** Default region. **/ + public static final String DEFAULT_REGION = "us-east1"; + + /** Default tier. **/ + public static final String DEFAULT_TIER = "serverless"; + + /** Default cloud. **/ + public static final CloudProviderType DEFAULT_CLOUD = CloudProviderType.GCP; + + /** CloudProvider where the database lives. */ + private CloudProviderType cloudProvider = DEFAULT_CLOUD; + + /** Region. */ + private String region = DEFAULT_REGION; + + /** Database type. */ + private String tier = DEFAULT_TIER; + + /** Name of the database--user friendly identifier. */ + private String name; + + /** Keyspace name in database */ + private String keyspace; + + /** + * CapacityUnits is the amount of space available (horizontal scaling) + * for the database. For free tier the max CU's is 1, and 100 + * for CXX/DXX the max is 12 on startup. + */ + private Integer capacity = 1; + + /** + * Default is null, if vector will be added + */ + private DatabaseCreationType dbType; + + /** + * Identifier to assign a database to a PCU group directly. + */ + private UUID pcuGroupID; + + /** + * Projection as the creation request + * + * @return + * db creation request + */ + public DatabaseCreationRequest asRequest() { + DatabaseCreationBuilder builder = DatabaseCreationRequest.builder(); + builder.capacityUnit(capacity); + builder.name(name); + builder.cloudProvider(cloudProvider); + builder.cloudRegion(region); + builder.tier(tier); + builder.keyspace(keyspace); + builder.withVector(); + builder.dbType(dbType); + if (pcuGroupID != null) { + builder.assignToPCUGroup(pcuGroupID); + } + return builder.build(); + } +} diff --git a/astra-db-java/src/main/java/com/datastax/astra/client/admin/options/CreateDatabaseOptions.java b/astra-db-java/src/main/java/com/datastax/astra/client/admin/options/CreateDatabaseOptions.java new file mode 100644 index 00000000..78e748c3 --- /dev/null +++ b/astra-db-java/src/main/java/com/datastax/astra/client/admin/options/CreateDatabaseOptions.java @@ -0,0 +1,21 @@ +package com.datastax.astra.client.admin.options; + +import com.datastax.astra.client.core.options.BaseOptions; +import lombok.Setter; +import lombok.experimental.Accessors; + +@Setter +@Accessors(fluent = true, chain = true) +public class CreateDatabaseOptions extends BaseOptions { + + boolean waitForDb = false; + + /** + * Gets waitForDb + * + * @return value of waitForDb + */ + public boolean isWaitForDb() { + return waitForDb; + } +} diff --git a/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/AstraOpsClient.java b/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/AstraOpsClient.java index ec7202ab..2faef93f 100644 --- a/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/AstraOpsClient.java +++ b/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/AstraOpsClient.java @@ -6,7 +6,7 @@ import com.dtsx.astra.sdk.org.TokensClient; import com.dtsx.astra.sdk.org.UsersClient; import com.dtsx.astra.sdk.org.domain.*; -import com.dtsx.astra.sdk.pcu.PcuGroupsClient; +import com.dtsx.astra.sdk.pcu.PcuGroupsOpsClient; import com.dtsx.astra.sdk.streaming.AstraStreamingClient; import com.dtsx.astra.sdk.utils.ApiLocator; import com.dtsx.astra.sdk.utils.ApiResponseHttp; @@ -172,12 +172,13 @@ public TokensClient tokens() { // ------------------------------------------------------ /** - * Work with PCU groups. + * Work with PCU groups. With are using 'pcus' matching both devops path, also pcus support types + * https://docs.datastax.com/en/astra-api-docs/_attachments/devops-api/index.html#tag/PCU/operation/pcuGet * * @return * pcu groups client */ - public PcuGroupsClient pcuGroups() { // TODO `pcu()` or `pcuGroups()`? - return new PcuGroupsClient(token, environment); + public PcuGroupsOpsClient pcus() { + return new PcuGroupsOpsClient(token, environment); } } diff --git a/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/db/domain/DatabaseCreationBuilder.java b/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/db/domain/DatabaseCreationBuilder.java index 1251c888..7250c00c 100644 --- a/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/db/domain/DatabaseCreationBuilder.java +++ b/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/db/domain/DatabaseCreationBuilder.java @@ -16,6 +16,8 @@ package com.dtsx.astra.sdk.db.domain; +import java.util.UUID; + /** * Builder for database creation. */ @@ -48,9 +50,15 @@ public class DatabaseCreationBuilder { /** Option to enable the vector preview. */ protected boolean vector = false; + /** Option to enable the vector preview. */ + protected DatabaseCreationType dbType; + /** capacity unit. */ protected int capacityUnits = 1; + /** Identifier to assign a database to a PCU group directly. */ + protected UUID pcuGroupUUID; + /** Default constructor. */ public DatabaseCreationBuilder() {} @@ -132,6 +140,19 @@ public DatabaseCreationBuilder capacityUnit(int unit) { return this; } + /** + * Builder for a PCU group + * + * @param pcuGroupId + * identifier for the PCU group + * @return + * current instance + */ + public DatabaseCreationBuilder assignToPCUGroup(UUID pcuGroupId) { + this.pcuGroupUUID = pcuGroupId; + return this; + } + /** * Enable Vector. * @@ -143,6 +164,17 @@ public DatabaseCreationBuilder withVector() { return this; } + /** + * Builder for a dbType + * + * @return + * database creation request + */ + public DatabaseCreationBuilder dbType(DatabaseCreationType dbType) { + this.dbType = dbType; + return this; + } + /** * Build the immutable beans. * diff --git a/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/db/domain/DatabaseCreationRequest.java b/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/db/domain/DatabaseCreationRequest.java index 14d3beba..76ae47ea 100644 --- a/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/db/domain/DatabaseCreationRequest.java +++ b/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/db/domain/DatabaseCreationRequest.java @@ -16,6 +16,11 @@ package com.dtsx.astra.sdk.db.domain; +import lombok.AccessLevel; +import lombok.Setter; + +import java.util.UUID; + /** * Database creation request * @@ -58,7 +63,12 @@ public class DatabaseCreationRequest { /** * Default is null, if vector will be added */ - private DatabaseCreationType dbType; + protected DatabaseCreationType dbType; + + /** + * Identifier to assign a database to a PCU group directly. + */ + private UUID pcuGroupUUID; /** * default constructor. @@ -78,7 +88,10 @@ public DatabaseCreationRequest(DatabaseCreationBuilder builder) { this.name = builder.name; this.region = builder.region; this.tier = builder.tier; - if (builder.vector) { + this.pcuGroupUUID = builder.pcuGroupUUID; + if (builder.dbType != null) { + this.dbType = builder.dbType; + } else if (builder.vector) { this.dbType = DatabaseCreationType.vector; } } @@ -103,6 +116,16 @@ public String getName() { return name; } + /** + * Setter name update + * + * @param name + * name update + */ + public void setName(String name) { + this.name = name; + } + /** * Getter accessor for attribute 'keyspace'. * @@ -132,6 +155,16 @@ public CloudProviderType getCloudProvider() { public String getTier() { return tier; } + + /** + * Getter accessor for attribute 'pcuGroupUUID'. + * + * @return + * current value of 'pcuGroupUUID' + */ + public UUID getPcuGroupUUID() { + return pcuGroupUUID; + } /** * Getter accessor for attribute 'capacityUnits'. diff --git a/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/PcuGroupOpsClient.java b/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/PcuGroupOpsClient.java index 5aaa748a..2ff58ffb 100644 --- a/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/PcuGroupOpsClient.java +++ b/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/PcuGroupOpsClient.java @@ -21,6 +21,7 @@ */ @Slf4j public class PcuGroupOpsClient extends AbstractApiClient { + /** * PCU group unique identifier. */ @@ -87,7 +88,7 @@ public Optional find() { * if the PCU group does not exist */ public PcuGroup get() { - return new PcuGroupsClient(token, environment).findById(pcuGroupId).orElseThrow(() -> PcuGroupNotFoundException.forId(pcuGroupId)); + return new PcuGroupsOpsClient(token, environment).findById(pcuGroupId).orElseThrow(() -> PcuGroupNotFoundException.forId(pcuGroupId)); } /** diff --git a/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/PcuGroupsClient.java b/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/PcuGroupsOpsClient.java similarity index 68% rename from astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/PcuGroupsClient.java rename to astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/PcuGroupsOpsClient.java index 9ad0f7e7..69c2d259 100644 --- a/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/PcuGroupsClient.java +++ b/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/PcuGroupsOpsClient.java @@ -2,16 +2,20 @@ import com.dtsx.astra.sdk.pcu.domain.PcuGroup; import com.dtsx.astra.sdk.pcu.domain.PcuGroupCreationRequest; +import com.dtsx.astra.sdk.pcu.domain.PcuType; +import com.dtsx.astra.sdk.pcu.domain.PcuTypeLocationFilter; import com.dtsx.astra.sdk.pcu.exception.PcuGroupNotFoundException; import com.dtsx.astra.sdk.pcu.exception.PcuGroupsNotFoundException; import com.dtsx.astra.sdk.AbstractApiClient; import com.dtsx.astra.sdk.utils.*; +import com.dtsx.astra.sdk.utils.observability.ApiRequestObserver; import com.fasterxml.jackson.core.type.TypeReference; import lombok.extern.slf4j.Slf4j; import lombok.val; import java.net.HttpURLConnection; import java.util.List; +import java.util.Map; import java.util.Optional; import java.util.stream.Stream; @@ -20,38 +24,91 @@ * Provides operations for creating, finding, and managing PCU groups. */ @Slf4j -public class PcuGroupsClient extends AbstractApiClient { +public class PcuGroupsOpsClient extends AbstractApiClient { + private static final TypeReference> RESPONSE_PCU_GROUPS = new TypeReference<>(){}; /** * Constructor with token for production environment. * - * @param token - * authentication token + * @param token authentication token */ - public PcuGroupsClient(String token) { - super(token, AstraEnvironment.PROD); + public PcuGroupsOpsClient(String token) { + this(token, AstraEnvironment.PROD); } /** - * Constructor with token and environment. + * Constructor with token for different environment + * + * @param token authentication token + * @param environment astra environment + */ + public PcuGroupsOpsClient(String token, AstraEnvironment environment) { + super(token, environment); + } + + /** + * As immutable object use builder to initiate the object. * - * @param token - * authentication token * @param env - * target Astra environment + * define target environment to be used + * @param token + * authenticated token + * @param observers + * list of observers */ - public PcuGroupsClient(String token, AstraEnvironment env) { - super(token, env); + public PcuGroupsOpsClient(String token, AstraEnvironment env, Map observers) { + super(token, env, observers); + HttpClientWrapper.registerObservers(observers); } + // --------------------------------- + // ---- TYPES ---- + // --------------------------------- + + private static final TypeReference> RESPONSE_PCU_TYPES = new TypeReference<>(){}; + /** {@inheritDoc} */ @Override public String getServiceName() { return "pcu.groups"; } + // --------------------------------- + // ---- PCU TYPES ---- + // --------------------------------- + + public Stream listPcuTypes(PcuTypeLocationFilter request) { + String contextPath = "/types"; + boolean first = true; + if (request != null) { + if (Utils.hasLength(request.getProvider())) { + first = false; + contextPath = contextPath + "?provider=" + request.getProvider(); + } + if (Utils.hasLength(request.getRegion())) { + if (!first) { + contextPath = contextPath + "®ion=" + request.getRegion(); + } else { + contextPath = contextPath + "?region=" + request.getRegion(); + } + } + } + + val res = GET(getEndpointPcus() + contextPath, getOperationName("find")); + try { + return JsonUtils.unmarshallType(res.getBody(), RESPONSE_PCU_TYPES).stream(); + } catch (Exception e) { + ApiResponseError responseError = null; + try { + responseError = JsonUtils.unmarshallBean(res.getBody(), ApiResponseError.class); + System.out.println(responseError.toString()); + } catch (Exception ignored) {} + throw e; + } + } + // --------------------------------- // ---- CRUD ---- // --------------------------------- @@ -67,7 +124,9 @@ public String getServiceName() { * if creation fails */ public PcuGroup create(PcuGroupCreationRequest req) { - val res = POST(getEndpointPcus(), JsonUtils.marshall(List.of(req.withDefaultsAndValidations())), getOperationName("create")); + String payload = JsonUtils.marshall(List.of(req.withDefaultsAndValidations())); + System.out.println(payload); + val res = POST(getEndpointPcus(), payload, getOperationName("create")); if (HttpURLConnection.HTTP_CREATED != res.getCode()) { throw new IllegalStateException("Expected code 201 to create pcu group but got " + res.getCode() + "body=" + res.getBody()); diff --git a/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PcuCapacityWorkloadType.java b/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PcuCapacityWorkloadType.java new file mode 100644 index 00000000..3e5e0c26 --- /dev/null +++ b/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PcuCapacityWorkloadType.java @@ -0,0 +1,34 @@ +package com.dtsx.astra.sdk.pcu.domain; + +import com.fasterxml.jackson.annotation.JsonValue; +import lombok.Getter; +import lombok.RequiredArgsConstructor; +import lombok.experimental.Accessors; + +/** + * Enumeration of PCU (Processing Capacity Units) provisioning types. + * Defines how compute resources are allocated for a PCU group. + */ +@Getter +@Accessors(fluent = true) +@RequiredArgsConstructor +public enum PcuCapacityWorkloadType { + + /** + * Shared provisioning - resources are shared across multiple tenants. + * More cost-effective but with potential resource contention. + */ + FLEXIBLE("flexible"), + + /** + * Dedicated provisioning - resources are exclusively allocated. + * Higher cost but guaranteed performance and isolation. + */ + COMMITED("commited"); + + /** + * JSON serialization value for the provision type. + */ + @JsonValue + private final String fieldValue; +} diff --git a/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PcuGroup.java b/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PcuGroup.java index 0e6d47e8..60b30152 100644 --- a/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PcuGroup.java +++ b/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PcuGroup.java @@ -6,6 +6,8 @@ import lombok.Data; import lombok.NoArgsConstructor; +import java.util.UUID; + /** * Represents a PCU (Processing Capacity Units) Group in Astra. * A PCU group manages compute resources for databases across cloud providers and regions. @@ -18,7 +20,7 @@ public class PcuGroup { * Unique identifier for the PCU group. */ @JsonProperty("uuid") - private String id; + private UUID id; /** * Organization identifier. diff --git a/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PcuGroupCreateUpdateRequest.java b/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PcuGroupCreateUpdateRequest.java index 98ce90f1..c8362445 100644 --- a/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PcuGroupCreateUpdateRequest.java +++ b/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PcuGroupCreateUpdateRequest.java @@ -1,6 +1,7 @@ package com.dtsx.astra.sdk.pcu.domain; import com.dtsx.astra.sdk.db.domain.CloudProviderType; +import lombok.AccessLevel; import lombok.Getter; import lombok.NoArgsConstructor; import lombok.Setter; @@ -36,16 +37,45 @@ public abstract class PcuGroupCreateUpdateRequest { */ protected String region; + // -------------------------------------- + // Capacity Details + // -------------------------------------- + + /** + * Committed vs Flexible Workload. + *

+ * Commited: Committed capacity workloads include continuously-provisioned resources, and they can never scale to zero. + * Committed capacity workloads are intended for any database in any environment that requires long-term, continuous + * availability, such as multi-region databases and latency sensitive workloads. + *

+ * Flexible capacity workloads: PCU groups for flexible capacity workloads are billed entirely at the HCU rate, and they + * have the option to manually scale to zero. With flexible capacity workloads, you are billed for continuous HCU usage + * based on the group’s minimum capacity. While flexible capacity workloads don’t require a commitment to reserved capacity, + * they don’t offer cost savings for continuous usage that can be realized at the RCU rate. + */ + protected PcuCapacityWorkloadType workloadType; + + /** + * Provisioning type for the PCU group. + */ + @Setter(AccessLevel.NONE) + protected PcuProvisionType provisionType; + + public PcuGroupCreateUpdateRequest setProvisionType(PcuProvisionType provisionType) { + this.provisionType = provisionType; + return this; + } + /** * Minimum number of PCUs (must be greater or equals to 1). */ protected Integer min; // Integers so they're nullable - + /** * Maximum number of PCUs (must be greater or equals to min). */ protected Integer max; - + /** * Number of reserved PCUs (must be non-negative and lower or equals to min). */ diff --git a/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PcuGroupCreationRequest.java b/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PcuGroupCreationRequest.java index 2b155551..7062761b 100644 --- a/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PcuGroupCreationRequest.java +++ b/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PcuGroupCreationRequest.java @@ -12,15 +12,11 @@ @Setter @SuperBuilder public final class PcuGroupCreationRequest extends PcuGroupCreateUpdateRequest { + /** * Instance type for the PCU group (e.g., "standard"). */ private String instanceType; - - /** - * Provisioning type for the PCU group. - */ - private PcuProvisionType provisionType; /** * Applies default values and validates the request before creation. @@ -34,15 +30,19 @@ public PcuGroupCreationRequest withDefaultsAndValidations() { this.provisionType = PcuProvisionType.SHARED; } - // TODO do we really want a default for this? (since pcu instance types are changing) + // De if (this.instanceType == null || this.instanceType.isBlank()) { - this.instanceType = "standard"; + this.instanceType = PcuInstanceType.SMALL.toString(); } if (this.reserved == null) { this.reserved = 0; + this.min = 1; + this.max = 1; } return this; } + + } diff --git a/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PcuGroupUpdateRequest.java b/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PcuGroupUpdateRequest.java index e97dd5c8..d0e43a33 100644 --- a/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PcuGroupUpdateRequest.java +++ b/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PcuGroupUpdateRequest.java @@ -32,11 +32,10 @@ public PcuGroupCreateUpdateRequest withDefaultsAndValidations(PcuGroup base) { internalRep.setMin(this.min == null ? base.getMin() : this.min); internalRep.setMax(this.max == null ? base.getMax() : this.max); internalRep.setReserved(this.reserved == null ? base.getReserved() : this.reserved); - internalRep.validate(); return internalRep - .setPcuGroupUUID(base.getId()) + .setPcuGroupUUID(base.getId().toString()) .setInstanceType(base.getInstanceType()) .setProvisionType(base.getProvisionType()); } @@ -50,10 +49,14 @@ public PcuGroupCreateUpdateRequest withDefaultsAndValidations(PcuGroup base) { static class InternalRep extends PcuGroupUpdateRequest { private String pcuGroupUUID; private String instanceType; - private PcuProvisionType provisionType; InternalRep() { super(); } + + public InternalRep setProvisionType(PcuProvisionType provisionType) { + super.setProvisionType(provisionType); + return this; + } } } diff --git a/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PcuInstanceType.java b/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PcuInstanceType.java new file mode 100644 index 00000000..25c6989c --- /dev/null +++ b/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PcuInstanceType.java @@ -0,0 +1,22 @@ +package com.dtsx.astra.sdk.pcu.domain; + +import lombok.Getter; + +@Getter +public enum PcuInstanceType { + + SMALL("small"), + MEDIUM("medium"), + GENERAL_PURPOSE("generalPurpose"), + CACHE_OPTIMIZED("cacheOptimized"), + + // Legacy + STANDARD("standard"), + STORAGE_OPTIMIZED("storageOptimized"); + + final String code; + + PcuInstanceType(String code) { + this.code = code; + } +} diff --git a/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PcuProvisionType.java b/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PcuProvisionType.java index 87718e8c..4d5dfd98 100644 --- a/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PcuProvisionType.java +++ b/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PcuProvisionType.java @@ -13,6 +13,7 @@ @Accessors(fluent = true) @RequiredArgsConstructor public enum PcuProvisionType { + /** * Shared provisioning - resources are shared across multiple tenants. * More cost-effective but with potential resource contention. diff --git a/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PcuType.java b/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PcuType.java new file mode 100644 index 00000000..087503ff --- /dev/null +++ b/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PcuType.java @@ -0,0 +1,19 @@ +package com.dtsx.astra.sdk.pcu.domain; + +import com.dtsx.astra.sdk.db.domain.CloudProviderType; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.Map; + +@Data +@NoArgsConstructor +@JsonIgnoreProperties(ignoreUnknown = true) +public class PcuType { + String type; + String region; + String provider; + Map details; + boolean enabled; +} diff --git a/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PcuTypeLocationFilter.java b/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PcuTypeLocationFilter.java new file mode 100644 index 00000000..d2588df9 --- /dev/null +++ b/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PcuTypeLocationFilter.java @@ -0,0 +1,15 @@ +package com.dtsx.astra.sdk.pcu.domain; + +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import lombok.AllArgsConstructor; +import lombok.Data; +import lombok.NoArgsConstructor; + +@Data +@NoArgsConstructor +@AllArgsConstructor +@JsonIgnoreProperties(ignoreUnknown = true) +public class PcuTypeLocationFilter { + String provider; + String region; +} diff --git a/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PcuTypeResolver.java b/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PcuTypeResolver.java new file mode 100644 index 00000000..3c6d5ef1 --- /dev/null +++ b/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PcuTypeResolver.java @@ -0,0 +1,58 @@ +package com.dtsx.astra.sdk.pcu.domain; + +import java.util.List; + +/** + * Utility class for resolving default PCU types based on availability and configuration. + */ +public class PcuTypeResolver { + + /** + * Resolves the default PCU type based on available types and mini PCU configuration. + * + *

Selection priority when mini PCU is enabled: + * SMALL > MEDIUM > GENERAL_PURPOSE > CACHE_OPTIMIZED + * + *

Selection priority when mini PCU is disabled: + * GENERAL_PURPOSE > CACHE_OPTIMIZED (SMALL and MEDIUM are ignored) + * + * @param availableTypes list of available PCU family types + * @param miniPcuEnabled whether mini PCU is enabled + * @return the selected PCU family, or null if no suitable type is available + */ + public static PcuInstanceType resolveDefaultPcuType(List availableTypes, boolean miniPcuEnabled) { + if (availableTypes == null || availableTypes.isEmpty()) { + return null; + } + + if (miniPcuEnabled) { + // Priority: SMALL > MEDIUM > GENERAL_PURPOSE > CACHE_OPTIMIZED + if (availableTypes.contains(PcuInstanceType.SMALL)) { + return PcuInstanceType.SMALL; + } + if (availableTypes.contains(PcuInstanceType.MEDIUM)) { + return PcuInstanceType.MEDIUM; + } + if (availableTypes.contains(PcuInstanceType.GENERAL_PURPOSE)) { + return PcuInstanceType.GENERAL_PURPOSE; + } + if (availableTypes.contains(PcuInstanceType.CACHE_OPTIMIZED)) { + return PcuInstanceType.CACHE_OPTIMIZED; + } + } else { + // Priority: GENERAL_PURPOSE > CACHE_OPTIMIZED (ignore SMALL and MEDIUM) + if (availableTypes.contains(PcuInstanceType.GENERAL_PURPOSE)) { + return PcuInstanceType.GENERAL_PURPOSE; + } + if (availableTypes.contains(PcuInstanceType.CACHE_OPTIMIZED)) { + return PcuInstanceType.CACHE_OPTIMIZED; + } + } + + return null; + } + + private PcuTypeResolver() { + // Utility class - prevent instantiation + } +} diff --git a/astra-sdk-devops/src/test/java/com/dtsx/astra/sdk/AbstractDevopsApiTest.java b/astra-sdk-devops/src/test/java/com/dtsx/astra/sdk/AbstractDevopsApiTest.java index 64607136..e6af0f1c 100644 --- a/astra-sdk-devops/src/test/java/com/dtsx/astra/sdk/AbstractDevopsApiTest.java +++ b/astra-sdk-devops/src/test/java/com/dtsx/astra/sdk/AbstractDevopsApiTest.java @@ -36,22 +36,22 @@ public abstract class AbstractDevopsApiTest { /** * Reference to Databases Client. */ - private static AstraDBOpsClient databasesClient; + protected static AstraDBOpsClient databasesClient; /** * Reference to organization client. */ - private static AstraOpsClient apiDevopsClient; + protected static AstraOpsClient apiDevopsClient; /** * Working db. */ - private static DbOpsClient dbClient; + protected static DbOpsClient dbClient; /** * Reference to Databases Client. */ - private static AstraStreamingClient streamingClient; + protected static AstraStreamingClient streamingClient; /** * Access DB client. diff --git a/astra-sdk-devops/src/test/java/com/dtsx/astra/sdk/pcu/PCUGroupClientTest.java b/astra-sdk-devops/src/test/java/com/dtsx/astra/sdk/pcu/PCUGroupClientTest.java new file mode 100644 index 00000000..0b641318 --- /dev/null +++ b/astra-sdk-devops/src/test/java/com/dtsx/astra/sdk/pcu/PCUGroupClientTest.java @@ -0,0 +1,135 @@ +package com.dtsx.astra.sdk.pcu; + +import com.dtsx.astra.sdk.AbstractDevopsApiTest; +import com.dtsx.astra.sdk.AstraOpsClient; +import com.dtsx.astra.sdk.db.domain.CloudProviderType; +import com.dtsx.astra.sdk.db.domain.DatabaseCreationRequest; +import com.dtsx.astra.sdk.db.domain.DatabaseStatusType; +import com.dtsx.astra.sdk.org.domain.Organization; +import com.dtsx.astra.sdk.pcu.domain.PcuCapacityWorkloadType; +import com.dtsx.astra.sdk.pcu.domain.PcuGroup; +import com.dtsx.astra.sdk.pcu.domain.PcuGroupCreationRequest; +import com.dtsx.astra.sdk.pcu.domain.PcuInstanceType; +import com.dtsx.astra.sdk.pcu.domain.PcuProvisionType; +import com.dtsx.astra.sdk.pcu.domain.PcuType; +import com.dtsx.astra.sdk.pcu.domain.PcuTypeLocationFilter; +import com.dtsx.astra.sdk.utils.AstraEnvironment; +import com.dtsx.astra.sdk.utils.JsonUtils; +import com.dtsx.astra.sdk.utils.TestUtils; +import org.junit.jupiter.api.Assertions; +import org.junit.jupiter.api.BeforeAll; +import org.junit.jupiter.api.MethodOrderer; +import org.junit.jupiter.api.Order; +import org.junit.jupiter.api.Test; +import org.junit.jupiter.api.TestMethodOrder; + +import java.util.UUID; +import java.util.stream.Stream; + +@TestMethodOrder(MethodOrderer.OrderAnnotation.class) +public class PCUGroupClientTest extends AbstractDevopsApiTest { + + public static final String TOKEN = "change_me"; + public static final String TEST_REGION = "us-west-2"; + + @BeforeAll + public static void beforeAll() { + apiDevopsClient = new AstraOpsClient(TOKEN, AstraEnvironment.DEV); + } + + @Test + @Order(1) + public void shouldAccessOrganizationInDev() { + Organization org = getApiDevopsClient().getOrganization(); + Assertions.assertNotNull(org); + Assertions.assertNotNull(org.getId()); + Assertions.assertNotNull(org.getName()); + Assertions.assertTrue(org .getName().startsWith("Data API")); + } + + @Test + @Order(2) + public void shouldListPcuGroupsType() { + PcuTypeLocationFilter location = new PcuTypeLocationFilter(CloudProviderType.AWS.getCode().toLowerCase(), TEST_REGION); + Stream types = getApiDevopsClient().pcus().listPcuTypes(location); + Assertions.assertNotNull(types); + System.out.println(JsonUtils.marshall(types.toList())); + } + + @Test + @Order(2) + public void shouldListPcuGroups() { + Stream groups = getApiDevopsClient().pcus().findAll(); + System.out.println(groups.toList()); + } + + @Test + @Order(2) + public void shouldCreatePcuGroup() { + PcuGroupCreationRequest createPcu = PcuGroupCreationRequest + .builder() + .title("pcu_group_from_java") + .description("my first PCU group") + .instanceType("standard") + .cloudProvider(CloudProviderType.AWS) + .region(TEST_REGION) + .workloadType(PcuCapacityWorkloadType.FLEXIBLE) + .provisionType(PcuProvisionType.SHARED) + .reserved(1) + .min(1) + .max(1) + .build(); + + PcuGroup group = getApiDevopsClient().pcus().create(createPcu); + System.out.println(group); + } + + @Test + @Order(2) + public void shouldCreateMiniPcu() { + PcuGroupCreationRequest createPcu = PcuGroupCreationRequest + .builder() + .title("java_client_mini_pcu") + .description("java_client_mini_pcu") + .instanceType(PcuInstanceType.SMALL.getCode()) + .cloudProvider(CloudProviderType.AWS) + .region(TEST_REGION) + .workloadType(PcuCapacityWorkloadType.COMMITED) + .provisionType(PcuProvisionType.SHARED) + .reserved(1) + .min(1) + .max(1) + .build(); + PcuGroup group = getApiDevopsClient().pcus().create(createPcu); + System.out.println(group); + } + + @Test + @Order(2) + public void shouldDeletePcuGroup() { + getApiDevopsClient().pcus().group("57dde257-86c6-4646-9247-670cd8a4d360").delete(); + } + + @Test + @Order(3) + public void should_create_db_and_assign_pcu() throws InterruptedException { + UUID miniPcuUUID = UUID.fromString("57dde257-86c6-4646-9247-670cd8a4d360"); + DatabaseCreationRequest dbCreation = DatabaseCreationRequest + .builder() + .name("vector_db_in_mini_pcu") + .keyspace(SDK_TEST_KEYSPACE) + .cloudProvider(CloudProviderType.AWS) + .cloudRegion(TEST_REGION) + .withVector() + .assignToPCUGroup(miniPcuUUID) + .build(); + String dbId = getApiDevopsClient().db().create(dbCreation); + Thread.sleep(10000); + Assertions.assertTrue(getDatabasesClient().findById(dbId).isPresent()); + Assertions.assertNotNull(getDatabasesClient().database(dbId).get()); + Assertions.assertTrue(getDatabasesClient().findByName("vector_db_in_mini_pcu").count() > 0); + // When + TestUtils.waitForDbStatus(getDatabasesClient().database(dbId), DatabaseStatusType.ACTIVE, 500); + } + +} diff --git a/astra-sdk-devops/src/test/java/com/dtsx/astra/sdk/pcu/ParkingTest.java b/astra-sdk-devops/src/test/java/com/dtsx/astra/sdk/pcu/ParkingTest.java deleted file mode 100644 index 0d1b53e4..00000000 --- a/astra-sdk-devops/src/test/java/com/dtsx/astra/sdk/pcu/ParkingTest.java +++ /dev/null @@ -1,10 +0,0 @@ -package com.dtsx.astra.sdk.pcu; - -import com.dtsx.astra.sdk.AstraOpsClient; -import com.dtsx.astra.sdk.utils.AstraEnvironment; -import lombok.val; -import org.junit.jupiter.api.Test; - -public class ParkingTest { - -} diff --git a/astra-sdk-devops/src/test/java/com/dtsx/astra/sdk/pcu/PcuTypeResolverTest.java b/astra-sdk-devops/src/test/java/com/dtsx/astra/sdk/pcu/PcuTypeResolverTest.java new file mode 100644 index 00000000..1cae4610 --- /dev/null +++ b/astra-sdk-devops/src/test/java/com/dtsx/astra/sdk/pcu/PcuTypeResolverTest.java @@ -0,0 +1,132 @@ +package com.dtsx.astra.sdk.pcu; + +import com.dtsx.astra.sdk.pcu.domain.PcuInstanceType; +import com.dtsx.astra.sdk.pcu.domain.PcuTypeResolver; +import org.junit.jupiter.api.DisplayName; +import org.junit.jupiter.api.Nested; +import org.junit.jupiter.api.Test; + +import java.util.Arrays; +import java.util.Collections; +import java.util.List; + +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertNull; + +/** + * Test class for PcuTypeResolver. + */ +@DisplayName("PcuTypeResolver Tests") +class PcuTypeResolverTest { + + @Nested + @DisplayName("Mini PCU Enabled") + class MiniPcuEnabled { + + @Test + @DisplayName("Selects SMALL when SMALL is available") + void selectsSmallWhenSmallIsAvailable() { + List availableTypes = Arrays.asList( + PcuInstanceType.SMALL, + PcuInstanceType.MEDIUM, + PcuInstanceType.GENERAL_PURPOSE, + PcuInstanceType.CACHE_OPTIMIZED + ); + + assertEquals( + PcuInstanceType.SMALL, + PcuTypeResolver.resolveDefaultPcuType(availableTypes, true) + ); + } + + @Test + @DisplayName("Selects MEDIUM when SMALL is unavailable but MEDIUM exists") + void selectsMediumWhenSmallUnavailableButMediumExists() { + List availableTypes = Arrays.asList( + PcuInstanceType.MEDIUM, + PcuInstanceType.GENERAL_PURPOSE + ); + + assertEquals( + PcuInstanceType.MEDIUM, + PcuTypeResolver.resolveDefaultPcuType(availableTypes, true) + ); + } + + @Test + @DisplayName("Selects GENERAL_PURPOSE when only GENERAL_PURPOSE and CACHE_OPTIMIZED exist") + void selectsGeneralPurposeWhenOnlyGeneralPurposeAndCacheOptimizedExist() { + List availableTypes = Arrays.asList( + PcuInstanceType.GENERAL_PURPOSE, + PcuInstanceType.CACHE_OPTIMIZED + ); + + assertEquals( + PcuInstanceType.GENERAL_PURPOSE, + PcuTypeResolver.resolveDefaultPcuType(availableTypes, true) + ); + } + + @Test + @DisplayName("Selects CACHE_OPTIMIZED when it is the only available type") + void selectsCacheOptimizedWhenItIsTheOnlyAvailableType() { + List availableTypes = Collections.singletonList( + PcuInstanceType.CACHE_OPTIMIZED + ); + + assertEquals( + PcuInstanceType.CACHE_OPTIMIZED, + PcuTypeResolver.resolveDefaultPcuType(availableTypes, true) + ); + } + + @Test + @DisplayName("Returns null when no types are available") + void returnsNullWhenNoTypesAreAvailable() { + assertNull(PcuTypeResolver.resolveDefaultPcuType(Collections.emptyList(), true)); + } + } + + @Nested + @DisplayName("Mini PCU Disabled") + class MiniPcuDisabled { + + @Test + @DisplayName("Selects GENERAL_PURPOSE when GENERAL_PURPOSE is available") + void selectsGeneralPurposeWhenGeneralPurposeIsAvailable() { + List availableTypes = Arrays.asList( + PcuInstanceType.GENERAL_PURPOSE, + PcuInstanceType.CACHE_OPTIMIZED + ); + + assertEquals( + PcuInstanceType.GENERAL_PURPOSE, + PcuTypeResolver.resolveDefaultPcuType(availableTypes, false) + ); + } + + @Test + @DisplayName("Selects CACHE_OPTIMIZED when it is the only available type") + void selectsCacheOptimizedWhenItIsTheOnlyAvailableType() { + List availableTypes = Collections.singletonList( + PcuInstanceType.CACHE_OPTIMIZED + ); + + assertEquals( + PcuInstanceType.CACHE_OPTIMIZED, + PcuTypeResolver.resolveDefaultPcuType(availableTypes, false) + ); + } + + @Test + @DisplayName("Returns null when only SMALL or MEDIUM are available") + void returnsNullWhenOnlySmallOrMediumAreAvailable() { + List availableTypes = Arrays.asList( + PcuInstanceType.SMALL, + PcuInstanceType.MEDIUM + ); + + assertNull(PcuTypeResolver.resolveDefaultPcuType(availableTypes, false)); + } + } +} diff --git a/integrations/skills/spring-boot-data-api/README.md b/integrations/skills/spring-boot-data-api/README.md index a290b4a0..04fc6257 100644 --- a/integrations/skills/spring-boot-data-api/README.md +++ b/integrations/skills/spring-boot-data-api/README.md @@ -5,8 +5,8 @@ A comprehensive AI-powered skill for building production-ready Spring Boot appli ## Quick Links - πŸ“š **[Main Skill Document](SKILL.md)** - Complete step-by-step guide -- πŸ“ **[Code Templates](templates/)** - Reusable code templates -- πŸ’‘ **[Basic Example](examples/basic/)** - Minimal working example +- πŸ“ **[Code Templates](assets/templates/)** - Reusable code templates +- πŸ’‘ **[Basic Example](assets/examples/basic/)** - Minimal working example ## What You'll Learn @@ -29,6 +29,26 @@ A comprehensive AI-powered skill for building production-ready Spring Boot appli 30-45 minutes +## Folder Structure + +``` +spring-boot-data-api/ +β”œβ”€β”€ README.md # This file +β”œβ”€β”€ SKILL.md # Main skill guide +β”œβ”€β”€ references/ # Additional reference docs (future) +β”œβ”€β”€ scripts/ # Automation scripts (future) +└── assets/ # Reusable assets + β”œβ”€β”€ templates/ # Code templates + β”‚ β”œβ”€β”€ Document.java.template + β”‚ β”œβ”€β”€ Repository.java.template + β”‚ β”œβ”€β”€ Service.java.template + β”‚ β”œβ”€β”€ Controller.java.template + β”‚ └── application.yml.template + └── examples/ # Working examples + └── basic/ # Basic example + └── README.md +``` + ## How to Use This Skill ### With Claude @@ -70,7 +90,7 @@ integrations/skills/spring-boot-data-api/SKILL.md ``` 2. **Use templates to generate code:** - - Copy templates from `templates/` directory + - Copy templates from `assets/templates/` directory - Replace placeholders ({{CLASS_NAME}}, {{COLLECTION_NAME}}, etc.) - Customize for your use case diff --git a/integrations/skills/spring-boot-data-api/examples/basic/README.md b/integrations/skills/spring-boot-data-api/assets/examples/basic/README.md similarity index 100% rename from integrations/skills/spring-boot-data-api/examples/basic/README.md rename to integrations/skills/spring-boot-data-api/assets/examples/basic/README.md diff --git a/integrations/skills/spring-boot-data-api/templates/Controller.java.template b/integrations/skills/spring-boot-data-api/assets/templates/Controller.java.template similarity index 100% rename from integrations/skills/spring-boot-data-api/templates/Controller.java.template rename to integrations/skills/spring-boot-data-api/assets/templates/Controller.java.template diff --git a/integrations/skills/spring-boot-data-api/templates/Document.java.template b/integrations/skills/spring-boot-data-api/assets/templates/Document.java.template similarity index 100% rename from integrations/skills/spring-boot-data-api/templates/Document.java.template rename to integrations/skills/spring-boot-data-api/assets/templates/Document.java.template diff --git a/integrations/skills/spring-boot-data-api/templates/Repository.java.template b/integrations/skills/spring-boot-data-api/assets/templates/Repository.java.template similarity index 100% rename from integrations/skills/spring-boot-data-api/templates/Repository.java.template rename to integrations/skills/spring-boot-data-api/assets/templates/Repository.java.template diff --git a/integrations/skills/spring-boot-data-api/templates/Service.java.template b/integrations/skills/spring-boot-data-api/assets/templates/Service.java.template similarity index 100% rename from integrations/skills/spring-boot-data-api/templates/Service.java.template rename to integrations/skills/spring-boot-data-api/assets/templates/Service.java.template diff --git a/integrations/skills/spring-boot-data-api/templates/application.yml.template b/integrations/skills/spring-boot-data-api/assets/templates/application.yml.template similarity index 100% rename from integrations/skills/spring-boot-data-api/templates/application.yml.template rename to integrations/skills/spring-boot-data-api/assets/templates/application.yml.template diff --git a/tools/data-api-tools/pom.xml b/tools/data-api-tools/pom.xml index df336ac0..5814c186 100644 --- a/tools/data-api-tools/pom.xml +++ b/tools/data-api-tools/pom.xml @@ -19,6 +19,15 @@ astra-db-java ${project.version} + + + + com.datastax.astra + astra-db-java + ${project.version} + test-jar + test + diff --git a/tools/data-api-tools/src/test/java/com/datastax/astra/tool/copy/README.md b/tools/data-api-tools/src/test/java/com/datastax/astra/tool/copy/README.md new file mode 100644 index 00000000..a6b24de8 --- /dev/null +++ b/tools/data-api-tools/src/test/java/com/datastax/astra/tool/copy/README.md @@ -0,0 +1,86 @@ +# CollectionCloner Integration Tests + +This directory contains integration tests for the `CollectionCloner` utility. + +## Test Coverage + +The `CollectionClonerIT` test suite covers: + +1. **Basic Cloning** - Small collection (50 documents) with default settings +2. **Large Collection Cloning** - 2500+ documents with parallel reading (tests estimatedDocumentCount) +3. **Document Transformation** - Using DocumentMapper to transform documents during cloning +4. **Custom Thread Pools** - Testing different read/insert thread pool configurations +5. **Empty Collection** - Handling edge case of empty source collection +6. **Duplicate Prevention** - Verifying no duplicates are created on repeated cloning + +## Running the Tests + +### Prerequisites + +- Local HCD/DSE instance running on `http://localhost:8181` (default) +- OR Astra database with proper credentials configured + +### Run Tests Locally (HCD/DSE) + +```bash +# From project root +mvn test -pl tools/data-api-tools + +# Or from tools/data-api-tools directory +mvn test +``` + +### Run Tests Against Astra + +```bash +# Set environment variables +export ASTRA_DB_APPLICATION_TOKEN= +export ASTRA_DB_API_ENDPOINT= + +# Run tests +mvn test -pl tools/data-api-tools -Dtest.environment=astra_prod +``` + +## Test Configuration + +Tests use configuration from: +- `src/test/resources/test-config.properties` - Default local settings +- Environment variables can override config file settings +- Inherits from `AbstractDataAPITest` in astra-db-java module + +## Performance Expectations + +With default settings (5 read threads, 10 insert threads): +- Small collections (< 100 docs): < 5 seconds +- Medium collections (500 docs): < 15 seconds +- Large collections (2500+ docs): < 60 seconds + +Actual performance depends on: +- Network latency +- Database load +- Document size and complexity +- Available system resources + +## Troubleshooting + +### Test Failures + +1. **Connection refused**: Ensure HCD/DSE is running on localhost:8181 +2. **Timeout errors**: Increase timeout in test configuration +3. **Duplicate key errors**: Expected behavior when cloning to non-empty target + +### Logging + +Adjust log levels in `src/test/resources/logback-test.xml`: +```xml + +``` + +## Adding New Tests + +When adding new test cases: +1. Extend `CollectionClonerIT` class +2. Use `@Order` annotation to control execution sequence +3. Clean up collections in `@BeforeAll` and `@AfterAll` +4. Use descriptive test method names: `should__()` +5. Add assertions to verify expected behavior diff --git a/tools/data-api-tools/src/test/resources/logback-test.xml b/tools/data-api-tools/src/test/resources/logback-test.xml new file mode 100644 index 00000000..5cf5eec7 --- /dev/null +++ b/tools/data-api-tools/src/test/resources/logback-test.xml @@ -0,0 +1,15 @@ + + + + + %d{HH:mm:ss.SSS} [%thread] %-5level %logger{36} - %msg%n + + + + + + + + + + diff --git a/tools/data-api-tools/src/test/resources/test-config.properties b/tools/data-api-tools/src/test/resources/test-config.properties new file mode 100644 index 00000000..252cf7cf --- /dev/null +++ b/tools/data-api-tools/src/test/resources/test-config.properties @@ -0,0 +1,49 @@ +# Test Configuration for Data API Tools Integration Tests +# This file is used by CollectionClonerIT and other integration tests + +# Default test environment - Astra Production +test.environment=astra_prod + +# ======================================== +# Astra Configuration +# ======================================== +# You can configure Astra connection in two ways: +# +# Option 1: Environment Variables (recommended for CI/CD) +# ASTRA_DB_APPLICATION_TOKEN - Your Astra DB token +# +# Option 2: Properties file (convenient for local development) +# Uncomment and set the property below: +# astra.token=AstraCS:...your-token-here... + +# Astra settings +astra.keyspace=default_keyspace +astra.cloud.provider=AWS +astra.cloud.region=us-east-2 + +# Test settings +test.timeout.seconds=300 +test.log.progress=true +test.vectorize=true +test.reranking=true + +# ======================================== +# Local HCD/DSE Configuration (commented out) +# Uncomment these lines and set test.environment=local to run against local HCD/DSE +# ======================================== +# test.environment=local +# local.endpoint=http://localhost:8181 +# local.keyspace=default_keyspace +# local.username=cassandra +# local.password=cassandra +# test.vectorize=false +# test.reranking=false + +# ======================================== +# Notes: +# ======================================== +# - For Astra tests, the framework automatically creates/finds a database +# based on cloud provider and region settings above +# - You don't need to specify ASTRA_DB_API_ENDPOINT - it's derived from +# the database name, cloud provider, and region +# - Priority: Environment Variables > System Properties > Config File From 63e88e5164d13a87924fc140418d473cca9d468b Mon Sep 17 00:00:00 2001 From: Cedrick Lunven Date: Thu, 25 Jun 2026 18:37:33 +0200 Subject: [PATCH 2/4] PCU group updqtes --- .../client/admin/definition/PCUGroupDefinition.java | 4 ++++ .../client/admin/definition/PCUTypeDefinition.java | 4 ++++ .../client/exceptions/AstraDevOpsAPIException.java | 13 +++++++++++++ ...va => PCUGroupDatacenterAssociationsClient.java} | 0 ...cuGroupOpsClient.java => PCUGroupOpsClient.java} | 0 ...GroupsOpsClient.java => PCUGroupsOpsClient.java} | 0 ...rkloadType.java => PCUCapacityWorkloadType.java} | 0 .../sdk/pcu/domain/{PcuGroup.java => PCUGroup.java} | 0 ...equest.java => PCUGroupCreateUpdateRequest.java} | 0 ...ionRequest.java => PCUGroupCreationRequest.java} | 0 ...tion.java => PCUGroupDatacenterAssociation.java} | 0 ...GroupStatusType.java => PCUGroupStatusType.java} | 0 ...pdateRequest.java => PCUGroupUpdateRequest.java} | 0 .../{PcuInstanceType.java => PCUInstanceType.java} | 0 ...{PcuProvisionType.java => PCUProvisionType.java} | 0 .../sdk/pcu/domain/{PcuType.java => PCUType.java} | 0 ...cationFilter.java => PCUTypeLocationFilter.java} | 0 .../{PcuTypeResolver.java => PCUTypeResolver.java} | 0 ...upClientTest.java => PCUGroupClientDevTest.java} | 0 ...peResolverTest.java => PCUTypeResolverTest.java} | 0 20 files changed, 21 insertions(+) create mode 100644 astra-db-java/src/main/java/com/datastax/astra/client/admin/definition/PCUGroupDefinition.java create mode 100644 astra-db-java/src/main/java/com/datastax/astra/client/admin/definition/PCUTypeDefinition.java create mode 100644 astra-db-java/src/main/java/com/datastax/astra/client/exceptions/AstraDevOpsAPIException.java rename astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/{PcuGroupDatacenterAssociationsClient.java => PCUGroupDatacenterAssociationsClient.java} (100%) rename astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/{PcuGroupOpsClient.java => PCUGroupOpsClient.java} (100%) rename astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/{PcuGroupsOpsClient.java => PCUGroupsOpsClient.java} (100%) rename astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/{PcuCapacityWorkloadType.java => PCUCapacityWorkloadType.java} (100%) rename astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/{PcuGroup.java => PCUGroup.java} (100%) rename astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/{PcuGroupCreateUpdateRequest.java => PCUGroupCreateUpdateRequest.java} (100%) rename astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/{PcuGroupCreationRequest.java => PCUGroupCreationRequest.java} (100%) rename astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/{PcuGroupDatacenterAssociation.java => PCUGroupDatacenterAssociation.java} (100%) rename astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/{PcuGroupStatusType.java => PCUGroupStatusType.java} (100%) rename astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/{PcuGroupUpdateRequest.java => PCUGroupUpdateRequest.java} (100%) rename astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/{PcuInstanceType.java => PCUInstanceType.java} (100%) rename astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/{PcuProvisionType.java => PCUProvisionType.java} (100%) rename astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/{PcuType.java => PCUType.java} (100%) rename astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/{PcuTypeLocationFilter.java => PCUTypeLocationFilter.java} (100%) rename astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/{PcuTypeResolver.java => PCUTypeResolver.java} (100%) rename astra-sdk-devops/src/test/java/com/dtsx/astra/sdk/pcu/{PCUGroupClientTest.java => PCUGroupClientDevTest.java} (100%) rename astra-sdk-devops/src/test/java/com/dtsx/astra/sdk/pcu/{PcuTypeResolverTest.java => PCUTypeResolverTest.java} (100%) diff --git a/astra-db-java/src/main/java/com/datastax/astra/client/admin/definition/PCUGroupDefinition.java b/astra-db-java/src/main/java/com/datastax/astra/client/admin/definition/PCUGroupDefinition.java new file mode 100644 index 00000000..9be09bd7 --- /dev/null +++ b/astra-db-java/src/main/java/com/datastax/astra/client/admin/definition/PCUGroupDefinition.java @@ -0,0 +1,4 @@ +package com.datastax.astra.client.admin.definition; + +public class PCUGroupDefinition { +} diff --git a/astra-db-java/src/main/java/com/datastax/astra/client/admin/definition/PCUTypeDefinition.java b/astra-db-java/src/main/java/com/datastax/astra/client/admin/definition/PCUTypeDefinition.java new file mode 100644 index 00000000..c01721e3 --- /dev/null +++ b/astra-db-java/src/main/java/com/datastax/astra/client/admin/definition/PCUTypeDefinition.java @@ -0,0 +1,4 @@ +package com.datastax.astra.client.admin.definition; + +public class PCUTypeDefinition { +} diff --git a/astra-db-java/src/main/java/com/datastax/astra/client/exceptions/AstraDevOpsAPIException.java b/astra-db-java/src/main/java/com/datastax/astra/client/exceptions/AstraDevOpsAPIException.java new file mode 100644 index 00000000..03f9a2c1 --- /dev/null +++ b/astra-db-java/src/main/java/com/datastax/astra/client/exceptions/AstraDevOpsAPIException.java @@ -0,0 +1,13 @@ +package com.datastax.astra.client.exceptions; + +import lombok.Getter; + +@Getter +public class DevOpsAPIException extends RuntimeException { + + /** Default error message. */ + public static final String DEFAULT_ERROR_MESSAGE = "Unexpected error occurred for Astra Devops API"; + + + +} diff --git a/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/PcuGroupDatacenterAssociationsClient.java b/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/PCUGroupDatacenterAssociationsClient.java similarity index 100% rename from astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/PcuGroupDatacenterAssociationsClient.java rename to astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/PCUGroupDatacenterAssociationsClient.java diff --git a/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/PcuGroupOpsClient.java b/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/PCUGroupOpsClient.java similarity index 100% rename from astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/PcuGroupOpsClient.java rename to astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/PCUGroupOpsClient.java diff --git a/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/PcuGroupsOpsClient.java b/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/PCUGroupsOpsClient.java similarity index 100% rename from astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/PcuGroupsOpsClient.java rename to astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/PCUGroupsOpsClient.java diff --git a/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PcuCapacityWorkloadType.java b/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PCUCapacityWorkloadType.java similarity index 100% rename from astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PcuCapacityWorkloadType.java rename to astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PCUCapacityWorkloadType.java diff --git a/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PcuGroup.java b/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PCUGroup.java similarity index 100% rename from astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PcuGroup.java rename to astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PCUGroup.java diff --git a/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PcuGroupCreateUpdateRequest.java b/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PCUGroupCreateUpdateRequest.java similarity index 100% rename from astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PcuGroupCreateUpdateRequest.java rename to astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PCUGroupCreateUpdateRequest.java diff --git a/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PcuGroupCreationRequest.java b/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PCUGroupCreationRequest.java similarity index 100% rename from astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PcuGroupCreationRequest.java rename to astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PCUGroupCreationRequest.java diff --git a/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PcuGroupDatacenterAssociation.java b/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PCUGroupDatacenterAssociation.java similarity index 100% rename from astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PcuGroupDatacenterAssociation.java rename to astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PCUGroupDatacenterAssociation.java diff --git a/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PcuGroupStatusType.java b/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PCUGroupStatusType.java similarity index 100% rename from astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PcuGroupStatusType.java rename to astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PCUGroupStatusType.java diff --git a/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PcuGroupUpdateRequest.java b/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PCUGroupUpdateRequest.java similarity index 100% rename from astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PcuGroupUpdateRequest.java rename to astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PCUGroupUpdateRequest.java diff --git a/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PcuInstanceType.java b/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PCUInstanceType.java similarity index 100% rename from astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PcuInstanceType.java rename to astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PCUInstanceType.java diff --git a/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PcuProvisionType.java b/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PCUProvisionType.java similarity index 100% rename from astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PcuProvisionType.java rename to astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PCUProvisionType.java diff --git a/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PcuType.java b/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PCUType.java similarity index 100% rename from astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PcuType.java rename to astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PCUType.java diff --git a/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PcuTypeLocationFilter.java b/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PCUTypeLocationFilter.java similarity index 100% rename from astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PcuTypeLocationFilter.java rename to astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PCUTypeLocationFilter.java diff --git a/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PcuTypeResolver.java b/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PCUTypeResolver.java similarity index 100% rename from astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PcuTypeResolver.java rename to astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PCUTypeResolver.java diff --git a/astra-sdk-devops/src/test/java/com/dtsx/astra/sdk/pcu/PCUGroupClientTest.java b/astra-sdk-devops/src/test/java/com/dtsx/astra/sdk/pcu/PCUGroupClientDevTest.java similarity index 100% rename from astra-sdk-devops/src/test/java/com/dtsx/astra/sdk/pcu/PCUGroupClientTest.java rename to astra-sdk-devops/src/test/java/com/dtsx/astra/sdk/pcu/PCUGroupClientDevTest.java diff --git a/astra-sdk-devops/src/test/java/com/dtsx/astra/sdk/pcu/PcuTypeResolverTest.java b/astra-sdk-devops/src/test/java/com/dtsx/astra/sdk/pcu/PCUTypeResolverTest.java similarity index 100% rename from astra-sdk-devops/src/test/java/com/dtsx/astra/sdk/pcu/PcuTypeResolverTest.java rename to astra-sdk-devops/src/test/java/com/dtsx/astra/sdk/pcu/PCUTypeResolverTest.java From 1a2ba5f08dfe60c46043e736a61a97e1ba64f5eb Mon Sep 17 00:00:00 2001 From: Cedrick Lunven Date: Fri, 26 Jun 2026 17:37:32 +0200 Subject: [PATCH 3/4] pcu --- .../astra/client/admin/AstraDBAdmin.java | 118 ++++-- .../admin/definition/DatabaseDefinition.java | 30 +- .../admin/definition/PCUGroupDefinition.java | 157 ++++++++ .../admin/definition/PCUTypeDefinition.java | 59 +++ .../admin/options/CreateDatabaseOptions.java | 20 + .../exceptions/AstraDevOpsAPIException.java | 81 +++- .../com/dtsx/astra/sdk/AstraOpsClient.java | 6 +- .../PCUGroupDatacenterAssociationsClient.java | 29 +- .../dtsx/astra/sdk/pcu/PCUGroupOpsClient.java | 31 +- .../astra/sdk/pcu/PCUGroupsOpsClient.java | 56 +-- .../pcu/domain/PCUCapacityWorkloadType.java | 12 +- .../dtsx/astra/sdk/pcu/domain/PCUGroup.java | 363 +++++++++++++++++- .../domain/PCUGroupCreateUpdateRequest.java | 8 +- .../pcu/domain/PCUGroupCreationRequest.java | 8 +- .../domain/PCUGroupDatacenterAssociation.java | 2 +- .../sdk/pcu/domain/PCUGroupStatusType.java | 2 +- .../sdk/pcu/domain/PCUGroupUpdateRequest.java | 8 +- .../astra/sdk/pcu/domain/PCUInstanceType.java | 20 +- .../sdk/pcu/domain/PCUProvisionType.java | 12 +- .../dtsx/astra/sdk/pcu/domain/PCUType.java | 3 +- .../sdk/pcu/domain/PCUTypeLocationFilter.java | 2 +- .../astra/sdk/pcu/domain/PCUTypeResolver.java | 30 +- .../PcuGroupDbAssociationNotFound.java | 6 +- .../exception/PcuGroupNotFoundException.java | 25 +- .../dtsx/astra/sdk/AbstractDevopsApiTest.java | 27 +- .../astra/sdk/pcu/PCUGroupClientDevTest.java | 140 ++++--- .../astra/sdk/pcu/PCUTypeResolverTest.java | 76 ++-- tools/data-api-tools/pom.xml | 9 - 28 files changed, 1065 insertions(+), 275 deletions(-) diff --git a/astra-db-java/src/main/java/com/datastax/astra/client/admin/AstraDBAdmin.java b/astra-db-java/src/main/java/com/datastax/astra/client/admin/AstraDBAdmin.java index 0c66ae26..b1cfd30c 100644 --- a/astra-db-java/src/main/java/com/datastax/astra/client/admin/AstraDBAdmin.java +++ b/astra-db-java/src/main/java/com/datastax/astra/client/admin/AstraDBAdmin.java @@ -22,12 +22,14 @@ import com.datastax.astra.client.admin.commands.AstraAvailableRegionInfo; import com.datastax.astra.client.admin.definition.DatabaseDefinition; +import com.datastax.astra.client.admin.definition.PCUGroupDefinition; import com.datastax.astra.client.admin.options.AdminOptions; import com.datastax.astra.client.admin.options.AstraFindAvailableRegionsOptions; import com.datastax.astra.client.admin.options.CreateDatabaseOptions; import com.datastax.astra.client.core.options.DataAPIClientOptions; import com.datastax.astra.client.databases.definition.DatabaseInfo; import com.datastax.astra.client.databases.DatabaseOptions; +import com.datastax.astra.client.exceptions.AstraDevOpsAPIException; import com.datastax.astra.internal.api.AstraApiEndpoint; import com.datastax.astra.internal.command.LoggingCommandObserver; import com.datastax.astra.internal.utils.Assert; @@ -40,8 +42,8 @@ import com.dtsx.astra.sdk.db.domain.FilterByOrgType; import com.dtsx.astra.sdk.db.domain.RegionType; import com.dtsx.astra.sdk.db.exception.DatabaseNotFoundException; -import com.dtsx.astra.sdk.pcu.PcuGroupsOpsClient; -import com.dtsx.astra.sdk.pcu.domain.PcuGroup; +import com.dtsx.astra.sdk.pcu.PCUGroupsOpsClient; +import com.dtsx.astra.sdk.pcu.domain.PCUGroup; import com.dtsx.astra.sdk.utils.AstraRc; import com.dtsx.astra.sdk.utils.observability.ApiRequestObserver; import com.dtsx.astra.sdk.utils.observability.LoggingRequestObserver; @@ -81,7 +83,7 @@ public class AstraDBAdmin { final AstraDBOpsClient devopsDbClient; /** Client for Astra Devops Api PCU. */ - final PcuGroupsOpsClient devopsPcuClient; + final PCUGroupsOpsClient devopsPcuClient; /** Options to personalized http client other client options. */ final AdminOptions adminOptions; @@ -120,12 +122,12 @@ public AstraDBAdmin(AdminOptions options) { } this.devopsDbClient = new AstraDBOpsClient(options.getToken(), dataAPIClientOptions.getAstraEnvironment(), devopsObservers); - this.devopsPcuClient = new PcuGroupsOpsClient(options.getToken(), + this.devopsPcuClient = new PCUGroupsOpsClient(options.getToken(), dataAPIClientOptions.getAstraEnvironment(), devopsObservers); } else { this.devopsDbClient = new AstraDBOpsClient(options.getToken(), dataAPIClientOptions.getAstraEnvironment()); - this.devopsPcuClient = new PcuGroupsOpsClient(options.getToken(), + this.devopsPcuClient = new PCUGroupsOpsClient(options.getToken(), dataAPIClientOptions.getAstraEnvironment()); } @@ -172,33 +174,35 @@ public List findAvailableRegions(AstraFindAvailableReg // -------------------- /** - * Lists PCU (Processing Capacity Units) groups filtered by cloud provider and region. - * PCU groups manage compute resources for databases across cloud providers and regions. + * Lists PCU (Processing Capacity Units) groups filtered by cloudProvider provider and region. + * PCU groups manage compute resources for databases across cloudProvider providers and regions. * - * @param cloud - * cloud provider to filter by (AWS, GCP, AZURE), or null for all providers - * @param cloudRegion - * cloud region to filter by (e.g., "us-east-1"), or null for all regions + * @param cloudProvider + * cloudProvider provider to filter by (AWS, GCP, AZURE), or null for all providers + * @param region + * cloudProvider region to filter by (e.g., "us-east-1"), or null for all regions * @return * list of PCU groups matching the specified filters */ - public List listPcuGroups(CloudProviderType cloud, String cloudRegion) { - List pcus = devopsPcuClient.findAll().toList(); - // Filter by cloud provider if specified - if (cloud != null) { + public List listPCUGroups(CloudProviderType cloudProvider, String region) { + List pcus = devopsPcuClient.findAll().toList(); + // Filter by cloudProvider provider if specified + if (cloudProvider != null) { pcus = pcus.stream() - .filter(pcu -> cloud.equals(pcu.getCloudProvider())) + .filter(pcu -> cloudProvider.equals(pcu.getCloudProvider())) .collect(Collectors.toList()); } // Filter by region if specified - if (cloudRegion != null && !cloudRegion.isBlank()) { + if (region != null && !region.isBlank()) { pcus = pcus.stream() - .filter(pcu -> cloudRegion.equals(pcu.getRegion())) + .filter(pcu -> region.equals(pcu.getRegion())) .collect(Collectors.toList()); } - - return pcus; + return pcus + .stream() + .map(PCUGroupDefinition::new) + .collect(Collectors.toList()); } /** @@ -208,40 +212,40 @@ public List listPcuGroups(CloudProviderType cloud, String cloudRegion) * @return * list of all PCU groups */ - public List listPcuGroups() { - return listPcuGroups(null, null); + public List listPCUGroups() { + return listPCUGroups(null, null); } /** * Checks if a PCU group exists by its identifier. * This is a convenience method that checks existence without filtering by cloud or region. * - * @param pcuGroupId + * @param PCUGroupId * PCU group UUID to check * @return * true if the PCU group exists, false otherwise */ - public boolean pcuGroupExists(UUID pcuGroupId) { - return pcuGroupExists(pcuGroupId, null, null); + public boolean PCUGroupExists(UUID PCUGroupId) { + return PCUGroupExists(PCUGroupId, null, null); } /** - * Checks if a PCU group exists by its identifier, optionally filtered by cloud provider and region. + * Checks if a PCU group exists by its identifier, optionally filtered by cloudProvider provider and region. * - * @param pcuGroupId + * @param PCUGroupId * PCU group UUID to check - * @param cloud - * cloud provider to filter by (AWS, GCP, AZURE), or null for all providers - * @param cloudRegion - * cloud region to filter by (e.g., "us-east-1"), or null for all regions + * @param cloudProvider + * cloudProvider provider to filter by (AWS, GCP, AZURE), or null for all providers + * @param region + * cloudProvider region to filter by (e.g., "us-east-1"), or null for all regions * @return * true if the PCU group exists and matches the filters, false otherwise */ - public boolean pcuGroupExists(UUID pcuGroupId, CloudProviderType cloud, String cloudRegion) { - Assert.notNull(pcuGroupId, "pcuGroupId"); - return listPcuGroups(cloud, cloudRegion) + public boolean PCUGroupExists(UUID PCUGroupId, CloudProviderType cloudProvider, String region) { + Assert.notNull(PCUGroupId, "PCUGroupId"); + return listPCUGroups(cloudProvider, region) .stream() - .anyMatch(pcuGroup -> pcuGroupId.equals(pcuGroup.getId())); + .anyMatch(pcuGroup -> PCUGroupId.equals(pcuGroup.getId())); } // -------------------- @@ -399,6 +403,9 @@ public DatabaseAdmin createDatabase(String name, DatabaseDefinition definition, Assert.hasLength(name, "name"); DatabaseCreationRequest req = definition.asRequest(); req.setName(name); + if (definition.getPCUGroupId() != null) { + validatePCUGroup(definition); + } UUID newDbId = UUID.fromString(devopsDbClient.create(req)); log.info("Database {} is starting (id={}): it will take about a minute please wait...", name, newDbId); if (options != null && options.isWaitForDb()) { @@ -545,6 +552,47 @@ public AstraDBDatabaseAdmin getDatabaseAdmin(String databaseEndpoint) { return getDatabaseAdmin(AstraApiEndpoint.parse(databaseEndpoint).getDatabaseId()); } + /** + * Validates that the PCU group specified in the database definition exists and is in the correct region. + * This method checks both the existence of the PCU group globally and its availability in the + * specified cloud provider and region. + * + * @param definition + * the database definition containing PCU group ID, cloud provider, and region + * @throws AstraDevOpsAPIException + * if the PCU group does not exist or is not in the expected cloud/region + */ + private void validatePCUGroup(DatabaseDefinition definition) { + // Testing PCUGroup in proper region but swallow error if cannot list the PCU groupsInRegion. + List groupsInRegion = null; + List all = null; + try { + all = listPCUGroups(); + groupsInRegion = listPCUGroups(definition.getCloudProvider(), definition.getRegion()); + } catch (AstraDevOpsAPIException e) { + log.warn("Could not list PCU group - The PCUGroup id will not be tested " + e.getMessage()); + } + if (all != null) { + boolean groupExist = all + .stream() + .anyMatch(pcuGroup -> definition.getPCUGroupId().equals(pcuGroup.getId())); + if (!groupExist) { + throw new AstraDevOpsAPIException("Pcu group " + definition.getPCUGroupId() + " does not exist"); + } + } + if (groupsInRegion != null) { + boolean groupExist = groupsInRegion + .stream() + .anyMatch(pcuGroup -> definition.getPCUGroupId().equals(pcuGroup.getId())); + if (!groupExist) { + throw new AstraDevOpsAPIException("Pcu group " + definition.getPCUGroupId() + + " is not in expected cloud/region : " + + definition.getCloudProvider() + "/" + + definition.getRegion()); + } + } + } + /** * Wait for db to have proper status. * diff --git a/astra-db-java/src/main/java/com/datastax/astra/client/admin/definition/DatabaseDefinition.java b/astra-db-java/src/main/java/com/datastax/astra/client/admin/definition/DatabaseDefinition.java index b884dee3..8ccfea59 100644 --- a/astra-db-java/src/main/java/com/datastax/astra/client/admin/definition/DatabaseDefinition.java +++ b/astra-db-java/src/main/java/com/datastax/astra/client/admin/definition/DatabaseDefinition.java @@ -1,5 +1,25 @@ package com.datastax.astra.client.admin.definition; +/*- + * #%L + * Data API Java Client + * -- + * Copyright (C) 2024 - 2026 DataStax + * -- + * Licensed under the Apache License, Version 2.0 + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + import com.dtsx.astra.sdk.db.domain.CloudProviderType; import com.dtsx.astra.sdk.db.domain.DatabaseCreationBuilder; import com.dtsx.astra.sdk.db.domain.DatabaseCreationRequest; @@ -42,7 +62,7 @@ public class DatabaseDefinition { * for the database. For free tier the max CU's is 1, and 100 * for CXX/DXX the max is 12 on startup. */ - private Integer capacity = 1; + private Integer capacityUnits = 1; /** * Default is null, if vector will be added @@ -52,7 +72,7 @@ public class DatabaseDefinition { /** * Identifier to assign a database to a PCU group directly. */ - private UUID pcuGroupID; + private UUID PCUGroupId; /** * Projection as the creation request @@ -62,7 +82,7 @@ public class DatabaseDefinition { */ public DatabaseCreationRequest asRequest() { DatabaseCreationBuilder builder = DatabaseCreationRequest.builder(); - builder.capacityUnit(capacity); + builder.capacityUnit(capacityUnits); builder.name(name); builder.cloudProvider(cloudProvider); builder.cloudRegion(region); @@ -70,8 +90,8 @@ public DatabaseCreationRequest asRequest() { builder.keyspace(keyspace); builder.withVector(); builder.dbType(dbType); - if (pcuGroupID != null) { - builder.assignToPCUGroup(pcuGroupID); + if (PCUGroupId != null) { + builder.assignToPCUGroup(PCUGroupId); } return builder.build(); } diff --git a/astra-db-java/src/main/java/com/datastax/astra/client/admin/definition/PCUGroupDefinition.java b/astra-db-java/src/main/java/com/datastax/astra/client/admin/definition/PCUGroupDefinition.java index 9be09bd7..fe3d06c7 100644 --- a/astra-db-java/src/main/java/com/datastax/astra/client/admin/definition/PCUGroupDefinition.java +++ b/astra-db-java/src/main/java/com/datastax/astra/client/admin/definition/PCUGroupDefinition.java @@ -1,4 +1,161 @@ package com.datastax.astra.client.admin.definition; +/*- + * #%L + * Data API Java Client + * -- + * Copyright (C) 2024 - 2026 DataStax + * -- + * Licensed under the Apache License, Version 2.0 + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +import com.dtsx.astra.sdk.db.domain.CloudProviderType; +import com.dtsx.astra.sdk.pcu.domain.PCUGroup; +import com.dtsx.astra.sdk.pcu.domain.PCUType; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import com.fasterxml.jackson.annotation.JsonProperty; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.time.Instant; +import java.util.UUID; + +@Data +@NoArgsConstructor +@JsonIgnoreProperties(ignoreUnknown = true) public class PCUGroupDefinition { + + /** + * Unique identifier for the PCU group. + */ + private UUID id; + + /** + * Associated PCU Types + */ + private PCUTypeDefinition pcuType; + + @JsonProperty("name") + private String name; + + /** + * Organization identifier. + */ + private String orgId; + + /** + * Human-readable title for the PCU group. + */ + private String title; + + /** + * Description of the PCU group. + */ + private String description; + + /** + * Cloud provider where the PCU group is deployed. + */ + private CloudProviderType cloudProvider; + + /** + * Cloud region where the PCU group is deployed. + */ + private String region; + + /** + * Instance type for the PCU group. + */ + private String instanceType; + + /** + * Provisioning type (e.g., on-demand, reserved). + */ + private String provisionType; + + /** + * Minimum number of PCUs. + */ + private int min; + + /** + * Maximum number of PCUs. + */ + private int max; + + /** + * Number of reserved PCUs. + */ + private int reserved; + + /** + * Timestamp when the PCU group was created. + */ + private Instant createdAt; + + /** + * Timestamp when the PCU group was last updated. + */ + private Instant updatedAt; + + /** + * User identifier who created the PCU group. + * This is an Astra user identifier, not a standard UUID. + */ + private String createdBy; + + /** + * User identifier who last updated the PCU group. + * This is an Astra user identifier, not a standard UUID. + */ + private String updatedBy; + + /** + * Current status of the PCU group. + */ + private String status; + + /** + * Constructor to map from PCUGroup (devops API) to PCUGroupDefinition. + * + * @param devopsPCUGroup the PCUGroup from devops API + */ + public PCUGroupDefinition(PCUGroup devopsPCUGroup) { + if (devopsPCUGroup != null) { + this.id = devopsPCUGroup.getId(); + this.name = devopsPCUGroup.getName(); + this.orgId = devopsPCUGroup.getOrgId(); + this.title = devopsPCUGroup.getTitle(); + this.description = devopsPCUGroup.getDescription(); + this.cloudProvider = devopsPCUGroup.getCloudProvider(); + this.region = devopsPCUGroup.getRegion(); + this.instanceType = devopsPCUGroup.getInstanceType(); + this.provisionType = devopsPCUGroup.getProvisionType(); + this.min = devopsPCUGroup.getMin(); + this.max = devopsPCUGroup.getMax(); + this.reserved = devopsPCUGroup.getReserved(); + this.createdAt = devopsPCUGroup.getCreatedAt(); + this.updatedAt = devopsPCUGroup.getUpdatedAt(); + this.createdBy = devopsPCUGroup.getCreatedBy(); + this.updatedBy = devopsPCUGroup.getUpdatedBy(); + this.status = devopsPCUGroup.getStatus(); + + // Map PCUType to PCUTypeDefinition + if (devopsPCUGroup.getPcuType() != null) { + this.pcuType = new PCUTypeDefinition(devopsPCUGroup.getPcuType()); + } + } + } + } diff --git a/astra-db-java/src/main/java/com/datastax/astra/client/admin/definition/PCUTypeDefinition.java b/astra-db-java/src/main/java/com/datastax/astra/client/admin/definition/PCUTypeDefinition.java index c01721e3..7ca6836e 100644 --- a/astra-db-java/src/main/java/com/datastax/astra/client/admin/definition/PCUTypeDefinition.java +++ b/astra-db-java/src/main/java/com/datastax/astra/client/admin/definition/PCUTypeDefinition.java @@ -1,4 +1,63 @@ package com.datastax.astra.client.admin.definition; +/*- + * #%L + * Data API Java Client + * -- + * Copyright (C) 2024 - 2026 DataStax + * -- + * Licensed under the Apache License, Version 2.0 + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + +import com.dtsx.astra.sdk.db.domain.CloudProviderType; +import com.dtsx.astra.sdk.pcu.domain.PCUType; +import com.fasterxml.jackson.annotation.JsonIgnoreProperties; +import lombok.Data; +import lombok.NoArgsConstructor; + +import java.util.Map; + +@Data +@NoArgsConstructor +@JsonIgnoreProperties(ignoreUnknown = true) public class PCUTypeDefinition { + String type; + String region; + CloudProviderType cloudProvider; + Map details; + boolean enabled; + + /** + * Constructor to map from PCUType to PCUTypeDefinition. + * + * @param pcuType the PCUType from devops API + */ + public PCUTypeDefinition(PCUType pcuType) { + if (pcuType != null) { + this.type = pcuType.getType(); + this.region = pcuType.getRegion(); + // Map provider string to CloudProviderType enum + if (pcuType.getProvider() != null) { + try { + this.cloudProvider = CloudProviderType.valueOf(pcuType.getProvider().toUpperCase()); + } catch (IllegalArgumentException e) { + // If provider string doesn't match enum, leave cloudProvider as null + this.cloudProvider = null; + } + } + this.details = pcuType.getDetails(); + this.enabled = pcuType.isEnabled(); + } + } } diff --git a/astra-db-java/src/main/java/com/datastax/astra/client/admin/options/CreateDatabaseOptions.java b/astra-db-java/src/main/java/com/datastax/astra/client/admin/options/CreateDatabaseOptions.java index 78e748c3..31d6d990 100644 --- a/astra-db-java/src/main/java/com/datastax/astra/client/admin/options/CreateDatabaseOptions.java +++ b/astra-db-java/src/main/java/com/datastax/astra/client/admin/options/CreateDatabaseOptions.java @@ -1,5 +1,25 @@ package com.datastax.astra.client.admin.options; +/*- + * #%L + * Data API Java Client + * -- + * Copyright (C) 2024 - 2026 DataStax + * -- + * Licensed under the Apache License, Version 2.0 + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + import com.datastax.astra.client.core.options.BaseOptions; import lombok.Setter; import lombok.experimental.Accessors; diff --git a/astra-db-java/src/main/java/com/datastax/astra/client/exceptions/AstraDevOpsAPIException.java b/astra-db-java/src/main/java/com/datastax/astra/client/exceptions/AstraDevOpsAPIException.java index 03f9a2c1..3a628c1a 100644 --- a/astra-db-java/src/main/java/com/datastax/astra/client/exceptions/AstraDevOpsAPIException.java +++ b/astra-db-java/src/main/java/com/datastax/astra/client/exceptions/AstraDevOpsAPIException.java @@ -1,13 +1,90 @@ package com.datastax.astra.client.exceptions; +/*- + * #%L + * Data API Java Client + * -- + * Copyright (C) 2024 - 2026 DataStax + * -- + * Licensed under the Apache License, Version 2.0 + * You may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * #L% + */ + import lombok.Getter; +import java.util.Optional; +import java.util.UUID; + +/** + * Exception thrown when an error occurs during Astra DevOps API operations. + *

+ * This runtime exception is used to signal failures in interactions with the + * Astra DevOps API, such as database creation, deletion, or configuration errors. + * It provides multiple constructors to accommodate different error scenarios, + * including wrapping underlying exceptions and providing custom error messages. + *

+ * + * @see RuntimeException + */ @Getter -public class DevOpsAPIException extends RuntimeException { +public class AstraDevOpsAPIException extends RuntimeException { - /** Default error message. */ + /** + * Default error message used when no specific message is provided. + * This message indicates an unexpected error occurred during Astra DevOps API operations. + */ public static final String DEFAULT_ERROR_MESSAGE = "Unexpected error occurred for Astra Devops API"; + /** + * Constructs a new AstraDevOpsAPIException with the specified detail message and cause. + *

+ * This constructor is useful when you want to provide both a descriptive error message + * and wrap an underlying exception that caused the failure. + *

+ * + * @param message the detail message explaining the reason for the exception + * @param parent the underlying cause of this exception (can be null) + */ + public AstraDevOpsAPIException(String message, Throwable parent) { + super(message, parent); + } + + /** + * Constructs a new AstraDevOpsAPIException with the specified detail message. + *

+ * Use this constructor when you have a specific error message to communicate + * but no underlying exception to wrap. + *

+ * + * @param message the detail message explaining the reason for the exception + */ + public AstraDevOpsAPIException(String message) { + super(message); + } + + /** + * Constructs a new AstraDevOpsAPIException wrapping an underlying throwable. + *

+ * This constructor is useful when you want to propagate an exception from + * a lower layer while converting it to an AstraDevOpsAPIException. The message + * will be derived from the throwable's message. + *

+ * + * @param throwable the underlying cause of this exception + */ + public AstraDevOpsAPIException(Throwable throwable) { + super(throwable); + } } diff --git a/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/AstraOpsClient.java b/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/AstraOpsClient.java index 2faef93f..982b2f54 100644 --- a/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/AstraOpsClient.java +++ b/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/AstraOpsClient.java @@ -6,7 +6,7 @@ import com.dtsx.astra.sdk.org.TokensClient; import com.dtsx.astra.sdk.org.UsersClient; import com.dtsx.astra.sdk.org.domain.*; -import com.dtsx.astra.sdk.pcu.PcuGroupsOpsClient; +import com.dtsx.astra.sdk.pcu.PCUGroupsOpsClient; import com.dtsx.astra.sdk.streaming.AstraStreamingClient; import com.dtsx.astra.sdk.utils.ApiLocator; import com.dtsx.astra.sdk.utils.ApiResponseHttp; @@ -178,7 +178,7 @@ public TokensClient tokens() { * @return * pcu groups client */ - public PcuGroupsOpsClient pcus() { - return new PcuGroupsOpsClient(token, environment); + public PCUGroupsOpsClient pcus() { + return new PCUGroupsOpsClient(token, environment); } } diff --git a/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/PCUGroupDatacenterAssociationsClient.java b/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/PCUGroupDatacenterAssociationsClient.java index c61a5c11..c25f3a59 100644 --- a/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/PCUGroupDatacenterAssociationsClient.java +++ b/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/PCUGroupDatacenterAssociationsClient.java @@ -1,6 +1,6 @@ package com.dtsx.astra.sdk.pcu; -import com.dtsx.astra.sdk.pcu.domain.PcuGroupDatacenterAssociation; +import com.dtsx.astra.sdk.pcu.domain.PCUGroupDatacenterAssociation; import com.dtsx.astra.sdk.pcu.exception.PcuGroupDbAssociationNotFound; import com.dtsx.astra.sdk.pcu.exception.PcuGroupNotFoundException; import com.dtsx.astra.sdk.AbstractApiClient; @@ -12,6 +12,7 @@ import lombok.val; import java.util.List; +import java.util.UUID; import java.util.stream.Stream; /** @@ -19,15 +20,15 @@ * Provides operations to associate, dissociate, transfer, and query datacenter associations. */ @Slf4j -public class PcuGroupDatacenterAssociationsClient extends AbstractApiClient { - private static final TypeReference> PCU_GROUP_DB_ASSOCIATIONS = +public class PCUGroupDatacenterAssociationsClient extends AbstractApiClient { + private static final TypeReference> PCU_GROUP_DB_ASSOCIATIONS = new TypeReference<>() {}; /** * PCU group unique identifier. */ @Getter - private final String pcuGroupId; + private final UUID pcuGroupId; /** * Constructor with token and PCU group ID for production environment. @@ -37,7 +38,7 @@ public class PcuGroupDatacenterAssociationsClient extends AbstractApiClient { * @param pcuGroupId * PCU group UUID */ - public PcuGroupDatacenterAssociationsClient(String token, String pcuGroupId) { + public PCUGroupDatacenterAssociationsClient(String token, UUID pcuGroupId) { this(token, AstraEnvironment.PROD, pcuGroupId); } @@ -51,7 +52,7 @@ public PcuGroupDatacenterAssociationsClient(String token, String pcuGroupId) { * @param pcuGroupId * PCU group UUID */ - public PcuGroupDatacenterAssociationsClient(String token, AstraEnvironment env, String pcuGroupId) { + public PCUGroupDatacenterAssociationsClient(String token, AstraEnvironment env, UUID pcuGroupId) { super(token, env); this.pcuGroupId = pcuGroupId; } @@ -91,7 +92,7 @@ public boolean exist(@NonNull String datacenterId) { * @throws PcuGroupDbAssociationNotFound * if the datacenter is not associated with this PCU group */ - public PcuGroupDatacenterAssociation findByDatacenterId(@NonNull String datacenterId) { + public PCUGroupDatacenterAssociation findByDatacenterId(@NonNull String datacenterId) { Assert.isDatacenterID(datacenterId, "datacenter id"); return findAll() @@ -106,7 +107,7 @@ public PcuGroupDatacenterAssociation findByDatacenterId(@NonNull String datacent * @return * stream of datacenter associations */ - public Stream findAll() { + public Stream findAll() { val res = GET(getEndpointPcuAssociations() + "/" + pcuGroupId, getOperationName("findAll")); return unmarshallOrThrow(res, PCU_GROUP_DB_ASSOCIATIONS, "get pcu group db associations").stream(); @@ -120,15 +121,15 @@ public Stream findAll() { * @return * the created datacenter association */ - public PcuGroupDatacenterAssociation associate(@NonNull String datacenterId) { + public PCUGroupDatacenterAssociation associate(@NonNull String datacenterId) { Assert.isDatacenterID(datacenterId, "datacenter id"); val res = POST(getEndpointPcuAssociations() + "/" + pcuGroupId + "/" + datacenterId, getOperationName("associate")); - return unmarshallOrThrow(res, new TypeReference>() {}, "associate db to pcu group").get(0); + return unmarshallOrThrow(res, new TypeReference>() {}, "associate db to pcu group").get(0); } - private record TransferReqBody(String fromPCUGroupUUID, String toPCUGroupUUID, String datacenterUUID) {} + private record TransferReqBody(UUID fromPCUGroupUUID, UUID toPCUGroupUUID, String datacenterUUID) {} /** * Transfers a datacenter association from this PCU group to another PCU group. @@ -140,14 +141,14 @@ private record TransferReqBody(String fromPCUGroupUUID, String toPCUGroupUUID, S * @return * the updated datacenter association */ - public PcuGroupDatacenterAssociation transfer(@NonNull String toPcuGroup, @NonNull String datacenterId) { - Assert.isUUID(toPcuGroup, "target pcu group id"); + public PCUGroupDatacenterAssociation transfer(@NonNull UUID toPcuGroup, @NonNull String datacenterId) { + Assert.notNull(toPcuGroup, "target pcu group id"); Assert.isDatacenterID(datacenterId, "datacenter id"); val reqBody = JsonUtils.marshall(new TransferReqBody(this.pcuGroupId, toPcuGroup, datacenterId)); val res = POST(getEndpointPcuAssociations() + "/transfer/" + pcuGroupId, reqBody, getOperationName("transfer")); - return unmarshallOrThrow(res, new TypeReference>() {}, "transfer db to pcu group").get(0); + return unmarshallOrThrow(res, new TypeReference>() {}, "transfer db to pcu group").get(0); } /** diff --git a/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/PCUGroupOpsClient.java b/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/PCUGroupOpsClient.java index 2ff58ffb..cc98002c 100644 --- a/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/PCUGroupOpsClient.java +++ b/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/PCUGroupOpsClient.java @@ -1,8 +1,8 @@ package com.dtsx.astra.sdk.pcu; -import com.dtsx.astra.sdk.pcu.domain.PcuGroup; -import com.dtsx.astra.sdk.pcu.domain.PcuGroupStatusType; -import com.dtsx.astra.sdk.pcu.domain.PcuGroupUpdateRequest; +import com.dtsx.astra.sdk.pcu.domain.PCUGroup; +import com.dtsx.astra.sdk.pcu.domain.PCUGroupStatusType; +import com.dtsx.astra.sdk.pcu.domain.PCUGroupUpdateRequest; import com.dtsx.astra.sdk.pcu.exception.PcuGroupNotFoundException; import com.dtsx.astra.sdk.AbstractApiClient; import com.dtsx.astra.sdk.utils.ApiLocator; @@ -14,19 +14,20 @@ import java.util.List; import java.util.Optional; +import java.util.UUID; /** * Operations client for managing a specific PCU (Processing Capacity Units) Group. * Provides CRUD operations, maintenance actions, and datacenter association management. */ @Slf4j -public class PcuGroupOpsClient extends AbstractApiClient { +public class PCUGroupOpsClient extends AbstractApiClient { /** * PCU group unique identifier. */ @Getter - private final String pcuGroupId; + private final UUID pcuGroupId; /** * Constructor with token and PCU group ID for production environment. @@ -36,7 +37,7 @@ public class PcuGroupOpsClient extends AbstractApiClient { * @param pcuGroupId * PCU group UUID */ - public PcuGroupOpsClient(String token, String pcuGroupId) { + public PCUGroupOpsClient(String token, UUID pcuGroupId) { this(token, AstraEnvironment.PROD, pcuGroupId); } @@ -50,7 +51,7 @@ public PcuGroupOpsClient(String token, String pcuGroupId) { * @param pcuGroupId * PCU group UUID */ - public PcuGroupOpsClient(String token, AstraEnvironment env, String pcuGroupId) { + public PCUGroupOpsClient(String token, AstraEnvironment env, UUID pcuGroupId) { super(token, env); this.pcuGroupId = pcuGroupId; } @@ -71,7 +72,7 @@ public String getServiceName() { * @return * optional containing the PCU group if found */ - public Optional find() { + public Optional find() { try { return Optional.of(get()); } catch (PcuGroupNotFoundException e) { @@ -87,8 +88,8 @@ public Optional find() { * @throws PcuGroupNotFoundException * if the PCU group does not exist */ - public PcuGroup get() { - return new PcuGroupsOpsClient(token, environment).findById(pcuGroupId).orElseThrow(() -> PcuGroupNotFoundException.forId(pcuGroupId)); + public PCUGroup get() { + return new PCUGroupsOpsClient(token, environment).findById(pcuGroupId).orElseThrow(() -> PcuGroupNotFoundException.forId(pcuGroupId)); } /** @@ -108,7 +109,7 @@ public boolean exist() { * true if the PCU group status is ACTIVE */ public boolean isActive() { - return PcuGroupStatusType.ACTIVE == get().getStatus(); + return PCUGroupStatusType.ACTIVE.name().equals(get().getStatus()); } /** @@ -118,7 +119,7 @@ public boolean isActive() { * true if the PCU group status is CREATED or ACTIVE */ public boolean isCreatedOrActive() { - return PcuGroupStatusType.CREATED == get().getStatus() || isActive(); + return PCUGroupStatusType.CREATED.name().equals(get().getStatus()) || isActive(); } // --------------------------------- @@ -131,7 +132,7 @@ public boolean isCreatedOrActive() { * @param req * PCU group update request with new configuration */ - public void update(PcuGroupUpdateRequest req) { + public void update(PCUGroupUpdateRequest req) { val base = get(); PUT(getEndpointPcus(), JsonUtils.marshall(List.of(req.withDefaultsAndValidations(base))), getOperationName("update")); } @@ -191,8 +192,8 @@ public void delete() { * @return * datacenter associations client */ - public PcuGroupDatacenterAssociationsClient datacenterAssociations() { - return new PcuGroupDatacenterAssociationsClient(token, environment, pcuGroupId); + public PCUGroupDatacenterAssociationsClient datacenterAssociations() { + return new PCUGroupDatacenterAssociationsClient(token, environment, pcuGroupId); } /** diff --git a/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/PCUGroupsOpsClient.java b/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/PCUGroupsOpsClient.java index 69c2d259..336f0cbe 100644 --- a/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/PCUGroupsOpsClient.java +++ b/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/PCUGroupsOpsClient.java @@ -1,9 +1,9 @@ package com.dtsx.astra.sdk.pcu; -import com.dtsx.astra.sdk.pcu.domain.PcuGroup; -import com.dtsx.astra.sdk.pcu.domain.PcuGroupCreationRequest; -import com.dtsx.astra.sdk.pcu.domain.PcuType; -import com.dtsx.astra.sdk.pcu.domain.PcuTypeLocationFilter; +import com.dtsx.astra.sdk.pcu.domain.PCUGroup; +import com.dtsx.astra.sdk.pcu.domain.PCUGroupCreationRequest; +import com.dtsx.astra.sdk.pcu.domain.PCUType; +import com.dtsx.astra.sdk.pcu.domain.PCUTypeLocationFilter; import com.dtsx.astra.sdk.pcu.exception.PcuGroupNotFoundException; import com.dtsx.astra.sdk.pcu.exception.PcuGroupsNotFoundException; import com.dtsx.astra.sdk.AbstractApiClient; @@ -14,9 +14,11 @@ import lombok.val; import java.net.HttpURLConnection; +import java.util.Collections; import java.util.List; import java.util.Map; import java.util.Optional; +import java.util.UUID; import java.util.stream.Stream; /** @@ -24,9 +26,9 @@ * Provides operations for creating, finding, and managing PCU groups. */ @Slf4j -public class PcuGroupsOpsClient extends AbstractApiClient { +public class PCUGroupsOpsClient extends AbstractApiClient { - private static final TypeReference> RESPONSE_PCU_GROUPS = + private static final TypeReference> RESPONSE_PCU_GROUPS = new TypeReference<>(){}; /** @@ -34,7 +36,7 @@ public class PcuGroupsOpsClient extends AbstractApiClient { * * @param token authentication token */ - public PcuGroupsOpsClient(String token) { + public PCUGroupsOpsClient(String token) { this(token, AstraEnvironment.PROD); } @@ -44,7 +46,7 @@ public PcuGroupsOpsClient(String token) { * @param token authentication token * @param environment astra environment */ - public PcuGroupsOpsClient(String token, AstraEnvironment environment) { + public PCUGroupsOpsClient(String token, AstraEnvironment environment) { super(token, environment); } @@ -58,7 +60,7 @@ public PcuGroupsOpsClient(String token, AstraEnvironment environment) { * @param observers * list of observers */ - public PcuGroupsOpsClient(String token, AstraEnvironment env, Map observers) { + public PCUGroupsOpsClient(String token, AstraEnvironment env, Map observers) { super(token, env, observers); HttpClientWrapper.registerObservers(observers); } @@ -67,7 +69,7 @@ public PcuGroupsOpsClient(String token, AstraEnvironment env, Map> RESPONSE_PCU_TYPES = new TypeReference<>(){}; + private static final TypeReference> RESPONSE_PCU_TYPES = new TypeReference<>(){}; /** {@inheritDoc} */ @Override @@ -78,8 +80,10 @@ public String getServiceName() { // --------------------------------- // ---- PCU TYPES ---- // --------------------------------- - - public Stream listPcuTypes(PcuTypeLocationFilter request) { + public Stream listPcuTypes() { + return listPcuTypes(null); + } + public Stream listPcuTypes(PCUTypeLocationFilter request) { String contextPath = "/types"; boolean first = true; if (request != null) { @@ -123,7 +127,7 @@ public Stream listPcuTypes(PcuTypeLocationFilter request) { * @throws IllegalStateException * if creation fails */ - public PcuGroup create(PcuGroupCreationRequest req) { + public PCUGroup create(PCUGroupCreationRequest req) { String payload = JsonUtils.marshall(List.of(req.withDefaultsAndValidations())); System.out.println(payload); val res = POST(getEndpointPcus(), payload, getOperationName("create")); @@ -143,9 +147,10 @@ public PcuGroup create(PcuGroupCreationRequest req) { * @return * optional containing the PCU group if found */ - public Optional findById(String id) { + public Optional findById(UUID id) { try { - return findAllImpl(List.of(id), "id", (_e) -> PcuGroupNotFoundException.forId(id)).findFirst(); + return findAllImpl(Collections.singletonList(id), "id", + (_e) -> PcuGroupNotFoundException.forId(id)).findFirst(); } catch (PcuGroupNotFoundException e) { return Optional.empty(); } @@ -159,7 +164,7 @@ public Optional findById(String id) { * @return * stream of matching PCU groups */ - public Stream findByTitle(String title) { + public Stream findByTitle(String title) { return findAll().filter(pg -> title.equals(pg.getTitle())); // order is important here since pg.title is nullable } @@ -171,7 +176,7 @@ public Stream findByTitle(String title) { * @return * optional containing the first matching PCU group */ - public Optional findFirstByTitle(String title) { + public Optional findFirstByTitle(String title) { return findByTitle(title).findFirst(); } @@ -181,7 +186,7 @@ public Optional findFirstByTitle(String title) { * @return * stream of all PCU groups */ - public Stream findAll() { + public Stream findAll() { return findAll(null); } @@ -195,7 +200,7 @@ public Stream findAll() { * @throws PcuGroupsNotFoundException * if any of the specified groups are not found */ - public Stream findAll(List ids) { + public Stream findAll(List ids) { return findAllImpl(ids, "ids[%d]", (e) -> new PcuGroupsNotFoundException(e.getErrors().get(0).getMessage())); } @@ -203,21 +208,18 @@ protected interface FindAll404Handler { RuntimeException getError(ApiResponseError res); } - private record FindAllReqBody(List pcuGroupUUIDs) {} + private record FindAllReqBody(List pcuGroupUUIDs) {} - protected Stream findAllImpl(List ids, String validationErrorFmtStr, FindAll404Handler on404) { + protected Stream findAllImpl(List ids, String validationErrorFmtStr, FindAll404Handler on404) { if (ids != null) { if (ids.isEmpty()) { return Stream.of(); // TODO throw error or just return empty list or return all pcu groups? (devops api does the third) } - - for (var i = 0; i < ids.size(); i++) { - Assert.isUUID(ids.get(i), validationErrorFmtStr.formatted(i)); - } } val reqBody = JsonUtils.marshall(new FindAllReqBody(ids)); val res = POST(getEndpointPcus() + "/actions/get", reqBody, getOperationName("find")); + System.out.println(res.getBody()); try { return JsonUtils.unmarshallType(res.getBody(), RESPONSE_PCU_GROUPS).stream(); @@ -255,8 +257,8 @@ protected Stream findAllImpl(List ids, String validationErrorF * @return * operations client for the specified PCU group */ - public PcuGroupOpsClient group(String pcuGroupId) { - return new PcuGroupOpsClient(getToken(), getEnvironment(), pcuGroupId); + public PCUGroupOpsClient group(UUID pcuGroupId) { + return new PCUGroupOpsClient(getToken(), getEnvironment(), pcuGroupId); } /** diff --git a/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PCUCapacityWorkloadType.java b/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PCUCapacityWorkloadType.java index 3e5e0c26..5a2af2ad 100644 --- a/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PCUCapacityWorkloadType.java +++ b/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PCUCapacityWorkloadType.java @@ -12,23 +12,19 @@ @Getter @Accessors(fluent = true) @RequiredArgsConstructor -public enum PcuCapacityWorkloadType { +public enum PCUCapacityWorkloadType { /** * Shared provisioning - resources are shared across multiple tenants. * More cost-effective but with potential resource contention. */ - FLEXIBLE("flexible"), + flexible, /** * Dedicated provisioning - resources are exclusively allocated. * Higher cost but guaranteed performance and isolation. */ - COMMITED("commited"); + commited; + - /** - * JSON serialization value for the provision type. - */ - @JsonValue - private final String fieldValue; } diff --git a/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PCUGroup.java b/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PCUGroup.java index 60b30152..820eb235 100644 --- a/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PCUGroup.java +++ b/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PCUGroup.java @@ -3,25 +3,32 @@ import com.dtsx.astra.sdk.db.domain.CloudProviderType; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; -import lombok.Data; -import lombok.NoArgsConstructor; +import java.time.Instant; import java.util.UUID; /** * Represents a PCU (Processing Capacity Units) Group in Astra. * A PCU group manages compute resources for databases across cloud providers and regions. */ -@Data -@NoArgsConstructor @JsonIgnoreProperties(ignoreUnknown = true) -public class PcuGroup { +public class PCUGroup { + /** * Unique identifier for the PCU group. */ @JsonProperty("uuid") private UUID id; - + + /** + * Associated PCU Types + */ + @JsonProperty("pcuType") + private PCUType pcuType; + + @JsonProperty("name") + private String name; + /** * Organization identifier. */ @@ -55,7 +62,7 @@ public class PcuGroup { /** * Provisioning type (e.g., on-demand, reserved). */ - private PcuProvisionType provisionType; + private String provisionType; /** * Minimum number of PCUs. @@ -75,25 +82,357 @@ public class PcuGroup { /** * Timestamp when the PCU group was created. */ - private String createdAt; + private Instant createdAt; /** * Timestamp when the PCU group was last updated. */ - private String updatedAt; + private Instant updatedAt; /** - * User who created the PCU group. + * User identifier who created the PCU group. + * This is an Astra user identifier, not a standard UUID. */ private String createdBy; /** - * User who last updated the PCU group. + * User identifier who last updated the PCU group. + * This is an Astra user identifier, not a standard UUID. */ private String updatedBy; /** * Current status of the PCU group. */ - private PcuGroupStatusType status; + private String status; + + /** + * Default constructor. + */ + public PCUGroup() { + } + + /** + * Gets id + * + * @return value of id + */ + public UUID getId() { + return id; + } + + /** + * Set value for id + * + * @param id new value for id + */ + public void setId(UUID id) { + this.id = id; + } + + /** + * Gets pcuType + * + * @return value of pcuType + */ + public PCUType getPcuType() { + return pcuType; + } + + /** + * Set value for pcuType + * + * @param pcuType new value for pcuType + */ + public void setPcuType(PCUType pcuType) { + this.pcuType = pcuType; + } + + /** + * Gets name + * + * @return value of name + */ + public String getName() { + return name; + } + + /** + * Set value for name + * + * @param name new value for name + */ + public void setName(String name) { + this.name = name; + } + + /** + * Gets orgId + * + * @return value of orgId + */ + public String getOrgId() { + return orgId; + } + + /** + * Set value for orgId + * + * @param orgId new value for orgId + */ + public void setOrgId(String orgId) { + this.orgId = orgId; + } + + /** + * Gets title + * + * @return value of title + */ + public String getTitle() { + return title; + } + + /** + * Set value for title + * + * @param title new value for title + */ + public void setTitle(String title) { + this.title = title; + } + + /** + * Gets description + * + * @return value of description + */ + public String getDescription() { + return description; + } + + /** + * Set value for description + * + * @param description new value for description + */ + public void setDescription(String description) { + this.description = description; + } + + /** + * Gets cloudProvider + * + * @return value of cloudProvider + */ + public CloudProviderType getCloudProvider() { + return cloudProvider; + } + + /** + * Set value for cloudProvider + * + * @param cloudProvider new value for cloudProvider + */ + public void setCloudProvider(CloudProviderType cloudProvider) { + this.cloudProvider = cloudProvider; + } + + /** + * Gets region + * + * @return value of region + */ + public String getRegion() { + return region; + } + + /** + * Set value for region + * + * @param region new value for region + */ + public void setRegion(String region) { + this.region = region; + } + + /** + * Gets instanceType + * + * @return value of instanceType + */ + public String getInstanceType() { + return instanceType; + } + + /** + * Set value for instanceType + * + * @param instanceType new value for instanceType + */ + public void setInstanceType(String instanceType) { + this.instanceType = instanceType; + } + + /** + * Gets provisionType + * + * @return value of provisionType + */ + public String getProvisionType() { + return provisionType; + } + + /** + * Set value for provisionType + * + * @param provisionType new value for provisionType + */ + public void setProvisionType(String provisionType) { + this.provisionType = provisionType; + } + + /** + * Gets min + * + * @return value of min + */ + public int getMin() { + return min; + } + + /** + * Set value for min + * + * @param min new value for min + */ + public void setMin(int min) { + this.min = min; + } + + /** + * Gets max + * + * @return value of max + */ + public int getMax() { + return max; + } + + /** + * Set value for max + * + * @param max new value for max + */ + public void setMax(int max) { + this.max = max; + } + + /** + * Gets reserved + * + * @return value of reserved + */ + public int getReserved() { + return reserved; + } + + /** + * Set value for reserved + * + * @param reserved new value for reserved + */ + public void setReserved(int reserved) { + this.reserved = reserved; + } + + /** + * Gets createdAt + * + * @return value of createdAt + */ + public Instant getCreatedAt() { + return createdAt; + } + + /** + * Set value for createdAt + * + * @param createdAt new value for createdAt + */ + public void setCreatedAt(Instant createdAt) { + this.createdAt = createdAt; + } + + /** + * Gets updatedAt + * + * @return value of updatedAt + */ + public Instant getUpdatedAt() { + return updatedAt; + } + + /** + * Set value for updatedAt + * + * @param updatedAt new value for updatedAt + */ + public void setUpdatedAt(Instant updatedAt) { + this.updatedAt = updatedAt; + } + + /** + * Gets createdBy + * + * @return value of createdBy + */ + public String getCreatedBy() { + return createdBy; + } + + /** + * Set value for createdBy + * + * @param createdBy new value for createdBy + */ + public void setCreatedBy(String createdBy) { + this.createdBy = createdBy; + } + + /** + * Gets updatedBy + * + * @return value of updatedBy + */ + public String getUpdatedBy() { + return updatedBy; + } + + /** + * Set value for updatedBy + * + * @param updatedBy new value for updatedBy + */ + public void setUpdatedBy(String updatedBy) { + this.updatedBy = updatedBy; + } + + /** + * Gets status + * + * @return value of status + */ + public String getStatus() { + return status; + } + + /** + * Set value for status + * + * @param status new value for status + */ + public void setStatus(String status) { + this.status = status; + } } diff --git a/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PCUGroupCreateUpdateRequest.java b/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PCUGroupCreateUpdateRequest.java index c8362445..e9c48273 100644 --- a/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PCUGroupCreateUpdateRequest.java +++ b/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PCUGroupCreateUpdateRequest.java @@ -15,7 +15,7 @@ @Setter @SuperBuilder @NoArgsConstructor -public abstract class PcuGroupCreateUpdateRequest { +public abstract class PCUGroupCreateUpdateRequest { /** * Human-readable title for the PCU group. @@ -53,15 +53,15 @@ public abstract class PcuGroupCreateUpdateRequest { * based on the group’s minimum capacity. While flexible capacity workloads don’t require a commitment to reserved capacity, * they don’t offer cost savings for continuous usage that can be realized at the RCU rate. */ - protected PcuCapacityWorkloadType workloadType; + protected String workloadType; /** * Provisioning type for the PCU group. */ @Setter(AccessLevel.NONE) - protected PcuProvisionType provisionType; + protected String provisionType; - public PcuGroupCreateUpdateRequest setProvisionType(PcuProvisionType provisionType) { + public PCUGroupCreateUpdateRequest setProvisionType(String provisionType) { this.provisionType = provisionType; return this; } diff --git a/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PCUGroupCreationRequest.java b/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PCUGroupCreationRequest.java index 7062761b..7e5ee9b9 100644 --- a/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PCUGroupCreationRequest.java +++ b/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PCUGroupCreationRequest.java @@ -11,7 +11,7 @@ @Getter @Setter @SuperBuilder -public final class PcuGroupCreationRequest extends PcuGroupCreateUpdateRequest { +public final class PCUGroupCreationRequest extends PCUGroupCreateUpdateRequest { /** * Instance type for the PCU group (e.g., "standard"). @@ -25,14 +25,14 @@ public final class PcuGroupCreationRequest extends PcuGroupCreateUpdateRequest { * @return * this request with defaults applied */ - public PcuGroupCreationRequest withDefaultsAndValidations() { + public PCUGroupCreationRequest withDefaultsAndValidations() { if (this.provisionType == null) { - this.provisionType = PcuProvisionType.SHARED; + this.provisionType = PCUProvisionType.shared.name(); } // De if (this.instanceType == null || this.instanceType.isBlank()) { - this.instanceType = PcuInstanceType.SMALL.toString(); + this.instanceType = PCUInstanceType.small.toString(); } if (this.reserved == null) { diff --git a/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PCUGroupDatacenterAssociation.java b/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PCUGroupDatacenterAssociation.java index 4e0481d9..cb1d0121 100644 --- a/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PCUGroupDatacenterAssociation.java +++ b/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PCUGroupDatacenterAssociation.java @@ -10,7 +10,7 @@ // TODO add the rest of the fields once the PCU team is clear about what is going on @Data @JsonIgnoreProperties(ignoreUnknown = true) -public class PcuGroupDatacenterAssociation { +public class PCUGroupDatacenterAssociation { /** * PCU group unique identifier. */ diff --git a/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PCUGroupStatusType.java b/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PCUGroupStatusType.java index 1b0227c8..363deca1 100644 --- a/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PCUGroupStatusType.java +++ b/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PCUGroupStatusType.java @@ -4,7 +4,7 @@ * Enumeration of PCU (Processing Capacity Units) Group status types. * Represents the various lifecycle states of a PCU group. */ -public enum PcuGroupStatusType { +public enum PCUGroupStatusType { /** * PCU group has been created but not yet placed. */ diff --git a/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PCUGroupUpdateRequest.java b/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PCUGroupUpdateRequest.java index d0e43a33..f2ecd646 100644 --- a/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PCUGroupUpdateRequest.java +++ b/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PCUGroupUpdateRequest.java @@ -12,7 +12,7 @@ */ @SuperBuilder @NoArgsConstructor -public class PcuGroupUpdateRequest extends PcuGroupCreateUpdateRequest { +public class PCUGroupUpdateRequest extends PCUGroupCreateUpdateRequest { /** * Applies defaults from the existing PCU group and validates the update request. * Fields not specified in the update request will retain their current values from the base PCU group. @@ -23,7 +23,7 @@ public class PcuGroupUpdateRequest extends PcuGroupCreateUpdateRequest { * internal representation with defaults applied and validation performed */ // TODO once the bug that causes fields to potentially be lost during partial updates is fixed, we can remove the base parameter here - public PcuGroupCreateUpdateRequest withDefaultsAndValidations(PcuGroup base) { + public PCUGroupCreateUpdateRequest withDefaultsAndValidations(PCUGroup base) { InternalRep internalRep = new InternalRep(); internalRep.setTitle(this.title == null ? base.getTitle() : this.title); internalRep.setDescription(this.description == null ? base.getDescription() : this.description); @@ -46,7 +46,7 @@ public PcuGroupCreateUpdateRequest withDefaultsAndValidations(PcuGroup base) { @Setter @Getter @Accessors(chain = true) - static class InternalRep extends PcuGroupUpdateRequest { + static class InternalRep extends PCUGroupUpdateRequest { private String pcuGroupUUID; private String instanceType; @@ -54,7 +54,7 @@ static class InternalRep extends PcuGroupUpdateRequest { super(); } - public InternalRep setProvisionType(PcuProvisionType provisionType) { + public InternalRep setProvisionType(String provisionType) { super.setProvisionType(provisionType); return this; } diff --git a/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PCUInstanceType.java b/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PCUInstanceType.java index 25c6989c..b7dc30b9 100644 --- a/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PCUInstanceType.java +++ b/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PCUInstanceType.java @@ -3,20 +3,14 @@ import lombok.Getter; @Getter -public enum PcuInstanceType { - - SMALL("small"), - MEDIUM("medium"), - GENERAL_PURPOSE("generalPurpose"), - CACHE_OPTIMIZED("cacheOptimized"), +public enum PCUInstanceType { + small, + medium, + generalPurpose, + cacheOptimized, // Legacy - STANDARD("standard"), - STORAGE_OPTIMIZED("storageOptimized"); - - final String code; + standard, + storageOptimized; - PcuInstanceType(String code) { - this.code = code; - } } diff --git a/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PCUProvisionType.java b/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PCUProvisionType.java index 4d5dfd98..9ddca76c 100644 --- a/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PCUProvisionType.java +++ b/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PCUProvisionType.java @@ -12,23 +12,17 @@ @Getter @Accessors(fluent = true) @RequiredArgsConstructor -public enum PcuProvisionType { +public enum PCUProvisionType { /** * Shared provisioning - resources are shared across multiple tenants. * More cost-effective but with potential resource contention. */ - SHARED("shared"), + shared, /** * Dedicated provisioning - resources are exclusively allocated. * Higher cost but guaranteed performance and isolation. */ - DEDICATED("dedicated"); - - /** - * JSON serialization value for the provision type. - */ - @JsonValue - private final String fieldValue; + dedicated; } diff --git a/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PCUType.java b/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PCUType.java index 087503ff..ba2d8469 100644 --- a/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PCUType.java +++ b/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PCUType.java @@ -1,6 +1,5 @@ package com.dtsx.astra.sdk.pcu.domain; -import com.dtsx.astra.sdk.db.domain.CloudProviderType; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import lombok.Data; import lombok.NoArgsConstructor; @@ -10,7 +9,7 @@ @Data @NoArgsConstructor @JsonIgnoreProperties(ignoreUnknown = true) -public class PcuType { +public class PCUType { String type; String region; String provider; diff --git a/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PCUTypeLocationFilter.java b/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PCUTypeLocationFilter.java index d2588df9..9e27babb 100644 --- a/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PCUTypeLocationFilter.java +++ b/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PCUTypeLocationFilter.java @@ -9,7 +9,7 @@ @NoArgsConstructor @AllArgsConstructor @JsonIgnoreProperties(ignoreUnknown = true) -public class PcuTypeLocationFilter { +public class PCUTypeLocationFilter { String provider; String region; } diff --git a/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PCUTypeResolver.java b/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PCUTypeResolver.java index 3c6d5ef1..e393c61e 100644 --- a/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PCUTypeResolver.java +++ b/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/domain/PCUTypeResolver.java @@ -5,7 +5,7 @@ /** * Utility class for resolving default PCU types based on availability and configuration. */ -public class PcuTypeResolver { +public class PCUTypeResolver { /** * Resolves the default PCU type based on available types and mini PCU configuration. @@ -20,39 +20,39 @@ public class PcuTypeResolver { * @param miniPcuEnabled whether mini PCU is enabled * @return the selected PCU family, or null if no suitable type is available */ - public static PcuInstanceType resolveDefaultPcuType(List availableTypes, boolean miniPcuEnabled) { + public static PCUInstanceType resolveDefaultPcuType(List availableTypes, boolean miniPcuEnabled) { if (availableTypes == null || availableTypes.isEmpty()) { return null; } if (miniPcuEnabled) { // Priority: SMALL > MEDIUM > GENERAL_PURPOSE > CACHE_OPTIMIZED - if (availableTypes.contains(PcuInstanceType.SMALL)) { - return PcuInstanceType.SMALL; + if (availableTypes.contains(PCUInstanceType.small)) { + return PCUInstanceType.small; } - if (availableTypes.contains(PcuInstanceType.MEDIUM)) { - return PcuInstanceType.MEDIUM; + if (availableTypes.contains(PCUInstanceType.medium)) { + return PCUInstanceType.medium; } - if (availableTypes.contains(PcuInstanceType.GENERAL_PURPOSE)) { - return PcuInstanceType.GENERAL_PURPOSE; + if (availableTypes.contains(PCUInstanceType.generalPurpose)) { + return PCUInstanceType.generalPurpose; } - if (availableTypes.contains(PcuInstanceType.CACHE_OPTIMIZED)) { - return PcuInstanceType.CACHE_OPTIMIZED; + if (availableTypes.contains(PCUInstanceType.cacheOptimized)) { + return PCUInstanceType.cacheOptimized; } } else { // Priority: GENERAL_PURPOSE > CACHE_OPTIMIZED (ignore SMALL and MEDIUM) - if (availableTypes.contains(PcuInstanceType.GENERAL_PURPOSE)) { - return PcuInstanceType.GENERAL_PURPOSE; + if (availableTypes.contains(PCUInstanceType.generalPurpose)) { + return PCUInstanceType.generalPurpose; } - if (availableTypes.contains(PcuInstanceType.CACHE_OPTIMIZED)) { - return PcuInstanceType.CACHE_OPTIMIZED; + if (availableTypes.contains(PCUInstanceType.cacheOptimized)) { + return PCUInstanceType.cacheOptimized; } } return null; } - private PcuTypeResolver() { + private PCUTypeResolver() { // Utility class - prevent instantiation } } diff --git a/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/exception/PcuGroupDbAssociationNotFound.java b/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/exception/PcuGroupDbAssociationNotFound.java index 8f0fbfb4..ee1833b4 100644 --- a/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/exception/PcuGroupDbAssociationNotFound.java +++ b/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/exception/PcuGroupDbAssociationNotFound.java @@ -2,6 +2,8 @@ import lombok.Getter; +import java.util.UUID; + /** * Exception thrown when a datacenter association with a PCU (Processing Capacity Units) Group cannot be found. * This occurs when attempting to access or modify an association that doesn't exist. @@ -11,7 +13,7 @@ public class PcuGroupDbAssociationNotFound extends RuntimeException { * PCU group unique identifier. */ @Getter - private final String pcuGroupId; + private final UUID pcuGroupId; /** * Datacenter unique identifier. @@ -27,7 +29,7 @@ public class PcuGroupDbAssociationNotFound extends RuntimeException { * @param datacenterId * the datacenter ID */ - public PcuGroupDbAssociationNotFound(String pcuGroupId, String datacenterId) { + public PcuGroupDbAssociationNotFound(UUID pcuGroupId, String datacenterId) { super("Association not found for pcu group '" + pcuGroupId + "' and datacenter '" + datacenterId + "'"); this.pcuGroupId = pcuGroupId; this.datacenterId = datacenterId; diff --git a/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/exception/PcuGroupNotFoundException.java b/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/exception/PcuGroupNotFoundException.java index 920d3e4c..04ccb451 100644 --- a/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/exception/PcuGroupNotFoundException.java +++ b/astra-sdk-devops/src/main/java/com/dtsx/astra/sdk/pcu/exception/PcuGroupNotFoundException.java @@ -3,6 +3,7 @@ import lombok.Getter; import java.util.Optional; +import java.util.UUID; /** * Exception thrown when a PCU (Processing Capacity Units) Group cannot be found. @@ -20,7 +21,7 @@ public class PcuGroupNotFoundException extends RuntimeException { * Optional ID of the PCU group that was not found. */ @Getter - private final Optional id; + private final Optional id; /** * Private constructor for creating the exception. @@ -30,12 +31,28 @@ public class PcuGroupNotFoundException extends RuntimeException { * @param id * optional ID of the PCU group */ - private PcuGroupNotFoundException(Optional title, Optional id) { - super("PCU group " + title.or(() -> id).map(s -> "'" + s + "' ").orElse("") + "has not been found."); + private PcuGroupNotFoundException(Optional title, Optional id) { + super(buildErrorMessage(title, id)); this.title = title; this.id = id; } + /** + * Build Error Message. + * @param title + * title + * @param id + * PUC group identifier + * @return + * exception + */ + private static String buildErrorMessage(Optional title, Optional id) { + String identifier = title + .map(t -> "'" + t + "'") + .orElseGet(() -> id.map(uuid -> "'" + uuid + "'").orElse("")); + return "PCU group " + identifier + " has not been found."; + } + /** * Creates an exception for a PCU group not found by title. * @@ -56,7 +73,7 @@ public static PcuGroupNotFoundException forTitle(String title) { * @return * exception instance */ - public static PcuGroupNotFoundException forId(String id) { + public static PcuGroupNotFoundException forId(UUID id) { return new PcuGroupNotFoundException(Optional.empty(), Optional.of(id)); } } diff --git a/astra-sdk-devops/src/test/java/com/dtsx/astra/sdk/AbstractDevopsApiTest.java b/astra-sdk-devops/src/test/java/com/dtsx/astra/sdk/AbstractDevopsApiTest.java index e6af0f1c..4dcccfd7 100644 --- a/astra-sdk-devops/src/test/java/com/dtsx/astra/sdk/AbstractDevopsApiTest.java +++ b/astra-sdk-devops/src/test/java/com/dtsx/astra/sdk/AbstractDevopsApiTest.java @@ -4,6 +4,7 @@ import com.dtsx.astra.sdk.db.AstraDBOpsClient; import com.dtsx.astra.sdk.db.domain.DatabaseCreationRequest; import com.dtsx.astra.sdk.streaming.AstraStreamingClient; +import com.dtsx.astra.sdk.utils.AstraEnvironment; import com.dtsx.astra.sdk.utils.AstraRc; import com.dtsx.astra.sdk.utils.Utils; import org.junit.jupiter.api.Assertions; @@ -33,6 +34,11 @@ public abstract class AbstractDevopsApiTest { */ private static String token; + /** + * Hold reference to token + */ + private static AstraEnvironment env; + /** * Reference to Databases Client. */ @@ -61,7 +67,7 @@ public abstract class AbstractDevopsApiTest { */ protected AstraOpsClient getApiDevopsClient() { if (apiDevopsClient == null) { - apiDevopsClient = new AstraOpsClient(getToken()); + apiDevopsClient = new AstraOpsClient(getToken(), getEnvironment()); } return apiDevopsClient; } @@ -74,7 +80,7 @@ protected AstraOpsClient getApiDevopsClient() { */ protected AstraDBOpsClient getDatabasesClient() { if (databasesClient == null) { - databasesClient = new AstraDBOpsClient(getToken()); + databasesClient = new AstraDBOpsClient(getToken(), getEnvironment()); } return databasesClient; } @@ -87,7 +93,7 @@ protected AstraDBOpsClient getDatabasesClient() { */ protected AstraStreamingClient getStreamingClient() { if (streamingClient == null) { - streamingClient = new AstraStreamingClient(getToken()); + streamingClient = new AstraStreamingClient(getToken(), getEnvironment()); } return streamingClient; } @@ -110,6 +116,21 @@ protected String getToken() { return token; } + protected AstraEnvironment getEnvironment() { + String envStr = null; + if (env == null) { + if (AstraRc.isDefaultConfigFileExists()) { + envStr = new AstraRc() + .getSectionKey(AstraRc.ASTRARC_DEFAULT, AstraRc.ASTRA_ENV) + .orElse(null); + env = AstraEnvironment.valueOf(envStr); + } + envStr = Utils.readEnvVariable(AstraRc.ASTRA_ENV).orElse(envStr); + env = AstraEnvironment.valueOf(envStr); + } + return env; + } + /** * Create DB if not exist * diff --git a/astra-sdk-devops/src/test/java/com/dtsx/astra/sdk/pcu/PCUGroupClientDevTest.java b/astra-sdk-devops/src/test/java/com/dtsx/astra/sdk/pcu/PCUGroupClientDevTest.java index 0b641318..161c3cff 100644 --- a/astra-sdk-devops/src/test/java/com/dtsx/astra/sdk/pcu/PCUGroupClientDevTest.java +++ b/astra-sdk-devops/src/test/java/com/dtsx/astra/sdk/pcu/PCUGroupClientDevTest.java @@ -6,16 +6,17 @@ import com.dtsx.astra.sdk.db.domain.DatabaseCreationRequest; import com.dtsx.astra.sdk.db.domain.DatabaseStatusType; import com.dtsx.astra.sdk.org.domain.Organization; -import com.dtsx.astra.sdk.pcu.domain.PcuCapacityWorkloadType; -import com.dtsx.astra.sdk.pcu.domain.PcuGroup; -import com.dtsx.astra.sdk.pcu.domain.PcuGroupCreationRequest; -import com.dtsx.astra.sdk.pcu.domain.PcuInstanceType; -import com.dtsx.astra.sdk.pcu.domain.PcuProvisionType; -import com.dtsx.astra.sdk.pcu.domain.PcuType; -import com.dtsx.astra.sdk.pcu.domain.PcuTypeLocationFilter; +import com.dtsx.astra.sdk.pcu.domain.PCUCapacityWorkloadType; +import com.dtsx.astra.sdk.pcu.domain.PCUGroup; +import com.dtsx.astra.sdk.pcu.domain.PCUGroupCreationRequest; +import com.dtsx.astra.sdk.pcu.domain.PCUInstanceType; +import com.dtsx.astra.sdk.pcu.domain.PCUProvisionType; +import com.dtsx.astra.sdk.pcu.domain.PCUType; +import com.dtsx.astra.sdk.pcu.domain.PCUTypeLocationFilter; import com.dtsx.astra.sdk.utils.AstraEnvironment; import com.dtsx.astra.sdk.utils.JsonUtils; import com.dtsx.astra.sdk.utils.TestUtils; +import com.dtsx.astra.sdk.utils.Utils; import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.MethodOrderer; @@ -23,18 +24,27 @@ import org.junit.jupiter.api.Test; import org.junit.jupiter.api.TestMethodOrder; +import java.util.List; import java.util.UUID; import java.util.stream.Stream; -@TestMethodOrder(MethodOrderer.OrderAnnotation.class) -public class PCUGroupClientTest extends AbstractDevopsApiTest { +// Unpredictable so re;oving fro; automated tests +//@TestMethodOrder(MethodOrderer.OrderAnnotation.class) +public class PCUGroupClientDevTest extends AbstractDevopsApiTest { - public static final String TOKEN = "change_me"; - public static final String TEST_REGION = "us-west-2"; + public static final String DEV_REGION = "us-west-2"; + public static final CloudProviderType DEV_PROVIDER = CloudProviderType.AWS; + + public static final String DEV_TOKEN = Utils + .readEnvVariable("ASTRA_DB_APPLICATION_TOKEN_DEV") + .orElseThrow(() -> new IllegalStateException("Please set env var 'ASTRA_DB_APPLICATION_TOKEN_DEV' with a dev token")); + + protected static PCUGroupsOpsClient PCUGroupsOpsClient; @BeforeAll public static void beforeAll() { - apiDevopsClient = new AstraOpsClient(TOKEN, AstraEnvironment.DEV); + apiDevopsClient = new AstraOpsClient(DEV_TOKEN, AstraEnvironment.DEV); + PCUGroupsOpsClient = apiDevopsClient.pcus(); } @Test @@ -44,70 +54,112 @@ public void shouldAccessOrganizationInDev() { Assertions.assertNotNull(org); Assertions.assertNotNull(org.getId()); Assertions.assertNotNull(org.getName()); - Assertions.assertTrue(org .getName().startsWith("Data API")); + System.out.println("[test-pcu] - You are connected to organization: " + org.getName() + "(" + org.getId() + ")"); } @Test @Order(2) public void shouldListPcuGroupsType() { - PcuTypeLocationFilter location = new PcuTypeLocationFilter(CloudProviderType.AWS.getCode().toLowerCase(), TEST_REGION); - Stream types = getApiDevopsClient().pcus().listPcuTypes(location); - Assertions.assertNotNull(types); - System.out.println(JsonUtils.marshall(types.toList())); + // Full List + System.out.println("[test-pcu] - Listing PCU Types (no filters)"); + Stream types = PCUGroupsOpsClient.listPcuTypes(); + System.out.println("[test-pcu] - Items " + types.toList().size()); + + // Filtered by DC + PCUTypeLocationFilter location = new PCUTypeLocationFilter(DEV_PROVIDER.getCode().toLowerCase(), DEV_REGION); + System.out.println("[test-pcu] - Listing PCU Types on " + JsonUtils.marshall(location)); + List filtered = getApiDevopsClient().pcus().listPcuTypes(location).toList(); + Assertions.assertNotNull(filtered); + System.out.println("[test-pcu] - Items " + filtered.size()); + System.out.println("[test-pcu] - Items " + JsonUtils.marshall(filtered)); + Assertions.assertTrue(filtered.stream().anyMatch(pcu -> pcu.getType().equals("small"))); } @Test @Order(2) public void shouldListPcuGroups() { - Stream groups = getApiDevopsClient().pcus().findAll(); - System.out.println(groups.toList()); + List allGroups = PCUGroupsOpsClient.findAll().toList(); + System.out.println("[test-pcu] - Listing pcu groups " + JsonUtils.marshall(allGroups)); + System.out.println("[test-pcu] - Items " + allGroups.size()); } @Test - @Order(2) - public void shouldCreatePcuGroup() { - PcuGroupCreationRequest createPcu = PcuGroupCreationRequest - .builder() - .title("pcu_group_from_java") - .description("my first PCU group") - .instanceType("standard") - .cloudProvider(CloudProviderType.AWS) - .region(TEST_REGION) - .workloadType(PcuCapacityWorkloadType.FLEXIBLE) - .provisionType(PcuProvisionType.SHARED) - .reserved(1) - .min(1) - .max(1) - .build(); + @Order(3) + public void shouldCreatePcuGroupStandard() { - PcuGroup group = getApiDevopsClient().pcus().create(createPcu); - System.out.println(group); + UUID pcuGroupStandardId = null; + try { + PCUGroupCreationRequest createPcu = PCUGroupCreationRequest + .builder() + .title("pcu_group_from_java") + .description("my first PCU group") + .instanceType("standard") + .cloudProvider(CloudProviderType.AWS) + .region(DEV_REGION) + .workloadType(PCUCapacityWorkloadType.flexible.name()) + .provisionType(PCUProvisionType.shared.name()) + .reserved(1) + .min(1) + .max(1) + .build(); + + // Creating standard pcu Group + PCUGroup group = PCUGroupsOpsClient.create(createPcu); + Assertions.assertNotNull(group); + pcuGroupStandardId = pcuGroupStandardId = group.getId(); + System.out.println("[test-pcu] - Created PCU group: " + group.getId()); + Assertions.assertTrue(getApiDevopsClient().pcus().findById(group.getId()).isPresent()); + + // Create DB + DatabaseCreationRequest dbCreation = DatabaseCreationRequest + .builder() + .name("vector_db_in_standard_pcu") + .keyspace(SDK_TEST_KEYSPACE) + .cloudProvider(CloudProviderType.AWS) + .cloudRegion(DEV_REGION) + .withVector() + .assignToPCUGroup(pcuGroupStandardId) + .build(); + + String dbId = getApiDevopsClient().db().create(dbCreation); + TestUtils.waitForDbStatus(getDatabasesClient().database(dbId), DatabaseStatusType.ACTIVE, 500); + Assertions.assertTrue(getDatabasesClient().findById(dbId).isPresent()); + Assertions.assertNotNull(getDatabasesClient().database(dbId).get()); + Assertions.assertTrue(getDatabasesClient().findByName("vector_db_in_standard_pcu").findAny().isPresent());*/ + + } catch (RuntimeException e) { + + } finally { + if (pcuGroupStandardId != null) { + PCUGroupsOpsClient.group(pcuGroupStandardId).delete(); + } + } } @Test @Order(2) public void shouldCreateMiniPcu() { - PcuGroupCreationRequest createPcu = PcuGroupCreationRequest + PCUGroupCreationRequest createPcu = PCUGroupCreationRequest .builder() .title("java_client_mini_pcu") .description("java_client_mini_pcu") - .instanceType(PcuInstanceType.SMALL.getCode()) + .instanceType(PCUInstanceType.small.name()) .cloudProvider(CloudProviderType.AWS) - .region(TEST_REGION) - .workloadType(PcuCapacityWorkloadType.COMMITED) - .provisionType(PcuProvisionType.SHARED) + .region(DEV_REGION) + .workloadType(PCUCapacityWorkloadType.flexible.name()) + .provisionType(PCUProvisionType.shared.name()) .reserved(1) .min(1) .max(1) .build(); - PcuGroup group = getApiDevopsClient().pcus().create(createPcu); + PCUGroup group = getApiDevopsClient().pcus().create(createPcu); System.out.println(group); } @Test @Order(2) public void shouldDeletePcuGroup() { - getApiDevopsClient().pcus().group("57dde257-86c6-4646-9247-670cd8a4d360").delete(); + PCUGroupsOpsClient.group(UUID.fromString("0c1f67a8-1fd6-4f52-ae2c-ea1483718a11")).delete(); } @Test @@ -119,7 +171,7 @@ public void should_create_db_and_assign_pcu() throws InterruptedException { .name("vector_db_in_mini_pcu") .keyspace(SDK_TEST_KEYSPACE) .cloudProvider(CloudProviderType.AWS) - .cloudRegion(TEST_REGION) + .cloudRegion(DEV_REGION) .withVector() .assignToPCUGroup(miniPcuUUID) .build(); diff --git a/astra-sdk-devops/src/test/java/com/dtsx/astra/sdk/pcu/PCUTypeResolverTest.java b/astra-sdk-devops/src/test/java/com/dtsx/astra/sdk/pcu/PCUTypeResolverTest.java index 1cae4610..ab38ecc9 100644 --- a/astra-sdk-devops/src/test/java/com/dtsx/astra/sdk/pcu/PCUTypeResolverTest.java +++ b/astra-sdk-devops/src/test/java/com/dtsx/astra/sdk/pcu/PCUTypeResolverTest.java @@ -1,7 +1,7 @@ package com.dtsx.astra.sdk.pcu; -import com.dtsx.astra.sdk.pcu.domain.PcuInstanceType; -import com.dtsx.astra.sdk.pcu.domain.PcuTypeResolver; +import com.dtsx.astra.sdk.pcu.domain.PCUInstanceType; +import com.dtsx.astra.sdk.pcu.domain.PCUTypeResolver; import org.junit.jupiter.api.DisplayName; import org.junit.jupiter.api.Nested; import org.junit.jupiter.api.Test; @@ -17,7 +17,7 @@ * Test class for PcuTypeResolver. */ @DisplayName("PcuTypeResolver Tests") -class PcuTypeResolverTest { +class PCUTypeResolverTest { @Nested @DisplayName("Mini PCU Enabled") @@ -26,64 +26,64 @@ class MiniPcuEnabled { @Test @DisplayName("Selects SMALL when SMALL is available") void selectsSmallWhenSmallIsAvailable() { - List availableTypes = Arrays.asList( - PcuInstanceType.SMALL, - PcuInstanceType.MEDIUM, - PcuInstanceType.GENERAL_PURPOSE, - PcuInstanceType.CACHE_OPTIMIZED + List availableTypes = Arrays.asList( + PCUInstanceType.small, + PCUInstanceType.medium, + PCUInstanceType.generalPurpose, + PCUInstanceType.cacheOptimized ); assertEquals( - PcuInstanceType.SMALL, - PcuTypeResolver.resolveDefaultPcuType(availableTypes, true) + PCUInstanceType.small, + PCUTypeResolver.resolveDefaultPcuType(availableTypes, true) ); } @Test @DisplayName("Selects MEDIUM when SMALL is unavailable but MEDIUM exists") void selectsMediumWhenSmallUnavailableButMediumExists() { - List availableTypes = Arrays.asList( - PcuInstanceType.MEDIUM, - PcuInstanceType.GENERAL_PURPOSE + List availableTypes = Arrays.asList( + PCUInstanceType.medium, + PCUInstanceType.generalPurpose ); assertEquals( - PcuInstanceType.MEDIUM, - PcuTypeResolver.resolveDefaultPcuType(availableTypes, true) + PCUInstanceType.medium, + PCUTypeResolver.resolveDefaultPcuType(availableTypes, true) ); } @Test @DisplayName("Selects GENERAL_PURPOSE when only GENERAL_PURPOSE and CACHE_OPTIMIZED exist") void selectsGeneralPurposeWhenOnlyGeneralPurposeAndCacheOptimizedExist() { - List availableTypes = Arrays.asList( - PcuInstanceType.GENERAL_PURPOSE, - PcuInstanceType.CACHE_OPTIMIZED + List availableTypes = Arrays.asList( + PCUInstanceType.generalPurpose, + PCUInstanceType.cacheOptimized ); assertEquals( - PcuInstanceType.GENERAL_PURPOSE, - PcuTypeResolver.resolveDefaultPcuType(availableTypes, true) + PCUInstanceType.generalPurpose, + PCUTypeResolver.resolveDefaultPcuType(availableTypes, true) ); } @Test @DisplayName("Selects CACHE_OPTIMIZED when it is the only available type") void selectsCacheOptimizedWhenItIsTheOnlyAvailableType() { - List availableTypes = Collections.singletonList( - PcuInstanceType.CACHE_OPTIMIZED + List availableTypes = Collections.singletonList( + PCUInstanceType.cacheOptimized ); assertEquals( - PcuInstanceType.CACHE_OPTIMIZED, - PcuTypeResolver.resolveDefaultPcuType(availableTypes, true) + PCUInstanceType.cacheOptimized, + PCUTypeResolver.resolveDefaultPcuType(availableTypes, true) ); } @Test @DisplayName("Returns null when no types are available") void returnsNullWhenNoTypesAreAvailable() { - assertNull(PcuTypeResolver.resolveDefaultPcuType(Collections.emptyList(), true)); + assertNull(PCUTypeResolver.resolveDefaultPcuType(Collections.emptyList(), true)); } } @@ -94,39 +94,39 @@ class MiniPcuDisabled { @Test @DisplayName("Selects GENERAL_PURPOSE when GENERAL_PURPOSE is available") void selectsGeneralPurposeWhenGeneralPurposeIsAvailable() { - List availableTypes = Arrays.asList( - PcuInstanceType.GENERAL_PURPOSE, - PcuInstanceType.CACHE_OPTIMIZED + List availableTypes = Arrays.asList( + PCUInstanceType.generalPurpose, + PCUInstanceType.cacheOptimized ); assertEquals( - PcuInstanceType.GENERAL_PURPOSE, - PcuTypeResolver.resolveDefaultPcuType(availableTypes, false) + PCUInstanceType.generalPurpose, + PCUTypeResolver.resolveDefaultPcuType(availableTypes, false) ); } @Test @DisplayName("Selects CACHE_OPTIMIZED when it is the only available type") void selectsCacheOptimizedWhenItIsTheOnlyAvailableType() { - List availableTypes = Collections.singletonList( - PcuInstanceType.CACHE_OPTIMIZED + List availableTypes = Collections.singletonList( + PCUInstanceType.cacheOptimized ); assertEquals( - PcuInstanceType.CACHE_OPTIMIZED, - PcuTypeResolver.resolveDefaultPcuType(availableTypes, false) + PCUInstanceType.cacheOptimized, + PCUTypeResolver.resolveDefaultPcuType(availableTypes, false) ); } @Test @DisplayName("Returns null when only SMALL or MEDIUM are available") void returnsNullWhenOnlySmallOrMediumAreAvailable() { - List availableTypes = Arrays.asList( - PcuInstanceType.SMALL, - PcuInstanceType.MEDIUM + List availableTypes = Arrays.asList( + PCUInstanceType.small, + PCUInstanceType.medium ); - assertNull(PcuTypeResolver.resolveDefaultPcuType(availableTypes, false)); + assertNull(PCUTypeResolver.resolveDefaultPcuType(availableTypes, false)); } } } diff --git a/tools/data-api-tools/pom.xml b/tools/data-api-tools/pom.xml index 5814c186..df336ac0 100644 --- a/tools/data-api-tools/pom.xml +++ b/tools/data-api-tools/pom.xml @@ -19,15 +19,6 @@ astra-db-java ${project.version} - - - - com.datastax.astra - astra-db-java - ${project.version} - test-jar - test - From f63c2a407e8ea3bf3c0697b2ef86aa6dceac2180 Mon Sep 17 00:00:00 2001 From: Cedrick Lunven Date: Fri, 26 Jun 2026 17:42:57 +0200 Subject: [PATCH 4/4] pcu --- .../test/java/com/dtsx/astra/sdk/pcu/PCUGroupClientDevTest.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/astra-sdk-devops/src/test/java/com/dtsx/astra/sdk/pcu/PCUGroupClientDevTest.java b/astra-sdk-devops/src/test/java/com/dtsx/astra/sdk/pcu/PCUGroupClientDevTest.java index 161c3cff..9e9ddcf1 100644 --- a/astra-sdk-devops/src/test/java/com/dtsx/astra/sdk/pcu/PCUGroupClientDevTest.java +++ b/astra-sdk-devops/src/test/java/com/dtsx/astra/sdk/pcu/PCUGroupClientDevTest.java @@ -125,7 +125,7 @@ public void shouldCreatePcuGroupStandard() { TestUtils.waitForDbStatus(getDatabasesClient().database(dbId), DatabaseStatusType.ACTIVE, 500); Assertions.assertTrue(getDatabasesClient().findById(dbId).isPresent()); Assertions.assertNotNull(getDatabasesClient().database(dbId).get()); - Assertions.assertTrue(getDatabasesClient().findByName("vector_db_in_standard_pcu").findAny().isPresent());*/ + Assertions.assertTrue(getDatabasesClient().findByName("vector_db_in_standard_pcu").findAny().isPresent()); } catch (RuntimeException e) {