diff --git a/.devcontainer/devcontainer.json b/.devcontainer/devcontainer.json new file mode 100644 index 0000000..b64e15c --- /dev/null +++ b/.devcontainer/devcontainer.json @@ -0,0 +1,29 @@ +{ + "name": "Pulumi Builder", + "image": "mcr.microsoft.com/devcontainers/base:ubuntu", + "features": { + "ghcr.io/devcontainers/features/go:1": {}, + "ghcr.io/guiyomh/features/golangci-lint:0": {}, + "ghcr.io/devcontainers/features/dotnet:2": {}, + "ghcr.io/devcontainers/features/python:1": {}, + "ghcr.io/devcontainers-community/npm-features/typescript:1": {}, + "ghcr.io/devcontainers/features/git:1": {}, + "ghcr.io/jungaretti/features/make:1": {}, + "ghcr.io/flexwie/devcontainer-features/pulumi:1": {}, + "ghcr.io/stuartleeks/dev-container-features/shell-history:0": {} + }, + "customizations": { + "vscode": { + "extensions": [ + "DavidAnson.vscode-markdownlint", + "bierner.markdown-preview-github-styles", + "esbenp.prettier-vscode", + "ms-vscode.makefile-tools", + "golang.go", + "github.vscode-github-actions", + "pulumi.pulumi-lsp-client" + ] + } + }, + "postCreateCommand": "${PWD}/.devcontainer/setup.sh" +} diff --git a/.devcontainer/setup.sh b/.devcontainer/setup.sh new file mode 100755 index 0000000..97c106d --- /dev/null +++ b/.devcontainer/setup.sh @@ -0,0 +1,97 @@ +#!/usr/bin/env bash + +set -eEo pipefail + +# Create a temporary directory to download pulumictl +download_dir=$(mktemp -d) + +# Cleanup function to remove the temporary directory +cleanup() { + local dir="${1}" + echo "Cleaning up download destination directory ${dir}" + rm -rf "${dir}" +} + +# Set up trap to call cleanup on exit +trap 'cleanup "${download_dir}"' EXIT + +# Function to get the latest release tag from pulumi/pulumictl +get_latest_pulumictl_release() { + local arch="${1:-amd64}" + local os="${2:-linux}" + curl -s https://api.github.com/repos/pulumi/pulumictl/releases/latest | \ + jq -r '.assets[] | + select(.browser_download_url | + test("pulumictl-.*'"${os}-${arch}"'.tar.gz")) | + .browser_download_url' +} + +# Function to download the latest pulumictl release for a given OS and arch +# Usage: download_pulumictl_release +download_pulumictl_release() { + local dest_dir="$1" + local arch="${2:-amd64}" + local os="${3:-linux}" + local url + local filename + + filename="pulumictl-${os}-${arch}.tar.gz" + + url=$(get_latest_pulumictl_release "${arch}" "${os}") + if [[ -z "$url" ]]; then + echo "No pulumictl release found for ${os} ${arch}" + return 1 + fi + + mkdir -p "${dest_dir}" + echo "Downloading pulumictl ${url} for ${os} ${arch}" + curl -s -L "${url}" -o "${dest_dir}/${filename}" + echo "Downloaded pulumictl to ${dest_dir}/${filename}" +} + +get_os() { + local os + os=$(uname -s) + case $os in + Linux) echo "linux";; + Darwin) echo "darwin";; + *) echo "Unsupported OS: ${os}" >&2 ; return 1;; + esac +} + +get_arch() { + local arch + arch=$(uname -m) + case $arch in + x86_64) echo "amd64";; + aarch64 | arm64) echo "arm64";; + *) echo "Unsupported architecture: ${arch}" >&2 ; return 1;; + esac +} + +install_pulumictl() { + local dest_dir="${1}" + local os + local arch + local filename + + if [[ -z "${dest_dir}" ]]; then + echo "Destination directory is required" + return 1 + fi + + os=$(get_os) || return 1 + arch=$(get_arch) || return 1 + + download_pulumictl_release "${dest_dir}" "${arch}" "${os}" + + filename="pulumictl-${os}-${arch}.tar.gz" + echo "Extracting ${filename} to ${dest_dir}" + tar -xzf "${dest_dir}/${filename}" -C "${dest_dir}" + sudo mv "${dest_dir}/pulumictl" "/usr/local/bin/pulumictl" + sudo chmod +x "/usr/local/bin/pulumictl" + echo "Installed pulumictl to /usr/local/bin/pulumictl" +} + +# Install pulumictl +install_pulumictl "${download_dir}" diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 23b08a2..06f996b 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -5,21 +5,111 @@ Do you want to hack on Pulumi? Awesome! We are so happy to have you. Please refer to the [main Pulumi repo](https://github.com/pulumi/pulumi/)'s [CONTRIBUTING.md file]( https://github.com/pulumi/pulumi/blob/master/CONTRIBUTING.md) for details on how to do so. +## Prerequisites + +- Go 1.24 or later +- Node.js 18 or later +- Python 3.7 or later +- .NET SDK 6.0 or later +- [`pulumictl`](https://github.com/pulumi/pulumictl) + +This repository includes a config to setup a [devcontainer](https://containers.dev/), which will +setup an environment with all necessary requirements installed. + ## Committing Generated Code Code generated for Pulumi SDKs should be checked in as part of the pull request containing a -particular change. To generate code after making changes, run `make` from the root of this +particular change. To generate code after making changes, run `make build` from the root of this repository. -If a large number of seemingly-unrelated diffs are produced by `make` (for example, lots of changes -to comments unrelated to the change you are making), ensure that the latest dependencies for the -provider are installed by running `make ensure` in the root of the repository. +## Building the Provider + +The provider is generated from the Event Store Cloud Terraform provider. To build the Pulumi provider +and generate SDKs: + +1. Ensure you're in the development container +2. Run the following command to build all SDKs: + + ```bash + make build + ``` + +This will: + +- Build the provider binary +- Generate SDKs for Node.js, Python, Go, and .NET + +## Manual Testing + +> [!IMPORTANT] +> This will create and destroy **real** Kurrent Cloud resources + +To test your changes before committing them: + +1. Build the provider using the [steps above](#building-the-provider) +2. Install the provider locally: + + ```bash + pulumi plugin install resource eventstorecloud --file bin/pulumi-resource-eventstorecloud + ``` + +3. Temporarily set the version in the TypeScript SDKs `package.json` + + ```bash + sed -i 's/${VERSION}/0.0.1-dev/' sdk/nodejs/package.json + ``` + +4. Login to Pulumi locally to prevent being prompted to login to the hosted service + + ```bash + pulumi login --local + ``` + +5. Change directory to the test project + + ```bash + cd test + ``` + +6. Install the local version of the TypeScript SDK + + ```bash + yarn add @eventstore/pulumi-eventstorecloud@file:../sdk/nodejs + ``` + +7. Create a new stack + + ```bash + PULUMI_CONFIG_PASSPHRASE=very-secure-passphrase pulumi stack init -s dev + ``` + +8. Set config values + + ```bash + pulumi config set eventstorecloud:organizationId + pulumi config set eventstorecloud:token --secret + ``` + +9. Create the stack + + ```bash + pulumi up -y + ``` + +10. Once you're done, clean up resources and revert the change to `package.json` + + ```bash + PULUMI_CONFIG_PASSPHRASE=very-secure-passphrase pulumi destroy -y && + pulumi stack rm dev -y && + cd .. && sed -i 's/0.0.1-dev/${VERSION}/' sdk/nodejs/package.json + ``` -## Running Integration Tests +## Publishing a New Release -The examples and integration tests in this repository will create and destroy real AWS -cloud resources while running. Before running these tests, make sure that you have -[configured Pulumi with AWS](https://pulumi.io/install/aws.html) successfully once before. +Once all changes have been merged to the `main` branch and you're ready to cut a new release, all +that needs to be done is to create a new tag using semver format, e.g. v0.2.21. -_TODO: Add any steps you need to take to run integration tests here_ +Once the tag has been pushed to the Github repo, an action will be triggered. This will create new a +new Github release with the binary artifacts, as well as publish the release to NPM and Nuget. +The provider docs in the Pulumi Package Registry will be updated automatically sometime later. diff --git a/Makefile b/Makefile index df29d8d..32259cb 100644 --- a/Makefile +++ b/Makefile @@ -103,6 +103,7 @@ lint_provider:: provider # lint the provider code cleanup:: # cleans up the temporary directory rm -r $(WORKING_DIR)/bin rm -f provider/cmd/${PROVIDER}/schema.go + rm -rf node_modules nuget help:: @grep '^[^.#]\+:\s\+.*#' Makefile | \ @@ -111,10 +112,11 @@ help:: clean:: rm -rf sdk/{dotnet,nodejs,go,python} + rm -rf test/node_modules install_plugins:: [ -x $(shell which pulumi) ] || curl -fsSL https://get.pulumi.com | sh - pulumi plugin install resource random 4.6.0 + pulumi plugin install resource random install_dotnet_sdk:: mkdir -p $(WORKING_DIR)/nuget @@ -131,4 +133,3 @@ install_sdks:: install_dotnet_sdk install_python_sdk install_nodejs_sdk test:: cd examples && go test -v -tags=all -parallel ${TESTPARALLELISM} -timeout 2h - diff --git a/README.md b/README.md index 3d0b19f..0d6fec8 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ -# Pulumi provider for Event Store Cloud +# Pulumi provider for Kurrent Cloud (formerly Event Store Cloud) -The Event Store Cloud provider allows you to manage resources in [Event Store Cloud](https://eventstore.com/cloud). +The `eventstorecloud` provider allows you to manage resources in [Kurrent Cloud](https://www.kurrent.io/kurrent-cloud). ## Installing @@ -12,47 +12,53 @@ For projects that use .NET and Go Pulumi SDK you have to install the provider be Use the following command to add the plugin to your environment: -``` -pulumi plugin install resource eventstorecloud [version] \ - --server https://github.com/EventStore/pulumi-eventstorecloud/releases/download/[version] -``` - -Example: - -``` -pulumi plugin install resource eventstorecloud v0.2.3 \ - --server https://github.com/EventStore/pulumi-eventstorecloud/releases/download/v0.2.7 +```bash +pulumi plugin install resource eventstorecloud --server github://api.github.com/kurrent-io ``` ### Configuration -The following configuration points are available for the `eventstorecloud` provider: +The following configuration options are required for the `eventstorecloud` provider: - `eventstorecloud:organizationId` - the organization ID for an existing organization in Event Store Cloud - `eventstorecloud:token` - a valid refresh token for an Event Store Cloud account with admin access to the organization +Alternatively, these values can be set via the `ESC_ORG_ID` and `ESC_TOKEN` environment variables. ### Node.js (Java/TypeScript) To use from JavaScript or TypeScript in Node.js, install using either `npm`: - $ npm install @eventstore/pulumi-eventstorecloud +```bash +npm install @eventstore/pulumi-eventstorecloud +``` or `yarn`: - $ yarn add @eventstore/pulumi-eventstorecloud +```bash +yarn add @eventstore/pulumi-eventstorecloud +``` -### .NET +### Go -Add the NuGet package `Pulumi.EventStoreCloud` to your Pulumi project, which uses the .NET Pulumi SDK. +To use from Go, use `go get` to grab the latest version of the library -### Python +```bash +go get github.com/EventStore/pulumi-eventstorecloud/sdk/go/eventstorecloud +``` -[WIP] +### .NET -### Go +To use from .NET, install using `dotnet add package`: -To use from Go, use `go get` to grab the latest version of the library +```bash +dotnet add package Pulumi.EventStoreCloud +``` + +### Python + +\[WIP] - $ go get github.com/EventStore/pulumi-eventstorecloud/sdk/go/eventstorecloud +## Reference +For detailed reference documentation, please visit [the Pulumi registry](https://www.pulumi.com/registry/packages/eventstorecloud/). diff --git a/test/Pulumi.yaml b/test/Pulumi.yaml new file mode 100644 index 0000000..d533673 --- /dev/null +++ b/test/Pulumi.yaml @@ -0,0 +1,10 @@ +name: esc-test +description: esc-test +runtime: + name: nodejs + options: + packagemanager: npm +config: + pulumi:tags: + value: + pulumi:template: typescript diff --git a/test/index.ts b/test/index.ts new file mode 100644 index 0000000..c97c99a --- /dev/null +++ b/test/index.ts @@ -0,0 +1,32 @@ +import * as pulumi from "@pulumi/pulumi"; +import * as esc from "@eventstore/pulumi-eventstorecloud"; +import * as random from "@pulumi/random"; + +const name = new random.RandomPet("project-name", {}); + +const project = new esc.Project("project", { + name: pulumi.interpolate`test-project-${name.id}`, +}); + +const network = new esc.Network("network", { + name: pulumi.interpolate`network-${name.id}`, + projectId: project.id, + resourceProvider: "aws", + region: "us-west-2", + cidrBlock: "172.21.0.0/16", +}); + +const cluster = new esc.ManagedCluster("server", { + name: pulumi.interpolate`cluster-${name.id}`, + projectId: project.id, + networkId: network.id, + topology: "single-node", + instanceType: "F1", + diskSize: 10, + diskType: "gp3", + diskIops: 3000, + diskThroughput: 125, + serverVersion: "24.10", +}); + +export let clusterDnsName = cluster.dnsName; diff --git a/test/package.json b/test/package.json new file mode 100644 index 0000000..7b0645c --- /dev/null +++ b/test/package.json @@ -0,0 +1,13 @@ +{ + "name": "esc-test", + "main": "index.ts", + "devDependencies": { + "@types/node": "^18", + "typescript": "^5.0.0" + }, + "dependencies": { + "@eventstore/pulumi-eventstorecloud": "file:../sdk/nodejs", + "@pulumi/pulumi": "^3.113.0", + "@pulumi/random": "^4.18.0" + } +} diff --git a/test/tsconfig.json b/test/tsconfig.json new file mode 100644 index 0000000..f960d51 --- /dev/null +++ b/test/tsconfig.json @@ -0,0 +1,18 @@ +{ + "compilerOptions": { + "strict": true, + "outDir": "bin", + "target": "es2020", + "module": "commonjs", + "moduleResolution": "node", + "sourceMap": true, + "experimentalDecorators": true, + "pretty": true, + "noFallthroughCasesInSwitch": true, + "noImplicitReturns": true, + "forceConsistentCasingInFileNames": true + }, + "files": [ + "index.ts" + ] +}