Skip to content
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .github/workflows/ruby-rubypg-integ-tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,8 @@ jobs:
env:
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

bah, L37 and L40 are out of scope for "suggest changes" functionality.

anyway! Can you change those 2.5 -> 3.3 so CI builds against our advertised supported version?

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🚢

CLUSTER_ENDPOINT: ${{ secrets.RUBY_RUBYPG_CLUSTER_ENDPOINT }}
REGION: ${{ secrets.RUBY_RUBYPG_CLUSTER_REGION }}
CLUSTER_USER: admin
run: |
bundle install
wget https://www.amazontrust.com/repository/AmazonRootCA1.pem -O root.pem
rspec
6 changes: 2 additions & 4 deletions ruby/ruby-pg/Gemfile
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,5 @@ source "https://rubygems.org"

gem 'pg', '1.5.9'
gem 'rspec', '3.13.0'
gem 'aws-sdk-core', '3.211.0'
gem 'aws-sigv4', '1.10.1'

gem "aws-sdk-dsql", "~> 1"
gem 'aws-sdk-core', '3.216.0'
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: don't think this is needed, was just for hand-rolled sigv4 token generation

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Removed

gem 'aws-sdk-dsql', '~> 1.6'
125 changes: 106 additions & 19 deletions ruby/ruby-pg/README.md
Original file line number Diff line number Diff line change
@@ -1,43 +1,130 @@
# Aurora DSQL Ruby-pg code examples
# Ruby-pg with Aurora DSQL

## Overview

The code examples in this topic show you how to use the Ruby-pg work with Aurora DSQL.
This code example demonstrates how to use Ruby-pg to interact with Amazon Aurora DSQL (DSQL). The example shows you how
to connect to an Aurora DSQL cluster and perform basic database operations.

## Run the examples
Aurora DSQL is a distributed SQL database service that provides high availability and scalability for
your PostgreSQL-compatible applications. Ruby-pg is a popular PostgreSQL adapter for Ruby that allows
you to interact with PostgreSQL databases using Ruby code.

## About the code example

The example demonstrates a flexible connection approach that works for both admin and non-admin users:

* When connecting as an **admin user**, the example uses the `public` schema and generates an admin authentication
token.
* When connecting as a **non-admin user**, the example uses a custom `myschema` schema and generates a standard
authentication token. The `myschema` schema needs to be created prior to running the example and the **non-admin user** needs to be granted access to the schema.

The code automatically detects the user type and adjusts its behavior accordingly.
The example contains comments explaining the code and the operations being performed.

## ⚠️ Important

* Running this code 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).

## Run the example

### Prerequisites

