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

asset-management.mddocs/

Asset Management

Pulumi's asset system enables packaging and deployment of files, directories, and remote content as part of your infrastructure resources, commonly used for Lambda functions, container images, and configuration files.

Core Asset Classes

abstract class Asset {
  readonly __pulumiAsset: boolean;
}

abstract class Archive {
  readonly __pulumiArchive: boolean;
}

// File-based assets
class FileAsset extends Asset {
  constructor(path: string);
  readonly path: string;
}

class StringAsset extends Asset {
  constructor(text: string);
  readonly text: string;
}

class RemoteAsset extends Asset {
  constructor(uri: string);
  readonly uri: string;
}

// Archive types
class FileArchive extends Archive {
  constructor(path: string);
  readonly path: string;
}

class AssetArchive extends Archive {
  constructor(assets: AssetMap);
  readonly assets: AssetMap;
}

class RemoteArchive extends Archive {
  constructor(uri: string);
  readonly uri: string;
}

type AssetMap = {[name: string]: Asset | Archive};

Usage Examples

File Assets

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

// Single file asset
const configFile = new pulumi.asset.FileAsset("./config/app.json");

// Use in S3 bucket object
const configObject = new aws.s3.BucketObject("app-config", {
  bucket: bucket.id,
  key: "config/app.json",
  source: configFile,
  contentType: "application/json",
});

// String-based asset for generated content
const indexHtml = new pulumi.asset.StringAsset(`
<!DOCTYPE html>
<html>
<head>
    <title>My App</title>
</head>
<body>
    <h1>Welcome to My App</h1>
    <p>Environment: ${config.require("environment")}</p>
</body>
</html>
`);

const indexObject = new aws.s3.BucketObject("index", {
  bucket: bucket.id,
  key: "index.html",
  source: indexHtml,
  contentType: "text/html",
});

Archive Assets

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

// Directory archive for Lambda function
const lambdaCode = new pulumi.asset.FileArchive("./lambda-function");

const lambdaFunction = new aws.lambda.Function("my-function", {
  runtime: "nodejs18.x",
  code: lambdaCode,
  handler: "index.handler",
  role: lambdaRole.arn,
});

// Selective file archive
const webAssets = new pulumi.asset.AssetArchive({
  "index.html": new pulumi.asset.FileAsset("./web/index.html"),
  "styles.css": new pulumi.asset.FileAsset("./web/styles.css"),
  "app.js": new pulumi.asset.FileAsset("./web/app.js"),
  "assets/": new pulumi.asset.FileArchive("./web/assets"),
});

const websiteZip = new aws.s3.BucketObject("website", {
  bucket: bucket.id,
  key: "website.zip",
  source: webAssets,
});

Remote Assets

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

// Remote file asset
const remoteScript = new pulumi.asset.RemoteAsset(
  "https://raw.githubusercontent.com/myorg/scripts/main/setup.sh"
);

// Remote archive
const applicationCode = new pulumi.asset.RemoteArchive(
  "https://github.com/myorg/myapp/archive/v1.2.3.tar.gz"
);

const lambdaFromRemote = new aws.lambda.Function("remote-function", {
  runtime: "python3.9",
  code: applicationCode,
  handler: "main.handler",
  role: lambdaRole.arn,
});

Dynamic Asset Generation

import * as pulumi from "@pulumi/pulumi";
import * as aws from "@pulumi/aws";
import * as fs from "fs";
import * as path from "path";

// Generate configuration file dynamically
const config = new pulumi.Config();
const environment = config.require("environment");

const appConfig = {
  environment: environment,
  apiEndpoint: config.require("apiEndpoint"),
  features: {
    authentication: config.getBoolean("enableAuth") || false,
    analytics: config.getBoolean("enableAnalytics") || false,
  },
  buildTimestamp: new Date().toISOString(),
};

const configAsset = new pulumi.asset.StringAsset(
  JSON.stringify(appConfig, null, 2)
);

// Create archive with generated content
const deploymentPackage = new pulumi.asset.AssetArchive({
  "config.json": configAsset,
  "app/": new pulumi.asset.FileArchive("./src"),
  "package.json": new pulumi.asset.FileAsset("./package.json"),
  "yarn.lock": new pulumi.asset.FileAsset("./yarn.lock"),
});

Container Image Assets

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

// Build and push container image
const repository = new aws.ecr.Repository("app-repo");

