or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

asset-management.mdautomation.mdconfiguration.mddynamic-resources.mdindex.mdlogging-diagnostics.mdoutput-system.mdprovider-development.mdresource-management.mdruntime-operations.mdstack-references.mdutilities.md

utilities.mddocs/

0

# Utilities

1

2

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

3

4

## Type Utilities

5

6

```typescript { .api }

7

function isInstance<T>(obj: any, name: string): obj is T;

8

function hasTrueBooleanMember(obj: any, memberName: string): boolean;

9

function hasFunctionMember(obj: any, memberName: string): boolean;

10

```

11

12

## Collection Utilities

13

14

```typescript { .api }

15

function values(obj: any): any[];

16

function union<T>(set1: Set<T>, set2: Set<T>): Set<T>;

17

function toObject<T, V>(source: Iterable<T>, keySelector: (item: T) => string, elementSelector?: (item: T) => V): {[key: string]: V};

18

function groupBy<T, V>(source: Iterable<T>, keySelector: (item: T) => string, elementSelector?: (item: T) => V): {[key: string]: V[]};

19

```

20

21

## Metadata Functions

22

23

```typescript { .api }

24

function getOrganization(): string;

25

function getProject(): string;

26

function getStack(): string;

27

function getRootDirectory(): string;

28

```

29

30

## Configuration Constants

31

32

```typescript { .api }

33

const disableResourceReferences: boolean;

34

const errorOutputString: boolean;

35

```

36

37

## Usage Examples

38

39

### Type Checking Utilities

40

41

```typescript

42

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

43

44

// Safe type checking for Pulumi types across versions

45

function isOutput(obj: any): obj is pulumi.Output<any> {

46

return pulumi.utils.isInstance(obj, "__pulumiOutput");

47

}

48

49

function isResource(obj: any): obj is pulumi.Resource {

50

return pulumi.utils.isInstance(obj, "__pulumiResource");

51

}

52

53

function isAsset(obj: any): obj is pulumi.Asset {

54

return pulumi.utils.isInstance(obj, "__pulumiAsset");

55

}

56

57

// Check for specific members

58

function hasOutputMethods(obj: any): boolean {

59

return pulumi.utils.hasFunctionMember(obj, "apply") &&

60

pulumi.utils.hasFunctionMember(obj, "isKnown");

61

}

62

63

// Check boolean flags

64

function isProtectedResource(obj: any): boolean {

65

return pulumi.utils.hasTrueBooleanMember(obj, "__pulumiProtected");

66

}

67

68

// Usage

69

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

70

71

if (isResource(bucket)) {

72

console.log("Object is a Pulumi resource");

73

}

74

75

if (isOutput(bucket.id)) {

76

console.log("Bucket ID is an Output");

77

}

78

```

79

80

### Collection Operations

81

82

```typescript

83

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

84

85

// Convert array to object with key selector

86

const resources = [

87

{ name: "web-server-1", type: "ec2", region: "us-east-1" },

88

{ name: "web-server-2", type: "ec2", region: "us-west-2" },

89

{ name: "db-server-1", type: "rds", region: "us-east-1" },

90

];

91

92

const resourcesByName = pulumi.iterable.toObject(

93

resources,

94

item => item.name,

95

item => item

96

);

97

98

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

99

100

// Group resources by type

101

const resourcesByType = pulumi.iterable.groupBy(

102

resources,

103

item => item.type,

104

item => item.name

105

);

106

107

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

108

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

109

110

// Get object values

111

const config = {

112

environment: "production",

113

region: "us-east-1",

114

debug: false,

115

};

116

117

const configValues = pulumi.utils.values(config);

118

console.log(configValues); // ["production", "us-east-1", false]

119

120

// Set operations

121

const set1 = new Set(["a", "b", "c"]);

122

const set2 = new Set(["c", "d", "e"]);

123

const combined = pulumi.utils.union(set1, set2);

124

console.log(Array.from(combined)); // ["a", "b", "c", "d", "e"]

125

```

