CtrlK
BlogDocsLog inGet started
Tessl Logo

tessl/npm-pulumi--pulumi

Pulumi's Node.js SDK for infrastructure-as-code platform that allows you to create, deploy, and manage infrastructure using familiar programming languages and tools.

85

1.02x
Overview
Eval results
Files

utilities.mddocs/

Utilities

Pulumi provides various utility functions and helpers for common operations, type checking, and metadata access in Pulumi programs.

Type Utilities

function isInstance<T>(obj: any, name: string): obj is T;
function hasTrueBooleanMember(obj: any, memberName: string): boolean;
function hasFunctionMember(obj: any, memberName: string): boolean;

Collection Utilities

function values(obj: any): any[];
function union<T>(set1: Set<T>, set2: Set<T>): Set<T>;
function toObject<T, V>(source: Iterable<T>, keySelector: (item: T) => string, elementSelector?: (item: T) => V): {[key: string]: V};
function groupBy<T, V>(source: Iterable<T>, keySelector: (item: T) => string, elementSelector?: (item: T) => V): {[key: string]: V[]};

Metadata Functions

function getOrganization(): string;
function getProject(): string;
function getStack(): string;
function getRootDirectory(): string;

Configuration Constants

const disableResourceReferences: boolean;
const errorOutputString: boolean;

Usage Examples

Type Checking Utilities

import * as pulumi from "@pulumi/pulumi";

// Safe type checking for Pulumi types across versions
function isOutput(obj: any): obj is pulumi.Output<any> {
  return pulumi.utils.isInstance(obj, "__pulumiOutput");
}

function isResource(obj: any): obj is pulumi.Resource {
  return pulumi.utils.isInstance(obj, "__pulumiResource");
}

function isAsset(obj: any): obj is pulumi.Asset {
  return pulumi.utils.isInstance(obj, "__pulumiAsset");
}

// Check for specific members
function hasOutputMethods(obj: any): boolean {
  return pulumi.utils.hasFunctionMember(obj, "apply") &&
         pulumi.utils.hasFunctionMember(obj, "isKnown");
}

// Check boolean flags
function isProtectedResource(obj: any): boolean {
  return pulumi.utils.hasTrueBooleanMember(obj, "__pulumiProtected");
}

// Usage
const bucket = new aws.s3.Bucket("my-bucket");

if (isResource(bucket)) {
  console.log("Object is a Pulumi resource");
}

if (isOutput(bucket.id)) {
  console.log("Bucket ID is an Output");
}

Collection Operations

import * as pulumi from "@pulumi/pulumi";

// Convert array to object with key selector
const resources = [
  { name: "web-server-1", type: "ec2", region: "us-east-1" },
  { name: "web-server-2", type: "ec2", region: "us-west-2" },
  { name: "db-server-1", type: "rds", region: "us-east-1" },
];

const resourcesByName = pulumi.iterable.toObject(
  resources,
  item => item.name,
  item => item
);

console.log(resourcesByName["web-server-1"]); // { name: "web-server-1", ... }

// Group resources by type
const resourcesByType = pulumi.iterable.groupBy(
  resources,
  item => item.type,
  item => item.name
);

console.log(resourcesByType.ec2); // ["web-server-1", "web-server-2"]
console.log(resourcesByType.rds); // ["db-server-1"]

// Get object values
const config = {
  environment: "production",
  region: "us-east-1",
  debug: false,
};

const configValues = pulumi.utils.values(config);
console.log(configValues); // ["production", "us-east-1", false]

// Set operations
const set1 = new Set(["a", "b", "c"]);
const set2 = new Set(["c", "d", "e"]);
const combined = pulumi.utils.union(set1, set2);
console.log(Array.from(combined)); // ["a", "b", "c", "d", "e"]

Metadata Access

import * as pulumi from "@pulumi/pulumi";

// Get deployment context information
const organization = pulumi.getOrganization();
const project = pulumi.getProject();
const stack = pulumi.getStack();
const rootDir = pulumi.getRootDirectory();

console.log(`Deploying ${organization}/${project}/${stack}`);
console.log(`Project root: ${rootDir}`);

// Use metadata in resource naming
const resourcePrefix = `${project}-${stack}`;

const bucket = new aws.s3.Bucket(`${resourcePrefix}-assets`, {
  bucket: `${organization}-${project}-${stack}-assets`,
  tags: {
    Project: project,
    Stack: stack,
    Organization: organization,
  },
});

// Create environment-aware configurations
function getEnvironmentConfig() {
  const stackName = pulumi.getStack();
  
  const configs = {
    development: {
      instanceType: "t3.micro",
      minSize: 1,
      maxSize: 2,
    },
    staging: {
      instanceType: "t3.small",
      minSize: 2,
      maxSize: 4,
    },
    production: {
      instanceType: "t3.medium",
      minSize: 3,
      maxSize: 10,
    },
  };
  
  return configs[stackName as keyof typeof configs] || configs.development;
}

const envConfig = getEnvironmentConfig();
console.log(`Using configuration for ${pulumi.getStack()}:`, envConfig);

Utility Helper Functions

import * as pulumi from "@pulumi/pulumi";

// Helper for checking resource types
function getResourceType(resource: pulumi.Resource): string {
  if (pulumi.utils.isInstance(resource, "__pulumiCustomResource")) {
    return "CustomResource";
  } else if (pulumi.utils.isInstance(resource, "__pulumiComponentResource")) {
    return "ComponentResource";
  } else if (pulumi.utils.isInstance(resource, "__pulumiProviderResource")) {
    return "ProviderResource";
  }
  return "Resource";
}

