Loading...
Loading...
This skill should be used when the user asks to "create Pulumi Python project", "write Pulumi Python code", "use Pulumi ESC with Python", "set up OIDC for Pulumi", or mentions Pulumi infrastructure automation with Python.
npx skill4agent add dirien/claude-skills pulumi-python# Create new Python project
pulumi new python
# Or with a cloud-specific template
pulumi new aws-python
pulumi new azure-python
pulumi new gcp-pythonmy-project/
├── Pulumi.yaml
├── Pulumi.dev.yaml # Stack config (use ESC instead)
├── __main__.py
├── requirements.txt # or pyproject.toml
└── venv/ # Virtual environmentpulumi config set# Create ESC environment
pulumi env init myorg/myproject-dev
# Edit environment
pulumi env edit myorg/myproject-dev
# Link to Pulumi stack
pulumi config env add myorg/myproject-devvalues:
# Static configuration
pulumiConfig:
aws:region: us-west-2
myapp:instanceType: t3.medium
# Dynamic OIDC credentials for AWS
aws:
login:
fn::open::aws-login:
oidc:
roleArn: arn:aws:iam::123456789:role/pulumi-oidc
sessionName: pulumi-deploy
# Pull secrets from AWS Secrets Manager
secrets:
fn::open::aws-secrets:
region: us-west-2
login: ${aws.login}
get:
dbPassword:
secretId: prod/database/password
# Expose to environment variables
environmentVariables:
AWS_ACCESS_KEY_ID: ${aws.login.accessKeyId}
AWS_SECRET_ACCESS_KEY: ${aws.login.secretAccessKey}
AWS_SESSION_TOKEN: ${aws.login.sessionToken}import pulumi
import pulumi_aws as aws
# Get configuration from ESC
config = pulumi.Config()
instance_type = config.require("instanceType")
# Create resources with proper tagging
bucket = aws.s3.Bucket(
"my-bucket",
versioning=aws.s3.BucketVersioningArgs(
enabled=True,
),
server_side_encryption_configuration=aws.s3.BucketServerSideEncryptionConfigurationArgs(
rule=aws.s3.BucketServerSideEncryptionConfigurationRuleArgs(
apply_server_side_encryption_by_default=aws.s3.BucketServerSideEncryptionConfigurationRuleApplyServerSideEncryptionByDefaultArgs(
sse_algorithm="AES256",
),
),
),
tags={
"Environment": pulumi.get_stack(),
"ManagedBy": "Pulumi",
},
)
# Export outputs
pulumi.export("bucket_name", bucket.id)
pulumi.export("bucket_arn", bucket.arn)import pulumi
import pulumi_aws as aws
bucket = aws.s3.Bucket(
"my-bucket",
versioning={"enabled": True},
server_side_encryption_configuration={
"rule": {
"apply_server_side_encryption_by_default": {
"sse_algorithm": "AES256",
},
},
},
tags={
"Environment": pulumi.get_stack(),
"ManagedBy": "Pulumi",
},
)import pulumi
from pulumi_aws import lb
class WebServiceArgs:
def __init__(self, port: pulumi.Input[int], image_uri: pulumi.Input[str]):
self.port = port
self.image_uri = image_uri
class WebService(pulumi.ComponentResource):
url: pulumi.Output[str]
def __init__(self, name: str, args: WebServiceArgs, opts: pulumi.ResourceOptions = None):
super().__init__("custom:app:WebService", name, {}, opts)
# Create child resources with parent=self
load_balancer = lb.LoadBalancer(
f"{name}-lb",
load_balancer_type="application",
# ... configuration
opts=pulumi.ResourceOptions(parent=self),
)
self.url = load_balancer.dns_name
self.register_outputs({
"url": self.url,
})import pulumi
# Reference outputs from networking stack
networking_stack = pulumi.StackReference("myorg/networking/prod")
vpc_id = networking_stack.get_output("vpc_id")
subnet_ids = networking_stack.get_output("private_subnet_ids")import pulumi
# Apply transformation
uppercase_name = bucket.id.apply(lambda id: id.upper())
# Combine multiple outputs
combined = pulumi.Output.all(bucket.id, bucket.arn).apply(
lambda args: f"Bucket {args[0]} has ARN {args[1]}"
)
# Using Output.concat for string interpolation
message = pulumi.Output.concat("Bucket ARN: ", bucket.arn)
# Conditional resources
is_prod = pulumi.get_stack() == "prod"
if is_prod:
alarm = aws.cloudwatch.MetricAlarm(
"alarm",
# ... configuration
)# Run pulumi commands with ESC credentials
pulumi env run myorg/aws-dev -- pulumi up
# Run tests with secrets
pulumi env run myorg/test-env -- pytest
# Open environment and export to shell
pulumi env open myorg/myproject-dev --format shellimport pulumi
import asyncio
# Pulumi programs are single-threaded
# Use Output.from_input for async-like patterns
async def fetch_data():
# Async operation
return {"key": "value"}
# Convert async result to Output
data = pulumi.Output.from_input(asyncio.get_event_loop().run_until_complete(fetch_data()))my-component/
├── PulumiPlugin.yaml # Required for multi-language
├── pyproject.toml # or requirements.txt
└── __main__.py # Component + entry pointruntime: pythonfrom typing import Optional
import pulumi
from pulumi import Input, Output, ResourceOptions
from pulumi.provider.experimental import component_provider_host
import pulumi_aws as aws
class SecureBucketArgs:
"""Args class - use Input types for all properties."""
def __init__(
self,
bucket_name: Input[str],
enable_versioning: Optional[Input[bool]] = None,
tags: Optional[Input[dict]] = None,
):
self.bucket_name = bucket_name
self.enable_versioning = enable_versioning or True
self.tags = tags
class SecureBucket(pulumi.ComponentResource):
"""A secure S3 bucket with encryption and versioning."""
bucket_id: Output[str]
bucket_arn: Output[str]
# Constructor must have 'args' parameter with type annotation
def __init__(
self,
name: str,
args: SecureBucketArgs,
opts: Optional[ResourceOptions] = None,
):
super().__init__("myorg:storage:SecureBucket", name, {}, opts)
bucket = aws.s3.Bucket(
f"{name}-bucket",
bucket=args.bucket_name,
versioning={"enabled": args.enable_versioning},
server_side_encryption_configuration={
"rule": {
"apply_server_side_encryption_by_default": {
"sse_algorithm": "AES256",
},
},
},
tags=args.tags,
opts=ResourceOptions(parent=self),
)
self.bucket_id = bucket.id
self.bucket_arn = bucket.arn
self.register_outputs({
"bucket_id": self.bucket_id,
"bucket_arn": self.bucket_arn,
})
# Entry point for multi-language support
if __name__ == "__main__":
component_provider_host(
name="python-components",
components=[SecureBucket],
)# Consume from git repository
pulumi package add github.com/myorg/my-component
# With version tag
pulumi package add github.com/myorg/my-component@v1.0.0
# Local development
pulumi package add /path/to/local/my-componentpulumi.Input[T]__init__argsOptional[Input[T]]pulumi previewpulumi upvenvpoetryuv# Environment Commands (pulumi env)
pulumi env init <org>/<project>/<env> # Create environment
pulumi env edit <org>/<env> # Edit environment
pulumi env open <org>/<env> # View resolved values
pulumi env run <org>/<env> -- <command> # Run with env vars
pulumi env version tag <org>/<env> <tag> # Tag version
# Pulumi Commands
pulumi new python # New project
pulumi config env add <org>/<env> # Link ESC environment
pulumi preview # Preview changes
pulumi up # Deploy
pulumi stack output # View outputs
pulumi destroy # Tear down
# Dependency Management
pip install -r requirements.txt # Install deps (pip)
poetry add pulumi-aws # Add dep (poetry)
uv add pulumi-aws # Add dep (uv)# Pulumi.yaml
runtime:
name: python
options:
toolchain: pip
virtualenv: venv# Pulumi.yaml
runtime:
name: python
options:
toolchain: poetry# Pulumi.yaml
runtime:
name: python
options:
toolchain: uv
virtualenv: .venv# Pulumi.yaml - Enable type checking
runtime:
name: python
options:
typechecker: mypy # or pyright# Using Args classes (type-safe)
bucket = aws.s3.Bucket(
"bucket",
versioning=aws.s3.BucketVersioningArgs(enabled=True),
)
# Using dict literals (concise)
bucket = aws.s3.Bucket(
"bucket",
versioning={"enabled": True},
)