126

127

### Metadata Access

128

129

```typescript

130

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

131

132

// Get deployment context information

133

const organization = pulumi.getOrganization();

134

const project = pulumi.getProject();

135

const stack = pulumi.getStack();

136

const rootDir = pulumi.getRootDirectory();

137

138

console.log(`Deploying ${organization}/${project}/${stack}`);

139

console.log(`Project root: ${rootDir}`);

140

141

// Use metadata in resource naming

142

const resourcePrefix = `${project}-${stack}`;

143

144

const bucket = new aws.s3.Bucket(`${resourcePrefix}-assets`, {

145

bucket: `${organization}-${project}-${stack}-assets`,

146

tags: {

147

Project: project,

148

Stack: stack,

149

Organization: organization,

150

},

151

});

152

153

// Create environment-aware configurations

154

function getEnvironmentConfig() {

155

const stackName = pulumi.getStack();

156

157

const configs = {

158

development: {

159

instanceType: "t3.micro",

160

minSize: 1,

161

maxSize: 2,

162

},

163

staging: {

164

instanceType: "t3.small",

165

minSize: 2,

166

maxSize: 4,

167

},

168

production: {

169

instanceType: "t3.medium",

170

minSize: 3,

171

maxSize: 10,

172

},

173

};

174

175

return configs[stackName as keyof typeof configs] || configs.development;

176

}

177

178

const envConfig = getEnvironmentConfig();

179

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

180

```

181

182

### Utility Helper Functions

183

184

```typescript

185

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

186

187

// Helper for checking resource types

188

function getResourceType(resource: pulumi.Resource): string {

189

if (pulumi.utils.isInstance(resource, "__pulumiCustomResource")) {

190

return "CustomResource";

191

} else if (pulumi.utils.isInstance(resource, "__pulumiComponentResource")) {

192

return "ComponentResource";

193

} else if (pulumi.utils.isInstance(resource, "__pulumiProviderResource")) {

194

return "ProviderResource";

195

}

196

return "Resource";

197

}

198

199

// Helper for extracting output values safely

200

function extractOutputValue<T>(output: pulumi.Output<T>, defaultValue: T): Promise<T> {

201

return output.apply(value => value !== undefined ? value : defaultValue);

202

}

203

204

// Helper for creating resource names with metadata

205

function createResourceName(baseName: string, suffix?: string): string {

206

const project = pulumi.getProject();

207

const stack = pulumi.getStack();

208

209

let name = `${project}-${stack}-${baseName}`;

210

if (suffix) {

211

name += `-${suffix}`;

212

}

213

214

// Ensure name meets resource naming requirements

215

return name.toLowerCase().replace(/[^a-z0-9-]/g, '-');

216

}

217

218

// Helper for validating resource configurations

219

function validateResourceConfig(config: any, required: string[]): void {

220

const missing = required.filter(key => !pulumi.utils.hasTrueBooleanMember(config, key) && !config[key]);

221

222

if (missing.length > 0) {

223

throw new pulumi.RunError(`Missing required configuration: ${missing.join(", ")}`);

224

}

225

}

226

227

// Usage examples

228

const bucket = new aws.s3.Bucket("assets");

229

console.log(`Resource type: ${getResourceType(bucket)}`);

230

231

const bucketId = await extractOutputValue(bucket.id, "default-bucket-id");

232

console.log(`Bucket ID: ${bucketId}`);

233

234

const resourceName = createResourceName("web-server", "primary");

235

console.log(`Generated name: ${resourceName}`);

236

237

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

238

```

239

240

### Debugging and Inspection Utilities

241

242