// Helper for extracting output values safely
function extractOutputValue<T>(output: pulumi.Output<T>, defaultValue: T): Promise<T> {
  return output.apply(value => value !== undefined ? value : defaultValue);
}

// Helper for creating resource names with metadata
function createResourceName(baseName: string, suffix?: string): string {
  const project = pulumi.getProject();
  const stack = pulumi.getStack();
  
  let name = `${project}-${stack}-${baseName}`;
  if (suffix) {
    name += `-${suffix}`;
  }
  
  // Ensure name meets resource naming requirements
  return name.toLowerCase().replace(/[^a-z0-9-]/g, '-');
}

// Helper for validating resource configurations
function validateResourceConfig(config: any, required: string[]): void {
  const missing = required.filter(key => !pulumi.utils.hasTrueBooleanMember(config, key) && !config[key]);
  
  if (missing.length > 0) {
    throw new pulumi.RunError(`Missing required configuration: ${missing.join(", ")}`);
  }
}

// Usage examples
const bucket = new aws.s3.Bucket("assets");
console.log(`Resource type: ${getResourceType(bucket)}`);

const bucketId = await extractOutputValue(bucket.id, "default-bucket-id");
console.log(`Bucket ID: ${bucketId}`);

const resourceName = createResourceName("web-server", "primary");
console.log(`Generated name: ${resourceName}`);

validateResourceConfig({ name: "test", enabled: true }, ["name", "enabled"]);

Debugging and Inspection Utilities

import * as pulumi from "@pulumi/pulumi";

// Utility for inspecting resource properties
function inspectResource(resource: pulumi.Resource): void {
  console.log(`Resource URN: ${resource.urn}`);
  
  if (pulumi.utils.isInstance(resource, "__pulumiCustomResource")) {
    const customResource = resource as pulumi.CustomResource;
    customResource.id.apply(id => console.log(`Resource ID: ${id}`));
  }
  
  // Check for common properties
  const resourceAny = resource as any;
  Object.keys(resourceAny).forEach(key => {
    if (pulumi.utils.isInstance(resourceAny[key], "__pulumiOutput")) {
      console.log(`Property ${key} is an Output`);
    }
  });
}

// Utility for checking Pulumi state
function checkPulumiState(): void {
  const hasSecrets = Object.keys(process.env).some(key => 
    key.startsWith('PULUMI_CONFIG_') && key.endsWith('_SECRET')
  );
  
  console.log(`Project: ${pulumi.getProject()}`);
  console.log(`Stack: ${pulumi.getStack()}`);
  console.log(`Organization: ${pulumi.getOrganization()}`);
  console.log(`Has secrets: ${hasSecrets}`);
}

// Development helper for listing all outputs
function listAllOutputs(resources: pulumi.Resource[]): void {
  resources.forEach((resource, index) => {
    console.log(`Resource ${index}: ${getResourceType(resource)}`);
    
    const resourceAny = resource as any;
    Object.keys(resourceAny).forEach(key => {
      if (pulumi.utils.isInstance(resourceAny[key], "__pulumiOutput")) {
        resourceAny[key].apply((value: any) => {
          console.log(`  ${key}: ${JSON.stringify(value)}`);
        });
      }
    });
  });
}

// Usage
const bucket = new aws.s3.Bucket("debug-bucket");
const database = new aws.rds.Instance("debug-db", {
  engine: "postgres",
  instanceClass: "db.t3.micro",
});

inspectResource(bucket);
checkPulumiState();
listAllOutputs([bucket, database]);

Performance and Optimization Helpers

import * as pulumi from "@pulumi/pulumi";

// Helper for batching operations
function batchOperations<T, R>(
  items: T[],
  batchSize: number,
  operation: (batch: T[]) => Promise<R[]>
): Promise<R[]> {
  const batches: T[][] = [];
  
  for (let i = 0; i < items.length; i += batchSize) {
    batches.push(items.slice(i, i + batchSize));
  }
  
  return Promise.all(batches.map(operation)).then(results => 
    results.flat()
  );
}

// Helper for memoizing expensive operations
function memoize<T extends (...args: any[]) => any>(fn: T): T {
  const cache = new Map();
  
  return ((...args: any[]) => {
    const key = JSON.stringify(args);
    
    if (cache.has(key)) {
      return cache.get(key);
    }
    
    const result = fn(...args);
    cache.set(key, result);
    return result;
  }) as T;
}

// Memoized expensive configuration calculation
const getExpensiveConfig = memoize((stack: string) => {
  console.log(`Computing expensive config for ${stack}`);
  // Expensive operation here
  return {
    setting1: `value-for-${stack}`,
    setting2: Math.random(),
  };
});

// Usage
const config1 = getExpensiveConfig(pulumi.getStack()); // Computed
const config2 = getExpensiveConfig(pulumi.getStack()); // Cached

Best Practices

  • Use type checking utilities for robust cross-version compatibility
  • Leverage metadata functions for consistent resource naming
  • Use collection utilities for data transformation and grouping
  • Implement proper validation using utility functions
  • Use memoization for expensive computations
  • Create reusable helper functions for common patterns
  • Use debugging utilities during development
  • Leverage set operations for managing collections
  • Extract utility functions into shared modules
  • Document custom utility functions thoroughly
  • Test utility functions independently
  • Use TypeScript types with utility functions for better safety

Install with Tessl CLI

npx tessl i tessl/npm-pulumi--pulumi

docs

asset-management.md

automation.md

configuration.md

dynamic-resources.md

index.md

logging-diagnostics.md

output-system.md

provider-development.md

resource-management.md

runtime-operations.md

stack-references.md

utilities.md

tile.json