Name | pulumi-command JSON |
Version |
1.0.1
JSON |
| download |
home_page | None |
Summary | The Pulumi Command Provider enables you to execute commands and scripts either locally or remotely as part of the Pulumi resource model. |
upload_time | 2024-07-19 10:24:29 |
maintainer | None |
docs_url | None |
author | None |
requires_python | >=3.8 |
license | Apache-2.0 |
keywords |
pulumi
command
category/utility
kind/native
|
VCS |
 |
bugtrack_url |
|
requirements |
No requirements were recorded.
|
Travis-CI |
No Travis.
|
coveralls test coverage |
No coveralls.
|
[](https://github.com/pulumi/pulumi-command/actions)
[](https://slack.pulumi.com)
[](https://www.npmjs.com/package/@pulumi/command)
[](https://pypi.org/project/pulumi-command)
[](https://badge.fury.io/nu/pulumi.command)
[](https://pkg.go.dev/github.com/pulumi/pulumi-command/sdk/go)
[](https://github.com/pulumi/pulumi-command/blob/master/LICENSE)
# Pulumi Command Provider (preview)
The Pulumi Command Provider enables you to execute commands and scripts either locally or remotely as part of the Pulumi resource model. Resources in the command package support running scripts on `create` and `destroy` operations, supporting stateful local and remote command execution.
There are many scenarios where the Command package can be useful:
* Running a command locally after creating a resource, to register it with an external service
* Running a command locally before deleting a resource, to deregister it with an external service
* Running a command remotely on a remote host immediately after creating it
* Copying a file to a remote host after creating it (potentially as a script to be executed afterwards)
* As a simple alternative to some use cases for Dynamic Providers (especially in languages which do not yet support Dynamic Providers).
Some users may have experience with Terraform "provisioners", and the Command package offers support for similar scenarios. However, the Command package is provided as independent resources which can be combined with other resources in many interesting ways. This has many strengths, but also some differences, such as the fact that a Command resource failing does not cause a resource it is operating on to fail.
You can use the Command package from a Pulumi program written in any Pulumi language: C#, Go, JavaScript/TypeScript, Python, and YAML.
You'll need to [install and configure the Pulumi CLI](https://pulumi.com/docs/get-started/install) if you haven't already.
> **NOTE**: The Command package is in preview. The API design may change ahead of general availability based on [user feedback](https://github.com/pulumi/pulumi-command/issues).
## Examples
### A simple local resource (random)
The simplest use case for `local.Command` is to just run a command on `create`, which can return some value which will be stored in the state file, and will be persistent for the life of the stack (or until the resource is destroyed or replaced). The example below uses this as an alternative to the `random` package to create some randomness which is stored in Pulumi state.
```ts
import { local } from "@pulumi/command";
const random = new local.Command("random", {
create: "openssl rand -hex 16",
});
export const output = random.stdout;
```
```go
package main
import (
"github.com/pulumi/pulumi-command/sdk/go/command/local"
"github.com/pulumi/pulumi/sdk/v3/go/pulumi"
)
func main() {
pulumi.Run(func(ctx *pulumi.Context) error {
random, err := local.NewCommand(ctx, "my-bucket", &local.CommandInput{
Create: pulumi.String("openssl rand -hex 16"),
})
if err != nil {
return err
}
ctx.Export("output", random.Stdout)
return nil
})
}
```
### Remote provisioning of an EC2 instance
This example creates and EC2 instance, and then uses `remote.Command` and `remote.CopyFile` to run commands and copy files to the remote instance (via SSH). Similar things are possible with Azure, Google Cloud and other cloud provider virtual machines. Support for Windows-based VMs is being tracked [here](https://github.com/pulumi/pulumi-command/issues/15).
Note that implicit and explicit (`dependsOn`) dependencies can be used to control the order that these `Command` and `CopyFile` resources are constructed relative to each other and to the cloud resources they depend on. This ensures that the `create` operations run after all dependencies are created, and the `delete` operations run before all dependencies are deleted.
Because the `Command` and `CopyFile` resources replace on changes to their connection, if the EC2 instance is replaced, the commands will all re-run on the new instance (and the `delete` operations will run on the old instance).
Note also that `deleteBeforeReplace` can be composed with `Command` resources to ensure that the `delete` operation on an "old" instance is run before the `create` operation of the new instance, in case a scarce resource is managed by the command. Similarly, other resource options can naturally be applied to `Command` resources, like `ignoreChanges`.
```ts
import { interpolate, Config } from "@pulumi/pulumi";
import { local, remote, types } from "@pulumi/command";
import * as aws from "@pulumi/aws";
import * as fs from "fs";
import * as os from "os";
import * as path from "path";
import { size } from "./size";
const config = new Config();
const keyName = config.get("keyName") ?? new aws.ec2.KeyPair("key", { publicKey: config.require("publicKey") }).keyName;
const privateKeyBase64 = config.get("privateKeyBase64");
const privateKey = privateKeyBase64 ? Buffer.from(privateKeyBase64, 'base64').toString('ascii') : fs.readFileSync(path.join(os.homedir(), ".ssh", "id_rsa")).toString("utf8");
const secgrp = new aws.ec2.SecurityGroup("secgrp", {
description: "Foo",
ingress: [
{ protocol: "tcp", fromPort: 22, toPort: 22, cidrBlocks: ["0.0.0.0/0"] },
{ protocol: "tcp", fromPort: 80, toPort: 80, cidrBlocks: ["0.0.0.0/0"] },
],
});
const ami = aws.ec2.getAmiOutput({
owners: ["amazon"],
mostRecent: true,
filters: [{
name: "name",
values: ["amzn2-ami-hvm-2.0.????????-x86_64-gp2"],
}],
});
const server = new aws.ec2.Instance("server", {
instanceType: size,
ami: ami.id,
keyName: keyName,
vpcSecurityGroupIds: [secgrp.id],
}, { replaceOnChanges: ["instanceType"] });
// Now set up a connection to the instance and run some provisioning operations on the instance.
const connection: types.input.remote.ConnectionInput = {
host: server.publicIp,
user: "ec2-user",
privateKey: privateKey,
};
const hostname = new remote.Command("hostname", {
connection,
create: "hostname",
});
new remote.Command("remotePrivateIP", {
connection,
create: interpolate`echo ${server.privateIp} > private_ip.txt`,
delete: `rm private_ip.txt`,
}, { deleteBeforeReplace: true });
new local.Command("localPrivateIP", {
create: interpolate`echo ${server.privateIp} > private_ip.txt`,
delete: `rm private_ip.txt`,
}, { deleteBeforeReplace: true });
const sizeFile = new remote.CopyFile("size", {
connection,
localPath: "./size.ts",
remotePath: "size.ts",
})
const catSize = new remote.Command("checkSize", {
connection,
create: "cat size.ts",
}, { dependsOn: sizeFile })
export const confirmSize = catSize.stdout;
export const publicIp = server.publicIp;
export const publicHostName = server.publicDns;
export const hostnameStdout = hostname.stdout;
```
### Invoking a Lambda during Pulumi deployment
There may be cases where it is useful to run some code within an AWS Lambda or other serverless function during the deployment. For example, this may allow running some code from within a VPC, or with a specific role, without needing to have persistent compute available (such as the EC2 example above).
Note that the Lambda function itself can be created within the same Pulumi program, and then invoked after creation.
The example below simply creates some random value within the Lambda, which is a very roundabout way of doing the same thing as the first "random" example above, but this pattern can be used for more complex scenarios where the Lambda does things a local script could not.
```ts
import { local } from "@pulumi/command";
import * as aws from "@pulumi/aws";
import * as crypto from "crypto";
const f = new aws.lambda.CallbackFunction("f", {
publish: true,
callback: async (ev: any) => {
return crypto.randomBytes(ev.len/2).toString('hex');
}
});
const rand = new local.Command("execf", {
create: `aws lambda invoke --function-name "$FN" --payload '{"len": 10}' --cli-binary-format raw-in-base64-out out.txt >/dev/null && cat out.txt | tr -d '"' && rm out.txt`,
environment: {
FN: f.qualifiedArn,
AWS_REGION: aws.config.region!,
AWS_PAGER: "",
},
})
export const output = rand.stdout;
```
### Using `local.Command `with CURL to manage external REST API
This example uses `local.Command` to create a simple resource provider for managing GitHub labels, by invoking `curl` commands on `create` and `delete` commands against the GitHub REST API. A similar approach could be applied to build other simple providers against any REST API directly from within Pulumi programs in any language. This approach is somewhat limited by the fact that `local.Command` does not yet support `diff`/`read`. Support for [Read](https://github.com/pulumi/pulumi-command/issues/432) and [Diff](https://github.com/pulumi/pulumi-command/issues/433) may be added in the future.
This example also shows how `local.Command` can be used as an implementation detail inside a nicer abstraction, like the `GitHubLabel` component defined below.
```ts
import * as pulumi from "@pulumi/pulumi";
import * as random from "@pulumi/random";
import { local } from "@pulumi/command";
interface LabelArgs {
owner: pulumi.Input<string>;
repo: pulumi.Input<string>;
name: pulumi.Input<string>;
githubToken: pulumi.Input<string>;
}
class GitHubLabel extends pulumi.ComponentResource {
public url: pulumi.Output<string>;
constructor(name: string, args: LabelArgs, opts?: pulumi.ComponentResourceOptions) {
super("example:github:Label", name, args, opts);
const label = new local.Command("label", {
create: "./create_label.sh",
delete: "./delete_label.sh",
environment: {
OWNER: args.owner,
REPO: args.repo,
NAME: args.name,
GITHUB_TOKEN: args.githubToken,
}
}, { parent: this });
const response = label.stdout.apply(JSON.parse);
this.url = response.apply((x: any) => x.url as string);
}
}
const config = new pulumi.Config();
const rand = new random.RandomString("s", { length: 10, special: false });
const label = new GitHubLabel("l", {
owner: "pulumi",
repo: "pulumi-command",
name: rand.result,
githubToken: config.requireSecret("githubToken"),
});
export const labelUrl = label.url;
```
```sh
# create_label.sh
curl \
-s \
-X POST \
-H "authorization: Bearer $GITHUB_TOKEN" \
-H "Accept: application/vnd.github.v3+json" \
https://api.github.com/repos/$OWNER/$REPO/labels \
-d "{\"name\":\"$NAME\"}"
```
```sh
# delete_label.sh
curl \
-s \
-X DELETE \
-H "authorization: Bearer $GITHUB_TOKEN" \
-H "Accept: application/vnd.github.v3+json" \
https://api.github.com/repos/$OWNER/$REPO/labels/$NAME
```
### Graceful cleanup of workloads in a Kubernetes cluster
There are cases where it's important to run some cleanup operation before destroying a resource such as when destroying the resource does not properly handle orderly cleanup. For example, destroying an EKS Cluster will not ensure that all Kubernetes object finalizers are run, which may lead to leaking external resources managed by those Kubernetes resources. This example shows how we can use a `delete`-only `Command` to ensure some cleanup is run within a cluster before destroying it.
```yaml
resources:
cluster:
type: eks:Cluster
cleanupKubernetesNamespaces:
# We could also use `RemoteCommand` to run this from
# within a node in the cluster.
type: command:local:Command
properties:
# This will run before the cluster is destroyed.
# Everything else will need to depend on this resource
# to ensure this cleanup doesn't happen too early.
delete: |
kubectl --kubeconfig <(echo "$KUBECONFIG_DATA") delete namespace nginx
# Process substitution "<()" doesn't work in the default interpreter sh.
interpreter: ["/bin/bash", "-c"]
environment:
KUBECONFIG_DATA: "${cluster.kubeconfigJson}"
```
```ts
import * as pulumi from "@pulumi/pulumi";
import * as command from "@pulumi/command";
import * as eks from "@pulumi/eks";
const cluster = new eks.Cluster("cluster", {});
// We could also use `RemoteCommand` to run this from within a node in the cluster
const cleanupKubernetesNamespaces = new command.local.Command("cleanupKubernetesNamespaces", {
// This will run before the cluster is destroyed. Everything else will need to
// depend on this resource to ensure this cleanup doesn't happen too early.
"delete": "kubectl --kubeconfig <(echo \"$KUBECONFIG_DATA\") delete namespace nginx\n",
// Process substitution "<()" doesn't work in the default interpreter sh.
interpreter: [
"/bin/bash",
"-c",
],
environment: {
KUBECONFIG_DATA: cluster.kubeconfigJson,
},
});
```
### Working with Assets and Paths
When a local command creates assets as part of its execution, these can be captured by specifying `assetPaths` or `archivePaths`.
```typescript
const lambdaBuild = local.runOutput({
dir: "../my-function",
command: `yarn && yarn build`,
archivePaths: ["dist/**"],
});
new aws.lambda.Function("my-function", {
code: lambdaBuild.archive,
// ...
});
```
When using the `assetPaths` and `archivePaths`, they take a list of 'globs'.
- We only include files not directories for assets and archives.
- Path separators are `/` on all platforms - including Windows.
- Patterns starting with `!` are 'exclude' rules.
- Rules are evaluated in order, so exclude rules should be after inclusion rules.
- `*` matches anything except `/`
- `**` matches anything, _including_ `/`
- All returned paths are relative to the working directory (without leading `./`) e.g. `file.text` or `subfolder/file.txt`.
- For full details of the globbing syntax, see [github.com/gobwas/glob](https://github.com/gobwas/glob)
#### Asset Paths Example
Given the rules:
```yaml
- "assets/**"
- "src/**.js"
- "!**secret.*"
```
When evaluating against this folder:
```yaml
- assets/
- logos/
- logo.svg
- src/
- index.js
- secret.js
```
The following paths will be returned:
```yaml
- assets/logos/logo.svg
- src/index.js
```
## Building
### Dependencies
- Go 1.17
- NodeJS 10.X.X or later
- Python 3.6 or later
- .NET Core 3.1
Please refer to [Contributing to Pulumi](https://github.com/pulumi/pulumi/blob/master/CONTRIBUTING.md) for installation
guidance.
### Building locally
Run the following commands to install Go modules, generate all SDKs, and build the provider:
```
$ make ensure
$ make build
$ make install
```
Add the `bin` folder to your `$PATH` or copy the `bin/pulumi-resource-command` file to another location in your `$PATH`.
### Running an example
Navigate to the simple example and run Pulumi:
```
$ cd examples/simple
$ yarn link @pulumi/command
$ yarn install
$ pulumi up
```
Raw data
{
"_id": null,
"home_page": null,
"name": "pulumi-command",
"maintainer": null,
"docs_url": null,
"requires_python": ">=3.8",
"maintainer_email": null,
"keywords": "pulumi, command, category/utility, kind/native",
"author": null,
"author_email": null,
"download_url": "https://files.pythonhosted.org/packages/dd/c0/a6304d7697a22cec1f71101613eb81fe5f98549c36040d40a5d0a9cc759e/pulumi_command-1.0.1.tar.gz",
"platform": null,
"description": "[](https://github.com/pulumi/pulumi-command/actions)\n[](https://slack.pulumi.com)\n[](https://www.npmjs.com/package/@pulumi/command)\n[](https://pypi.org/project/pulumi-command)\n[](https://badge.fury.io/nu/pulumi.command)\n[](https://pkg.go.dev/github.com/pulumi/pulumi-command/sdk/go)\n[](https://github.com/pulumi/pulumi-command/blob/master/LICENSE)\n\n# Pulumi Command Provider (preview)\n\nThe Pulumi Command Provider enables you to execute commands and scripts either locally or remotely as part of the Pulumi resource model. Resources in the command package support running scripts on `create` and `destroy` operations, supporting stateful local and remote command execution.\n\nThere are many scenarios where the Command package can be useful:\n\n* Running a command locally after creating a resource, to register it with an external service\n* Running a command locally before deleting a resource, to deregister it with an external service\n* Running a command remotely on a remote host immediately after creating it\n* Copying a file to a remote host after creating it (potentially as a script to be executed afterwards)\n* As a simple alternative to some use cases for Dynamic Providers (especially in languages which do not yet support Dynamic Providers).\n\nSome users may have experience with Terraform \"provisioners\", and the Command package offers support for similar scenarios. However, the Command package is provided as independent resources which can be combined with other resources in many interesting ways. This has many strengths, but also some differences, such as the fact that a Command resource failing does not cause a resource it is operating on to fail.\n\nYou can use the Command package from a Pulumi program written in any Pulumi language: C#, Go, JavaScript/TypeScript, Python, and YAML.\nYou'll need to [install and configure the Pulumi CLI](https://pulumi.com/docs/get-started/install) if you haven't already.\n\n\n> **NOTE**: The Command package is in preview. The API design may change ahead of general availability based on [user feedback](https://github.com/pulumi/pulumi-command/issues). \n\n## Examples\n\n### A simple local resource (random)\n\nThe simplest use case for `local.Command` is to just run a command on `create`, which can return some value which will be stored in the state file, and will be persistent for the life of the stack (or until the resource is destroyed or replaced). The example below uses this as an alternative to the `random` package to create some randomness which is stored in Pulumi state.\n\n```ts\nimport { local } from \"@pulumi/command\";\n\nconst random = new local.Command(\"random\", {\n create: \"openssl rand -hex 16\",\n});\n\nexport const output = random.stdout;\n```\n\n```go\npackage main\n\nimport (\n\t\"github.com/pulumi/pulumi-command/sdk/go/command/local\"\n\t\"github.com/pulumi/pulumi/sdk/v3/go/pulumi\"\n)\n\nfunc main() {\n\tpulumi.Run(func(ctx *pulumi.Context) error {\n\n\t\trandom, err := local.NewCommand(ctx, \"my-bucket\", &local.CommandInput{\n\t\t\tCreate: pulumi.String(\"openssl rand -hex 16\"),\n\t\t})\n\t\tif err != nil {\n\t\t\treturn err\n\t\t}\n\n\t\tctx.Export(\"output\", random.Stdout)\n\t\treturn nil\n\t})\n}\n```\n\n### Remote provisioning of an EC2 instance\n\nThis example creates and EC2 instance, and then uses `remote.Command` and `remote.CopyFile` to run commands and copy files to the remote instance (via SSH). Similar things are possible with Azure, Google Cloud and other cloud provider virtual machines. Support for Windows-based VMs is being tracked [here](https://github.com/pulumi/pulumi-command/issues/15).\n\nNote that implicit and explicit (`dependsOn`) dependencies can be used to control the order that these `Command` and `CopyFile` resources are constructed relative to each other and to the cloud resources they depend on. This ensures that the `create` operations run after all dependencies are created, and the `delete` operations run before all dependencies are deleted.\n\nBecause the `Command` and `CopyFile` resources replace on changes to their connection, if the EC2 instance is replaced, the commands will all re-run on the new instance (and the `delete` operations will run on the old instance).\n\nNote also that `deleteBeforeReplace` can be composed with `Command` resources to ensure that the `delete` operation on an \"old\" instance is run before the `create` operation of the new instance, in case a scarce resource is managed by the command. Similarly, other resource options can naturally be applied to `Command` resources, like `ignoreChanges`.\n\n```ts\nimport { interpolate, Config } from \"@pulumi/pulumi\";\nimport { local, remote, types } from \"@pulumi/command\";\nimport * as aws from \"@pulumi/aws\";\nimport * as fs from \"fs\";\nimport * as os from \"os\";\nimport * as path from \"path\";\nimport { size } from \"./size\";\n\nconst config = new Config();\nconst keyName = config.get(\"keyName\") ?? new aws.ec2.KeyPair(\"key\", { publicKey: config.require(\"publicKey\") }).keyName;\nconst privateKeyBase64 = config.get(\"privateKeyBase64\");\nconst privateKey = privateKeyBase64 ? Buffer.from(privateKeyBase64, 'base64').toString('ascii') : fs.readFileSync(path.join(os.homedir(), \".ssh\", \"id_rsa\")).toString(\"utf8\");\n\nconst secgrp = new aws.ec2.SecurityGroup(\"secgrp\", {\n description: \"Foo\",\n ingress: [\n { protocol: \"tcp\", fromPort: 22, toPort: 22, cidrBlocks: [\"0.0.0.0/0\"] },\n { protocol: \"tcp\", fromPort: 80, toPort: 80, cidrBlocks: [\"0.0.0.0/0\"] },\n ],\n});\n\nconst ami = aws.ec2.getAmiOutput({\n owners: [\"amazon\"],\n mostRecent: true,\n filters: [{\n name: \"name\",\n values: [\"amzn2-ami-hvm-2.0.????????-x86_64-gp2\"],\n }],\n});\n\nconst server = new aws.ec2.Instance(\"server\", {\n instanceType: size,\n ami: ami.id,\n keyName: keyName,\n vpcSecurityGroupIds: [secgrp.id],\n}, { replaceOnChanges: [\"instanceType\"] });\n\n// Now set up a connection to the instance and run some provisioning operations on the instance.\n\nconst connection: types.input.remote.ConnectionInput = {\n host: server.publicIp,\n user: \"ec2-user\",\n privateKey: privateKey,\n};\n\nconst hostname = new remote.Command(\"hostname\", {\n connection,\n create: \"hostname\",\n});\n\nnew remote.Command(\"remotePrivateIP\", {\n connection,\n create: interpolate`echo ${server.privateIp} > private_ip.txt`,\n delete: `rm private_ip.txt`,\n}, { deleteBeforeReplace: true });\n\nnew local.Command(\"localPrivateIP\", {\n create: interpolate`echo ${server.privateIp} > private_ip.txt`,\n delete: `rm private_ip.txt`,\n}, { deleteBeforeReplace: true });\n\nconst sizeFile = new remote.CopyFile(\"size\", {\n connection,\n localPath: \"./size.ts\",\n remotePath: \"size.ts\",\n})\n\nconst catSize = new remote.Command(\"checkSize\", {\n connection,\n create: \"cat size.ts\",\n}, { dependsOn: sizeFile })\n\nexport const confirmSize = catSize.stdout;\nexport const publicIp = server.publicIp;\nexport const publicHostName = server.publicDns;\nexport const hostnameStdout = hostname.stdout;\n```\n\n### Invoking a Lambda during Pulumi deployment\n\nThere may be cases where it is useful to run some code within an AWS Lambda or other serverless function during the deployment. For example, this may allow running some code from within a VPC, or with a specific role, without needing to have persistent compute available (such as the EC2 example above).\n\nNote that the Lambda function itself can be created within the same Pulumi program, and then invoked after creation. \n\nThe example below simply creates some random value within the Lambda, which is a very roundabout way of doing the same thing as the first \"random\" example above, but this pattern can be used for more complex scenarios where the Lambda does things a local script could not.\n\n```ts\nimport { local } from \"@pulumi/command\";\nimport * as aws from \"@pulumi/aws\";\nimport * as crypto from \"crypto\";\n\nconst f = new aws.lambda.CallbackFunction(\"f\", {\n publish: true,\n callback: async (ev: any) => {\n return crypto.randomBytes(ev.len/2).toString('hex');\n }\n});\n\nconst rand = new local.Command(\"execf\", {\n create: `aws lambda invoke --function-name \"$FN\" --payload '{\"len\": 10}' --cli-binary-format raw-in-base64-out out.txt >/dev/null && cat out.txt | tr -d '\"' && rm out.txt`,\n environment: {\n FN: f.qualifiedArn,\n AWS_REGION: aws.config.region!,\n AWS_PAGER: \"\",\n },\n})\n\nexport const output = rand.stdout;\n```\n\n### Using `local.Command `with CURL to manage external REST API\n\nThis example uses `local.Command` to create a simple resource provider for managing GitHub labels, by invoking `curl` commands on `create` and `delete` commands against the GitHub REST API. A similar approach could be applied to build other simple providers against any REST API directly from within Pulumi programs in any language. This approach is somewhat limited by the fact that `local.Command` does not yet support `diff`/`read`. Support for [Read](https://github.com/pulumi/pulumi-command/issues/432) and [Diff](https://github.com/pulumi/pulumi-command/issues/433) may be added in the future.\n\nThis example also shows how `local.Command` can be used as an implementation detail inside a nicer abstraction, like the `GitHubLabel` component defined below.\n\n```ts\nimport * as pulumi from \"@pulumi/pulumi\";\nimport * as random from \"@pulumi/random\";\nimport { local } from \"@pulumi/command\";\n\ninterface LabelArgs {\n owner: pulumi.Input<string>;\n repo: pulumi.Input<string>;\n name: pulumi.Input<string>;\n githubToken: pulumi.Input<string>;\n}\n\nclass GitHubLabel extends pulumi.ComponentResource {\n public url: pulumi.Output<string>;\n\n constructor(name: string, args: LabelArgs, opts?: pulumi.ComponentResourceOptions) {\n super(\"example:github:Label\", name, args, opts);\n\n const label = new local.Command(\"label\", {\n create: \"./create_label.sh\",\n delete: \"./delete_label.sh\",\n environment: {\n OWNER: args.owner,\n REPO: args.repo,\n NAME: args.name,\n GITHUB_TOKEN: args.githubToken,\n }\n }, { parent: this });\n\n const response = label.stdout.apply(JSON.parse);\n this.url = response.apply((x: any) => x.url as string);\n }\n}\n\nconst config = new pulumi.Config();\nconst rand = new random.RandomString(\"s\", { length: 10, special: false });\n\nconst label = new GitHubLabel(\"l\", {\n owner: \"pulumi\",\n repo: \"pulumi-command\",\n name: rand.result,\n githubToken: config.requireSecret(\"githubToken\"),\n});\n\nexport const labelUrl = label.url;\n```\n\n```sh\n# create_label.sh\ncurl \\\n -s \\\n -X POST \\\n -H \"authorization: Bearer $GITHUB_TOKEN\" \\\n -H \"Accept: application/vnd.github.v3+json\" \\\n https://api.github.com/repos/$OWNER/$REPO/labels \\\n -d \"{\\\"name\\\":\\\"$NAME\\\"}\"\n```\n\n```sh\n# delete_label.sh\ncurl \\\n -s \\\n -X DELETE \\\n -H \"authorization: Bearer $GITHUB_TOKEN\" \\\n -H \"Accept: application/vnd.github.v3+json\" \\\n https://api.github.com/repos/$OWNER/$REPO/labels/$NAME\n```\n\n### Graceful cleanup of workloads in a Kubernetes cluster\n\nThere are cases where it's important to run some cleanup operation before destroying a resource such as when destroying the resource does not properly handle orderly cleanup. For example, destroying an EKS Cluster will not ensure that all Kubernetes object finalizers are run, which may lead to leaking external resources managed by those Kubernetes resources. This example shows how we can use a `delete`-only `Command` to ensure some cleanup is run within a cluster before destroying it.\n\n```yaml\nresources:\n cluster:\n type: eks:Cluster\n\n cleanupKubernetesNamespaces:\n # We could also use `RemoteCommand` to run this from\n # within a node in the cluster.\n type: command:local:Command\n properties:\n # This will run before the cluster is destroyed.\n # Everything else will need to depend on this resource\n # to ensure this cleanup doesn't happen too early.\n delete: |\n kubectl --kubeconfig <(echo \"$KUBECONFIG_DATA\") delete namespace nginx\n # Process substitution \"<()\" doesn't work in the default interpreter sh.\n interpreter: [\"/bin/bash\", \"-c\"]\n environment:\n KUBECONFIG_DATA: \"${cluster.kubeconfigJson}\"\n```\n\n```ts\nimport * as pulumi from \"@pulumi/pulumi\";\nimport * as command from \"@pulumi/command\";\nimport * as eks from \"@pulumi/eks\";\n\nconst cluster = new eks.Cluster(\"cluster\", {});\n\n// We could also use `RemoteCommand` to run this from within a node in the cluster\nconst cleanupKubernetesNamespaces = new command.local.Command(\"cleanupKubernetesNamespaces\", {\n // This will run before the cluster is destroyed. Everything else will need to \n // depend on this resource to ensure this cleanup doesn't happen too early.\n \"delete\": \"kubectl --kubeconfig <(echo \\\"$KUBECONFIG_DATA\\\") delete namespace nginx\\n\",\n // Process substitution \"<()\" doesn't work in the default interpreter sh.\n interpreter: [\n \"/bin/bash\",\n \"-c\",\n ],\n environment: {\n KUBECONFIG_DATA: cluster.kubeconfigJson,\n },\n});\n```\n\n### Working with Assets and Paths\n\nWhen a local command creates assets as part of its execution, these can be captured by specifying `assetPaths` or `archivePaths`.\n\n```typescript\nconst lambdaBuild = local.runOutput({\n dir: \"../my-function\",\n command: `yarn && yarn build`,\n archivePaths: [\"dist/**\"],\n});\n\nnew aws.lambda.Function(\"my-function\", {\n code: lambdaBuild.archive,\n // ...\n});\n```\n\nWhen using the `assetPaths` and `archivePaths`, they take a list of 'globs'.\n- We only include files not directories for assets and archives.\n- Path separators are `/` on all platforms - including Windows.\n- Patterns starting with `!` are 'exclude' rules.\n- Rules are evaluated in order, so exclude rules should be after inclusion rules.\n- `*` matches anything except `/`\n- `**` matches anything, _including_ `/`\n- All returned paths are relative to the working directory (without leading `./`) e.g. `file.text` or `subfolder/file.txt`.\n- For full details of the globbing syntax, see [github.com/gobwas/glob](https://github.com/gobwas/glob)\n\n#### Asset Paths Example\n\nGiven the rules:\n```yaml\n- \"assets/**\"\n- \"src/**.js\"\n- \"!**secret.*\"\n```\n\nWhen evaluating against this folder:\n\n```yaml\n- assets/\n - logos/\n - logo.svg\n- src/\n - index.js\n - secret.js\n```\n\nThe following paths will be returned:\n\n```yaml\n- assets/logos/logo.svg\n- src/index.js\n```\n\n## Building\n\n### Dependencies\n\n- Go 1.17\n- NodeJS 10.X.X or later\n- Python 3.6 or later\n- .NET Core 3.1\n\nPlease refer to [Contributing to Pulumi](https://github.com/pulumi/pulumi/blob/master/CONTRIBUTING.md) for installation\nguidance.\n\n### Building locally\n\nRun the following commands to install Go modules, generate all SDKs, and build the provider:\n\n```\n$ make ensure\n$ make build\n$ make install\n```\n\nAdd the `bin` folder to your `$PATH` or copy the `bin/pulumi-resource-command` file to another location in your `$PATH`.\n\n### Running an example\n\nNavigate to the simple example and run Pulumi:\n\n```\n$ cd examples/simple\n$ yarn link @pulumi/command\n$ yarn install\n$ pulumi up\n```\n\n",
"bugtrack_url": null,
"license": "Apache-2.0",
"summary": "The Pulumi Command Provider enables you to execute commands and scripts either locally or remotely as part of the Pulumi resource model.",
"version": "1.0.1",
"project_urls": {
"Homepage": "https://pulumi.com",
"Repository": "https://github.com/pulumi/pulumi-command"
},
"split_keywords": [
"pulumi",
" command",
" category/utility",
" kind/native"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "adf1a7616bc13081a110d8c2d0fe26c42249735154fa2732c86fab9ef8de0844",
"md5": "50acbdbd0d3439a057f9f96e47eb7dc1",
"sha256": "672cdea9c0ced0f79ed47e578267a2b2160dcf88626dde34ee96f5524a003574"
},
"downloads": -1,
"filename": "pulumi_command-1.0.1-py3-none-any.whl",
"has_sig": false,
"md5_digest": "50acbdbd0d3439a057f9f96e47eb7dc1",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.8",
"size": 34742,
"upload_time": "2024-07-19T10:24:26",
"upload_time_iso_8601": "2024-07-19T10:24:26.782383Z",
"url": "https://files.pythonhosted.org/packages/ad/f1/a7616bc13081a110d8c2d0fe26c42249735154fa2732c86fab9ef8de0844/pulumi_command-1.0.1-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "ddc0a6304d7697a22cec1f71101613eb81fe5f98549c36040d40a5d0a9cc759e",
"md5": "d39a974d4f2219f896b502b34fac946a",
"sha256": "58e123707956aa7a9be2ce89c009642539cde5d9fa02e1e10501662600894843"
},
"downloads": -1,
"filename": "pulumi_command-1.0.1.tar.gz",
"has_sig": false,
"md5_digest": "d39a974d4f2219f896b502b34fac946a",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.8",
"size": 31532,
"upload_time": "2024-07-19T10:24:29",
"upload_time_iso_8601": "2024-07-19T10:24:29.187309Z",
"url": "https://files.pythonhosted.org/packages/dd/c0/a6304d7697a22cec1f71101613eb81fe5f98549c36040d40a5d0a9cc759e/pulumi_command-1.0.1.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2024-07-19 10:24:29",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "pulumi",
"github_project": "pulumi-command",
"travis_ci": false,
"coveralls": false,
"github_actions": true,
"lcname": "pulumi-command"
}