```typescript

243

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

244

245

// Utility for inspecting resource properties

246

function inspectResource(resource: pulumi.Resource): void {

247

console.log(`Resource URN: ${resource.urn}`);

248

249

if (pulumi.utils.isInstance(resource, "__pulumiCustomResource")) {

250

const customResource = resource as pulumi.CustomResource;

251

customResource.id.apply(id => console.log(`Resource ID: ${id}`));

252

}

253

254

// Check for common properties

255

const resourceAny = resource as any;

256

Object.keys(resourceAny).forEach(key => {

257

if (pulumi.utils.isInstance(resourceAny[key], "__pulumiOutput")) {

258

console.log(`Property ${key} is an Output`);

259

}

260

});

261

}

262

263

// Utility for checking Pulumi state

264

function checkPulumiState(): void {

265

const hasSecrets = Object.keys(process.env).some(key =>

266

key.startsWith('PULUMI_CONFIG_') && key.endsWith('_SECRET')

267

);

268

269

console.log(`Project: ${pulumi.getProject()}`);

270

console.log(`Stack: ${pulumi.getStack()}`);

271

console.log(`Organization: ${pulumi.getOrganization()}`);

272

console.log(`Has secrets: ${hasSecrets}`);

273

}

274

275

// Development helper for listing all outputs

276

function listAllOutputs(resources: pulumi.Resource[]): void {

277

resources.forEach((resource, index) => {

278

console.log(`Resource ${index}: ${getResourceType(resource)}`);

279

280

const resourceAny = resource as any;

281

Object.keys(resourceAny).forEach(key => {

282

if (pulumi.utils.isInstance(resourceAny[key], "__pulumiOutput")) {

283

resourceAny[key].apply((value: any) => {

284

console.log(` ${key}: ${JSON.stringify(value)}`);

285

});

286

}

287

});

288

});

289

}

290

291

// Usage

292

const bucket = new aws.s3.Bucket("debug-bucket");

293

const database = new aws.rds.Instance("debug-db", {

294

engine: "postgres",

295

instanceClass: "db.t3.micro",

296

});

297

298

inspectResource(bucket);

299

checkPulumiState();

300

listAllOutputs([bucket, database]);

301

```

302

303

### Performance and Optimization Helpers

304

305

```typescript

306

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

307

308

// Helper for batching operations

309

function batchOperations<T, R>(

310

items: T[],

311

batchSize: number,

312

operation: (batch: T[]) => Promise<R[]>

313

): Promise<R[]> {

314

const batches: T[][] = [];

315

316

for (let i = 0; i < items.length; i += batchSize) {

317

batches.push(items.slice(i, i + batchSize));

318

}

319

320

return Promise.all(batches.map(operation)).then(results =>

321

results.flat()

322

);

323

}

324

325

// Helper for memoizing expensive operations

326

function memoize<T extends (...args: any[]) => any>(fn: T): T {

327

const cache = new Map();

328

329

return ((...args: any[]) => {

330

const key = JSON.stringify(args);

331

332

if (cache.has(key)) {

333

return cache.get(key);

334

}

335

336

const result = fn(...args);

337

cache.set(key, result);

338

return result;

339

}) as T;

340

}

341

342

// Memoized expensive configuration calculation

343

const getExpensiveConfig = memoize((stack: string) => {

344

console.log(`Computing expensive config for ${stack}`);

345

// Expensive operation here

346

return {

347

setting1: `value-for-${stack}`,

348

setting2: Math.random(),

349

};

350

});

351

352

// Usage

353

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

354

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

355

```

356

357

## Best Practices

358

359

- Use type checking utilities for robust cross-version compatibility

360

- Leverage metadata functions for consistent resource naming

361

- Use collection utilities for data transformation and grouping

362

- Implement proper validation using utility functions

363

- Use memoization for expensive computations

364

- Create reusable helper functions for common patterns

365

- Use debugging utilities during development

366

- Leverage set operations for managing collections

367

- Extract utility functions into shared modules

368

- Document custom utility functions thoroughly

369

- Test utility functions independently

370

- Use TypeScript types with utility functions for better safety