* Ruby version >=2.5 is needed
* AWS credentials file is configured
* You must have an AWS account, and have your default credentials and AWS Region
configured as described in the
[Globally configuring AWS SDKs and tools](https://docs.aws.amazon.com/credref/latest/refdocs/creds-config-files.html)
guide.
* You must have an Aurora DSQL cluster. For information about creating an Aurora DSQL cluster, see the
[Getting started with Aurora DSQL](https://docs.aws.amazon.com/aurora-dsql/latest/userguide/getting-started.html)
guide.
* If connecting as a non-admin user, ensure the user is linked to an IAM role and is granted access to the `myschema`
schema. See the
[Using database roles with IAM roles](https://docs.aws.amazon.com/aurora-dsql/latest/userguide/using-database-and-iam-roles.html)
guide.


### Setup test running environment
### Driver Dependencies

```sh
Before using the Ruby-pg driver, ensure you have the following prerequisites installed:
Ruby: Ensure you have ruby v3.2+ installed from the [official website](https://www.ruby-lang.org/en/documentation/installation/).

bundle install
Verify install

```bash
ruby --version
```

For example: `v3.2.6"`.
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: CI is using 2.5 which has been EOL since 2017. Can update in a separate PR.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, initially in line 53 we used to have

Ensure you have ruby v2.5+ installed

We changed it to

.. have ruby v3.2+ installed

Should we revert line 53 to v2.5?

Perhaps the line 61 stating

For example: v3.2.6"

Is not even needed?


### Libpq library

Libpq is required by Ruby-pg

#### Obtaining the libpq library

- It is installed with postgres installation. Therefore, if postgres is installed on the system the libpq is present in ../postgres_install_dir/lib, ../postgres_install_dir/include
- It is installed when psql client program is installed, similarily as with postgres installation.
- On some systems libpq can be installed through package manager e.g.
- On Amazon Linux
```
sudo yum install libpq-devel
```
- On Mac libpq can be installed using brew
```
brew install libpq
```
- The [official website](https://www.postgresql.org/download/) may have a package for libpq or psql (which bundles libpq)
- Ultimately, build from source which also can be obtained from [official website](https://www.postgresql.org/ftp/source/)

#### Add libpq to PATH

In some cases, it may be necessary to add the location of the libpq/bin directory to PATH

```
export PATH="$PATH:<your installed location>/libpq/bin"
```

### Install Ruby-pg, Aurora DSQL SDK and other required dependencies

- All the required dependencies are present in the `Gemfile` file. To get all the required dependencies, run the following command from the directory where the `Gemfile` is present.

```bash
bundle install
```

### Run the example tests
### Download the Amazon root certificate from the official trust store

```sh
# Use the account credentials dedicated for ruby
Download the Amazon root certificate from the official trust store.
This example shows one of the available certs that can be used by the client.
Other certs such as AmazonRootCA2.pem, AmazonRootCA3.pem, etc. can also be used.

# Download the Amazon root certificate from the official trust store
# This example shows one of the available certs that can be used by the client;
# other certs such as AmazonRootCA2.pem, AmazonRootCA3.pem, etc. can also be used.
```
wget https://www.amazontrust.com/repository/AmazonRootCA1.pem -O root.pem
```

Place the root.pem file in the same directory as the hello_dsql.rb example file or modify the path to it in the example file.

### Set the environmet variables specifying cluster endpoint, region and cluster user

```
# e.g. 'admin' or 'non_admin_user'
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: implies two valid values. Can leave this open ended with something like "e.g. 'admin' or a custom user"

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed

export CLUSTER_USER=<your cluster user>

# e.g. "foo0bar1baz2quux3quuux4.dsql.us-east-1.on.aws"
export CLUSTER_ENDPOINT="<your cluster endpoint>"
export REGION="<your cluster region>"

rspec
# e.g. "us-east-1"
export REGION="<your cluster region>"
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: other examples call this CLUSTER_REGION

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agree that it would probably be better and consistent with the other related variable names. However, most languages at the moment call it REGION in code samples and readme.md.

Exceptions:
Java, typescript and secret variable names in GitHub action yml files.

I guess we should standardize? Make all to use CLUSTER_REGION?

```

---
### Run the example

Copyright Amazon.com, Inc. or its affiliates. All Rights Reserved.
Execute the following command:

SPDX-License-Identifier: MIT-0
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

License ID should be retained

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Re-added.

```
ruby hello_dsql.rb
```
85 changes: 57 additions & 28 deletions ruby/ruby-pg/lib/hello_dsql.rb
Original file line number Diff line number Diff line change
@@ -1,32 +1,39 @@
require 'pg'
require 'aws-sdk-dsql'

def example(cluster_endpoint, region)
credentials = Aws::SharedCredentials.new()

begin
token_generator = Aws::DSQL::AuthTokenGenerator.new({
def create_connection(cluster_user, cluster_endpoint, region)
# Generate a fresh password token for each connection, to ensure the token is not expired
# when the connection is established
credentials = Aws::CredentialProviderChain.new.resolve
token_generator = Aws::DSQL::AuthTokenGenerator.new({
:credentials => credentials
})

# The token expiration time is optional, and the default value 900 seconds
# if you are not using admin role, use generate_db_connect_auth_token instead
token = token_generator.generate_db_connect_admin_auth_token({

if cluster_user == "admin"
password_token = token_generator.generate_db_connect_admin_auth_token({
:endpoint => cluster_endpoint,
:region => region
})
else
password_token = token_generator.generate_db_connect_auth_token({
:endpoint => cluster_endpoint,
:region => region
})
Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit: file mixes hash styles. PG.connect uses implicit hashes (no {}) and map syntax but token methods above use explicit hashes and 'hash rockets'. See this file for a token generator with the PG.connect style syntax.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Changed

end

conn = PG.connect(
host: cluster_endpoint,
user: 'admin',
password: token,
dbname: 'postgres',
port: 5432,
sslmode: 'require'
)
rescue => _error
raise
end
PG.connect(
host: cluster_endpoint,
user: cluster_user,
password: password_token,
dbname: 'postgres',
port: 5432,
sslmode: 'verify-full',
sslrootcert: "./root.pem"
)

end

def example(conn)

# Create the owner table
conn.exec('CREATE TABLE IF NOT EXISTS owner (
Expand All @@ -50,13 +57,35 @@ def example(cluster_endpoint, region)
# Delete data we just inserted
conn.exec("DELETE FROM owner where name='John Doe'")

rescue => error
puts error.full_message
ensure
unless conn.nil?
conn.finish()
end
end

# Run the example
example(ENV["CLUSTER_ENDPOINT"], ENV["REGION"])
def main()
# Use environment variables.
cluster_endpoint = ENV["CLUSTER_ENDPOINT"]
region = ENV["REGION"]
cluster_user = ENV["CLUSTER_USER"]

# Raise errors if any of the variables are not set.
raise "CLUSTER_ENDPOINT environment variable is not set" unless cluster_endpoint
raise "REGION environment variable is not set" unless region
raise "CLUSTER_USER environment variable is not set" unless cluster_user

begin
conn = create_connection(cluster_user, cluster_endpoint, region)
if cluster_user != 'admin'
conn.exec("SET search_path = myschema")
end
example(conn)
puts "Ruby test passed"
rescue => error
puts error.full_message
puts "Ruby test failed"
raise
ensure
conn.close if conn
end
end

if __FILE__ == $0
main()
end
5 changes: 2 additions & 3 deletions ruby/ruby-pg/spec/smoke_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,8 @@

describe 'perform smoke tests' do
it 'does not raise any exception' do

expect {
example(ENV["CLUSTER_ENDPOINT"], ENV["REGION"])
main()
}.not_to raise_error
end
end
end
Loading