const image = new docker.Image("app-image", {
  build: {
    context: "./app",
    dockerfile: "./app/Dockerfile",
  },
  imageName: pulumi.interpolate`${repository.repositoryUrl}:latest`,
  registry: {
    server: repository.repositoryUrl,
    username: "AWS",
    password: pulumi.output(aws.ecr.getAuthorizationToken({
      registryId: repository.registryId,
    })).authorizationToken.apply(token => 
      Buffer.from(token, "base64").toString().split(":")[1]
    ),
  },
});

// Use in ECS task definition
const taskDefinition = new aws.ecs.TaskDefinition("app-task", {
  family: "my-app",
  containerDefinitions: pulumi.jsonStringify([{
    name: "app",
    image: image.imageName,
    memory: 512,
    essential: true,
    portMappings: [{
      containerPort: 8080,
      hostPort: 8080,
    }],
  }]),
});

Asset Transformation Patterns

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

// Template processing function
function processTemplate(templatePath: string, variables: Record<string, any>): pulumi.asset.StringAsset {
  let template = fs.readFileSync(templatePath, "utf8");
  
  Object.entries(variables).forEach(([key, value]) => {
    const placeholder = new RegExp(`{{\\s*${key}\\s*}}`, "g");
    template = template.replace(placeholder, String(value));
  });
  
  return new pulumi.asset.StringAsset(template);
}

// Use template processing
const config = new pulumi.Config();
const nginxConfig = processTemplate("./templates/nginx.conf.template", {
  serverName: config.require("serverName"),
  upstreamHost: config.require("upstreamHost"),
  upstreamPort: config.getNumber("upstreamPort") || 8080,
});

// Bundle multiple processed templates
const configBundle = new pulumi.asset.AssetArchive({
  "nginx.conf": nginxConfig,
  "mime.types": new pulumi.asset.FileAsset("./config/mime.types"),
  "ssl/": new pulumi.asset.FileArchive("./ssl-certificates"),
});

Conditional Assets

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

const config = new pulumi.Config();
const environment = config.require("environment");

// Different assets based on environment
function getLambdaCode(): pulumi.asset.Archive {
  if (environment === "development") {
    // Use local development build
    return new pulumi.asset.FileArchive("./dist/dev");
  } else if (environment === "production") {
    // Use optimized production build
    return new pulumi.asset.FileArchive("./dist/prod");
  } else {
    // Use pre-built artifact from CI/CD
    const artifactUrl = config.require("artifactUrl");
    return new pulumi.asset.RemoteArchive(artifactUrl);
  }
}

const lambdaFunction = new aws.lambda.Function("app-function", {
  runtime: "nodejs18.x",
  code: getLambdaCode(),
  handler: "index.handler",
  role: lambdaRole.arn,
  environment: {
    variables: {
      NODE_ENV: environment,
    },
  },
});

Asset Validation and Helpers

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

// Utility function to validate assets exist
function validateAssetPath(assetPath: string): string {
  const fullPath = path.resolve(assetPath);
  if (!fs.existsSync(fullPath)) {
    throw new Error(`Asset path does not exist: ${fullPath}`);
  }
  return assetPath;
}

// Helper for creating archives with validation
function createValidatedArchive(paths: Record<string, string>): pulumi.asset.AssetArchive {
  const assets: Record<string, pulumi.asset.Asset | pulumi.asset.Archive> = {};
  
  Object.entries(paths).forEach(([key, assetPath]) => {
    validateAssetPath(assetPath);
    
    const stats = fs.statSync(assetPath);
    if (stats.isDirectory()) {
      assets[key] = new pulumi.asset.FileArchive(assetPath);
    } else {
      assets[key] = new pulumi.asset.FileAsset(assetPath);
    }
  });
  
  return new pulumi.asset.AssetArchive(assets);
}

// Usage with validation
const applicationBundle = createValidatedArchive({
  "src/": "./src",
  "package.json": "./package.json",
  "config.json": "./config/production.json",
});

Best Practices

  • Use FileArchive for packaging entire directories (Lambda functions, web assets)
  • Use StringAsset for generated configuration files and templates
  • Validate asset paths exist before creating assets
  • Use remote assets for artifacts from CI/CD pipelines
  • Consider asset size limits for target services (e.g., Lambda 50MB limit)
  • Use appropriate content types for S3 objects
  • Cache remote assets locally during development when possible
  • Use consistent directory structures for deployable assets
  • Include only necessary files in archives to minimize deployment size
  • Use environment-specific asset selection patterns for different deployment stages

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