From ba365fdd3c7962592e1b8e85ca1706a6868a62ef Mon Sep 17 00:00:00 2001 From: Macdonald Date: Thu, 26 Jun 2025 14:56:57 -0400 Subject: [PATCH 01/32] added Kotlin Neptune files --- kotlin/services/neptune/.gitignore | 42 ++ kotlin/services/neptune/build.gradle.kts | 56 ++ kotlin/services/neptune/settings.gradle.kts | 10 + .../neptune/scenerio/NeptuneScenario.kt | 588 ++++++++++++++++++ .../neptune/src/test/java/NeptuneTest.kt | 145 +++++ 5 files changed, 841 insertions(+) create mode 100644 kotlin/services/neptune/.gitignore create mode 100644 kotlin/services/neptune/build.gradle.kts create mode 100644 kotlin/services/neptune/settings.gradle.kts create mode 100644 kotlin/services/neptune/src/main/java/com/example/neptune/scenerio/NeptuneScenario.kt create mode 100644 kotlin/services/neptune/src/test/java/NeptuneTest.kt diff --git a/kotlin/services/neptune/.gitignore b/kotlin/services/neptune/.gitignore new file mode 100644 index 00000000000..b63da4551b2 --- /dev/null +++ b/kotlin/services/neptune/.gitignore @@ -0,0 +1,42 @@ +.gradle +build/ +!gradle/wrapper/gradle-wrapper.jar +!**/src/main/**/build/ +!**/src/test/**/build/ + +### IntelliJ IDEA ### +.idea/modules.xml +.idea/jarRepositories.xml +.idea/compiler.xml +.idea/libraries/ +*.iws +*.iml +*.ipr +out/ +!**/src/main/**/out/ +!**/src/test/**/out/ + +### Eclipse ### +.apt_generated +.classpath +.factorypath +.project +.settings +.springBeans +.sts4-cache +bin/ +!**/src/main/**/bin/ +!**/src/test/**/bin/ + +### NetBeans ### +/nbproject/private/ +/nbbuild/ +/dist/ +/nbdist/ +/.nb-gradle/ + +### VS Code ### +.vscode/ + +### Mac OS ### +.DS_Store \ No newline at end of file diff --git a/kotlin/services/neptune/build.gradle.kts b/kotlin/services/neptune/build.gradle.kts new file mode 100644 index 00000000000..c75329475d5 --- /dev/null +++ b/kotlin/services/neptune/build.gradle.kts @@ -0,0 +1,56 @@ +import org.jetbrains.kotlin.gradle.tasks.KotlinCompile + +plugins { + kotlin("jvm") version "1.9.0" + application +} + +group = "me.scmacdon" +version = "1.0-SNAPSHOT" + +java { + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 +} + +buildscript { + repositories { + maven("https://plugins.gradle.org/m2/") + } + + dependencies { + classpath("org.jlleitschuh.gradle:ktlint-gradle:10.3.0") + } +} + +repositories { + mavenCentral() +} +apply(plugin = "org.jlleitschuh.gradle.ktlint") + +dependencies { + implementation(platform("aws.sdk.kotlin:bom:1.3.112")) + implementation("aws.sdk.kotlin:neptune") + implementation("aws.sdk.kotlin:ec2") + implementation("aws.smithy.kotlin:http-client-engine-okhttp") + implementation("aws.smithy.kotlin:http-client-engine-crt") + implementation("com.google.code.gson:gson:2.10") + testImplementation("org.junit.jupiter:junit-jupiter:5.9.0") + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4") + implementation("org.slf4j:slf4j-api:2.0.15") + implementation("org.slf4j:slf4j-simple:2.0.15") +} +tasks.withType { + kotlinOptions.jvmTarget = "17" +} + +tasks.test { + useJUnitPlatform() // Use JUnit 5 for running tests + testLogging { + events("passed", "skipped", "failed") + } + + // Define the test source set + testClassesDirs += files("build/classes/kotlin/test") + classpath += files("build/classes/kotlin/main", "build/resources/main") +} diff --git a/kotlin/services/neptune/settings.gradle.kts b/kotlin/services/neptune/settings.gradle.kts new file mode 100644 index 00000000000..9103dd94328 --- /dev/null +++ b/kotlin/services/neptune/settings.gradle.kts @@ -0,0 +1,10 @@ +pluginManagement { + plugins { + kotlin("jvm") version "2.1.10" + } +} +plugins { + id("org.gradle.toolchains.foojay-resolver-convention") version "0.8.0" +} +rootProject.name = "neptune" + diff --git a/kotlin/services/neptune/src/main/java/com/example/neptune/scenerio/NeptuneScenario.kt b/kotlin/services/neptune/src/main/java/com/example/neptune/scenerio/NeptuneScenario.kt new file mode 100644 index 00000000000..fc7150c5c9d --- /dev/null +++ b/kotlin/services/neptune/src/main/java/com/example/neptune/scenerio/NeptuneScenario.kt @@ -0,0 +1,588 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +package com.example.neptune.scenerio + +import aws.sdk.kotlin.services.ec2.Ec2Client +import aws.sdk.kotlin.services.ec2.model.DescribeSubnetsRequest +import aws.sdk.kotlin.services.ec2.model.DescribeVpcsRequest +import aws.sdk.kotlin.services.ec2.model.Filter +import aws.sdk.kotlin.services.neptune.NeptuneClient +import aws.sdk.kotlin.services.neptune.model.CreateDbClusterRequest +import aws.sdk.kotlin.services.neptune.model.CreateDbInstanceRequest +import aws.sdk.kotlin.services.neptune.model.CreateDbSubnetGroupRequest +import aws.sdk.kotlin.services.neptune.model.DeleteDbClusterRequest +import aws.sdk.kotlin.services.neptune.model.DeleteDbInstanceRequest +import aws.sdk.kotlin.services.neptune.model.DeleteDbSubnetGroupRequest +import aws.sdk.kotlin.services.neptune.model.DescribeDbClustersRequest +import aws.sdk.kotlin.services.neptune.model.DescribeDbInstancesRequest +import aws.sdk.kotlin.services.neptune.model.NeptuneException +import aws.sdk.kotlin.services.neptune.model.StartDbClusterRequest +import aws.sdk.kotlin.services.neptune.model.StopDbClusterRequest +import kotlinx.coroutines.delay +import java.time.Duration +import java.util.* + + +val DASHES = String(CharArray(80)).replace("\u0000", "-") +var scanner = Scanner(System.`in`) +private val pollInterval: Duration = Duration.ofSeconds(20) +private val timeout: Duration = Duration.ofMinutes(30) +suspend fun main(args: Array) { + val subnetGroupName = "neptuneSubnetGroup61" + val clusterName = "neptuneCluster61" + val dbInstanceId = "neptuneDB61" + + println( + """ + Amazon Neptune is a fully managed graph + database service by AWS, designed specifically + for handling complex relationships and connected + datasets at scale. It supports two popular graph models: + property graphs (via openCypher and Gremlin) and RDF + graphs (via SPARQL). This makes Neptune ideal for + use cases such as knowledge graphs, fraud detection, + social networking, recommendation engines, and + network management, where relationships between + entities are central to the data. + + Being fully managed, Neptune handles database + provisioning, patching, backups, and replication, + while also offering high availability and durability + within AWS's infrastructure. + + For developers, programming with Neptune allows + for building intelligent, relationship-aware + applications that go beyond traditional tabular + databases. Developers can use the AWS SDK for Kotlin + to automate infrastructure operations + (via NeptuneClient). + + Let's get started... + + """ + ) + waitForInputToContinue(scanner) + runScenario(subnetGroupName, dbInstanceId, clusterName) + println( + """ + Thank you for checking out the Amazon Neptune Service Use demo. We hope you + learned something new, or got some inspiration for your own apps today. + For more AWS code examples, have a look at: + https://docs.aws.amazon.com/code-library/latest/ug/what-is-code-library.html + + """ + ) +} + +suspend fun runScenario(subnetGroupName: String, dbInstanceId: String, clusterName: String) { + println(DASHES) + println("1. Create a Neptune DB Subnet Group") + println("The Neptune DB subnet group is used when launching a Neptune cluster") + waitForInputToContinue(scanner) + createSubnetGroup(subnetGroupName) + waitForInputToContinue(scanner) + println(DASHES) + + println(DASHES) + println("2. Create a Neptune Cluster") + println("A Neptune Cluster allows you to store and query highly connected datasets with low latency.") + waitForInputToContinue(scanner) + val dbClusterId = createDbCluster(clusterName) + waitForInputToContinue(scanner) + println(DASHES) + + println(DASHES) + println("3. Create a Neptune DB Instance"); + println("In this step, we add a new database instance to the Neptune cluster"); + waitForInputToContinue(scanner) + createDbInstance(dbInstanceId, dbClusterId) + waitForInputToContinue(scanner) + println(DASHES) + + println(DASHES) + println("4. Check the status of the Neptune DB Instance"); + println( + """ + In this step, we will wait until the DB instance + becomes available. This may take around 10 minutes. + """ + ) + waitForInputToContinue(scanner) + checkInstanceStatus(dbInstanceId, "available") + waitForInputToContinue(scanner) + println(DASHES) + + println(DASHES) + println("5. Show Neptune Cluster details"); + waitForInputToContinue(scanner) + describeDBClusters(dbClusterId) + waitForInputToContinue(scanner) + println(DASHES) + + println(DASHES) + println("6. Stop the Amazon Neptune cluster"); + println( + """ + Once stopped, this step polls the status + until the cluster is in a stopped state. + """ + ); + waitForInputToContinue(scanner) + stopDBCluster(dbClusterId) + waitForClusterStatus(dbClusterId, "stopped") + waitForInputToContinue(scanner) + println(DASHES) + + println(DASHES) + println("7. Start the Amazon Neptune cluster"); + println( + """ + Once started, this step polls the clusters + status until it's in an available state. + We will also poll the instance status. + """ + ); + waitForInputToContinue(scanner) + startDBCluster(dbClusterId) + waitForClusterStatus(dbClusterId, "available") + checkInstanceStatus(dbInstanceId, "available") + waitForInputToContinue(scanner) + println(DASHES) + + println(DASHES); + println("8. Delete the Neptune Assets"); + println("Would you like to delete the Neptune Assets? (y/n)"); + val delAns = scanner.nextLine().trim(); + if (delAns.equals("y")) { + println("You selected to delete the Neptune assets."); + deleteDbInstance(dbInstanceId) + waitUntilInstanceDeleted(dbInstanceId) + deleteDBCluster(dbClusterId) + deleteDBSubnetGroup(subnetGroupName) + println("Neptune resources deleted successfully.") + + } else { + println("You selected not to delete Neptune assets.") + } +} + +// snippet-start:[neptune.kotlin.delete.subnet.group.main] +/** + * Deletes a subnet group. + * + * @param subnetGroupName the identifier of the subnet group to delete + * @return a {@link CompletableFuture} that completes when the cluster has been deleted + */ +suspend fun deleteDBSubnetGroup(subnetGroupName:String) { + val request = DeleteDbSubnetGroupRequest { + dbSubnetGroupName = subnetGroupName + } + + NeptuneClient { region = "us-east-1" }.use { neptuneClient -> + neptuneClient.deleteDbSubnetGroup(request) + println(" Deleting Subnet Group: $subnetGroupName") + } +} +// snippet-end:[neptune.kotlin.delete.subnet.group.main] + +// snippet-start:[neptune.kotlin.delete.cluster.main] +/** + * Deletes a DB instance. + * + * @param clusterId the identifier of the cluster to delete + */ +suspend fun deleteDBCluster(clusterId: String) { + val request = DeleteDbClusterRequest { + dbClusterIdentifier = clusterId + skipFinalSnapshot = true + } + NeptuneClient { region = "us-east-1" }.use { neptuneClient -> + neptuneClient.deleteDbCluster(request) + println("️ Deleting DB Cluster: $clusterId") + } +} +// snippet-end:[neptune.kotlin.delete.cluster.main] + +suspend fun waitUntilInstanceDeleted( + instanceId: String, + timeout: Duration = Duration.ofMinutes(20), + pollInterval: Duration = Duration.ofSeconds(10) +): Boolean { + println(" Waiting for instance '$instanceId' to be deleted...") + + NeptuneClient { region = "us-east-1" }.use { neptuneClient -> + val startTime = System.currentTimeMillis() + + while (true) { + try { + val request = DescribeDbInstancesRequest { + dbInstanceIdentifier = instanceId + } + + val response = neptuneClient.describeDbInstances(request) + val status = response.dbInstances?.firstOrNull()?.dbInstanceStatus ?: "Unknown" + val elapsed = (System.currentTimeMillis() - startTime) / 1000 + + print("\r Waiting: Instance $instanceId status: ${status.padEnd(10)} (${elapsed}s elapsed)") + System.out.flush() + + } catch (e: NeptuneException) { + val errorCode = e.sdkErrorMetadata.errorCode + return if (errorCode == "DBInstanceNotFound") { + val elapsed = (System.currentTimeMillis() - startTime) / 1000 + println("\n Instance '$instanceId' deleted after ${elapsed}s.") + true + } else { + println("\n Error polling DB instance '$instanceId': ${errorCode ?: "Unknown"} — ${e.message}") + false + } + } catch (e: Exception) { + println("\n Unexpected error while polling DB instance '$instanceId': ${e.message}") + return false + } + + val elapsedMs = System.currentTimeMillis() - startTime + if (elapsedMs > timeout.toMillis()) { + println("\n Timeout: Instance '$instanceId' was not deleted after ${timeout.toMinutes()} minutes.") + return false + } + + delay(pollInterval.toMillis()) + } + } +} + +// snippet-start:[neptune.kotlin.delete.instance.main] +/** + * Deletes a DB instance. + * + * @param instanceId the identifier of the DB instance to be deleted + * @return a {@link CompletableFuture} that completes when the DB instance has been deleted + */ +suspend fun deleteDbInstance(instanceId: String) { + val request = DeleteDbInstanceRequest { + dbInstanceIdentifier = instanceId + skipFinalSnapshot = true + } + NeptuneClient { region = "us-east-1" }.use { neptuneClient -> + neptuneClient.deleteDbInstance(request) + println("Deleting DB Instance: $instanceId") + } +} +// snippet-end:[neptune.kotlin.delete.instance.main] + +/** + * Waits for a Neptune cluster to reach a desired status. + * + * @param clusterId the ID of the Neptune cluster to monitor + * @param desiredStatus the desired status of the Neptune cluster + * @param timeout the maximum time to wait for the cluster to reach the desired status + * @param pollInterval the interval at which to check the cluster's status + * + */ +suspend fun waitForClusterStatus( + clusterId: String, + desiredStatus: String, + timeout: Duration = Duration.ofMinutes(20), + pollInterval: Duration = Duration.ofSeconds(10) +) { + println("Waiting for cluster '$clusterId' to reach status '$desiredStatus'...") + + NeptuneClient { region = "us-east-1" }.use { neptuneClient -> + val startTime = System.currentTimeMillis() + + while (true) { + val request = DescribeDbClustersRequest { + dbClusterIdentifier = clusterId + } + + val response = neptuneClient.describeDbClusters(request) + val currentStatus = response.dbClusters?.firstOrNull()?.status + val elapsedSeconds = (System.currentTimeMillis() - startTime) / 1000 + + println( + "\r Elapsed: ${formatElapsedTime(elapsedSeconds.toInt()).padEnd(20)} Cluster status: ${ + currentStatus?.padEnd( + 20 + ) ?: "Unknown" + }" + ) + System.out.flush() + + if (desiredStatus.equals(currentStatus, ignoreCase = true)) { + println( + "\nNeptune cluster reached desired status '$desiredStatus' after ${ + formatElapsedTime( + elapsedSeconds.toInt() + ) + }." + ) + return + } + + if (Duration.ofMillis(System.currentTimeMillis() - startTime) > timeout) { + throw RuntimeException("Timeout waiting for Neptune cluster to reach status: $desiredStatus") + } + + delay(pollInterval.toMillis()) + } + } +} + +// snippet-start:[neptune.kotlin.start.cluster.main] +/** + * Starts an Amazon Neptune DB cluster. + * + * @param clusterIdentifier the unique identifier of the DB cluster to be stopped + */ +suspend fun startDBCluster(clusterIdentifier: String) { + val request = StartDbClusterRequest { + dbClusterIdentifier = clusterIdentifier + } + + NeptuneClient { region = "us-east-1" }.use { neptuneClient -> + neptuneClient.startDbCluster(request) + println("DB Cluster started : $clusterIdentifier") + } +} +// snippet-end:[neptune.kotlin.start.cluster.main] + +// snippet-start:[neptune.kotlin.stop.cluster.main] +/** + * Stops an Amazon Neptune DB cluster. + * + * @param clusterIdentifier the unique identifier of the DB cluster to be stopped + */ +suspend fun stopDBCluster(clusterIdentifier: String) { + val request = StopDbClusterRequest { + dbClusterIdentifier = clusterIdentifier + } + + NeptuneClient { region = "us-east-1" }.use { neptuneClient -> + neptuneClient.stopDbCluster(request) + println("DB Cluster stopped: $clusterIdentifier") + } +} +// snippet-end:[neptune.kotlin.stop.cluster.main] + +// snippet-start:[neptune.kotlin.describe.cluster.main] +/** + * Describes the specified Amazon Neptune cluster. + * + * @param clusterId the identifier of the cluster to describe + */ +suspend fun describeDBClusters(clusterId: String) { + val request = DescribeDbClustersRequest { + dbClusterIdentifier = clusterId + } + + NeptuneClient { region = "us-east-1" }.use { neptuneClient -> + val response = neptuneClient.describeDbClusters(request) + response.dbClusters?.forEach { cluster -> + println("Cluster Identifier: ${cluster.dbClusterIdentifier}") + println("Status: ${cluster.status}") + println("Engine: ${cluster.engine}") + println("Engine Version: ${cluster.engineVersion}") + println("Endpoint: ${cluster.endpoint}") + println("Reader Endpoint: ${cluster.readerEndpoint}") + println("Availability Zones: ${cluster.availabilityZones}") + println("Subnet Group: ${cluster.dbSubnetGroup}") + println("VPC Security Groups:") + cluster.vpcSecurityGroups?.forEach { vpcGroup -> + println(" - ${vpcGroup.vpcSecurityGroupId}") + } + println("Storage Encrypted: ${cluster.storageEncrypted}") + println("IAM DB Auth Enabled: ${cluster.iamDatabaseAuthenticationEnabled}") + println("Backup Retention Period: ${cluster.backupRetentionPeriod} days") + println("Preferred Backup Window: ${cluster.preferredBackupWindow}") + println("Preferred Maintenance Window: ${cluster.preferredMaintenanceWindow}") + println("------") + } + } +} +// snippet-end:[neptune.kotlin.describe.cluster.main] + +// snippet-start:[neptune.kotlin.describe.dbinstance.main] +/** + * Checks the status of a Neptune instance recursively until the desired status is reached or a timeout occurs. + * + * @param instanceId the ID of the Neptune instance to check + * @param desiredStatus the desired status of the Neptune instance + */ +suspend fun checkInstanceStatus(instanceId: String, desiredStatus: String) { + NeptuneClient { region = "us-east-1" }.use { neptuneClient -> + val startTime = System.currentTimeMillis() + while (true) { + val request = DescribeDbInstancesRequest { + dbInstanceIdentifier = instanceId + } + + val response = neptuneClient.describeDbInstances(request) + val instances = response.dbInstances + val currentStatus = instances?.get(0)?.dbInstanceStatus + val elapsedSeconds = (System.currentTimeMillis() - startTime) / 1000 + + print("\r Elapsed: ${formatElapsedTime(elapsedSeconds.toInt())} Status: $currentStatus") + System.out.flush() + + if (desiredStatus.equals(currentStatus, ignoreCase = true)) { + println( + "\nNeptune instance reached desired status '$desiredStatus' after ${ + formatElapsedTime( + elapsedSeconds.toInt() + ) + }." + ) + break + } + + if (Duration.ofMillis(System.currentTimeMillis() - startTime) > timeout) { + throw RuntimeException("Timeout waiting for Neptune instance to reach status: $desiredStatus") + } + + delay(pollInterval.toMillis()) + } + } +} +// snippet-end:[neptune.kotlin.describe.dbinstance.main] + +private fun formatElapsedTime(totalSeconds: Int): String { + val minutes = totalSeconds / 60 + val seconds = totalSeconds % 60 + return String.format("%02d:%02d", minutes, seconds) +} + + +// snippet-start:[neptune.kotlin.create.dbinstance.main] + +/*** Creates an Amazon Neptune DB instance. + * + * @param dbInstanceId the identifier for the new DB instance + * @param dbClusterId the identifier for the DB cluster that the new instance will be a part of + * @return the identifier of the newly created DB instance + */ +suspend fun createDbInstance(dbInstanceId: String, dbClusterId: String): String { + NeptuneClient { region = "us-east-1" }.use { neptuneClient -> + val request = CreateDbInstanceRequest { + dbInstanceIdentifier = dbInstanceId + dbInstanceClass = "db.r5.large" + engine = "neptune" + dbClusterIdentifier = dbClusterId + } + + val response = neptuneClient.createDbInstance(request) + val instanceId = response.dbInstance?.dbInstanceIdentifier + ?: throw RuntimeException("Instance creation succeeded but no ID returned.") + + println("Created Neptune DB Instance: $instanceId") + return instanceId + } +} +// snippet-end:[neptune.kotlin.create.dbinstance.main] + +// snippet-start:[neptune.kotlin.create.cluster.main] +/** + * Creates a new Amazon Neptune DB cluster. + * + * @param dbName the name of the DB cluster to be created + * @return the ID of the created DB cluster + */ +suspend fun createDbCluster(dbName: String): String { + NeptuneClient { region = "us-east-1" }.use { neptuneClient -> + val request = CreateDbClusterRequest { + dbClusterIdentifier = dbName + engine = "neptune" + deletionProtection = false + backupRetentionPeriod = 1 + } + + val response = neptuneClient.createDbCluster(request) + val clusterId = response.dbCluster?.dbClusterIdentifier + ?: throw RuntimeException("Cluster creation succeeded but no ID returned.") + + println("DB Cluster created: $clusterId") + return clusterId + } +} +// snippet-end:[neptune.kotlin.create.cluster.main] + +// snippet-start:[neptune.kotlin.create.subnet.main] +/** + * Creates a new Neptune DB subnet group asynchronously. + * + * @param groupName the name of the DB subnet group to create + * @return the Amazon Resource Name (ARN) of the created DB subnet group + */ +suspend fun createSubnetGroup(groupName: String) { + // Get the Amazon Virtual Private Cloud (VPC) where the Neptune cluster and resources will be created + val vpcId = getDefaultVpcId() + val subnetList = getSubnetIds(vpcId) + + val request = CreateDbSubnetGroupRequest { + dbSubnetGroupName = groupName + dbSubnetGroupDescription = "Subnet group for Neptune cluster" + subnetIds = subnetList + } + + NeptuneClient { region = "us-east-1" }.use { neptuneClient -> + val response = neptuneClient.createDbSubnetGroup(request) + val name = response.dbSubnetGroup?.dbSubnetGroupName + val arn = response.dbSubnetGroup?.dbSubnetGroupArn + println("Subnet group created: $name") + } +} +// snippet-end:[neptune.kotlin.create.subnet.main] + +suspend fun getDefaultVpcId(): String { + Ec2Client { region = "us-east-1" }.use { ec2Client -> + val request = DescribeVpcsRequest { + filters = listOf( + Filter { + name = "isDefault" + values = listOf("true") + } + ) + } + + val response = ec2Client.describeVpcs(request) + val defaultVpc = response.vpcs?.firstOrNull() + ?: throw RuntimeException("No default VPC found in this region.") + + println("Default VPC ID: ${defaultVpc.vpcId}") + return defaultVpc.vpcId!! + } +} + +suspend fun getSubnetIds(vpcId: String): List { + Ec2Client { region = "us-east-1" }.use { ec2Client -> + val request = DescribeSubnetsRequest { + filters = listOf( + Filter { + name = "vpc-id" + values = listOf(vpcId) + } + ) + } + + val response = ec2Client.describeSubnets(request) + return response.subnets?.mapNotNull { it.subnetId } ?: emptyList() + } +} + + +private fun waitForInputToContinue(scanner: Scanner) { + while (true) { + println("") + println("Enter 'c' followed by to continue:") + val input = scanner.nextLine() + + if (input.trim { it <= ' ' }.equals("c", ignoreCase = true)) { + println("Continuing with the program...") + println("") + break + } else { + println("Invalid input. Please try again.") + } + } +} \ No newline at end of file diff --git a/kotlin/services/neptune/src/test/java/NeptuneTest.kt b/kotlin/services/neptune/src/test/java/NeptuneTest.kt new file mode 100644 index 00000000000..4fd1368c2ac --- /dev/null +++ b/kotlin/services/neptune/src/test/java/NeptuneTest.kt @@ -0,0 +1,145 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +import com.example.neptune.scenerio.checkInstanceStatus +import com.example.neptune.scenerio.createDbCluster +import com.example.neptune.scenerio.createDbInstance +import com.example.neptune.scenerio.createSubnetGroup +import com.example.neptune.scenerio.deleteDBCluster +import com.example.neptune.scenerio.deleteDBSubnetGroup +import com.example.neptune.scenerio.deleteDbInstance +import com.example.neptune.scenerio.describeDBClusters +import com.example.neptune.scenerio.startDBCluster +import com.example.neptune.scenerio.stopDBCluster +import com.example.neptune.scenerio.waitForClusterStatus +import com.example.neptune.scenerio.waitUntilInstanceDeleted +import kotlinx.coroutines.runBlocking +import org.junit.jupiter.api.Assertions +import org.junit.jupiter.api.MethodOrderer +import org.junit.jupiter.api.Order +import org.junit.jupiter.api.Tag +import org.junit.jupiter.api.Test +import org.junit.jupiter.api.TestInstance +import org.junit.jupiter.api.TestMethodOrder + +@TestInstance(TestInstance.Lifecycle.PER_CLASS) +@TestMethodOrder(MethodOrderer.OrderAnnotation::class) +class NeptuneTest { + private val subnetGroupName = "neptuneSubnetGroup65" + private val clusterName = "neptuneCluster65" + private val dbInstanceId = "neptuneDB65" + private var dbClusterId = "" + + @Test + @Tag("IntegrationTest") + @Order(1) + fun testSubnetGroup() = runBlocking { + runCatching { + createSubnetGroup(subnetGroupName) + }.onFailure { + it.printStackTrace() + Assertions.fail("Subnet group creation failed: ${it.message}") + }.getOrThrow() + + println("Created Group: $subnetGroupName") + } + + @Test + @Tag("IntegrationTest") + @Order(2) + fun testCreateDbCluster() = runBlocking { + dbClusterId = runCatching { + createDbCluster(clusterName) + }.onFailure { + it.printStackTrace() + Assertions.fail("DB cluster creation failed: ${it.message}") + }.getOrThrow() + + Assertions.assertNotNull(dbClusterId, "Expected DB cluster ID to be non-null") + println("Created DB Cluster: $dbClusterId") + } + + @Test + @Tag("IntegrationTest") + @Order(3) + fun testCreateDbInstance() = runBlocking { + runCatching { + createDbInstance(dbInstanceId, dbClusterId) + }.onFailure { + it.printStackTrace() + Assertions.fail("DB Instance creation failed: ${it.message}") + }.getOrThrow() + println("Created DB Instance: $dbInstanceId") + } + + @Test + @Tag("IntegrationTest") + @Order(4) + fun testCheckInstanceStatus() = runBlocking { + runCatching { + checkInstanceStatus(dbInstanceId, "available") + }.onFailure { + it.printStackTrace() + Assertions.fail("Instance status check failed: ${it.message}") + }.getOrThrow() + println("Instance status check passed: $dbInstanceId") + } + + @Test + @Tag("IntegrationTest") + @Order(5) + fun testDescribeDBClusters() = runBlocking { + runCatching { + describeDBClusters(dbClusterId) + }.onFailure { + it.printStackTrace() + Assertions.fail("Describe Cluster failed: ${it.message}") + }.getOrThrow() + println("Describe cluster passed: $dbInstanceId") + } + + @Test + @Tag("IntegrationTest") + @Order(6) + fun testStopClusters() = runBlocking { + runCatching { + stopDBCluster(dbClusterId) + waitForClusterStatus(dbClusterId, "stopped") + }.onFailure { + it.printStackTrace() + Assertions.fail("Stopping the Cluster failed: ${it.message}") + }.getOrThrow() + println("Stopping the cluster passed: $dbInstanceId") + } + + @Test + @Tag("IntegrationTest") + @Order(7) + fun testStartClusters() = runBlocking { + runCatching { + startDBCluster(dbClusterId) + waitForClusterStatus(dbClusterId, "available") + checkInstanceStatus(dbInstanceId, "available") + }.onFailure { + it.printStackTrace() + Assertions.fail("Starting the Cluster failed: ${it.message}") + }.getOrThrow() + println("Starting the cluster passed: $dbInstanceId") + } + + @Test + @Tag("IntegrationTest") + @Order(8) + fun testDeleteResources() = runBlocking { + runCatching { + deleteDbInstance(dbInstanceId) + waitUntilInstanceDeleted(dbInstanceId) + deleteDBCluster(dbClusterId) + deleteDBSubnetGroup(subnetGroupName) + }.onFailure { + it.printStackTrace() + Assertions.fail("Deleting the resources failed: ${it.message}") + }.getOrThrow() + println("Deleting the resources passed: $dbInstanceId") + } +} \ No newline at end of file From a3d541530b985ce6b3094729d4ba335962baaf5e Mon Sep 17 00:00:00 2001 From: Macdonald Date: Thu, 26 Jun 2025 20:24:40 -0400 Subject: [PATCH 02/32] added Kotlin Neptune files --- .../neptune/scenerio/NeptuneScenario.kt | 42 +++++++------------ 1 file changed, 16 insertions(+), 26 deletions(-) diff --git a/kotlin/services/neptune/src/main/java/com/example/neptune/scenerio/NeptuneScenario.kt b/kotlin/services/neptune/src/main/java/com/example/neptune/scenerio/NeptuneScenario.kt index fc7150c5c9d..8528102e77e 100644 --- a/kotlin/services/neptune/src/main/java/com/example/neptune/scenerio/NeptuneScenario.kt +++ b/kotlin/services/neptune/src/main/java/com/example/neptune/scenerio/NeptuneScenario.kt @@ -29,36 +29,26 @@ var scanner = Scanner(System.`in`) private val pollInterval: Duration = Duration.ofSeconds(20) private val timeout: Duration = Duration.ofMinutes(30) suspend fun main(args: Array) { - val subnetGroupName = "neptuneSubnetGroup61" - val clusterName = "neptuneCluster61" - val dbInstanceId = "neptuneDB61" + val subnetGroupName = "neptuneSubnetGroup200" + val clusterName = "neptuneCluster200" + val dbInstanceId = "neptuneDB200" println( """ - Amazon Neptune is a fully managed graph - database service by AWS, designed specifically - for handling complex relationships and connected - datasets at scale. It supports two popular graph models: - property graphs (via openCypher and Gremlin) and RDF - graphs (via SPARQL). This makes Neptune ideal for - use cases such as knowledge graphs, fraud detection, - social networking, recommendation engines, and - network management, where relationships between - entities are central to the data. + Amazon Neptune is a fully managed AWS graph database optimized for complex, connected datasets. + It supports property graphs (Gremlin, openCypher) + and RDF graphs (SPARQL), making it ideal for knowledge + graphs, fraud detection, social networks, + recommendations, and network management. + + Neptune handles provisioning, patching, backups, a + nd replication, offering high availability by default + . + Developers can build relationship-aware apps using the + AWS SDK for Kotlin and automate infrastructure with + NeptuneClient. - Being fully managed, Neptune handles database - provisioning, patching, backups, and replication, - while also offering high availability and durability - within AWS's infrastructure. - - For developers, programming with Neptune allows - for building intelligent, relationship-aware - applications that go beyond traditional tabular - databases. Developers can use the AWS SDK for Kotlin - to automate infrastructure operations - (via NeptuneClient). - - Let's get started... + Let's get started... """ ) From adac7ec5cfcfeb3899805775bd1e09f132fc3b25 Mon Sep 17 00:00:00 2001 From: Macdonald Date: Fri, 27 Jun 2025 11:37:48 -0400 Subject: [PATCH 03/32] updated the metadata file --- .doc_gen/metadata/neptune_metadata.yaml | 101 ++++++++++++++++++ .../neptune/scenerio/NeptuneScenario.kt | 3 +- 2 files changed, 103 insertions(+), 1 deletion(-) diff --git a/.doc_gen/metadata/neptune_metadata.yaml b/.doc_gen/metadata/neptune_metadata.yaml index 821bd4a020c..c6d7b08f8a2 100644 --- a/.doc_gen/metadata/neptune_metadata.yaml +++ b/.doc_gen/metadata/neptune_metadata.yaml @@ -131,6 +131,17 @@ neptune_ExecuteGremlinQuery: neptune: {ExecuteGremlinQuery} neptune_DeleteDBSubnetGroup: languages: + services: + neptune: {ExecuteGremlinProfileQuery} + Kotlin: + versions: + - sdk_version: 1 + github: kotlin/services/neptune + sdkguide: + excerpts: + - description: + snippet_tags: + - neptune.kotlin.delete.subnet.group.main Python: versions: - sdk_version: 3 @@ -152,6 +163,15 @@ neptune_DeleteDBSubnetGroup: neptune: {DeleteDBSubnetGroup} neptune_DeleteDBCluster: languages: + Kotlin: + versions: + - sdk_version: 1 + github: kotlin/services/neptune + sdkguide: + excerpts: + - description: + snippet_tags: + - neptune.Kotlin.delete.cluster.main Python: versions: - sdk_version: 3 @@ -173,6 +193,15 @@ neptune_DeleteDBCluster: neptune: {DeleteDBCluster} neptune_DeleteDBInstance: languages: + Kotlin: + versions: + - sdk_version: 1 + github: kotlin/services/neptune + sdkguide: + excerpts: + - description: + snippet_tags: + - neptune.kotlin.delete.instance.main Python: versions: - sdk_version: 3 @@ -194,6 +223,15 @@ neptune_DeleteDBInstance: neptune: {DeleteDBInstance} neptune_StartDBCluster: languages: + Kotlin: + versions: + - sdk_version: 1 + github: kotlin/services/neptune + sdkguide: + excerpts: + - description: + snippet_tags: + - neptune.kotlin.start.cluster.main Python: versions: - sdk_version: 3 @@ -215,6 +253,15 @@ neptune_StartDBCluster: neptune: {StartDBCluster} neptune_StopDBCluster: languages: + Kotlin: + versions: + - sdk_version: 1 + github: kotlin/services/neptune + sdkguide: + excerpts: + - description: + snippet_tags: + - neptune.kotlin.stop.cluster.main Python: versions: - sdk_version: 3 @@ -236,6 +283,15 @@ neptune_StopDBCluster: neptune: {StopDBCluster} neptune_DescribeDBClusters: languages: + Kotlin: + versions: + - sdk_version: 1 + github: kotlin/services/neptune + sdkguide: + excerpts: + - description: + snippet_tags: + - neptune.kotlin.describe.cluster.main Python: versions: - sdk_version: 3 @@ -257,6 +313,15 @@ neptune_DescribeDBClusters: neptune: {DescribeDBClusters} neptune_DescribeDBInstances: languages: + Kotlin: + versions: + - sdk_version: 1 + github: kotlin/services/neptune + sdkguide: + excerpts: + - description: + snippet_tags: + - neptune.kotlin.describe.dbinstance.main Python: versions: - sdk_version: 3 @@ -278,6 +343,15 @@ neptune_DescribeDBInstances: neptune: {DescribeDBInstances} neptune_CreateDBInstance: languages: + Kotlin: + versions: + - sdk_version: 1 + github: kotlin/services/neptune + sdkguide: + excerpts: + - description: + snippet_tags: + - neptune.kotlin.create.dbinstance.main Python: versions: - sdk_version: 3 @@ -299,6 +373,15 @@ neptune_CreateDBInstance: neptune: {CreateDBInstance} neptune_CreateDBCluster: languages: + Kotlin: + versions: + - sdk_version: 1 + github: kotlin/services/neptune + sdkguide: + excerpts: + - description: + snippet_tags: + - neptune.kotlin.create.cluster.main Python: versions: - sdk_version: 3 @@ -320,6 +403,15 @@ neptune_CreateDBCluster: neptune: {CreateDBCluster} neptune_CreateDBSubnetGroup: languages: + Kotlin: + versions: + - sdk_version: 1 + github: kotlin/services/neptune + sdkguide: + excerpts: + - description: + snippet_tags: + - neptune.kotlin.create.subnet.main Python: versions: - sdk_version: 3 @@ -351,6 +443,15 @@ neptune_Scenario: - Delete the &neptune; Assets. category: Basics languages: + Kotlin: + versions: + - sdk_version: 1 + github: kotlin/services/neptune + sdkguide: + excerpts: + - description: + snippet_tags: + - neptune.kotlin.scenario.main Python: versions: - sdk_version: 3 diff --git a/kotlin/services/neptune/src/main/java/com/example/neptune/scenerio/NeptuneScenario.kt b/kotlin/services/neptune/src/main/java/com/example/neptune/scenerio/NeptuneScenario.kt index 8528102e77e..d0e2db290c5 100644 --- a/kotlin/services/neptune/src/main/java/com/example/neptune/scenerio/NeptuneScenario.kt +++ b/kotlin/services/neptune/src/main/java/com/example/neptune/scenerio/NeptuneScenario.kt @@ -23,7 +23,7 @@ import kotlinx.coroutines.delay import java.time.Duration import java.util.* - +// snippet-start:[neptune.kotlin.scenario.main] val DASHES = String(CharArray(80)).replace("\u0000", "-") var scanner = Scanner(System.`in`) private val pollInterval: Duration = Duration.ofSeconds(20) @@ -575,4 +575,5 @@ private fun waitForInputToContinue(scanner: Scanner) { println("Invalid input. Please try again.") } } + // snippet-end:[neptune.kotlin.scenario.main] } \ No newline at end of file From 1b6488b6d7aba36453e8037bfab1b891e2b6c15d Mon Sep 17 00:00:00 2001 From: Macdonald Date: Fri, 27 Jun 2025 11:46:16 -0400 Subject: [PATCH 04/32] updated the metadata file --- .doc_gen/metadata/neptune_metadata.yaml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.doc_gen/metadata/neptune_metadata.yaml b/.doc_gen/metadata/neptune_metadata.yaml index c6d7b08f8a2..6d7ea268ec2 100644 --- a/.doc_gen/metadata/neptune_metadata.yaml +++ b/.doc_gen/metadata/neptune_metadata.yaml @@ -171,7 +171,7 @@ neptune_DeleteDBCluster: excerpts: - description: snippet_tags: - - neptune.Kotlin.delete.cluster.main + - neptune.kotlin.delete.cluster.main Python: versions: - sdk_version: 3 From 534fa22c2b7e351f21d055f687de6c3ce445601a Mon Sep 17 00:00:00 2001 From: Macdonald Date: Fri, 27 Jun 2025 11:50:43 -0400 Subject: [PATCH 05/32] updated the metadata file --- .doc_gen/metadata/neptune_metadata.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/.doc_gen/metadata/neptune_metadata.yaml b/.doc_gen/metadata/neptune_metadata.yaml index 6d7ea268ec2..093ae5c75b8 100644 --- a/.doc_gen/metadata/neptune_metadata.yaml +++ b/.doc_gen/metadata/neptune_metadata.yaml @@ -132,7 +132,6 @@ neptune_ExecuteGremlinQuery: neptune_DeleteDBSubnetGroup: languages: services: - neptune: {ExecuteGremlinProfileQuery} Kotlin: versions: - sdk_version: 1 From f012aaeec4f5dbad8b7af69ab466a5e840840ea5 Mon Sep 17 00:00:00 2001 From: Macdonald Date: Fri, 27 Jun 2025 11:55:10 -0400 Subject: [PATCH 06/32] updated the metadata file --- .doc_gen/metadata/neptune_metadata.yaml | 1 - 1 file changed, 1 deletion(-) diff --git a/.doc_gen/metadata/neptune_metadata.yaml b/.doc_gen/metadata/neptune_metadata.yaml index 093ae5c75b8..3f6246a527f 100644 --- a/.doc_gen/metadata/neptune_metadata.yaml +++ b/.doc_gen/metadata/neptune_metadata.yaml @@ -131,7 +131,6 @@ neptune_ExecuteGremlinQuery: neptune: {ExecuteGremlinQuery} neptune_DeleteDBSubnetGroup: languages: - services: Kotlin: versions: - sdk_version: 1 From 67098ddad534c5a676e7caac9260c9e0693c4181 Mon Sep 17 00:00:00 2001 From: Macdonald Date: Wed, 2 Jul 2025 11:18:10 -0400 Subject: [PATCH 07/32] add Hello Kotlin --- .doc_gen/metadata/neptune_metadata.yaml | 9 ++++ .../example/neptune/scenerio/HelloNeptune.kt | 43 +++++++++++++++++++ .../neptune/scenerio/NeptuneScenario.kt | 8 ++++ 3 files changed, 60 insertions(+) create mode 100644 kotlin/services/neptune/src/main/java/com/example/neptune/scenerio/HelloNeptune.kt diff --git a/.doc_gen/metadata/neptune_metadata.yaml b/.doc_gen/metadata/neptune_metadata.yaml index 3f6246a527f..4b2595942be 100644 --- a/.doc_gen/metadata/neptune_metadata.yaml +++ b/.doc_gen/metadata/neptune_metadata.yaml @@ -5,6 +5,15 @@ neptune_Hello: synopsis: get started using &neptune;. category: Hello languages: + Kotlin: + versions: + - sdk_version: 1 + github: kotlin/services/neptune + sdkguide: + excerpts: + - description: + snippet_tags: + - neptune.kotlin.hello.main Python: versions: - sdk_version: 3 diff --git a/kotlin/services/neptune/src/main/java/com/example/neptune/scenerio/HelloNeptune.kt b/kotlin/services/neptune/src/main/java/com/example/neptune/scenerio/HelloNeptune.kt new file mode 100644 index 00000000000..eb5debcfbc4 --- /dev/null +++ b/kotlin/services/neptune/src/main/java/com/example/neptune/scenerio/HelloNeptune.kt @@ -0,0 +1,43 @@ +// Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. +// SPDX-License-Identifier: Apache-2.0 + +package com.example.neptune.scenerio + +import aws.sdk.kotlin.services.neptune.NeptuneClient +import aws.sdk.kotlin.services.neptune.model.DescribeDbClustersRequest + +// snippet-start:[neptune.kotlin.hello.main] +/** + * Before running this Kotlin code example, set up your development environment, including your credentials. + * + * For more information, see the following documentation topic: + * + * https://docs.aws.amazon.com/sdk-for-kotlin/latest/developer-guide/setup.html + */ +suspend fun main(args: Array) { + print("Hello Amazon Neptune") + listDBClusters() +} + +/** + * Suspends the current coroutine to list details of DB clusters in Amazon Neptune. + */ +public suspend fun listDBClusters() { + val request = DescribeDbClustersRequest { + maxRecords = 20 + } + + NeptuneClient { region = "us-east-1" }.use { neptuneClient -> + neptuneClient.describeDbClusters(request) + val response = neptuneClient.describeDbClusters(request) + response.dbClusters?.forEach { cluster -> + println("Cluster Identifier: ${cluster.dbClusterIdentifier}") + println("Status: ${cluster.status}") + println("Endpoint: ${cluster.endpoint}") + println("Engine: ${cluster.engine}") + println("Engine Version: ${cluster.engineVersion}") + println("---") + } + } +} +// snippet-end:[neptune.kotlin.hello.main] \ No newline at end of file diff --git a/kotlin/services/neptune/src/main/java/com/example/neptune/scenerio/NeptuneScenario.kt b/kotlin/services/neptune/src/main/java/com/example/neptune/scenerio/NeptuneScenario.kt index d0e2db290c5..3d3eb087efe 100644 --- a/kotlin/services/neptune/src/main/java/com/example/neptune/scenerio/NeptuneScenario.kt +++ b/kotlin/services/neptune/src/main/java/com/example/neptune/scenerio/NeptuneScenario.kt @@ -28,6 +28,14 @@ val DASHES = String(CharArray(80)).replace("\u0000", "-") var scanner = Scanner(System.`in`) private val pollInterval: Duration = Duration.ofSeconds(20) private val timeout: Duration = Duration.ofMinutes(30) + +/** + * Before running this Kotlin code example, set up your development environment, including your credentials. + * + * For more information, see the following documentation topic: + * + * https://docs.aws.amazon.com/sdk-for-kotlin/latest/developer-guide/setup.html + */ suspend fun main(args: Array) { val subnetGroupName = "neptuneSubnetGroup200" val clusterName = "neptuneCluster200" From 20286a1f9e035e3f468bd2df7f9ec64830ae1486 Mon Sep 17 00:00:00 2001 From: Macdonald Date: Wed, 2 Jul 2025 12:07:08 -0400 Subject: [PATCH 08/32] updated Hello Kotlin --- .../main/java/com/example/neptune/scenerio/HelloNeptune.kt | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/kotlin/services/neptune/src/main/java/com/example/neptune/scenerio/HelloNeptune.kt b/kotlin/services/neptune/src/main/java/com/example/neptune/scenerio/HelloNeptune.kt index eb5debcfbc4..7eb33d0c3c6 100644 --- a/kotlin/services/neptune/src/main/java/com/example/neptune/scenerio/HelloNeptune.kt +++ b/kotlin/services/neptune/src/main/java/com/example/neptune/scenerio/HelloNeptune.kt @@ -20,7 +20,7 @@ suspend fun main(args: Array) { } /** - * Suspends the current coroutine to list details of DB clusters in Amazon Neptune. + * List details of DB clusters in Amazon Neptune. */ public suspend fun listDBClusters() { val request = DescribeDbClustersRequest { @@ -38,6 +38,6 @@ public suspend fun listDBClusters() { println("Engine Version: ${cluster.engineVersion}") println("---") } - } + } } // snippet-end:[neptune.kotlin.hello.main] \ No newline at end of file From 812de5a1342f7096c3ecc8c53e71a24246f6b0c1 Mon Sep 17 00:00:00 2001 From: Macdonald Date: Wed, 2 Jul 2025 12:18:03 -0400 Subject: [PATCH 09/32] updated Neptune Readme --- kotlin/services/neptune/README.md | 123 ++++++++++++++++++++++++++++++ 1 file changed, 123 insertions(+) create mode 100644 kotlin/services/neptune/README.md diff --git a/kotlin/services/neptune/README.md b/kotlin/services/neptune/README.md new file mode 100644 index 00000000000..389a6a6eee7 --- /dev/null +++ b/kotlin/services/neptune/README.md @@ -0,0 +1,123 @@ +# Neptune code examples for the SDK for Kotlin + +## Overview + +Shows how to use the AWS SDK for Kotlin to work with Amazon Neptune. + + + + +_Neptune is a serverless graph database designed for superior scalability and availability._ + +## ⚠ Important + +* Running this code might result in charges to your AWS account. For more details, see [AWS Pricing](https://aws.amazon.com/pricing/) and [Free Tier](https://aws.amazon.com/free/). +* Running the tests might result in charges to your AWS account. +* We recommend that you grant your code least privilege. At most, grant only the minimum permissions required to perform the task. For more information, see [Grant least privilege](https://docs.aws.amazon.com/IAM/latest/UserGuide/best-practices.html#grant-least-privilege). +* This code is not tested in every AWS Region. For more information, see [AWS Regional Services](https://aws.amazon.com/about-aws/global-infrastructure/regional-product-services). + + + + +## Code examples + +### Prerequisites + +For prerequisites, see the [README](../../README.md#Prerequisites) in the `kotlin` folder. + + + + + +### Get started + +- [Hello Neptune](src/main/java/com/example/neptune/scenerio/HelloNeptune.kt#L9) (`DescribeDBClustersPaginator`) + + +### Basics + +Code examples that show you how to perform the essential operations within a service. + +- [Learn the basics](src/main/java/com/example/neptune/scenerio/NeptuneScenario.kt) + + +### Single actions + +Code excerpts that show you how to call individual service functions. + +- [CreateDBCluster](src/main/java/com/example/neptune/scenerio/NeptuneScenario.kt#L482) +- [CreateDBInstance](src/main/java/com/example/neptune/scenerio/NeptuneScenario.kt#L455) +- [CreateDBSubnetGroup](src/main/java/com/example/neptune/scenerio/NeptuneScenario.kt#L508) +- [DeleteDBCluster](src/main/java/com/example/neptune/scenerio/NeptuneScenario.kt#L187) +- [DeleteDBInstance](src/main/java/com/example/neptune/scenerio/NeptuneScenario.kt#L254) +- [DeleteDBSubnetGroup](src/main/java/com/example/neptune/scenerio/NeptuneScenario.kt#L168) +- [DescribeDBClusters](src/main/java/com/example/neptune/scenerio/NeptuneScenario.kt#L367) +- [DescribeDBInstances](src/main/java/com/example/neptune/scenerio/NeptuneScenario.kt#L404) +- [StartDBCluster](src/main/java/com/example/neptune/scenerio/NeptuneScenario.kt#L331) +- [StopDBCluster](src/main/java/com/example/neptune/scenerio/NeptuneScenario.kt#L349) + + + + + +## Run the examples + +### Instructions + + + + + +#### Hello Neptune + +This example shows you how to get started using Neptune. + + +#### Learn the basics + +This example shows you how to do the following: + +- Create an Amazon Neptune Subnet Group. +- Create an Neptune Cluster. +- Create an Neptune Instance. +- Check the status of the Neptune Instance. +- Show Neptune cluster details. +- Stop the Neptune cluster. +- Start the Neptune cluster. +- Delete the Neptune Assets. + + + + + + + + + +### Tests + +⚠ Running tests might result in charges to your AWS account. + + +To find instructions for running these tests, see the [README](../../README.md#Tests) +in the `kotlin` folder. + + + + + + +## Additional resources + +- [Neptune User Guide](https://docs.aws.amazon.com/neptune/latest/userguide/intro.html) +- [Neptune API Reference](https://docs.aws.amazon.com/neptune/latest/apiref/Welcome.html) +- [SDK for Kotlin Neptune reference](https://sdk.amazonaws.com/kotlin/api/latest/dynamodb/index.html) + + + + +--- + +Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. + +SPDX-License-Identifier: Apache-2.0 From 7b01b0d9beec30e60853baa30eed006d2cc31d43 Mon Sep 17 00:00:00 2001 From: Macdonald Date: Wed, 2 Jul 2025 12:37:17 -0400 Subject: [PATCH 10/32] updated Neptune Readme --- kotlin/services/neptune/README.md | 2 +- .../java/com/example/neptune/{scenerio => }/HelloNeptune.kt | 2 +- kotlin/services/neptune/src/test/java/NeptuneTest.kt | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) rename kotlin/services/neptune/src/main/java/com/example/neptune/{scenerio => }/HelloNeptune.kt (97%) diff --git a/kotlin/services/neptune/README.md b/kotlin/services/neptune/README.md index 389a6a6eee7..c24645e7179 100644 --- a/kotlin/services/neptune/README.md +++ b/kotlin/services/neptune/README.md @@ -31,7 +31,7 @@ For prerequisites, see the [README](../../README.md#Prerequisites) in the `kotli ### Get started -- [Hello Neptune](src/main/java/com/example/neptune/scenerio/HelloNeptune.kt#L9) (`DescribeDBClustersPaginator`) +- [Hello Neptune](src/main/java/com/example/neptune/HelloNeptune.kt#L9) (`DescribeDBClustersPaginator`) ### Basics diff --git a/kotlin/services/neptune/src/main/java/com/example/neptune/scenerio/HelloNeptune.kt b/kotlin/services/neptune/src/main/java/com/example/neptune/HelloNeptune.kt similarity index 97% rename from kotlin/services/neptune/src/main/java/com/example/neptune/scenerio/HelloNeptune.kt rename to kotlin/services/neptune/src/main/java/com/example/neptune/HelloNeptune.kt index 7eb33d0c3c6..88ed7b1b075 100644 --- a/kotlin/services/neptune/src/main/java/com/example/neptune/scenerio/HelloNeptune.kt +++ b/kotlin/services/neptune/src/main/java/com/example/neptune/HelloNeptune.kt @@ -1,7 +1,7 @@ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 -package com.example.neptune.scenerio +package com.example.neptune import aws.sdk.kotlin.services.neptune.NeptuneClient import aws.sdk.kotlin.services.neptune.model.DescribeDbClustersRequest diff --git a/kotlin/services/neptune/src/test/java/NeptuneTest.kt b/kotlin/services/neptune/src/test/java/NeptuneTest.kt index 4fd1368c2ac..d91bf9d5aa3 100644 --- a/kotlin/services/neptune/src/test/java/NeptuneTest.kt +++ b/kotlin/services/neptune/src/test/java/NeptuneTest.kt @@ -142,4 +142,4 @@ class NeptuneTest { }.getOrThrow() println("Deleting the resources passed: $dbInstanceId") } -} \ No newline at end of file +} From 873201fe125b37fc7e186099ed233b0cdffc2e48 Mon Sep 17 00:00:00 2001 From: Macdonald Date: Wed, 2 Jul 2025 13:36:37 -0400 Subject: [PATCH 11/32] fixed linter issues --- .../neptune/scenerio/NeptuneScenario.kt | 87 +++++++++---------- 1 file changed, 43 insertions(+), 44 deletions(-) diff --git a/kotlin/services/neptune/src/main/java/com/example/neptune/scenerio/NeptuneScenario.kt b/kotlin/services/neptune/src/main/java/com/example/neptune/scenerio/NeptuneScenario.kt index 3d3eb087efe..321a2024555 100644 --- a/kotlin/services/neptune/src/main/java/com/example/neptune/scenerio/NeptuneScenario.kt +++ b/kotlin/services/neptune/src/main/java/com/example/neptune/scenerio/NeptuneScenario.kt @@ -42,34 +42,33 @@ suspend fun main(args: Array) { val dbInstanceId = "neptuneDB200" println( - """ - Amazon Neptune is a fully managed AWS graph database optimized for complex, connected datasets. - It supports property graphs (Gremlin, openCypher) - and RDF graphs (SPARQL), making it ideal for knowledge - graphs, fraud detection, social networks, - recommendations, and network management. - - Neptune handles provisioning, patching, backups, a - nd replication, offering high availability by default - . - Developers can build relationship-aware apps using the - AWS SDK for Kotlin and automate infrastructure with - NeptuneClient. + """ + Amazon Neptune is a fully managed AWS graph database optimized for complex, connected datasets. + It supports property graphs (Gremlin, openCypher) + and RDF graphs (SPARQL), making it ideal for knowledge + graphs, fraud detection, social networks, + recommendations, and network management. + + Neptune handles provisioning, patching, backups, a + nd replication, offering high availability by default. + + Developers can build relationship-aware apps using the + AWS SDK for Kotlin and automate infrastructure with + NeptuneClient. - Let's get started... + Let's get started... - """ + """.trimIndent(), ) waitForInputToContinue(scanner) runScenario(subnetGroupName, dbInstanceId, clusterName) println( - """ + """ Thank you for checking out the Amazon Neptune Service Use demo. We hope you learned something new, or got some inspiration for your own apps today. For more AWS code examples, have a look at: https://docs.aws.amazon.com/code-library/latest/ug/what-is-code-library.html - - """ + """.trimIndent(), ) } @@ -91,20 +90,20 @@ suspend fun runScenario(subnetGroupName: String, dbInstanceId: String, clusterNa println(DASHES) println(DASHES) - println("3. Create a Neptune DB Instance"); - println("In this step, we add a new database instance to the Neptune cluster"); + println("3. Create a Neptune DB Instance") + println("In this step, we add a new database instance to the Neptune cluster") waitForInputToContinue(scanner) createDbInstance(dbInstanceId, dbClusterId) waitForInputToContinue(scanner) println(DASHES) println(DASHES) - println("4. Check the status of the Neptune DB Instance"); + println("4. Check the status of the Neptune DB Instance") println( - """ - In this step, we will wait until the DB instance - becomes available. This may take around 10 minutes. - """ + """ + In this step, we will wait until the DB instance + becomes available. This may take around 10 minutes. + """.trimIndent(), ) waitForInputToContinue(scanner) checkInstanceStatus(dbInstanceId, "available") @@ -112,20 +111,20 @@ suspend fun runScenario(subnetGroupName: String, dbInstanceId: String, clusterNa println(DASHES) println(DASHES) - println("5. Show Neptune Cluster details"); + println("5. Show Neptune Cluster details") waitForInputToContinue(scanner) describeDBClusters(dbClusterId) waitForInputToContinue(scanner) println(DASHES) println(DASHES) - println("6. Stop the Amazon Neptune cluster"); + println("6. Stop the Amazon Neptune cluster") println( - """ - Once stopped, this step polls the status - until the cluster is in a stopped state. - """ - ); + """ + Once stopped, this step polls the status + until the cluster is in a stopped state. + """.trimIndent(), + ) waitForInputToContinue(scanner) stopDBCluster(dbClusterId) waitForClusterStatus(dbClusterId, "stopped") @@ -133,14 +132,14 @@ suspend fun runScenario(subnetGroupName: String, dbInstanceId: String, clusterNa println(DASHES) println(DASHES) - println("7. Start the Amazon Neptune cluster"); + println("7. Start the Amazon Neptune cluster") println( - """ - Once started, this step polls the clusters - status until it's in an available state. - We will also poll the instance status. - """ - ); + """ + Once started, this step polls the clusters + status until it's in an available state. + We will also poll the instance status. + """.trimIndent(), + ) waitForInputToContinue(scanner) startDBCluster(dbClusterId) waitForClusterStatus(dbClusterId, "available") @@ -148,12 +147,12 @@ suspend fun runScenario(subnetGroupName: String, dbInstanceId: String, clusterNa waitForInputToContinue(scanner) println(DASHES) - println(DASHES); - println("8. Delete the Neptune Assets"); - println("Would you like to delete the Neptune Assets? (y/n)"); - val delAns = scanner.nextLine().trim(); + println(DASHES) + println("8. Delete the Neptune Assets") + println("Would you like to delete the Neptune Assets? (y/n)") + val delAns = scanner.nextLine().trim() if (delAns.equals("y")) { - println("You selected to delete the Neptune assets."); + println("You selected to delete the Neptune assets.") deleteDbInstance(dbInstanceId) waitUntilInstanceDeleted(dbInstanceId) deleteDBCluster(dbClusterId) From 7042aa12c91537cc7f2c82679d2eef8ad040c2b4 Mon Sep 17 00:00:00 2001 From: Macdonald Date: Wed, 2 Jul 2025 13:52:54 -0400 Subject: [PATCH 12/32] fixed linter issues --- .../neptune/scenerio/NeptuneScenario.kt | 66 +++++++++---------- 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/kotlin/services/neptune/src/main/java/com/example/neptune/scenerio/NeptuneScenario.kt b/kotlin/services/neptune/src/main/java/com/example/neptune/scenerio/NeptuneScenario.kt index 321a2024555..55dd4775545 100644 --- a/kotlin/services/neptune/src/main/java/com/example/neptune/scenerio/NeptuneScenario.kt +++ b/kotlin/services/neptune/src/main/java/com/example/neptune/scenerio/NeptuneScenario.kt @@ -42,33 +42,33 @@ suspend fun main(args: Array) { val dbInstanceId = "neptuneDB200" println( - """ - Amazon Neptune is a fully managed AWS graph database optimized for complex, connected datasets. - It supports property graphs (Gremlin, openCypher) - and RDF graphs (SPARQL), making it ideal for knowledge - graphs, fraud detection, social networks, - recommendations, and network management. - - Neptune handles provisioning, patching, backups, a - nd replication, offering high availability by default. + """ + Amazon Neptune is a fully managed AWS graph database optimized for complex, connected datasets. + It supports property graphs (Gremlin, openCypher) + and RDF graphs (SPARQL), making it ideal for knowledge + graphs, fraud detection, social networks, + recommendations, and network management. + + Neptune handles provisioning, patching, backups, a + nd replication, offering high availability by default. - Developers can build relationship-aware apps using the - AWS SDK for Kotlin and automate infrastructure with - NeptuneClient. + Developers can build relationship-aware apps using the + AWS SDK for Kotlin and automate infrastructure with + NeptuneClient. - Let's get started... + Let's get started... - """.trimIndent(), + """.trimIndent(), ) waitForInputToContinue(scanner) runScenario(subnetGroupName, dbInstanceId, clusterName) println( - """ - Thank you for checking out the Amazon Neptune Service Use demo. We hope you - learned something new, or got some inspiration for your own apps today. - For more AWS code examples, have a look at: - https://docs.aws.amazon.com/code-library/latest/ug/what-is-code-library.html - """.trimIndent(), + """ + Thank you for checking out the Amazon Neptune Service Use demo. We hope you + learned something new, or got some inspiration for your own apps today. + For more AWS code examples, have a look at: + https://docs.aws.amazon.com/code-library/latest/ug/what-is-code-library.html + """.trimIndent(), ) } @@ -100,10 +100,10 @@ suspend fun runScenario(subnetGroupName: String, dbInstanceId: String, clusterNa println(DASHES) println("4. Check the status of the Neptune DB Instance") println( - """ - In this step, we will wait until the DB instance - becomes available. This may take around 10 minutes. - """.trimIndent(), + """ + In this step, we will wait until the DB instance + becomes available. This may take around 10 minutes. + """.trimIndent(), ) waitForInputToContinue(scanner) checkInstanceStatus(dbInstanceId, "available") @@ -120,10 +120,10 @@ suspend fun runScenario(subnetGroupName: String, dbInstanceId: String, clusterNa println(DASHES) println("6. Stop the Amazon Neptune cluster") println( - """ - Once stopped, this step polls the status - until the cluster is in a stopped state. - """.trimIndent(), + """ + Once stopped, this step polls the status + until the cluster is in a stopped state. + """.trimIndent(), ) waitForInputToContinue(scanner) stopDBCluster(dbClusterId) @@ -134,11 +134,11 @@ suspend fun runScenario(subnetGroupName: String, dbInstanceId: String, clusterNa println(DASHES) println("7. Start the Amazon Neptune cluster") println( - """ - Once started, this step polls the clusters - status until it's in an available state. - We will also poll the instance status. - """.trimIndent(), + """ + Once started, this step polls the clusters + status until it's in an available state. + We will also poll the instance status. + """.trimIndent(), ) waitForInputToContinue(scanner) startDBCluster(dbClusterId) From 337c66fff5b4f3322fac8be6a14972143184cb16 Mon Sep 17 00:00:00 2001 From: Macdonald Date: Wed, 2 Jul 2025 14:58:04 -0400 Subject: [PATCH 13/32] fixed linter issues --- kotlin/services/neptune/settings.gradle.kts | 1 - .../neptune/src/main/java/com/example/neptune/HelloNeptune.kt | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/kotlin/services/neptune/settings.gradle.kts b/kotlin/services/neptune/settings.gradle.kts index 9103dd94328..b3b89751cd8 100644 --- a/kotlin/services/neptune/settings.gradle.kts +++ b/kotlin/services/neptune/settings.gradle.kts @@ -7,4 +7,3 @@ plugins { id("org.gradle.toolchains.foojay-resolver-convention") version "0.8.0" } rootProject.name = "neptune" - diff --git a/kotlin/services/neptune/src/main/java/com/example/neptune/HelloNeptune.kt b/kotlin/services/neptune/src/main/java/com/example/neptune/HelloNeptune.kt index 88ed7b1b075..cb7eb770b1c 100644 --- a/kotlin/services/neptune/src/main/java/com/example/neptune/HelloNeptune.kt +++ b/kotlin/services/neptune/src/main/java/com/example/neptune/HelloNeptune.kt @@ -40,4 +40,4 @@ public suspend fun listDBClusters() { } } } -// snippet-end:[neptune.kotlin.hello.main] \ No newline at end of file +// snippet-end:[neptune.kotlin.hello.main] From 8691276cb8d515d6251985d9b1e64de7f63c148b Mon Sep 17 00:00:00 2001 From: Macdonald Date: Wed, 2 Jul 2025 19:15:19 -0400 Subject: [PATCH 14/32] updated client pattern --- .../java/com/example/neptune/HelloNeptune.kt | 2 +- .../neptune/scenerio/NeptuneScenario.kt | 377 ++++++++---------- .../neptune/src/test/java/NeptuneTest.kt | 36 +- 3 files changed, 197 insertions(+), 218 deletions(-) diff --git a/kotlin/services/neptune/src/main/java/com/example/neptune/HelloNeptune.kt b/kotlin/services/neptune/src/main/java/com/example/neptune/HelloNeptune.kt index cb7eb770b1c..475fd3acfbe 100644 --- a/kotlin/services/neptune/src/main/java/com/example/neptune/HelloNeptune.kt +++ b/kotlin/services/neptune/src/main/java/com/example/neptune/HelloNeptune.kt @@ -27,7 +27,7 @@ public suspend fun listDBClusters() { maxRecords = 20 } - NeptuneClient { region = "us-east-1" }.use { neptuneClient -> + NeptuneClient.fromEnvironment { region = "us-east-1" }.use { neptuneClient -> neptuneClient.describeDbClusters(request) val response = neptuneClient.describeDbClusters(request) response.dbClusters?.forEach { cluster -> diff --git a/kotlin/services/neptune/src/main/java/com/example/neptune/scenerio/NeptuneScenario.kt b/kotlin/services/neptune/src/main/java/com/example/neptune/scenerio/NeptuneScenario.kt index 55dd4775545..4a903dd0e10 100644 --- a/kotlin/services/neptune/src/main/java/com/example/neptune/scenerio/NeptuneScenario.kt +++ b/kotlin/services/neptune/src/main/java/com/example/neptune/scenerio/NeptuneScenario.kt @@ -26,8 +26,6 @@ import java.util.* // snippet-start:[neptune.kotlin.scenario.main] val DASHES = String(CharArray(80)).replace("\u0000", "-") var scanner = Scanner(System.`in`) -private val pollInterval: Duration = Duration.ofSeconds(20) -private val timeout: Duration = Duration.ofMinutes(30) /** * Before running this Kotlin code example, set up your development environment, including your credentials. @@ -36,10 +34,11 @@ private val timeout: Duration = Duration.ofMinutes(30) * * https://docs.aws.amazon.com/sdk-for-kotlin/latest/developer-guide/setup.html */ -suspend fun main(args: Array) { +suspend fun main() { val subnetGroupName = "neptuneSubnetGroup200" val clusterName = "neptuneCluster200" val dbInstanceId = "neptuneDB200" + val client = NeptuneClient.fromEnvironment {region = "us-east-1" } println( """ @@ -61,7 +60,7 @@ suspend fun main(args: Array) { """.trimIndent(), ) waitForInputToContinue(scanner) - runScenario(subnetGroupName, dbInstanceId, clusterName) + runScenario(client, subnetGroupName, dbInstanceId, clusterName) println( """ Thank you for checking out the Amazon Neptune Service Use demo. We hope you @@ -72,12 +71,12 @@ suspend fun main(args: Array) { ) } -suspend fun runScenario(subnetGroupName: String, dbInstanceId: String, clusterName: String) { +suspend fun runScenario( client : NeptuneClient, subnetGroupName: String, dbInstanceId: String, clusterName: String) { println(DASHES) println("1. Create a Neptune DB Subnet Group") println("The Neptune DB subnet group is used when launching a Neptune cluster") waitForInputToContinue(scanner) - createSubnetGroup(subnetGroupName) + createSubnetGroup(client, subnetGroupName) waitForInputToContinue(scanner) println(DASHES) @@ -85,7 +84,7 @@ suspend fun runScenario(subnetGroupName: String, dbInstanceId: String, clusterNa println("2. Create a Neptune Cluster") println("A Neptune Cluster allows you to store and query highly connected datasets with low latency.") waitForInputToContinue(scanner) - val dbClusterId = createDbCluster(clusterName) + val dbClusterId = createDbCluster(client, clusterName) waitForInputToContinue(scanner) println(DASHES) @@ -93,7 +92,7 @@ suspend fun runScenario(subnetGroupName: String, dbInstanceId: String, clusterNa println("3. Create a Neptune DB Instance") println("In this step, we add a new database instance to the Neptune cluster") waitForInputToContinue(scanner) - createDbInstance(dbInstanceId, dbClusterId) + createDbInstance(client, dbInstanceId, dbClusterId) waitForInputToContinue(scanner) println(DASHES) @@ -106,14 +105,14 @@ suspend fun runScenario(subnetGroupName: String, dbInstanceId: String, clusterNa """.trimIndent(), ) waitForInputToContinue(scanner) - checkInstanceStatus(dbInstanceId, "available") + checkInstanceStatus(client, dbInstanceId, "available") waitForInputToContinue(scanner) println(DASHES) println(DASHES) println("5. Show Neptune Cluster details") waitForInputToContinue(scanner) - describeDBClusters(dbClusterId) + describeDBClusters(client, dbClusterId) waitForInputToContinue(scanner) println(DASHES) @@ -126,8 +125,8 @@ suspend fun runScenario(subnetGroupName: String, dbInstanceId: String, clusterNa """.trimIndent(), ) waitForInputToContinue(scanner) - stopDBCluster(dbClusterId) - waitForClusterStatus(dbClusterId, "stopped") + stopDBCluster(client, dbClusterId) + waitForClusterStatus(client, dbClusterId, "stopped") waitForInputToContinue(scanner) println(DASHES) @@ -141,9 +140,9 @@ suspend fun runScenario(subnetGroupName: String, dbInstanceId: String, clusterNa """.trimIndent(), ) waitForInputToContinue(scanner) - startDBCluster(dbClusterId) - waitForClusterStatus(dbClusterId, "available") - checkInstanceStatus(dbInstanceId, "available") + startDBCluster(client, dbClusterId) + waitForClusterStatus(client, dbClusterId, "available") + checkInstanceStatus(client, dbInstanceId, "available") waitForInputToContinue(scanner) println(DASHES) @@ -153,10 +152,10 @@ suspend fun runScenario(subnetGroupName: String, dbInstanceId: String, clusterNa val delAns = scanner.nextLine().trim() if (delAns.equals("y")) { println("You selected to delete the Neptune assets.") - deleteDbInstance(dbInstanceId) - waitUntilInstanceDeleted(dbInstanceId) - deleteDBCluster(dbClusterId) - deleteDBSubnetGroup(subnetGroupName) + deleteDbInstance(client, dbInstanceId) + waitUntilInstanceDeleted(client, dbInstanceId) + deleteDBCluster(client, dbClusterId) + deleteDBSubnetGroup(client, subnetGroupName) println("Neptune resources deleted successfully.") } else { @@ -171,15 +170,13 @@ suspend fun runScenario(subnetGroupName: String, dbInstanceId: String, clusterNa * @param subnetGroupName the identifier of the subnet group to delete * @return a {@link CompletableFuture} that completes when the cluster has been deleted */ -suspend fun deleteDBSubnetGroup(subnetGroupName:String) { +suspend fun deleteDBSubnetGroup(neptuneClient : NeptuneClient, subnetGroupName:String) { val request = DeleteDbSubnetGroupRequest { dbSubnetGroupName = subnetGroupName } - NeptuneClient { region = "us-east-1" }.use { neptuneClient -> - neptuneClient.deleteDbSubnetGroup(request) - println(" Deleting Subnet Group: $subnetGroupName") - } + neptuneClient.deleteDbSubnetGroup(request) + println(" Deleting Subnet Group: $subnetGroupName") } // snippet-end:[neptune.kotlin.delete.subnet.group.main] @@ -189,64 +186,61 @@ suspend fun deleteDBSubnetGroup(subnetGroupName:String) { * * @param clusterId the identifier of the cluster to delete */ -suspend fun deleteDBCluster(clusterId: String) { +suspend fun deleteDBCluster(neptuneClient : NeptuneClient, clusterId: String) { val request = DeleteDbClusterRequest { dbClusterIdentifier = clusterId skipFinalSnapshot = true } - NeptuneClient { region = "us-east-1" }.use { neptuneClient -> - neptuneClient.deleteDbCluster(request) - println("️ Deleting DB Cluster: $clusterId") - } -} + + neptuneClient.deleteDbCluster(request) + println("️ Deleting DB Cluster: $clusterId") + } // snippet-end:[neptune.kotlin.delete.cluster.main] suspend fun waitUntilInstanceDeleted( + neptuneClient: NeptuneClient, instanceId: String, timeout: Duration = Duration.ofMinutes(20), pollInterval: Duration = Duration.ofSeconds(10) ): Boolean { - println(" Waiting for instance '$instanceId' to be deleted...") + println("Waiting for instance '$instanceId' to be deleted...") - NeptuneClient { region = "us-east-1" }.use { neptuneClient -> - val startTime = System.currentTimeMillis() + val startTime = System.currentTimeMillis() - while (true) { - try { - val request = DescribeDbInstancesRequest { - dbInstanceIdentifier = instanceId - } - - val response = neptuneClient.describeDbInstances(request) - val status = response.dbInstances?.firstOrNull()?.dbInstanceStatus ?: "Unknown" - val elapsed = (System.currentTimeMillis() - startTime) / 1000 - - print("\r Waiting: Instance $instanceId status: ${status.padEnd(10)} (${elapsed}s elapsed)") - System.out.flush() - - } catch (e: NeptuneException) { - val errorCode = e.sdkErrorMetadata.errorCode - return if (errorCode == "DBInstanceNotFound") { - val elapsed = (System.currentTimeMillis() - startTime) / 1000 - println("\n Instance '$instanceId' deleted after ${elapsed}s.") - true - } else { - println("\n Error polling DB instance '$instanceId': ${errorCode ?: "Unknown"} — ${e.message}") - false - } - } catch (e: Exception) { - println("\n Unexpected error while polling DB instance '$instanceId': ${e.message}") - return false + while (true) { + try { + val request = DescribeDbInstancesRequest { + dbInstanceIdentifier = instanceId } - val elapsedMs = System.currentTimeMillis() - startTime - if (elapsedMs > timeout.toMillis()) { - println("\n Timeout: Instance '$instanceId' was not deleted after ${timeout.toMinutes()} minutes.") - return false + val response = neptuneClient.describeDbInstances(request) + val status = response.dbInstances?.firstOrNull()?.dbInstanceStatus ?: "Unknown" + val elapsed = (System.currentTimeMillis() - startTime) / 1000 + print("\r Waiting: Instance $instanceId status: ${status.padEnd(10)} (${elapsed}s elapsed)") + System.out.flush() + + } catch (e: NeptuneException) { + val errorCode = e.sdkErrorMetadata.errorCode + return if (errorCode == "DBInstanceNotFound") { + val elapsed = (System.currentTimeMillis() - startTime) / 1000 + println("\nInstance '$instanceId' deleted after ${elapsed}s.") + true + } else { + println("\nError polling DB instance '$instanceId': ${errorCode ?: "Unknown"} — ${e.message}") + false } + } catch (e: Exception) { + println("\nUnexpected error while polling DB instance '$instanceId': ${e.message}") + return false + } - delay(pollInterval.toMillis()) + val elapsedMs = System.currentTimeMillis() - startTime + if (elapsedMs > timeout.toMillis()) { + println("\nTimeout: Instance '$instanceId' was not deleted after ${timeout.toMinutes()} minutes.") + return false } + + delay(pollInterval.toMillis()) } } @@ -257,15 +251,14 @@ suspend fun waitUntilInstanceDeleted( * @param instanceId the identifier of the DB instance to be deleted * @return a {@link CompletableFuture} that completes when the DB instance has been deleted */ -suspend fun deleteDbInstance(instanceId: String) { +suspend fun deleteDbInstance(neptuneClient: NeptuneClient, instanceId: String) { val request = DeleteDbInstanceRequest { dbInstanceIdentifier = instanceId skipFinalSnapshot = true } - NeptuneClient { region = "us-east-1" }.use { neptuneClient -> - neptuneClient.deleteDbInstance(request) - println("Deleting DB Instance: $instanceId") - } + + neptuneClient.deleteDbInstance(request) + println("Deleting DB Instance: $instanceId") } // snippet-end:[neptune.kotlin.delete.instance.main] @@ -279,51 +272,42 @@ suspend fun deleteDbInstance(instanceId: String) { * */ suspend fun waitForClusterStatus( + neptuneClient: NeptuneClient, clusterId: String, desiredStatus: String, timeout: Duration = Duration.ofMinutes(20), pollInterval: Duration = Duration.ofSeconds(10) ) { println("Waiting for cluster '$clusterId' to reach status '$desiredStatus'...") + val startTime = System.currentTimeMillis() - NeptuneClient { region = "us-east-1" }.use { neptuneClient -> - val startTime = System.currentTimeMillis() - - while (true) { - val request = DescribeDbClustersRequest { - dbClusterIdentifier = clusterId - } - - val response = neptuneClient.describeDbClusters(request) - val currentStatus = response.dbClusters?.firstOrNull()?.status - val elapsedSeconds = (System.currentTimeMillis() - startTime) / 1000 + while (true) { + val request = DescribeDbClustersRequest { + dbClusterIdentifier = clusterId + } + val response = neptuneClient.describeDbClusters(request) + val currentStatus = response.dbClusters?.firstOrNull()?.status ?: "Unknown" + val elapsedSeconds = (System.currentTimeMillis() - startTime) / 1000 + + print( + "\rElapsed: ${formatElapsedTime(elapsedSeconds.toInt()).padEnd(20)} " + + "Cluster status: ${currentStatus.padEnd(20)}" + ) + System.out.flush() + if (desiredStatus.equals(currentStatus, ignoreCase = true)) { println( - "\r Elapsed: ${formatElapsedTime(elapsedSeconds.toInt()).padEnd(20)} Cluster status: ${ - currentStatus?.padEnd( - 20 - ) ?: "Unknown" - }" + "\nNeptune cluster reached desired status '$desiredStatus' after " + + "${formatElapsedTime(elapsedSeconds.toInt())}." ) - System.out.flush() - - if (desiredStatus.equals(currentStatus, ignoreCase = true)) { - println( - "\nNeptune cluster reached desired status '$desiredStatus' after ${ - formatElapsedTime( - elapsedSeconds.toInt() - ) - }." - ) - return - } - - if (Duration.ofMillis(System.currentTimeMillis() - startTime) > timeout) { - throw RuntimeException("Timeout waiting for Neptune cluster to reach status: $desiredStatus") - } + return + } - delay(pollInterval.toMillis()) + if ((System.currentTimeMillis() - startTime) > timeout.toMillis()) { + throw RuntimeException("Timeout waiting for Neptune cluster to reach status: $desiredStatus") } + + delay(pollInterval.toMillis()) } } @@ -333,15 +317,13 @@ suspend fun waitForClusterStatus( * * @param clusterIdentifier the unique identifier of the DB cluster to be stopped */ -suspend fun startDBCluster(clusterIdentifier: String) { +suspend fun startDBCluster(neptuneClient: NeptuneClient, clusterIdentifier: String) { val request = StartDbClusterRequest { dbClusterIdentifier = clusterIdentifier } - NeptuneClient { region = "us-east-1" }.use { neptuneClient -> - neptuneClient.startDbCluster(request) - println("DB Cluster started : $clusterIdentifier") - } + neptuneClient.startDbCluster(request) + println("DB Cluster started : $clusterIdentifier") } // snippet-end:[neptune.kotlin.start.cluster.main] @@ -351,15 +333,13 @@ suspend fun startDBCluster(clusterIdentifier: String) { * * @param clusterIdentifier the unique identifier of the DB cluster to be stopped */ -suspend fun stopDBCluster(clusterIdentifier: String) { +suspend fun stopDBCluster(neptuneClient: NeptuneClient, clusterIdentifier: String) { val request = StopDbClusterRequest { dbClusterIdentifier = clusterIdentifier } - NeptuneClient { region = "us-east-1" }.use { neptuneClient -> - neptuneClient.stopDbCluster(request) - println("DB Cluster stopped: $clusterIdentifier") - } + neptuneClient.stopDbCluster(request) + println("DB Cluster stopped: $clusterIdentifier") } // snippet-end:[neptune.kotlin.stop.cluster.main] @@ -369,33 +349,31 @@ suspend fun stopDBCluster(clusterIdentifier: String) { * * @param clusterId the identifier of the cluster to describe */ -suspend fun describeDBClusters(clusterId: String) { +suspend fun describeDBClusters(neptuneClient: NeptuneClient, clusterId: String) { val request = DescribeDbClustersRequest { dbClusterIdentifier = clusterId } - NeptuneClient { region = "us-east-1" }.use { neptuneClient -> - val response = neptuneClient.describeDbClusters(request) - response.dbClusters?.forEach { cluster -> - println("Cluster Identifier: ${cluster.dbClusterIdentifier}") - println("Status: ${cluster.status}") - println("Engine: ${cluster.engine}") - println("Engine Version: ${cluster.engineVersion}") - println("Endpoint: ${cluster.endpoint}") - println("Reader Endpoint: ${cluster.readerEndpoint}") - println("Availability Zones: ${cluster.availabilityZones}") - println("Subnet Group: ${cluster.dbSubnetGroup}") - println("VPC Security Groups:") - cluster.vpcSecurityGroups?.forEach { vpcGroup -> - println(" - ${vpcGroup.vpcSecurityGroupId}") - } - println("Storage Encrypted: ${cluster.storageEncrypted}") - println("IAM DB Auth Enabled: ${cluster.iamDatabaseAuthenticationEnabled}") - println("Backup Retention Period: ${cluster.backupRetentionPeriod} days") - println("Preferred Backup Window: ${cluster.preferredBackupWindow}") - println("Preferred Maintenance Window: ${cluster.preferredMaintenanceWindow}") - println("------") - } + val response = neptuneClient.describeDbClusters(request) + response.dbClusters?.forEach { cluster -> + println("Cluster Identifier: ${cluster.dbClusterIdentifier}") + println("Status: ${cluster.status}") + println("Engine: ${cluster.engine}") + println("Engine Version: ${cluster.engineVersion}") + println("Endpoint: ${cluster.endpoint}") + println("Reader Endpoint: ${cluster.readerEndpoint}") + println("Availability Zones: ${cluster.availabilityZones}") + println("Subnet Group: ${cluster.dbSubnetGroup}") + println("VPC Security Groups:") + cluster.vpcSecurityGroups?.forEach { vpcGroup -> + println(" - ${vpcGroup.vpcSecurityGroupId}") + } + println("Storage Encrypted: ${cluster.storageEncrypted}") + println("IAM DB Auth Enabled: ${cluster.iamDatabaseAuthenticationEnabled}") + println("Backup Retention Period: ${cluster.backupRetentionPeriod} days") + println("Preferred Backup Window: ${cluster.preferredBackupWindow}") + println("Preferred Maintenance Window: ${cluster.preferredMaintenanceWindow}") + println("------") } } // snippet-end:[neptune.kotlin.describe.cluster.main] @@ -407,39 +385,41 @@ suspend fun describeDBClusters(clusterId: String) { * @param instanceId the ID of the Neptune instance to check * @param desiredStatus the desired status of the Neptune instance */ -suspend fun checkInstanceStatus(instanceId: String, desiredStatus: String) { - NeptuneClient { region = "us-east-1" }.use { neptuneClient -> - val startTime = System.currentTimeMillis() - while (true) { - val request = DescribeDbInstancesRequest { - dbInstanceIdentifier = instanceId - } +suspend fun checkInstanceStatus( + neptuneClient: NeptuneClient, + instanceId: String, + desiredStatus: String, + timeout: Duration = Duration.ofMinutes(20), + pollInterval: Duration = Duration.ofSeconds(10) +) { + val startTime = System.currentTimeMillis() + println("Checking status for instance '$instanceId'...") - val response = neptuneClient.describeDbInstances(request) - val instances = response.dbInstances - val currentStatus = instances?.get(0)?.dbInstanceStatus - val elapsedSeconds = (System.currentTimeMillis() - startTime) / 1000 + while (true) { + val request = DescribeDbInstancesRequest { + dbInstanceIdentifier = instanceId + } - print("\r Elapsed: ${formatElapsedTime(elapsedSeconds.toInt())} Status: $currentStatus") - System.out.flush() + val response = neptuneClient.describeDbInstances(request) + val currentStatus = response.dbInstances?.firstOrNull()?.dbInstanceStatus ?: "Unknown" + val elapsedSeconds = (System.currentTimeMillis() - startTime) / 1000 - if (desiredStatus.equals(currentStatus, ignoreCase = true)) { - println( - "\nNeptune instance reached desired status '$desiredStatus' after ${ - formatElapsedTime( - elapsedSeconds.toInt() - ) - }." - ) - break - } + print("\rElapsed: ${formatElapsedTime(elapsedSeconds.toInt()).padEnd(20)} Status: ${currentStatus.padEnd(20)}") + System.out.flush() - if (Duration.ofMillis(System.currentTimeMillis() - startTime) > timeout) { - throw RuntimeException("Timeout waiting for Neptune instance to reach status: $desiredStatus") - } + if (desiredStatus.equals(currentStatus, ignoreCase = true)) { + println( + "\nInstance reached desired status '$desiredStatus' after " + + formatElapsedTime(elapsedSeconds.toInt()) + "." + ) + break + } - delay(pollInterval.toMillis()) + if ((System.currentTimeMillis() - startTime) > timeout.toMillis()) { + throw RuntimeException("Timeout waiting for Neptune instance to reach status: $desiredStatus") } + + delay(pollInterval.toMillis()) } } // snippet-end:[neptune.kotlin.describe.dbinstance.main] @@ -459,22 +439,20 @@ private fun formatElapsedTime(totalSeconds: Int): String { * @param dbClusterId the identifier for the DB cluster that the new instance will be a part of * @return the identifier of the newly created DB instance */ -suspend fun createDbInstance(dbInstanceId: String, dbClusterId: String): String { - NeptuneClient { region = "us-east-1" }.use { neptuneClient -> - val request = CreateDbInstanceRequest { - dbInstanceIdentifier = dbInstanceId - dbInstanceClass = "db.r5.large" - engine = "neptune" - dbClusterIdentifier = dbClusterId - } +suspend fun createDbInstance(neptuneClient: NeptuneClient, dbInstanceId: String, dbClusterId: String): String { + val request = CreateDbInstanceRequest { + dbInstanceIdentifier = dbInstanceId + dbInstanceClass = "db.r5.large" + engine = "neptune" + dbClusterIdentifier = dbClusterId + } - val response = neptuneClient.createDbInstance(request) - val instanceId = response.dbInstance?.dbInstanceIdentifier - ?: throw RuntimeException("Instance creation succeeded but no ID returned.") + val response = neptuneClient.createDbInstance(request) + val instanceId = response.dbInstance?.dbInstanceIdentifier + ?: throw RuntimeException("Instance creation succeeded but no ID returned.") - println("Created Neptune DB Instance: $instanceId") - return instanceId - } + println("Created Neptune DB Instance: $instanceId") + return instanceId } // snippet-end:[neptune.kotlin.create.dbinstance.main] @@ -485,22 +463,20 @@ suspend fun createDbInstance(dbInstanceId: String, dbClusterId: String): String * @param dbName the name of the DB cluster to be created * @return the ID of the created DB cluster */ -suspend fun createDbCluster(dbName: String): String { - NeptuneClient { region = "us-east-1" }.use { neptuneClient -> - val request = CreateDbClusterRequest { - dbClusterIdentifier = dbName - engine = "neptune" - deletionProtection = false - backupRetentionPeriod = 1 - } +suspend fun createDbCluster(neptuneClient: NeptuneClient, dbName: String): String { + val request = CreateDbClusterRequest { + dbClusterIdentifier = dbName + engine = "neptune" + deletionProtection = false + backupRetentionPeriod = 1 + } - val response = neptuneClient.createDbCluster(request) - val clusterId = response.dbCluster?.dbClusterIdentifier - ?: throw RuntimeException("Cluster creation succeeded but no ID returned.") + val response = neptuneClient.createDbCluster(request) + val clusterId = response.dbCluster?.dbClusterIdentifier + ?: throw RuntimeException("Cluster creation succeeded but no ID returned.") - println("DB Cluster created: $clusterId") - return clusterId - } + println("DB Cluster created: $clusterId") + return clusterId } // snippet-end:[neptune.kotlin.create.cluster.main] @@ -511,8 +487,7 @@ suspend fun createDbCluster(dbName: String): String { * @param groupName the name of the DB subnet group to create * @return the Amazon Resource Name (ARN) of the created DB subnet group */ -suspend fun createSubnetGroup(groupName: String) { - // Get the Amazon Virtual Private Cloud (VPC) where the Neptune cluster and resources will be created +suspend fun createSubnetGroup(neptuneClient: NeptuneClient, groupName: String) { val vpcId = getDefaultVpcId() val subnetList = getSubnetIds(vpcId) @@ -522,17 +497,14 @@ suspend fun createSubnetGroup(groupName: String) { subnetIds = subnetList } - NeptuneClient { region = "us-east-1" }.use { neptuneClient -> - val response = neptuneClient.createDbSubnetGroup(request) - val name = response.dbSubnetGroup?.dbSubnetGroupName - val arn = response.dbSubnetGroup?.dbSubnetGroupArn - println("Subnet group created: $name") - } + val response = neptuneClient.createDbSubnetGroup(request) + val name = response.dbSubnetGroup?.dbSubnetGroupName + println("Subnet group created: $name") } // snippet-end:[neptune.kotlin.create.subnet.main] suspend fun getDefaultVpcId(): String { - Ec2Client { region = "us-east-1" }.use { ec2Client -> + Ec2Client.fromEnvironment { region = "us-east-1" }.use { ec2Client -> val request = DescribeVpcsRequest { filters = listOf( Filter { @@ -552,7 +524,7 @@ suspend fun getDefaultVpcId(): String { } suspend fun getSubnetIds(vpcId: String): List { - Ec2Client { region = "us-east-1" }.use { ec2Client -> + Ec2Client.fromEnvironment { region = "us-east-1" }.use { ec2Client -> val request = DescribeSubnetsRequest { filters = listOf( Filter { @@ -567,7 +539,6 @@ suspend fun getSubnetIds(vpcId: String): List { } } - private fun waitForInputToContinue(scanner: Scanner) { while (true) { println("") @@ -582,5 +553,5 @@ private fun waitForInputToContinue(scanner: Scanner) { println("Invalid input. Please try again.") } } - // snippet-end:[neptune.kotlin.scenario.main] -} \ No newline at end of file +} +// snippet-end:[neptune.kotlin.scenario.main] \ No newline at end of file diff --git a/kotlin/services/neptune/src/test/java/NeptuneTest.kt b/kotlin/services/neptune/src/test/java/NeptuneTest.kt index d91bf9d5aa3..5cc0626ab68 100644 --- a/kotlin/services/neptune/src/test/java/NeptuneTest.kt +++ b/kotlin/services/neptune/src/test/java/NeptuneTest.kt @@ -1,6 +1,7 @@ // Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved. // SPDX-License-Identifier: Apache-2.0 +import aws.sdk.kotlin.services.neptune.NeptuneClient import com.example.neptune.scenerio.checkInstanceStatus import com.example.neptune.scenerio.createDbCluster import com.example.neptune.scenerio.createDbInstance @@ -15,6 +16,7 @@ import com.example.neptune.scenerio.waitForClusterStatus import com.example.neptune.scenerio.waitUntilInstanceDeleted import kotlinx.coroutines.runBlocking 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.Tag @@ -29,13 +31,19 @@ class NeptuneTest { private val clusterName = "neptuneCluster65" private val dbInstanceId = "neptuneDB65" private var dbClusterId = "" + private lateinit var client: NeptuneClient + + @BeforeAll + fun setup() = runBlocking { + client = NeptuneClient.fromEnvironment {region = "us-east-1" } + } @Test @Tag("IntegrationTest") @Order(1) fun testSubnetGroup() = runBlocking { runCatching { - createSubnetGroup(subnetGroupName) + createSubnetGroup(client, subnetGroupName) }.onFailure { it.printStackTrace() Assertions.fail("Subnet group creation failed: ${it.message}") @@ -49,7 +57,7 @@ class NeptuneTest { @Order(2) fun testCreateDbCluster() = runBlocking { dbClusterId = runCatching { - createDbCluster(clusterName) + createDbCluster(client, clusterName) }.onFailure { it.printStackTrace() Assertions.fail("DB cluster creation failed: ${it.message}") @@ -64,7 +72,7 @@ class NeptuneTest { @Order(3) fun testCreateDbInstance() = runBlocking { runCatching { - createDbInstance(dbInstanceId, dbClusterId) + createDbInstance(client, dbInstanceId, dbClusterId) }.onFailure { it.printStackTrace() Assertions.fail("DB Instance creation failed: ${it.message}") @@ -77,7 +85,7 @@ class NeptuneTest { @Order(4) fun testCheckInstanceStatus() = runBlocking { runCatching { - checkInstanceStatus(dbInstanceId, "available") + checkInstanceStatus(client, dbInstanceId, "available") }.onFailure { it.printStackTrace() Assertions.fail("Instance status check failed: ${it.message}") @@ -90,7 +98,7 @@ class NeptuneTest { @Order(5) fun testDescribeDBClusters() = runBlocking { runCatching { - describeDBClusters(dbClusterId) + describeDBClusters(client, dbClusterId) }.onFailure { it.printStackTrace() Assertions.fail("Describe Cluster failed: ${it.message}") @@ -103,8 +111,8 @@ class NeptuneTest { @Order(6) fun testStopClusters() = runBlocking { runCatching { - stopDBCluster(dbClusterId) - waitForClusterStatus(dbClusterId, "stopped") + stopDBCluster(client, dbClusterId) + waitForClusterStatus(client, dbClusterId, "stopped") }.onFailure { it.printStackTrace() Assertions.fail("Stopping the Cluster failed: ${it.message}") @@ -117,9 +125,9 @@ class NeptuneTest { @Order(7) fun testStartClusters() = runBlocking { runCatching { - startDBCluster(dbClusterId) - waitForClusterStatus(dbClusterId, "available") - checkInstanceStatus(dbInstanceId, "available") + startDBCluster(client, dbClusterId) + waitForClusterStatus(client, dbClusterId, "available") + checkInstanceStatus(client, dbInstanceId, "available") }.onFailure { it.printStackTrace() Assertions.fail("Starting the Cluster failed: ${it.message}") @@ -132,10 +140,10 @@ class NeptuneTest { @Order(8) fun testDeleteResources() = runBlocking { runCatching { - deleteDbInstance(dbInstanceId) - waitUntilInstanceDeleted(dbInstanceId) - deleteDBCluster(dbClusterId) - deleteDBSubnetGroup(subnetGroupName) + deleteDbInstance(client, dbInstanceId) + waitUntilInstanceDeleted(client, dbInstanceId) + deleteDBCluster(client, dbClusterId) + deleteDBSubnetGroup(client, subnetGroupName) }.onFailure { it.printStackTrace() Assertions.fail("Deleting the resources failed: ${it.message}") From ef609a1df1b1f1d289f564f3156439620807091c Mon Sep 17 00:00:00 2001 From: Macdonald Date: Thu, 3 Jul 2025 10:53:59 -0400 Subject: [PATCH 15/32] updated client pattern --- .../java/com/example/neptune/scenerio/NeptuneScenario.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/kotlin/services/neptune/src/main/java/com/example/neptune/scenerio/NeptuneScenario.kt b/kotlin/services/neptune/src/main/java/com/example/neptune/scenerio/NeptuneScenario.kt index 4a903dd0e10..3e0853aa587 100644 --- a/kotlin/services/neptune/src/main/java/com/example/neptune/scenerio/NeptuneScenario.kt +++ b/kotlin/services/neptune/src/main/java/com/example/neptune/scenerio/NeptuneScenario.kt @@ -35,9 +35,9 @@ var scanner = Scanner(System.`in`) * https://docs.aws.amazon.com/sdk-for-kotlin/latest/developer-guide/setup.html */ suspend fun main() { - val subnetGroupName = "neptuneSubnetGroup200" - val clusterName = "neptuneCluster200" - val dbInstanceId = "neptuneDB200" + val subnetGroupName = "neptuneSubnetGroup210" + val clusterName = "neptuneCluster210" + val dbInstanceId = "neptuneDB210" val client = NeptuneClient.fromEnvironment {region = "us-east-1" } println( From 40e40ecd219e20dbccd7088dfb468ec085b8cbe0 Mon Sep 17 00:00:00 2001 From: Macdonald Date: Thu, 3 Jul 2025 15:01:46 -0400 Subject: [PATCH 16/32] rolled in review comments --- .../neptune/scenerio/NeptuneScenario.kt | 492 +++++++++++------- 1 file changed, 312 insertions(+), 180 deletions(-) diff --git a/kotlin/services/neptune/src/main/java/com/example/neptune/scenerio/NeptuneScenario.kt b/kotlin/services/neptune/src/main/java/com/example/neptune/scenerio/NeptuneScenario.kt index 3e0853aa587..c3a23c2e6bf 100644 --- a/kotlin/services/neptune/src/main/java/com/example/neptune/scenerio/NeptuneScenario.kt +++ b/kotlin/services/neptune/src/main/java/com/example/neptune/scenerio/NeptuneScenario.kt @@ -19,9 +19,13 @@ import aws.sdk.kotlin.services.neptune.model.DescribeDbInstancesRequest import aws.sdk.kotlin.services.neptune.model.NeptuneException import aws.sdk.kotlin.services.neptune.model.StartDbClusterRequest import aws.sdk.kotlin.services.neptune.model.StopDbClusterRequest +import aws.sdk.kotlin.services.neptune.model.DbSubnetGroupQuotaExceededFault +import aws.sdk.kotlin.services.neptune.model.DbClusterNotFoundFault +import aws.sdk.kotlin.services.neptune.model.DbInstanceNotFoundFault +import aws.sdk.kotlin.services.neptune.model.DbSubnetGroupNotFoundFault import kotlinx.coroutines.delay import java.time.Duration -import java.util.* +import java.util.Scanner // snippet-start:[neptune.kotlin.scenario.main] val DASHES = String(CharArray(80)).replace("\u0000", "-") @@ -71,95 +75,105 @@ suspend fun main() { ) } -suspend fun runScenario( client : NeptuneClient, subnetGroupName: String, dbInstanceId: String, clusterName: String) { - println(DASHES) - println("1. Create a Neptune DB Subnet Group") - println("The Neptune DB subnet group is used when launching a Neptune cluster") - waitForInputToContinue(scanner) - createSubnetGroup(client, subnetGroupName) - waitForInputToContinue(scanner) - println(DASHES) - - println(DASHES) - println("2. Create a Neptune Cluster") - println("A Neptune Cluster allows you to store and query highly connected datasets with low latency.") - waitForInputToContinue(scanner) - val dbClusterId = createDbCluster(client, clusterName) - waitForInputToContinue(scanner) - println(DASHES) - - println(DASHES) - println("3. Create a Neptune DB Instance") - println("In this step, we add a new database instance to the Neptune cluster") - waitForInputToContinue(scanner) - createDbInstance(client, dbInstanceId, dbClusterId) - waitForInputToContinue(scanner) - println(DASHES) - - println(DASHES) - println("4. Check the status of the Neptune DB Instance") - println( - """ - In this step, we will wait until the DB instance - becomes available. This may take around 10 minutes. - """.trimIndent(), - ) - waitForInputToContinue(scanner) - checkInstanceStatus(client, dbInstanceId, "available") - waitForInputToContinue(scanner) - println(DASHES) - - println(DASHES) - println("5. Show Neptune Cluster details") - waitForInputToContinue(scanner) - describeDBClusters(client, dbClusterId) - waitForInputToContinue(scanner) - println(DASHES) - - println(DASHES) - println("6. Stop the Amazon Neptune cluster") - println( - """ - Once stopped, this step polls the status - until the cluster is in a stopped state. - """.trimIndent(), - ) - waitForInputToContinue(scanner) - stopDBCluster(client, dbClusterId) - waitForClusterStatus(client, dbClusterId, "stopped") - waitForInputToContinue(scanner) - println(DASHES) +suspend fun runScenario( + client: NeptuneClient, + subnetGroupName: String, + dbInstanceId: String, + clusterName: String +) { + try { + println(DASHES) + println("1. Create a Neptune DB Subnet Group") + println("The Neptune DB subnet group is used when launching a Neptune cluster") + waitForInputToContinue(scanner) + createSubnetGroup(client, subnetGroupName) + waitForInputToContinue(scanner) + println(DASHES) + + println(DASHES) + println("2. Create a Neptune Cluster") + println("A Neptune Cluster allows you to store and query highly connected datasets with low latency.") + waitForInputToContinue(scanner) + val dbClusterId = createDbCluster(client, clusterName) + waitForInputToContinue(scanner) + println(DASHES) + + println(DASHES) + println("3. Create a Neptune DB Instance") + println("In this step, we add a new database instance to the Neptune cluster") + waitForInputToContinue(scanner) + createDbInstance(client, dbInstanceId, dbClusterId) + waitForInputToContinue(scanner) + println(DASHES) + + println(DASHES) + println("4. Check the status of the Neptune DB Instance") + println( + """ + In this step, we will wait until the DB instance + becomes available. This may take around 10 minutes. + """.trimIndent() + ) + waitForInputToContinue(scanner) + checkInstanceStatus(client, dbInstanceId, "available") + waitForInputToContinue(scanner) + println(DASHES) + + println(DASHES) + println("5. Show Neptune Cluster details") + waitForInputToContinue(scanner) + describeDBClusters(client, dbClusterId) + waitForInputToContinue(scanner) + println(DASHES) + + println(DASHES) + println("6. Stop the Amazon Neptune cluster") + println( + """ + Once stopped, this step polls the status + until the cluster is in a stopped state. + """.trimIndent() + ) + waitForInputToContinue(scanner) + stopDBCluster(client, dbClusterId) + waitForClusterStatus(client, dbClusterId, "stopped") + waitForInputToContinue(scanner) + println(DASHES) + + println(DASHES) + println("7. Start the Amazon Neptune cluster") + println( + """ + Once started, this step polls the clusters + status until it's in an available state. + We will also poll the instance status. + """.trimIndent() + ) + waitForInputToContinue(scanner) + startDBCluster(client, dbClusterId) + waitForClusterStatus(client, dbClusterId, "available") + checkInstanceStatus(client, dbInstanceId, "available") + waitForInputToContinue(scanner) + println(DASHES) + + println(DASHES) + println("8. Delete the Neptune Assets") + println("Would you like to delete the Neptune Assets? (y/n)") + val delAns = scanner.nextLine().trim() + if (delAns.equals("y", ignoreCase = true)) { + println("You selected to delete the Neptune assets.") + deleteDbInstance(client, dbInstanceId) + waitUntilInstanceDeleted(client, dbInstanceId) + deleteDBCluster(client, dbClusterId) + deleteDBSubnetGroup(client, subnetGroupName) + println("Neptune resources deleted successfully.") + } else { + println("You selected not to delete Neptune assets.") + } - println(DASHES) - println("7. Start the Amazon Neptune cluster") - println( - """ - Once started, this step polls the clusters - status until it's in an available state. - We will also poll the instance status. - """.trimIndent(), - ) - waitForInputToContinue(scanner) - startDBCluster(client, dbClusterId) - waitForClusterStatus(client, dbClusterId, "available") - checkInstanceStatus(client, dbInstanceId, "available") - waitForInputToContinue(scanner) - println(DASHES) - - println(DASHES) - println("8. Delete the Neptune Assets") - println("Would you like to delete the Neptune Assets? (y/n)") - val delAns = scanner.nextLine().trim() - if (delAns.equals("y")) { - println("You selected to delete the Neptune assets.") - deleteDbInstance(client, dbInstanceId) - waitUntilInstanceDeleted(client, dbInstanceId) - deleteDBCluster(client, dbClusterId) - deleteDBSubnetGroup(client, subnetGroupName) - println("Neptune resources deleted successfully.") - - } else { - println("You selected not to delete Neptune assets.") + } catch (e: Exception) { + println("An error occurred during the scenario: ${e.message}") + e.printStackTrace() } } @@ -175,8 +189,17 @@ suspend fun deleteDBSubnetGroup(neptuneClient : NeptuneClient, subnetGroupName:S dbSubnetGroupName = subnetGroupName } - neptuneClient.deleteDbSubnetGroup(request) - println(" Deleting Subnet Group: $subnetGroupName") + try { + neptuneClient.deleteDbSubnetGroup(request) + println(" Deleting Subnet Group: $subnetGroupName") + + } catch (e: DbSubnetGroupNotFoundFault) { + println("\nThe subnet group not found: ${e.message}") + throw e + } catch (e: NeptuneException) { + println("Neptune exception occurred : ${e.message}") + throw e + } } // snippet-end:[neptune.kotlin.delete.subnet.group.main] @@ -192,8 +215,17 @@ suspend fun deleteDBCluster(neptuneClient : NeptuneClient, clusterId: String) { skipFinalSnapshot = true } - neptuneClient.deleteDbCluster(request) - println("️ Deleting DB Cluster: $clusterId") + try { + neptuneClient.deleteDbCluster(request) + println("️ Deleting DB Cluster: $clusterId") + + } catch (e: DbClusterNotFoundFault) { + println("\nResource not found: ${e.message}") + throw e + } catch (e: NeptuneException) { + println("Neptune exception occurred : ${e.message}") + throw e + } } // snippet-end:[neptune.kotlin.delete.cluster.main] @@ -246,10 +278,13 @@ suspend fun waitUntilInstanceDeleted( // snippet-start:[neptune.kotlin.delete.instance.main] /** - * Deletes a DB instance. + * Deletes the specified Amazon Neptune DB instance. + * + * @param neptuneClient The Neptune client used to perform the deletion. + * @param instanceId The identifier of the DB instance to be deleted. * - * @param instanceId the identifier of the DB instance to be deleted - * @return a {@link CompletableFuture} that completes when the DB instance has been deleted + * @throws DbInstanceNotFoundFault if the specified DB instance does not exist. + * @throws NeptuneException if any other error occurs during the deletion process. */ suspend fun deleteDbInstance(neptuneClient: NeptuneClient, instanceId: String) { val request = DeleteDbInstanceRequest { @@ -257,8 +292,17 @@ suspend fun deleteDbInstance(neptuneClient: NeptuneClient, instanceId: String) { skipFinalSnapshot = true } - neptuneClient.deleteDbInstance(request) - println("Deleting DB Instance: $instanceId") + try { + neptuneClient.deleteDbInstance(request) + println("Deleting DB Instance: $instanceId") + + } catch (e: DbInstanceNotFoundFault) { + println("\nThe DB instance was not found: ${e.message}") + throw e + } catch (e: NeptuneException) { + println("Neptune exception occurred : ${e.message}") + throw e + } } // snippet-end:[neptune.kotlin.delete.instance.main] @@ -313,17 +357,30 @@ suspend fun waitForClusterStatus( // snippet-start:[neptune.kotlin.start.cluster.main] /** - * Starts an Amazon Neptune DB cluster. + * Starts the specified Amazon Neptune DB cluster. + * + * @param neptuneClient The Neptune client used to make the request. + * @param clusterIdentifier The unique identifier of the DB cluster to be started. * - * @param clusterIdentifier the unique identifier of the DB cluster to be stopped + * @throws DbClusterNotFoundFault if the specified DB cluster does not exist. + * @throws NeptuneException if any other service-level error occurs. */ suspend fun startDBCluster(neptuneClient: NeptuneClient, clusterIdentifier: String) { val request = StartDbClusterRequest { dbClusterIdentifier = clusterIdentifier } - neptuneClient.startDbCluster(request) - println("DB Cluster started : $clusterIdentifier") + try { + neptuneClient.startDbCluster(request) + println("DB Cluster started : $clusterIdentifier") + + } catch (e: DbClusterNotFoundFault) { + println("\nResource not found: ${e.message}") + throw e + } catch (e: NeptuneException) { + println("Neptune exception occurred : ${e.message}") + throw e + } } // snippet-end:[neptune.kotlin.start.cluster.main] @@ -331,95 +388,133 @@ suspend fun startDBCluster(neptuneClient: NeptuneClient, clusterIdentifier: Stri /** * Stops an Amazon Neptune DB cluster. * - * @param clusterIdentifier the unique identifier of the DB cluster to be stopped + * @param neptuneClient The Neptune client used to make the request. + * @param clusterIdentifier The unique identifier of the DB cluster to be started. + * + * @throws DbClusterNotFoundFault if the specified DB cluster does not exist. + * @throws NeptuneException if any other service-level error occurs. */ suspend fun stopDBCluster(neptuneClient: NeptuneClient, clusterIdentifier: String) { val request = StopDbClusterRequest { dbClusterIdentifier = clusterIdentifier } - neptuneClient.stopDbCluster(request) - println("DB Cluster stopped: $clusterIdentifier") + try { + neptuneClient.stopDbCluster(request) + println("DB Cluster stopped: $clusterIdentifier") + + } catch (e: DbClusterNotFoundFault) { + println("\nThe Neptune DB cluster was not found: ${e.message}") + throw e + } catch (e: NeptuneException) { + println("A Neptune exception occurred : ${e.message}") + throw e + } } // snippet-end:[neptune.kotlin.stop.cluster.main] // snippet-start:[neptune.kotlin.describe.cluster.main] /** - * Describes the specified Amazon Neptune cluster. - * - * @param clusterId the identifier of the cluster to describe - */ +* Describes the specified Amazon Neptune DB cluster and prints detailed cluster information. +* +* @param neptuneClient The Neptune client used to make the describe request. +* @param clusterId The identifier of the Neptune DB cluster to describe. +* +* @throws DbClusterNotFoundFault if the specified DB cluster does not exist. +* @throws NeptuneException if any other error occurs while describing the cluster. +*/ suspend fun describeDBClusters(neptuneClient: NeptuneClient, clusterId: String) { val request = DescribeDbClustersRequest { dbClusterIdentifier = clusterId } - val response = neptuneClient.describeDbClusters(request) - response.dbClusters?.forEach { cluster -> - println("Cluster Identifier: ${cluster.dbClusterIdentifier}") - println("Status: ${cluster.status}") - println("Engine: ${cluster.engine}") - println("Engine Version: ${cluster.engineVersion}") - println("Endpoint: ${cluster.endpoint}") - println("Reader Endpoint: ${cluster.readerEndpoint}") - println("Availability Zones: ${cluster.availabilityZones}") - println("Subnet Group: ${cluster.dbSubnetGroup}") - println("VPC Security Groups:") - cluster.vpcSecurityGroups?.forEach { vpcGroup -> - println(" - ${vpcGroup.vpcSecurityGroupId}") - } - println("Storage Encrypted: ${cluster.storageEncrypted}") - println("IAM DB Auth Enabled: ${cluster.iamDatabaseAuthenticationEnabled}") - println("Backup Retention Period: ${cluster.backupRetentionPeriod} days") - println("Preferred Backup Window: ${cluster.preferredBackupWindow}") - println("Preferred Maintenance Window: ${cluster.preferredMaintenanceWindow}") - println("------") + try { + val response = neptuneClient.describeDbClusters(request) + response.dbClusters?.forEach { cluster -> + println("Cluster Identifier: ${cluster.dbClusterIdentifier}") + println("Status: ${cluster.status}") + println("Engine: ${cluster.engine}") + println("Engine Version: ${cluster.engineVersion}") + println("Endpoint: ${cluster.endpoint}") + println("Reader Endpoint: ${cluster.readerEndpoint}") + println("Availability Zones: ${cluster.availabilityZones}") + println("Subnet Group: ${cluster.dbSubnetGroup}") + println("VPC Security Groups:") + cluster.vpcSecurityGroups?.forEach { vpcGroup -> + println(" - ${vpcGroup.vpcSecurityGroupId}") + } + println("Storage Encrypted: ${cluster.storageEncrypted}") + println("IAM DB Auth Enabled: ${cluster.iamDatabaseAuthenticationEnabled}") + println("Backup Retention Period: ${cluster.backupRetentionPeriod} days") + println("Preferred Backup Window: ${cluster.preferredBackupWindow}") + println("Preferred Maintenance Window: ${cluster.preferredMaintenanceWindow}") + println("------") + } + + } catch (e: DbClusterNotFoundFault) { + println("\nThe Neptune DB cluster was not found: ${e.message}") + throw e + } catch (e: NeptuneException) { + println("Neptune exception occurred : ${e.message}") + throw e } } // snippet-end:[neptune.kotlin.describe.cluster.main] // snippet-start:[neptune.kotlin.describe.dbinstance.main] /** - * Checks the status of a Neptune instance recursively until the desired status is reached or a timeout occurs. + * Polls the status of an Amazon Neptune DB instance until it reaches the desired status or times out. + * + * @param neptuneClient The Neptune client used to query instance status. + * @param instanceId The identifier of the DB instance to monitor. + * @param desiredStatus The status to wait for (e.g., "available"). + * @param pollInterval The interval between status checks. Default is 10 seconds. * - * @param instanceId the ID of the Neptune instance to check - * @param desiredStatus the desired status of the Neptune instance + * @throws DbInstanceNotFoundFault if the DB instance is not found and should not be retried. + * @throws NeptuneException if a service-level error occurs. */ suspend fun checkInstanceStatus( neptuneClient: NeptuneClient, instanceId: String, desiredStatus: String, - timeout: Duration = Duration.ofMinutes(20), pollInterval: Duration = Duration.ofSeconds(10) ) { val startTime = System.currentTimeMillis() println("Checking status for instance '$instanceId'...") - while (true) { - val request = DescribeDbInstancesRequest { - dbInstanceIdentifier = instanceId - } + try { + while (true) { + val request = DescribeDbInstancesRequest { + dbInstanceIdentifier = instanceId + } - val response = neptuneClient.describeDbInstances(request) - val currentStatus = response.dbInstances?.firstOrNull()?.dbInstanceStatus ?: "Unknown" - val elapsedSeconds = (System.currentTimeMillis() - startTime) / 1000 + try { + val response = neptuneClient.describeDbInstances(request) + val currentStatus = response.dbInstances?.firstOrNull()?.dbInstanceStatus ?: "Unknown" + val elapsedSeconds = (System.currentTimeMillis() - startTime) / 1000 - print("\rElapsed: ${formatElapsedTime(elapsedSeconds.toInt()).padEnd(20)} Status: ${currentStatus.padEnd(20)}") - System.out.flush() + print("\rElapsed: ${formatElapsedTime(elapsedSeconds.toInt()).padEnd(20)} Status: ${currentStatus.padEnd(20)}") + System.out.flush() - if (desiredStatus.equals(currentStatus, ignoreCase = true)) { - println( - "\nInstance reached desired status '$desiredStatus' after " + - formatElapsedTime(elapsedSeconds.toInt()) + "." - ) - break - } + if (desiredStatus.equals(currentStatus, ignoreCase = true)) { + println("\nInstance reached desired status '$desiredStatus' after ${formatElapsedTime(elapsedSeconds.toInt())}.") + break + } - if ((System.currentTimeMillis() - startTime) > timeout.toMillis()) { - throw RuntimeException("Timeout waiting for Neptune instance to reach status: $desiredStatus") + } catch (e: DbInstanceNotFoundFault) { + println("\nInstance '$instanceId' not found. Retrying...") + // Keep polling — could be a temporary propagation delay + } + + delay(pollInterval.toMillis()) } - delay(pollInterval.toMillis()) + } catch (e: NeptuneException) { + println("\nNeptune exception while checking instance status: ${e.message}") + throw e + } catch (e: Exception) { + println("\nUnexpected exception while checking instance status: ${e.message}") + throw e } } // snippet-end:[neptune.kotlin.describe.dbinstance.main] @@ -430,16 +525,20 @@ private fun formatElapsedTime(totalSeconds: Int): String { return String.format("%02d:%02d", minutes, seconds) } - // snippet-start:[neptune.kotlin.create.dbinstance.main] -/*** Creates an Amazon Neptune DB instance. - * - * @param dbInstanceId the identifier for the new DB instance - * @param dbClusterId the identifier for the DB cluster that the new instance will be a part of - * @return the identifier of the newly created DB instance - */ -suspend fun createDbInstance(neptuneClient: NeptuneClient, dbInstanceId: String, dbClusterId: String): String { +/** +* Creates a new Amazon Neptune DB instance and returns its identifier. +* +* @param neptuneClient The Neptune client used to send the create request. +* @param dbInstanceId The identifier to assign to the new DB instance. +* @param dbClusterId The identifier of the Neptune DB cluster to associate the instance with. +* @return The identifier of the created Neptune DB instance. +* +* @throws DbSubnetGroupQuotaExceededFault if the subnet group quota has been exceeded. +* @throws NeptuneException if any other error occurs during the creation of the instance. +*/ +suspend fun createDbInstance(neptuneClient: NeptuneClient, dbInstanceId: String, dbClusterId: String): String? { val request = CreateDbInstanceRequest { dbInstanceIdentifier = dbInstanceId dbInstanceClass = "db.r5.large" @@ -447,21 +546,33 @@ suspend fun createDbInstance(neptuneClient: NeptuneClient, dbInstanceId: String, dbClusterIdentifier = dbClusterId } - val response = neptuneClient.createDbInstance(request) - val instanceId = response.dbInstance?.dbInstanceIdentifier - ?: throw RuntimeException("Instance creation succeeded but no ID returned.") - - println("Created Neptune DB Instance: $instanceId") - return instanceId + try { + val response = neptuneClient.createDbInstance(request) + val instanceId = response.dbInstance?.dbInstanceIdentifier + println("Created Neptune DB Instance: $instanceId") + return instanceId + + } catch (e: DbSubnetGroupQuotaExceededFault) { + println("Quota exceeded when creating '$dbInstanceId': ${e.message}") + throw e + } catch (e: NeptuneException) { + println("Neptune exception when creating '$dbInstanceId': ${e.message}") + throw e + } } // snippet-end:[neptune.kotlin.create.dbinstance.main] // snippet-start:[neptune.kotlin.create.cluster.main] /** - * Creates a new Amazon Neptune DB cluster. + * Creates a new Amazon Neptune DB cluster and returns its identifier. * - * @param dbName the name of the DB cluster to be created - * @return the ID of the created DB cluster + * @param neptuneClient The Neptune client used to perform the cluster creation. + * @param dbName The unique identifier to assign to the new DB cluster. + * @return The identifier of the created Neptune DB cluster. + * + * @throws DbSubnetGroupQuotaExceededFault if the subnet group quota is exceeded. + * @throws NeptuneException if a service-level error occurs during cluster creation. + * @throws RuntimeException if the cluster is created but no cluster ID is returned. */ suspend fun createDbCluster(neptuneClient: NeptuneClient, dbName: String): String { val request = CreateDbClusterRequest { @@ -471,21 +582,33 @@ suspend fun createDbCluster(neptuneClient: NeptuneClient, dbName: String): Strin backupRetentionPeriod = 1 } - val response = neptuneClient.createDbCluster(request) - val clusterId = response.dbCluster?.dbClusterIdentifier - ?: throw RuntimeException("Cluster creation succeeded but no ID returned.") + try { + val response = neptuneClient.createDbCluster(request) + val clusterId = response.dbCluster?.dbClusterIdentifier + ?: throw RuntimeException("Cluster creation succeeded but no ID returned.") + + println("DB Cluster created: $clusterId") + return clusterId - println("DB Cluster created: $clusterId") - return clusterId + } catch (e: DbSubnetGroupQuotaExceededFault) { + println("Quota exceeded when creating '$dbName': ${e.message}") + throw e + } catch (e: NeptuneException) { + println("Neptune exception when creating '$dbName': ${e.message}") + throw e + } } // snippet-end:[neptune.kotlin.create.cluster.main] // snippet-start:[neptune.kotlin.create.subnet.main] /** - * Creates a new Neptune DB subnet group asynchronously. + * Creates an Amazon Neptune DB subnet group using the default VPC and its associated subnets. * - * @param groupName the name of the DB subnet group to create - * @return the Amazon Resource Name (ARN) of the created DB subnet group + * @param neptuneClient The Neptune client used to send the create request. + * @param groupName The name to assign to the new subnet group. + * + * @throws DbSubnetGroupQuotaExceededFault if the subnet group quota has been exceeded. + * @throws NeptuneException if a service-level error occurs during subnet group creation. */ suspend fun createSubnetGroup(neptuneClient: NeptuneClient, groupName: String) { val vpcId = getDefaultVpcId() @@ -497,9 +620,18 @@ suspend fun createSubnetGroup(neptuneClient: NeptuneClient, groupName: String) { subnetIds = subnetList } - val response = neptuneClient.createDbSubnetGroup(request) - val name = response.dbSubnetGroup?.dbSubnetGroupName - println("Subnet group created: $name") + try { + val response = neptuneClient.createDbSubnetGroup(request) + val name = response.dbSubnetGroup?.dbSubnetGroupName + println("Subnet group created: $name") + + } catch (e: DbSubnetGroupQuotaExceededFault) { + println("Quota exceeded when creating subnet group '$groupName': ${e.message}") + throw e + } catch (e: NeptuneException) { + println("Neptune exception when creating subnet group '$groupName': ${e.message}") + throw e + } } // snippet-end:[neptune.kotlin.create.subnet.main] From 3279e6a53d35afa97d668926268a330c7d79fd05 Mon Sep 17 00:00:00 2001 From: Macdonald Date: Thu, 3 Jul 2025 15:09:41 -0400 Subject: [PATCH 17/32] fixed linter issue --- .../java/com/example/neptune/scenerio/NeptuneScenario.kt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/kotlin/services/neptune/src/main/java/com/example/neptune/scenerio/NeptuneScenario.kt b/kotlin/services/neptune/src/main/java/com/example/neptune/scenerio/NeptuneScenario.kt index c3a23c2e6bf..c22b9ecb4a8 100644 --- a/kotlin/services/neptune/src/main/java/com/example/neptune/scenerio/NeptuneScenario.kt +++ b/kotlin/services/neptune/src/main/java/com/example/neptune/scenerio/NeptuneScenario.kt @@ -39,10 +39,10 @@ var scanner = Scanner(System.`in`) * https://docs.aws.amazon.com/sdk-for-kotlin/latest/developer-guide/setup.html */ suspend fun main() { - val subnetGroupName = "neptuneSubnetGroup210" - val clusterName = "neptuneCluster210" - val dbInstanceId = "neptuneDB210" - val client = NeptuneClient.fromEnvironment {region = "us-east-1" } + val subnetGroupName = "neptuneSubnetGroup" + val clusterName = "neptuneCluster" + val dbInstanceId = "neptuneDB" + val client = NeptuneClient.fromEnvironment { region = "us-east-1" } println( """ From 6d486bab2f3bd67d219b1c660832c58027442319 Mon Sep 17 00:00:00 2001 From: Macdonald Date: Thu, 3 Jul 2025 15:17:05 -0400 Subject: [PATCH 18/32] fixed linter issue --- .../example/neptune/scenerio/NeptuneScenario.kt | 14 ++++++-------- 1 file changed, 6 insertions(+), 8 deletions(-) diff --git a/kotlin/services/neptune/src/main/java/com/example/neptune/scenerio/NeptuneScenario.kt b/kotlin/services/neptune/src/main/java/com/example/neptune/scenerio/NeptuneScenario.kt index c22b9ecb4a8..893161aede1 100644 --- a/kotlin/services/neptune/src/main/java/com/example/neptune/scenerio/NeptuneScenario.kt +++ b/kotlin/services/neptune/src/main/java/com/example/neptune/scenerio/NeptuneScenario.kt @@ -79,7 +79,7 @@ suspend fun runScenario( client: NeptuneClient, subnetGroupName: String, dbInstanceId: String, - clusterName: String + clusterName: String, ) { try { println(DASHES) @@ -112,7 +112,7 @@ suspend fun runScenario( """ In this step, we will wait until the DB instance becomes available. This may take around 10 minutes. - """.trimIndent() + """.trimIndent(), ) waitForInputToContinue(scanner) checkInstanceStatus(client, dbInstanceId, "available") @@ -132,7 +132,7 @@ suspend fun runScenario( """ Once stopped, this step polls the status until the cluster is in a stopped state. - """.trimIndent() + """.trimIndent(), ) waitForInputToContinue(scanner) stopDBCluster(client, dbClusterId) @@ -147,7 +147,7 @@ suspend fun runScenario( Once started, this step polls the clusters status until it's in an available state. We will also poll the instance status. - """.trimIndent() + """.trimIndent(), ) waitForInputToContinue(scanner) startDBCluster(client, dbClusterId) @@ -170,7 +170,6 @@ suspend fun runScenario( } else { println("You selected not to delete Neptune assets.") } - } catch (e: Exception) { println("An error occurred during the scenario: ${e.message}") e.printStackTrace() @@ -184,7 +183,7 @@ suspend fun runScenario( * @param subnetGroupName the identifier of the subnet group to delete * @return a {@link CompletableFuture} that completes when the cluster has been deleted */ -suspend fun deleteDBSubnetGroup(neptuneClient : NeptuneClient, subnetGroupName:String) { +suspend fun deleteDBSubnetGroup(neptuneClient:NeptuneClient, subnetGroupName:String) { val request = DeleteDbSubnetGroupRequest { dbSubnetGroupName = subnetGroupName } @@ -192,7 +191,6 @@ suspend fun deleteDBSubnetGroup(neptuneClient : NeptuneClient, subnetGroupName:S try { neptuneClient.deleteDbSubnetGroup(request) println(" Deleting Subnet Group: $subnetGroupName") - } catch (e: DbSubnetGroupNotFoundFault) { println("\nThe subnet group not found: ${e.message}") throw e @@ -209,7 +207,7 @@ suspend fun deleteDBSubnetGroup(neptuneClient : NeptuneClient, subnetGroupName:S * * @param clusterId the identifier of the cluster to delete */ -suspend fun deleteDBCluster(neptuneClient : NeptuneClient, clusterId: String) { +suspend fun deleteDBCluster(neptuneClient:NeptuneClient, clusterId: String) { val request = DeleteDbClusterRequest { dbClusterIdentifier = clusterId skipFinalSnapshot = true From f32d7f078a3503ab21b71b4b5e60944f48b902a2 Mon Sep 17 00:00:00 2001 From: Macdonald Date: Thu, 3 Jul 2025 15:20:01 -0400 Subject: [PATCH 19/32] fixed linter issue --- .../java/com/example/neptune/scenerio/NeptuneScenario.kt | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/kotlin/services/neptune/src/main/java/com/example/neptune/scenerio/NeptuneScenario.kt b/kotlin/services/neptune/src/main/java/com/example/neptune/scenerio/NeptuneScenario.kt index 893161aede1..1cc5451b3da 100644 --- a/kotlin/services/neptune/src/main/java/com/example/neptune/scenerio/NeptuneScenario.kt +++ b/kotlin/services/neptune/src/main/java/com/example/neptune/scenerio/NeptuneScenario.kt @@ -183,19 +183,19 @@ suspend fun runScenario( * @param subnetGroupName the identifier of the subnet group to delete * @return a {@link CompletableFuture} that completes when the cluster has been deleted */ -suspend fun deleteDBSubnetGroup(neptuneClient:NeptuneClient, subnetGroupName:String) { +suspend fun deleteDBSubnetGroup(neptuneClient: NeptuneClient, subnetGroupName: String) { val request = DeleteDbSubnetGroupRequest { dbSubnetGroupName = subnetGroupName } try { neptuneClient.deleteDbSubnetGroup(request) - println(" Deleting Subnet Group: $subnetGroupName") + println("Deleting Subnet Group: $subnetGroupName") } catch (e: DbSubnetGroupNotFoundFault) { - println("\nThe subnet group not found: ${e.message}") + println("The subnet group was not found: ${e.message}") throw e } catch (e: NeptuneException) { - println("Neptune exception occurred : ${e.message}") + println("Neptune exception occurred: ${e.message}") throw e } } From e2ee63fc47a8969ec27b56990d1925b2503e6957 Mon Sep 17 00:00:00 2001 From: Macdonald Date: Thu, 3 Jul 2025 15:42:28 -0400 Subject: [PATCH 20/32] fixed linter issue --- .../neptune/scenerio/NeptuneScenario.kt | 25 ++++++------------- 1 file changed, 8 insertions(+), 17 deletions(-) diff --git a/kotlin/services/neptune/src/main/java/com/example/neptune/scenerio/NeptuneScenario.kt b/kotlin/services/neptune/src/main/java/com/example/neptune/scenerio/NeptuneScenario.kt index 1cc5451b3da..7665d2f4dc8 100644 --- a/kotlin/services/neptune/src/main/java/com/example/neptune/scenerio/NeptuneScenario.kt +++ b/kotlin/services/neptune/src/main/java/com/example/neptune/scenerio/NeptuneScenario.kt @@ -207,7 +207,7 @@ suspend fun deleteDBSubnetGroup(neptuneClient: NeptuneClient, subnetGroupName: S * * @param clusterId the identifier of the cluster to delete */ -suspend fun deleteDBCluster(neptuneClient:NeptuneClient, clusterId: String) { +suspend fun deleteDBCluster(neptuneClient: NeptuneClient, clusterId: String) { val request = DeleteDbClusterRequest { dbClusterIdentifier = clusterId skipFinalSnapshot = true @@ -216,7 +216,6 @@ suspend fun deleteDBCluster(neptuneClient:NeptuneClient, clusterId: String) { try { neptuneClient.deleteDbCluster(request) println("️ Deleting DB Cluster: $clusterId") - } catch (e: DbClusterNotFoundFault) { println("\nResource not found: ${e.message}") throw e @@ -224,14 +223,14 @@ suspend fun deleteDBCluster(neptuneClient:NeptuneClient, clusterId: String) { println("Neptune exception occurred : ${e.message}") throw e } - } +} // snippet-end:[neptune.kotlin.delete.cluster.main] suspend fun waitUntilInstanceDeleted( neptuneClient: NeptuneClient, instanceId: String, timeout: Duration = Duration.ofMinutes(20), - pollInterval: Duration = Duration.ofSeconds(10) + pollInterval: Duration = Duration.ofSeconds(10), ): Boolean { println("Waiting for instance '$instanceId' to be deleted...") @@ -248,7 +247,6 @@ suspend fun waitUntilInstanceDeleted( val elapsed = (System.currentTimeMillis() - startTime) / 1000 print("\r Waiting: Instance $instanceId status: ${status.padEnd(10)} (${elapsed}s elapsed)") System.out.flush() - } catch (e: NeptuneException) { val errorCode = e.sdkErrorMetadata.errorCode return if (errorCode == "DBInstanceNotFound") { @@ -293,7 +291,6 @@ suspend fun deleteDbInstance(neptuneClient: NeptuneClient, instanceId: String) { try { neptuneClient.deleteDbInstance(request) println("Deleting DB Instance: $instanceId") - } catch (e: DbInstanceNotFoundFault) { println("\nThe DB instance was not found: ${e.message}") throw e @@ -320,9 +317,8 @@ suspend fun waitForClusterStatus( timeout: Duration = Duration.ofMinutes(20), pollInterval: Duration = Duration.ofSeconds(10) ) { - println("Waiting for cluster '$clusterId' to reach status '$desiredStatus'...") + println("Waiting for cluster $clusterId to reach status '$desiredStatus'...") val startTime = System.currentTimeMillis() - while (true) { val request = DescribeDbClustersRequest { dbClusterIdentifier = clusterId @@ -337,18 +333,14 @@ suspend fun waitForClusterStatus( "Cluster status: ${currentStatus.padEnd(20)}" ) System.out.flush() - if (desiredStatus.equals(currentStatus, ignoreCase = true)) { - println( - "\nNeptune cluster reached desired status '$desiredStatus' after " + - "${formatElapsedTime(elapsedSeconds.toInt())}." - ) + if (currentStatus.equals(desiredStatus, ignoreCase = true)) { + println("Neptune cluster reached desired status $desiredStatus after ${formatElapsedTime(elapsedSeconds.toInt())}") return } - if ((System.currentTimeMillis() - startTime) > timeout.toMillis()) { - throw RuntimeException("Timeout waiting for Neptune cluster to reach status: $desiredStatus") + if (System.currentTimeMillis() - startTime > timeout.toMillis()) { + throw RuntimeException("Timed out waiting for Neptune cluster to reach status: $desiredStatus") } - delay(pollInterval.toMillis()) } } @@ -400,7 +392,6 @@ suspend fun stopDBCluster(neptuneClient: NeptuneClient, clusterIdentifier: Strin try { neptuneClient.stopDbCluster(request) println("DB Cluster stopped: $clusterIdentifier") - } catch (e: DbClusterNotFoundFault) { println("\nThe Neptune DB cluster was not found: ${e.message}") throw e From 6bf6f06b74f018422aaed2ee86daeb86c75f0a61 Mon Sep 17 00:00:00 2001 From: Macdonald Date: Thu, 3 Jul 2025 15:52:09 -0400 Subject: [PATCH 21/32] fixed linter issue --- .../neptune/scenerio/NeptuneScenario.kt | 73 +++++++++---------- 1 file changed, 33 insertions(+), 40 deletions(-) diff --git a/kotlin/services/neptune/src/main/java/com/example/neptune/scenerio/NeptuneScenario.kt b/kotlin/services/neptune/src/main/java/com/example/neptune/scenerio/NeptuneScenario.kt index 7665d2f4dc8..aad2afbc883 100644 --- a/kotlin/services/neptune/src/main/java/com/example/neptune/scenerio/NeptuneScenario.kt +++ b/kotlin/services/neptune/src/main/java/com/example/neptune/scenerio/NeptuneScenario.kt @@ -315,7 +315,7 @@ suspend fun waitForClusterStatus( clusterId: String, desiredStatus: String, timeout: Duration = Duration.ofMinutes(20), - pollInterval: Duration = Duration.ofSeconds(10) + pollInterval: Duration = Duration.ofSeconds(10), ) { println("Waiting for cluster $clusterId to reach status '$desiredStatus'...") val startTime = System.currentTimeMillis() @@ -327,11 +327,7 @@ suspend fun waitForClusterStatus( val response = neptuneClient.describeDbClusters(request) val currentStatus = response.dbClusters?.firstOrNull()?.status ?: "Unknown" val elapsedSeconds = (System.currentTimeMillis() - startTime) / 1000 - - print( - "\rElapsed: ${formatElapsedTime(elapsedSeconds.toInt()).padEnd(20)} " + - "Cluster status: ${currentStatus.padEnd(20)}" - ) + println("Elapsed: ${formatElapsedTime(elapsedSeconds.toInt()).padEnd(20)} Cluster status: ${currentStatus.padEnd(20)}") System.out.flush() if (currentStatus.equals(desiredStatus, ignoreCase = true)) { println("Neptune cluster reached desired status $desiredStatus after ${formatElapsedTime(elapsedSeconds.toInt())}") @@ -363,7 +359,6 @@ suspend fun startDBCluster(neptuneClient: NeptuneClient, clusterIdentifier: Stri try { neptuneClient.startDbCluster(request) println("DB Cluster started : $clusterIdentifier") - } catch (e: DbClusterNotFoundFault) { println("\nResource not found: ${e.message}") throw e @@ -420,26 +415,25 @@ suspend fun describeDBClusters(neptuneClient: NeptuneClient, clusterId: String) try { val response = neptuneClient.describeDbClusters(request) response.dbClusters?.forEach { cluster -> - println("Cluster Identifier: ${cluster.dbClusterIdentifier}") - println("Status: ${cluster.status}") - println("Engine: ${cluster.engine}") - println("Engine Version: ${cluster.engineVersion}") - println("Endpoint: ${cluster.endpoint}") - println("Reader Endpoint: ${cluster.readerEndpoint}") - println("Availability Zones: ${cluster.availabilityZones}") - println("Subnet Group: ${cluster.dbSubnetGroup}") - println("VPC Security Groups:") - cluster.vpcSecurityGroups?.forEach { vpcGroup -> - println(" - ${vpcGroup.vpcSecurityGroupId}") + println("Cluster Identifier: ${cluster.dbClusterIdentifier}") + println("Status: ${cluster.status}") + println("Engine: ${cluster.engine}") + println("Engine Version: ${cluster.engineVersion}") + println("Endpoint: ${cluster.endpoint}") + println("Reader Endpoint: ${cluster.readerEndpoint}") + println("Availability Zones: ${cluster.availabilityZones}") + println("Subnet Group: ${cluster.dbSubnetGroup}") + println("VPC Security Groups:") + cluster.vpcSecurityGroups?.forEach { vpcGroup -> + println(" - ${vpcGroup.vpcSecurityGroupId}") + } + println("Storage Encrypted: ${cluster.storageEncrypted}") + println("IAM DB Auth Enabled: ${cluster.iamDatabaseAuthenticationEnabled}") + println("Backup Retention Period: ${cluster.backupRetentionPeriod} days") + println("Preferred Backup Window: ${cluster.preferredBackupWindow}") + println("Preferred Maintenance Window: ${cluster.preferredMaintenanceWindow}") + println("------") } - println("Storage Encrypted: ${cluster.storageEncrypted}") - println("IAM DB Auth Enabled: ${cluster.iamDatabaseAuthenticationEnabled}") - println("Backup Retention Period: ${cluster.backupRetentionPeriod} days") - println("Preferred Backup Window: ${cluster.preferredBackupWindow}") - println("Preferred Maintenance Window: ${cluster.preferredMaintenanceWindow}") - println("------") - } - } catch (e: DbClusterNotFoundFault) { println("\nThe Neptune DB cluster was not found: ${e.message}") throw e @@ -477,27 +471,26 @@ suspend fun checkInstanceStatus( dbInstanceIdentifier = instanceId } - try { + val currentStatus = try { val response = neptuneClient.describeDbInstances(request) - val currentStatus = response.dbInstances?.firstOrNull()?.dbInstanceStatus ?: "Unknown" - val elapsedSeconds = (System.currentTimeMillis() - startTime) / 1000 - - print("\rElapsed: ${formatElapsedTime(elapsedSeconds.toInt()).padEnd(20)} Status: ${currentStatus.padEnd(20)}") - System.out.flush() - - if (desiredStatus.equals(currentStatus, ignoreCase = true)) { - println("\nInstance reached desired status '$desiredStatus' after ${formatElapsedTime(elapsedSeconds.toInt())}.") - break - } - + response.dbInstances?.firstOrNull()?.dbInstanceStatus ?: "Unknown" } catch (e: DbInstanceNotFoundFault) { println("\nInstance '$instanceId' not found. Retrying...") - // Keep polling — could be a temporary propagation delay + delay(pollInterval.toMillis()) + continue // retry loop + } + + val elapsedSeconds = (System.currentTimeMillis() - startTime) / 1000 + print("\rElapsed: ${formatElapsedTime(elapsedSeconds.toInt()).padEnd(20)} Status: ${currentStatus.padEnd(20)}") + System.out.flush() + + if (desiredStatus.equals(currentStatus, ignoreCase = true)) { + println("\nInstance reached desired status '$desiredStatus' after ${formatElapsedTime(elapsedSeconds.toInt())}.") + break } delay(pollInterval.toMillis()) } - } catch (e: NeptuneException) { println("\nNeptune exception while checking instance status: ${e.message}") throw e From 72223a85cac294a110ed8880e9d1344453c46a04 Mon Sep 17 00:00:00 2001 From: Macdonald Date: Thu, 3 Jul 2025 15:58:14 -0400 Subject: [PATCH 22/32] fixed linter issue --- .../neptune/scenerio/NeptuneScenario.kt | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/kotlin/services/neptune/src/main/java/com/example/neptune/scenerio/NeptuneScenario.kt b/kotlin/services/neptune/src/main/java/com/example/neptune/scenerio/NeptuneScenario.kt index aad2afbc883..0ee411569b5 100644 --- a/kotlin/services/neptune/src/main/java/com/example/neptune/scenerio/NeptuneScenario.kt +++ b/kotlin/services/neptune/src/main/java/com/example/neptune/scenerio/NeptuneScenario.kt @@ -427,12 +427,12 @@ suspend fun describeDBClusters(neptuneClient: NeptuneClient, clusterId: String) cluster.vpcSecurityGroups?.forEach { vpcGroup -> println(" - ${vpcGroup.vpcSecurityGroupId}") } - println("Storage Encrypted: ${cluster.storageEncrypted}") - println("IAM DB Auth Enabled: ${cluster.iamDatabaseAuthenticationEnabled}") - println("Backup Retention Period: ${cluster.backupRetentionPeriod} days") - println("Preferred Backup Window: ${cluster.preferredBackupWindow}") - println("Preferred Maintenance Window: ${cluster.preferredMaintenanceWindow}") - println("------") + println("Storage Encrypted: ${cluster.storageEncrypted}") + println("IAM DB Auth Enabled: ${cluster.iamDatabaseAuthenticationEnabled}") + println("Backup Retention Period: ${cluster.backupRetentionPeriod} days") + println("Preferred Backup Window: ${cluster.preferredBackupWindow}") + println("Preferred Maintenance Window: ${cluster.preferredMaintenanceWindow}") + println("------") } } catch (e: DbClusterNotFoundFault) { println("\nThe Neptune DB cluster was not found: ${e.message}") @@ -460,7 +460,7 @@ suspend fun checkInstanceStatus( neptuneClient: NeptuneClient, instanceId: String, desiredStatus: String, - pollInterval: Duration = Duration.ofSeconds(10) + pollInterval: Duration = Duration.ofSeconds(10), ) { val startTime = System.currentTimeMillis() println("Checking status for instance '$instanceId'...") @@ -533,7 +533,6 @@ suspend fun createDbInstance(neptuneClient: NeptuneClient, dbInstanceId: String, val instanceId = response.dbInstance?.dbInstanceIdentifier println("Created Neptune DB Instance: $instanceId") return instanceId - } catch (e: DbSubnetGroupQuotaExceededFault) { println("Quota exceeded when creating '$dbInstanceId': ${e.message}") throw e @@ -571,7 +570,6 @@ suspend fun createDbCluster(neptuneClient: NeptuneClient, dbName: String): Strin println("DB Cluster created: $clusterId") return clusterId - } catch (e: DbSubnetGroupQuotaExceededFault) { println("Quota exceeded when creating '$dbName': ${e.message}") throw e @@ -606,7 +604,6 @@ suspend fun createSubnetGroup(neptuneClient: NeptuneClient, groupName: String) { val response = neptuneClient.createDbSubnetGroup(request) val name = response.dbSubnetGroup?.dbSubnetGroupName println("Subnet group created: $name") - } catch (e: DbSubnetGroupQuotaExceededFault) { println("Quota exceeded when creating subnet group '$groupName': ${e.message}") throw e @@ -627,7 +624,6 @@ suspend fun getDefaultVpcId(): String { } ) } - val response = ec2Client.describeVpcs(request) val defaultVpc = response.vpcs?.firstOrNull() ?: throw RuntimeException("No default VPC found in this region.") @@ -647,7 +643,6 @@ suspend fun getSubnetIds(vpcId: String): List { } ) } - val response = ec2Client.describeSubnets(request) return response.subnets?.mapNotNull { it.subnetId } ?: emptyList() } From 1ed8a395c003a9751c230cb4eaa9a620b5f07673 Mon Sep 17 00:00:00 2001 From: Macdonald Date: Thu, 3 Jul 2025 16:01:16 -0400 Subject: [PATCH 23/32] fixed linter issue --- .../java/com/example/neptune/scenerio/NeptuneScenario.kt | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/kotlin/services/neptune/src/main/java/com/example/neptune/scenerio/NeptuneScenario.kt b/kotlin/services/neptune/src/main/java/com/example/neptune/scenerio/NeptuneScenario.kt index 0ee411569b5..81ed0fabeb9 100644 --- a/kotlin/services/neptune/src/main/java/com/example/neptune/scenerio/NeptuneScenario.kt +++ b/kotlin/services/neptune/src/main/java/com/example/neptune/scenerio/NeptuneScenario.kt @@ -624,12 +624,13 @@ suspend fun getDefaultVpcId(): String { } ) } + val response = ec2Client.describeVpcs(request) - val defaultVpc = response.vpcs?.firstOrNull() + val defaultVpcId = response.vpcs?.firstOrNull()?.vpcId ?: throw RuntimeException("No default VPC found in this region.") - println("Default VPC ID: ${defaultVpc.vpcId}") - return defaultVpc.vpcId!! + println("Default VPC ID: $defaultVpcId") + return defaultVpcId } } @@ -663,4 +664,4 @@ private fun waitForInputToContinue(scanner: Scanner) { } } } -// snippet-end:[neptune.kotlin.scenario.main] \ No newline at end of file +// snippet-end:[neptune.kotlin.scenario.main] From 93ff6a07db31c4b7716fa115522302309bd7d0e2 Mon Sep 17 00:00:00 2001 From: Macdonald Date: Thu, 3 Jul 2025 16:05:18 -0400 Subject: [PATCH 24/32] fixed linter issue --- .../main/java/com/example/neptune/scenerio/NeptuneScenario.kt | 1 + 1 file changed, 1 insertion(+) diff --git a/kotlin/services/neptune/src/main/java/com/example/neptune/scenerio/NeptuneScenario.kt b/kotlin/services/neptune/src/main/java/com/example/neptune/scenerio/NeptuneScenario.kt index 81ed0fabeb9..a933da4f6e2 100644 --- a/kotlin/services/neptune/src/main/java/com/example/neptune/scenerio/NeptuneScenario.kt +++ b/kotlin/services/neptune/src/main/java/com/example/neptune/scenerio/NeptuneScenario.kt @@ -634,6 +634,7 @@ suspend fun getDefaultVpcId(): String { } } + suspend fun getSubnetIds(vpcId: String): List { Ec2Client.fromEnvironment { region = "us-east-1" }.use { ec2Client -> val request = DescribeSubnetsRequest { From 1aa9694d8013e75bcc0184ac57d6968648906f80 Mon Sep 17 00:00:00 2001 From: Macdonald Date: Thu, 3 Jul 2025 16:08:30 -0400 Subject: [PATCH 25/32] fixed linter issue --- .../com/example/neptune/scenerio/NeptuneScenario.kt | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/kotlin/services/neptune/src/main/java/com/example/neptune/scenerio/NeptuneScenario.kt b/kotlin/services/neptune/src/main/java/com/example/neptune/scenerio/NeptuneScenario.kt index a933da4f6e2..83fdeb52042 100644 --- a/kotlin/services/neptune/src/main/java/com/example/neptune/scenerio/NeptuneScenario.kt +++ b/kotlin/services/neptune/src/main/java/com/example/neptune/scenerio/NeptuneScenario.kt @@ -615,14 +615,14 @@ suspend fun createSubnetGroup(neptuneClient: NeptuneClient, groupName: String) { // snippet-end:[neptune.kotlin.create.subnet.main] suspend fun getDefaultVpcId(): String { + val myFilter = Filter { + name = "isDefault" + values = listOf("true") + } + Ec2Client.fromEnvironment { region = "us-east-1" }.use { ec2Client -> val request = DescribeVpcsRequest { - filters = listOf( - Filter { - name = "isDefault" - values = listOf("true") - } - ) + filters = listOf(myFilter) } val response = ec2Client.describeVpcs(request) From 1503f226f23751504bc178f1c5e0fd37577a0f99 Mon Sep 17 00:00:00 2001 From: Macdonald Date: Thu, 3 Jul 2025 16:11:35 -0400 Subject: [PATCH 26/32] fixed linter issue --- .../com/example/neptune/scenerio/NeptuneScenario.kt | 12 +++++------- 1 file changed, 5 insertions(+), 7 deletions(-) diff --git a/kotlin/services/neptune/src/main/java/com/example/neptune/scenerio/NeptuneScenario.kt b/kotlin/services/neptune/src/main/java/com/example/neptune/scenerio/NeptuneScenario.kt index 83fdeb52042..d989ef723d8 100644 --- a/kotlin/services/neptune/src/main/java/com/example/neptune/scenerio/NeptuneScenario.kt +++ b/kotlin/services/neptune/src/main/java/com/example/neptune/scenerio/NeptuneScenario.kt @@ -634,16 +634,14 @@ suspend fun getDefaultVpcId(): String { } } - suspend fun getSubnetIds(vpcId: String): List { + val myFilter = Filter { + name = "vpc-id" + values = listOf(vpcId) + } Ec2Client.fromEnvironment { region = "us-east-1" }.use { ec2Client -> val request = DescribeSubnetsRequest { - filters = listOf( - Filter { - name = "vpc-id" - values = listOf(vpcId) - } - ) + filters = listOf(myFilter) } val response = ec2Client.describeSubnets(request) return response.subnets?.mapNotNull { it.subnetId } ?: emptyList() From 827d70119bf815039e2a81a5410a2c453d0b5c4b Mon Sep 17 00:00:00 2001 From: Macdonald Date: Thu, 3 Jul 2025 16:14:34 -0400 Subject: [PATCH 27/32] fixed linter issue --- .../example/neptune/scenerio/NeptuneScenario.kt | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/kotlin/services/neptune/src/main/java/com/example/neptune/scenerio/NeptuneScenario.kt b/kotlin/services/neptune/src/main/java/com/example/neptune/scenerio/NeptuneScenario.kt index d989ef723d8..b3671e5024e 100644 --- a/kotlin/services/neptune/src/main/java/com/example/neptune/scenerio/NeptuneScenario.kt +++ b/kotlin/services/neptune/src/main/java/com/example/neptune/scenerio/NeptuneScenario.kt @@ -3,6 +3,9 @@ package com.example.neptune.scenerio +import java.time.Duration +import java.util.Scanner +import kotlinx.coroutines.delay import aws.sdk.kotlin.services.ec2.Ec2Client import aws.sdk.kotlin.services.ec2.model.DescribeSubnetsRequest import aws.sdk.kotlin.services.ec2.model.DescribeVpcsRequest @@ -11,6 +14,10 @@ import aws.sdk.kotlin.services.neptune.NeptuneClient import aws.sdk.kotlin.services.neptune.model.CreateDbClusterRequest import aws.sdk.kotlin.services.neptune.model.CreateDbInstanceRequest import aws.sdk.kotlin.services.neptune.model.CreateDbSubnetGroupRequest +import aws.sdk.kotlin.services.neptune.model.DbClusterNotFoundFault +import aws.sdk.kotlin.services.neptune.model.DbInstanceNotFoundFault +import aws.sdk.kotlin.services.neptune.model.DbSubnetGroupNotFoundFault +import aws.sdk.kotlin.services.neptune.model.DbSubnetGroupQuotaExceededFault import aws.sdk.kotlin.services.neptune.model.DeleteDbClusterRequest import aws.sdk.kotlin.services.neptune.model.DeleteDbInstanceRequest import aws.sdk.kotlin.services.neptune.model.DeleteDbSubnetGroupRequest @@ -19,13 +26,7 @@ import aws.sdk.kotlin.services.neptune.model.DescribeDbInstancesRequest import aws.sdk.kotlin.services.neptune.model.NeptuneException import aws.sdk.kotlin.services.neptune.model.StartDbClusterRequest import aws.sdk.kotlin.services.neptune.model.StopDbClusterRequest -import aws.sdk.kotlin.services.neptune.model.DbSubnetGroupQuotaExceededFault -import aws.sdk.kotlin.services.neptune.model.DbClusterNotFoundFault -import aws.sdk.kotlin.services.neptune.model.DbInstanceNotFoundFault -import aws.sdk.kotlin.services.neptune.model.DbSubnetGroupNotFoundFault -import kotlinx.coroutines.delay -import java.time.Duration -import java.util.Scanner + // snippet-start:[neptune.kotlin.scenario.main] val DASHES = String(CharArray(80)).replace("\u0000", "-") From 5b88cd08e3a72b2db947c8ee5a5e4174bc45af86 Mon Sep 17 00:00:00 2001 From: Macdonald Date: Thu, 3 Jul 2025 16:17:48 -0400 Subject: [PATCH 28/32] fixed linter issue --- .../main/java/com/example/neptune/scenerio/NeptuneScenario.kt | 1 - 1 file changed, 1 deletion(-) diff --git a/kotlin/services/neptune/src/main/java/com/example/neptune/scenerio/NeptuneScenario.kt b/kotlin/services/neptune/src/main/java/com/example/neptune/scenerio/NeptuneScenario.kt index b3671e5024e..b9f632c7c2e 100644 --- a/kotlin/services/neptune/src/main/java/com/example/neptune/scenerio/NeptuneScenario.kt +++ b/kotlin/services/neptune/src/main/java/com/example/neptune/scenerio/NeptuneScenario.kt @@ -27,7 +27,6 @@ import aws.sdk.kotlin.services.neptune.model.NeptuneException import aws.sdk.kotlin.services.neptune.model.StartDbClusterRequest import aws.sdk.kotlin.services.neptune.model.StopDbClusterRequest - // snippet-start:[neptune.kotlin.scenario.main] val DASHES = String(CharArray(80)).replace("\u0000", "-") var scanner = Scanner(System.`in`) From c154d33a2242771d0a9619eafeca00964129d08d Mon Sep 17 00:00:00 2001 From: Macdonald Date: Thu, 3 Jul 2025 16:22:55 -0400 Subject: [PATCH 29/32] fixed linter issue --- .../java/com/example/neptune/scenerio/NeptuneScenario.kt | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/kotlin/services/neptune/src/main/java/com/example/neptune/scenerio/NeptuneScenario.kt b/kotlin/services/neptune/src/main/java/com/example/neptune/scenerio/NeptuneScenario.kt index b9f632c7c2e..c95d0d7d3de 100644 --- a/kotlin/services/neptune/src/main/java/com/example/neptune/scenerio/NeptuneScenario.kt +++ b/kotlin/services/neptune/src/main/java/com/example/neptune/scenerio/NeptuneScenario.kt @@ -3,9 +3,6 @@ package com.example.neptune.scenerio -import java.time.Duration -import java.util.Scanner -import kotlinx.coroutines.delay import aws.sdk.kotlin.services.ec2.Ec2Client import aws.sdk.kotlin.services.ec2.model.DescribeSubnetsRequest import aws.sdk.kotlin.services.ec2.model.DescribeVpcsRequest @@ -26,6 +23,9 @@ import aws.sdk.kotlin.services.neptune.model.DescribeDbInstancesRequest import aws.sdk.kotlin.services.neptune.model.NeptuneException import aws.sdk.kotlin.services.neptune.model.StartDbClusterRequest import aws.sdk.kotlin.services.neptune.model.StopDbClusterRequest +import kotlinx.coroutines.delay +import java.time.Duration +import java.util.Scanner // snippet-start:[neptune.kotlin.scenario.main] val DASHES = String(CharArray(80)).replace("\u0000", "-") From 713e90a48d6d7087a990b879c23bb21a67f7f795 Mon Sep 17 00:00:00 2001 From: Macdonald Date: Thu, 3 Jul 2025 16:25:59 -0400 Subject: [PATCH 30/32] fixed linter issue --- kotlin/services/neptune/src/test/java/NeptuneTest.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kotlin/services/neptune/src/test/java/NeptuneTest.kt b/kotlin/services/neptune/src/test/java/NeptuneTest.kt index 5cc0626ab68..77f584393a0 100644 --- a/kotlin/services/neptune/src/test/java/NeptuneTest.kt +++ b/kotlin/services/neptune/src/test/java/NeptuneTest.kt @@ -35,7 +35,7 @@ class NeptuneTest { @BeforeAll fun setup() = runBlocking { - client = NeptuneClient.fromEnvironment {region = "us-east-1" } + client = NeptuneClient.fromEnvironment {region = "us-east-1"} } @Test From 4ab636b20e16fd0a06208aa9c7f517d55cc16875 Mon Sep 17 00:00:00 2001 From: Macdonald Date: Thu, 3 Jul 2025 16:27:35 -0400 Subject: [PATCH 31/32] fixed linter issue --- kotlin/services/neptune/src/test/java/NeptuneTest.kt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/kotlin/services/neptune/src/test/java/NeptuneTest.kt b/kotlin/services/neptune/src/test/java/NeptuneTest.kt index 77f584393a0..7fe118f777d 100644 --- a/kotlin/services/neptune/src/test/java/NeptuneTest.kt +++ b/kotlin/services/neptune/src/test/java/NeptuneTest.kt @@ -35,7 +35,7 @@ class NeptuneTest { @BeforeAll fun setup() = runBlocking { - client = NeptuneClient.fromEnvironment {region = "us-east-1"} + client = NeptuneClient.fromEnvironment { region = "us-east-1" } } @Test From 7ee447e1f41eeeef8f4d93cbba9fd6b8ec5bdade Mon Sep 17 00:00:00 2001 From: Macdonald Date: Thu, 3 Jul 2025 16:30:02 -0400 Subject: [PATCH 32/32] fixed linter issue --- kotlin/services/neptune/README.md | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/kotlin/services/neptune/README.md b/kotlin/services/neptune/README.md index c24645e7179..9a9e416756a 100644 --- a/kotlin/services/neptune/README.md +++ b/kotlin/services/neptune/README.md @@ -45,16 +45,16 @@ Code examples that show you how to perform the essential operations within a ser Code excerpts that show you how to call individual service functions. -- [CreateDBCluster](src/main/java/com/example/neptune/scenerio/NeptuneScenario.kt#L482) -- [CreateDBInstance](src/main/java/com/example/neptune/scenerio/NeptuneScenario.kt#L455) -- [CreateDBSubnetGroup](src/main/java/com/example/neptune/scenerio/NeptuneScenario.kt#L508) -- [DeleteDBCluster](src/main/java/com/example/neptune/scenerio/NeptuneScenario.kt#L187) -- [DeleteDBInstance](src/main/java/com/example/neptune/scenerio/NeptuneScenario.kt#L254) -- [DeleteDBSubnetGroup](src/main/java/com/example/neptune/scenerio/NeptuneScenario.kt#L168) -- [DescribeDBClusters](src/main/java/com/example/neptune/scenerio/NeptuneScenario.kt#L367) -- [DescribeDBInstances](src/main/java/com/example/neptune/scenerio/NeptuneScenario.kt#L404) -- [StartDBCluster](src/main/java/com/example/neptune/scenerio/NeptuneScenario.kt#L331) -- [StopDBCluster](src/main/java/com/example/neptune/scenerio/NeptuneScenario.kt#L349) +- [CreateDBCluster](src/main/java/com/example/neptune/scenerio/NeptuneScenario.kt#L546) +- [CreateDBInstance](src/main/java/com/example/neptune/scenerio/NeptuneScenario.kt#L510) +- [CreateDBSubnetGroup](src/main/java/com/example/neptune/scenerio/NeptuneScenario.kt#L583) +- [DeleteDBCluster](src/main/java/com/example/neptune/scenerio/NeptuneScenario.kt#L204) +- [DeleteDBInstance](src/main/java/com/example/neptune/scenerio/NeptuneScenario.kt#L275) +- [DeleteDBSubnetGroup](src/main/java/com/example/neptune/scenerio/NeptuneScenario.kt#L179) +- [DescribeDBClusters](src/main/java/com/example/neptune/scenerio/NeptuneScenario.kt#L400) +- [DescribeDBInstances](src/main/java/com/example/neptune/scenerio/NeptuneScenario.kt#L447) +- [StartDBCluster](src/main/java/com/example/neptune/scenerio/NeptuneScenario.kt#L344) +- [StopDBCluster](src/main/java/com/example/neptune/scenerio/NeptuneScenario.kt#L372)