Skip to content

Commit ddc00b8

Browse files
rohanshah18jhamon
andauthored
Release candidate/2024 07 (#142)
## Problem Add deletion protection and generate code based on latest open api spec. ## Solution Generated code based on 2024-07 open api spec which includes deletion protection support. Manually added deletion protection support to the control plane wrapper along with integration tests. ## Type of Change - [X] New feature (non-breaking change which adds functionality) ## Test Plan Added integration tests --------- Co-authored-by: Jennifer Hamon <[email protected]>
1 parent 8034dab commit ddc00b8

File tree

64 files changed

+2813
-988
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

64 files changed

+2813
-988
lines changed

.gitignore

+3-1
Original file line numberDiff line numberDiff line change
@@ -79,4 +79,6 @@ nb-configuration.xml
7979
##############################
8080
## OS X
8181
##############################
82-
.DS_Store
82+
.DS_Store
83+
84+
gen

.gitmodules

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[submodule "codegen/apis"]
2+
path = codegen/apis
3+
url = [email protected]:pinecone-io/apis.git

README.md

+2-3
Original file line numberDiff line numberDiff line change
@@ -39,8 +39,7 @@ having to obtain the *pinecone-client* dependencies separately.
3939
### Initializing the client
4040

4141
Before you can use the Pinecone Java SDK, you must sign up for a Pinecone account and find your API key in the Pinecone
42-
console
43-
dashboard at [https://app.pinecone.io](https://app.pinecone.io).
42+
console dashboard at [https://app.pinecone.io](https://app.pinecone.io).
4443

4544
#### Using apiKey
4645

@@ -75,7 +74,7 @@ public class InitializeClientExample {
7574

7675
OkHttpClient httpClient = builder.build();
7776

78-
Pinecone pinecone = new Pinecone.Builder("PINECONE_API_KEY").build();
77+
Pinecone pinecone = new Pinecone.Builder("PINECONE_API_KEY").withOkHttpClient(httpClient).build();
7978
}
8079
}
8180
```

codegen/apis

Submodule apis added at 3e5739b

codegen/build-oas.sh

+87
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
#!/bin/bash
2+
3+
set -eux -o pipefail
4+
5+
version=$1 # e.g. 2024-07
6+
modules=("control")
7+
8+
destination="src/main/java/org/openapitools"
9+
build_dir="gen"
10+
11+
update_apis_repo() {
12+
echo "Updating apis repo"
13+
pushd codegen/apis
14+
git fetch
15+
git checkout main
16+
git pull
17+
just build
18+
popd
19+
}
20+
21+
verify_spec_version() {
22+
local version=$1
23+
echo "Verifying spec version $version exists in apis repo"
24+
if [ -z "$version" ]; then
25+
echo "Version is required"
26+
exit 1
27+
fi
28+
29+
verify_directory_exists "codegen/apis/_build/${version}"
30+
}
31+
32+
verify_file_exists() {
33+
local filename=$1
34+
if [ ! -f "$filename" ]; then
35+
echo "File does not exist at $filename"
36+
exit 1
37+
fi
38+
}
39+
40+
verify_directory_exists() {
41+
local directory=$1
42+
if [ ! -d "$directory" ]; then
43+
echo "Directory does not exist at $directory"
44+
exit 1
45+
fi
46+
}
47+
48+
generate_client() {
49+
local module_name=$1
50+
51+
oas_file="codegen/apis/_build/${version}/${module_name}_${version}.oas.yaml"
52+
53+
verify_file_exists $oas_file
54+
55+
# Cleanup previous build files
56+
echo "Cleaning up previous build files"
57+
rm -rf "${build_dir}"
58+
59+
# Generate client module
60+
docker run --rm -v $(pwd):/workspace openapitools/openapi-generator-cli:v7.0.1 generate \
61+
--input-spec "/workspace/$oas_file" \
62+
--generator-name java \
63+
--additional-properties=dateLibrary='java8',disallowAdditionalPropertiesIfNotPresent=false \
64+
--output "/workspace/${build_dir}"
65+
66+
# Copy the generated module to the correct location
67+
rm -rf "${destination}/${module_name}"
68+
mkdir -p "${destination}/${module_name}"
69+
70+
path_to_copy="${build_dir}/src/main/java/org/openapitools/client"
71+
cp -r $path_to_copy "${destination}/${module_name}"
72+
73+
# Adjust package names in generated file
74+
find "${destination}/${module_name}" -name "*.java" | while IFS= read -r file; do
75+
sed -i '' "s/org\.openapitools\.client/org\.openapitools\.${module_name}\.client/g" "$file"
76+
done
77+
}
78+
79+
update_apis_repo
80+
verify_spec_version $version
81+
82+
rm -rf "${destination}"
83+
mkdir -p "${destination}"
84+
85+
for module in "${modules[@]}"; do
86+
generate_client $module
87+
done

src/integration/java/io/pinecone/helpers/TestResourcesManager.java

+4-4
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@
55
import io.pinecone.clients.Pinecone;
66
import io.pinecone.exceptions.PineconeException;
77
import io.pinecone.proto.DescribeIndexStatsResponse;
8-
import org.openapitools.client.model.*;
8+
import org.openapitools.control.client.model.*;
99
import org.slf4j.Logger;
1010
import org.slf4j.LoggerFactory;
1111

@@ -50,8 +50,8 @@ public class TestResourcesManager {
5050
? "us-east4-gcp"
5151
: System.getenv("PINECONE_ENVIRONMENT");
5252
private static final String metric = System.getenv("METRIC") == null
53-
? IndexMetric.DOTPRODUCT.toString()
54-
: IndexMetric.valueOf(System.getenv("METRIC")).toString();
53+
? IndexModel.MetricEnum.DOTPRODUCT.toString()
54+
: IndexModel.MetricEnum.valueOf(System.getenv("METRIC")).toString();
5555
private static final String cloud = System.getenv("CLOUD") == null
5656
? ServerlessSpec.CloudEnum.AWS.toString()
5757
: System.getenv("CLOUD");
@@ -317,7 +317,7 @@ public String getOrCreateServerlessIndex() throws InterruptedException, Pinecone
317317
String indexName = RandomStringBuilder.build("serverless-index", 8);
318318

319319
serverlessIndexModel = pineconeClient.createServerlessIndex(indexName, metric, dimension, cloud,
320-
region);
320+
region, DeletionProtection.DISABLED);
321321
waitUntilIndexIsReady(pineconeClient, indexName);
322322

323323
// Explicitly wait after ready to avoid the "no healthy upstream" issue

src/integration/java/io/pinecone/helpers/TestUtilities.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
import io.pinecone.clients.Pinecone;
55
import io.pinecone.proto.DescribeIndexStatsResponse;
66
import io.pinecone.proto.NamespaceSummary;
7-
import org.openapitools.client.model.*;
7+
import org.openapitools.control.client.model.*;
88
import org.slf4j.Logger;
99
import org.slf4j.LoggerFactory;
1010

src/integration/java/io/pinecone/integration/controlPlane/pod/CollectionTest.java

+5-5
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
import org.junit.jupiter.api.BeforeAll;
1313
import org.junit.jupiter.api.Disabled;
1414
import org.junit.jupiter.api.Test;
15-
import org.openapitools.client.model.*;
15+
import org.openapitools.control.client.model.*;
1616
import org.slf4j.Logger;
1717
import org.slf4j.LoggerFactory;
1818

@@ -117,11 +117,11 @@ public void testIndexFromCollectionHappyPath() throws InterruptedException {
117117
public void testCreateIndexFromCollectionWithDiffMetric() throws InterruptedException {
118118
// Use a different metric than the source index
119119
String[] metrics = {
120-
IndexMetric.COSINE.toString(),
121-
IndexMetric.EUCLIDEAN.toString(),
122-
IndexMetric.DOTPRODUCT.toString()
120+
IndexModel.MetricEnum.COSINE.toString(),
121+
IndexModel.MetricEnum.EUCLIDEAN.toString(),
122+
IndexModel.MetricEnum.DOTPRODUCT.toString()
123123
};
124-
String targetMetric = IndexMetric.COSINE.toString();
124+
String targetMetric = IndexModel.MetricEnum.COSINE.toString();
125125
for (String metric : metrics) {
126126
if (!metric.equals(sourceIndexMetric)) {
127127
targetMetric = metric;

src/integration/java/io/pinecone/integration/controlPlane/pod/ConfigureIndexTest.java

+10-9
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,10 @@
88
import org.junit.jupiter.api.AfterEach;
99
import org.junit.jupiter.api.BeforeAll;
1010
import org.junit.jupiter.api.Test;
11-
import org.openapitools.client.model.IndexModel;
12-
import org.openapitools.client.model.IndexModelStatus;
13-
import org.openapitools.client.model.PodSpec;
11+
import org.openapitools.control.client.model.DeletionProtection;
12+
import org.openapitools.control.client.model.IndexModel;
13+
import org.openapitools.control.client.model.IndexModelStatus;
14+
import org.openapitools.control.client.model.PodSpec;
1415
import org.slf4j.Logger;
1516
import org.slf4j.LoggerFactory;
1617

@@ -55,7 +56,7 @@ public void afterEach() throws InterruptedException {
5556
@Test
5657
public void configureIndexWithInvalidIndexName() {
5758
try {
58-
controlPlaneClient.configureIndex("non-existent-index", 3);
59+
controlPlaneClient.configurePodsIndex("non-existent-index", 3, DeletionProtection.DISABLED);
5960

6061
fail("Expected to throw PineconeNotFoundException");
6162
} catch (PineconeNotFoundException expected) {
@@ -66,7 +67,7 @@ public void configureIndexWithInvalidIndexName() {
6667
@Test
6768
public void configureIndexExceedingQuota() {
6869
try {
69-
controlPlaneClient.configureIndex(indexName, 600);
70+
controlPlaneClient.configurePodsIndex(indexName, 30, DeletionProtection.DISABLED);
7071
fail("Expected to throw PineconeForbiddenException");
7172
} catch (PineconeForbiddenException expected) {
7273
assertTrue(expected.getLocalizedMessage().contains("reached the max pods allowed"));
@@ -81,7 +82,7 @@ public void scaleUpAndDown() throws InterruptedException {
8182

8283
// Verify the scaled up replicas
8384
assertWithRetry(() -> {
84-
controlPlaneClient.configureIndex(indexName, 3);
85+
controlPlaneClient.configurePodsIndex(indexName, 3, DeletionProtection.DISABLED);
8586
PodSpec podSpec = controlPlaneClient.describeIndex(indexName).getSpec().getPod();
8687
assertNotNull(podSpec);
8788
assertEquals(podSpec.getReplicas(), 3);
@@ -91,7 +92,7 @@ public void scaleUpAndDown() throws InterruptedException {
9192

9293
// Verify replicas were scaled down
9394
assertWithRetry(() -> {
94-
controlPlaneClient.configureIndex(indexName, 1);
95+
controlPlaneClient.configurePodsIndex(indexName, 1, DeletionProtection.DISABLED);
9596
PodSpec podSpec = controlPlaneClient.describeIndex(indexName).getSpec().getPod();
9697
assertNotNull(podSpec);
9798
assertEquals(podSpec.getReplicas(), 1);
@@ -107,7 +108,7 @@ public void changingBasePodType() throws InterruptedException {
107108
assertEquals(1, indexModel.getSpec().getPod().getReplicas());
108109

109110
// Try to change the base pod type
110-
controlPlaneClient.configureIndex(indexName, "p2.x2");
111+
controlPlaneClient.configurePodsIndex(indexName, "p2.x2");
111112

112113
fail("Expected to throw PineconeBadRequestException");
113114
} catch (PineconeBadRequestException expected) {
@@ -125,7 +126,7 @@ public void sizeIncrease() throws InterruptedException {
125126
// Change the pod type to a larger one
126127
// Get the index description to verify the new pod type
127128
assertWithRetry(() -> {
128-
controlPlaneClient.configureIndex(indexName, "p1.x2");
129+
controlPlaneClient.configurePodsIndex(indexName, "p1.x2");
129130
PodSpec podSpec = controlPlaneClient.describeIndex(indexName).getSpec().getPod();
130131
assertNotNull(podSpec);
131132
assertEquals(podSpec.getPodType(), "p1.x2");

src/integration/java/io/pinecone/integration/controlPlane/pod/CreateDescribeListAndDeleteIndexTest.java

+3-3
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
import io.pinecone.helpers.TestResourcesManager;
77
import org.junit.jupiter.api.BeforeAll;
88
import org.junit.jupiter.api.Test;
9-
import org.openapitools.client.model.*;
9+
import org.openapitools.control.client.model.*;
1010

1111
import static org.junit.jupiter.api.Assertions.*;
1212

@@ -36,7 +36,7 @@ public void describeAndListIndex() {
3636
assertNotNull(indexModel);
3737
assertEquals(indexDimension, indexModel.getDimension());
3838
assertEquals(indexName, indexModel.getName());
39-
assertEquals(IndexMetric.DOTPRODUCT, indexModel.getMetric());
39+
assertEquals(IndexModel.MetricEnum.DOTPRODUCT, indexModel.getMetric());
4040
assertNotNull(indexModel.getSpec().getPod());
4141
assertEquals(indexPodType, indexModel.getSpec().getPod().getPodType());
4242

@@ -63,7 +63,7 @@ public void createPodsIndexWithMinimumRequiredParams() {
6363
assertEquals(podType, podsIndex.getSpec().getPod().getPodType());
6464

6565
// Confirm defaults are put in by the backend when not supplied by the user
66-
assertEquals(IndexMetric.COSINE, podsIndex.getMetric());
66+
assertEquals(IndexModel.MetricEnum.COSINE, podsIndex.getMetric());
6767
assertEquals(1, podsIndex.getSpec().getPod().getPods());
6868
assertEquals(1, podsIndex.getSpec().getPod().getReplicas());
6969
assertEquals(1, podsIndex.getSpec().getPod().getShards());
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
package io.pinecone.integration.controlPlane.pod;
2+
3+
import io.pinecone.clients.Pinecone;
4+
import io.pinecone.helpers.RandomStringBuilder;
5+
import org.junit.jupiter.api.Assertions;
6+
import org.junit.jupiter.api.Test;
7+
import org.openapitools.control.client.model.DeletionProtection;
8+
import org.openapitools.control.client.model.IndexModel;
9+
10+
public class DeletionProtectionTest {
11+
private static final Pinecone controlPlaneClient = new Pinecone
12+
.Builder(System.getenv("PINECONE_API_KEY"))
13+
.withSourceTag("pinecone_test")
14+
.build();
15+
16+
@Test
17+
public void createPodIndexWithDeletionProtectionEnabled() {
18+
String indexName = RandomStringBuilder.build("create-pod", 8);
19+
// Create pod index with deletion protection enabled
20+
controlPlaneClient.createPodsIndex(indexName, 3, "us-east-1-aws", "p1.x1", DeletionProtection.ENABLED);
21+
IndexModel indexModel = controlPlaneClient.describeIndex(indexName);
22+
DeletionProtection deletionProtection = indexModel.getDeletionProtection();
23+
Assertions.assertEquals(deletionProtection, DeletionProtection.ENABLED);
24+
// Configure index to disable deletionProtection
25+
controlPlaneClient.configurePodsIndex(indexName, DeletionProtection.DISABLED);
26+
// Delete index
27+
controlPlaneClient.deleteIndex(indexName);
28+
}
29+
30+
@Test
31+
public void createPodIndexWithDeletionProtectionDisabled() {
32+
String indexName = RandomStringBuilder.build("create-pod", 8);
33+
// Create pod index with deletion protection disabled
34+
controlPlaneClient.createPodsIndex(indexName, 3, "us-east-1-aws", "p1.x1");
35+
IndexModel indexModel = controlPlaneClient.describeIndex(indexName);
36+
DeletionProtection deletionProtection = indexModel.getDeletionProtection();
37+
Assertions.assertEquals(deletionProtection, DeletionProtection.DISABLED);
38+
// Configure index to enable deletionProtection
39+
controlPlaneClient.configurePodsIndex(indexName, DeletionProtection.ENABLED);
40+
indexModel = controlPlaneClient.describeIndex(indexName);
41+
deletionProtection = indexModel.getDeletionProtection();
42+
Assertions.assertEquals(deletionProtection, DeletionProtection.ENABLED);
43+
// Configure index to disable deletionProtection
44+
controlPlaneClient.configurePodsIndex(indexName, DeletionProtection.DISABLED);
45+
// Delete index
46+
controlPlaneClient.deleteIndex(indexName);
47+
}
48+
}

src/integration/java/io/pinecone/integration/controlPlane/serverless/CreateDescribeListAndDeleteIndexTest.java

+6-6
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
import io.pinecone.helpers.TestResourcesManager;
88
import org.junit.jupiter.api.BeforeAll;
99
import org.junit.jupiter.api.Test;
10-
import org.openapitools.client.model.*;
10+
import org.openapitools.control.client.model.*;
1111

1212
import java.util.Arrays;
1313

@@ -36,7 +36,7 @@ public void describeAndListIndex() {
3636
assertNotNull(indexModel);
3737
assertEquals(dimension, indexModel.getDimension());
3838
assertEquals(indexName, indexModel.getName());
39-
assertEquals(IndexMetric.DOTPRODUCT, indexModel.getMetric());
39+
assertEquals(IndexModel.MetricEnum.DOTPRODUCT, indexModel.getMetric());
4040
assertNotNull(indexModel.getSpec().getServerless());
4141

4242
// List the index
@@ -48,7 +48,7 @@ public void describeAndListIndex() {
4848
@Test
4949
public void createServerlessIndexWithInvalidName() {
5050
try {
51-
controlPlaneClient.createServerlessIndex("Invalid-name", "cosine", 3, "aws", "us-west-2");
51+
controlPlaneClient.createServerlessIndex("Invalid-name", "cosine", 3, "aws", "us-west-2", DeletionProtection.DISABLED);
5252

5353
fail("Expected to throw PineconeBadRequestException");
5454
} catch (PineconeBadRequestException expected) {
@@ -59,7 +59,7 @@ public void createServerlessIndexWithInvalidName() {
5959
@Test
6060
public void createServerlessIndexWithInvalidDimension() {
6161
try {
62-
controlPlaneClient.createServerlessIndex("serverless-test-index", "cosine", -3, "aws", "us-west-2");
62+
controlPlaneClient.createServerlessIndex("serverless-test-index", "cosine", -3, "aws", "us-west-2", DeletionProtection.DISABLED);
6363
fail("Expected to throw PineconeValidationException");
6464
} catch (PineconeValidationException expected) {
6565
assertTrue(expected.getLocalizedMessage().contains("Dimension must be greater than 0"));
@@ -69,7 +69,7 @@ public void createServerlessIndexWithInvalidDimension() {
6969
@Test
7070
public void createServerlessIndexWithInvalidCloud() {
7171
try {
72-
controlPlaneClient.createServerlessIndex("serverless-test-index", "cosine", 3, "blah", "us-west-2");
72+
controlPlaneClient.createServerlessIndex("serverless-test-index", "cosine", 3, "blah", "us-west-2", DeletionProtection.DISABLED);
7373
fail("Expected to throw PineconeValidationException");
7474
} catch (PineconeValidationException expected) {
7575
assertTrue(expected.getLocalizedMessage().contains("Cloud cannot be null or empty. Must be one of " + Arrays.toString(ServerlessSpec.CloudEnum.values())));
@@ -79,7 +79,7 @@ public void createServerlessIndexWithInvalidCloud() {
7979
@Test
8080
public void createServerlessIndexWithInvalidRegion() {
8181
try {
82-
controlPlaneClient.createServerlessIndex("serverless-test-index", "cosine", 3, "aws", "invalid-region");
82+
controlPlaneClient.createServerlessIndex("serverless-test-index", "cosine", 3, "aws", "invalid-region", DeletionProtection.DISABLED);
8383
fail("Expected to throw PineconeNotFoundException");
8484
} catch (PineconeNotFoundException expected) {
8585
assertTrue(expected.getLocalizedMessage().contains("Resource cloud: aws region: invalid-region not found"));

0 commit comments

Comments
 (0)