Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

improvement(pulumi): improve preview output #3096

Merged
merged 7 commits into from
Oct 21, 2022
Merged
Show file tree
Hide file tree
Changes from 3 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/reference/providers/pulumi.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ providers:
environments:

# The version of pulumi to use. Set to `null` to use whichever version of `pulumi` is on your PATH.
version: 3.25.1
version: 3.40.0

# Overrides the default plan directory path used when deploying with the `deployFromPreview` option for pulumi
# modules.
Expand Down
93 changes: 71 additions & 22 deletions plugins/pulumi/cli.ts
Original file line number Diff line number Diff line change
Expand Up @@ -59,17 +59,17 @@ export class GlobalPulumi extends CliWrapper {
}

export const pulumiCliSPecs: { [version: string]: PluginToolSpec } = {
"3.25.1": {
name: "pulumi-3-25-1",
description: "The pulumi CLI, v3.24.1",
"3.40.0": {
name: "pulumi-3-40-0",
description: "The pulumi CLI, v3.40.0",
type: "binary",
_includeInGardenImage: true,
builds: [
{
platform: "darwin",
architecture: "amd64",
url: "https://github.com/pulumi/pulumi/releases/download/v3.25.1/pulumi-v3.25.1-darwin-x64.tar.gz",
sha256: "c91ef64aedcd10a925858a21fc4b52f9a566b4f14bc0d175c0c51c7745cdd175",
url: "https://github.com/pulumi/pulumi/releases/download/v3.40.0/pulumi-v3.40.0-darwin-x64.tar.gz",
sha256: "3d48d917b64fb3a1380d47a5733726edb99c3a0f5565fe04cfa26ccb67cb415a",
extract: {
format: "tar",
targetPath: "pulumi/pulumi",
Expand All @@ -78,8 +78,8 @@ export const pulumiCliSPecs: { [version: string]: PluginToolSpec } = {
{
platform: "darwin",
architecture: "arm64",
url: "https://github.com/pulumi/pulumi/releases/download/v3.25.1/pulumi-v3.25.1-darwin-arm64.tar.gz",
sha256: "a5ab29db86733b5f730a0f352b407aed64b82337a222a0c7cd1492b55189e6c1",
url: "https://github.com/pulumi/pulumi/releases/download/v3.40.0/pulumi-v3.40.0-darwin-arm64.tar.gz",
sha256: "f093cc460aa4a4773e6910db2b9a3ba71f6443b99194d8ad2752be66c4822861",
extract: {
format: "tar",
targetPath: "pulumi/pulumi",
Expand All @@ -88,8 +88,8 @@ export const pulumiCliSPecs: { [version: string]: PluginToolSpec } = {
{
platform: "linux",
architecture: "amd64",
url: "https://github.com/pulumi/pulumi/releases/download/v3.25.1/pulumi-v3.25.1-linux-x64.tar.gz",
sha256: "71e94634492b54e09810649f3753a5b414f4a1895b012ee445c275f1a0f94c5c",
url: "https://github.com/pulumi/pulumi/releases/download/v3.40.0/pulumi-v3.40.0-linux-x64.tar.gz",
sha256: "7abc0ccb17e6b0b1ed89be0897bd6a73cb3c6784d7fb5c2e20ad2a8d976c42fe",
extract: {
format: "tar",
targetPath: "pulumi/pulumi",
Expand All @@ -98,26 +98,74 @@ export const pulumiCliSPecs: { [version: string]: PluginToolSpec } = {
{
platform: "windows",
architecture: "amd64",
url: "https://github.com/pulumi/pulumi/releases/download/v3.25.1/pulumi-v3.25.1-windows-x64.zip",
sha256: "60d891f65e69e0eb14acb26e0a8a102d54ebc432060631f867c44b84cde09bdb",
url: "https://github.com/pulumi/pulumi/releases/download/v3.40.0/pulumi-v3.40.0-windows-x64.zip",
sha256: "f0ca025d7a47175852ed5a6e7f7c4e97f1d1326c448bd172e81e7130bd447b74",
extract: {
format: "zip",
targetPath: "pulumi/bin/pulumi.exe",
},
},
],
},
"3.39.4": {
name: "pulumi-3-39-4",
description: "The pulumi CLI, v3.39.4",
type: "binary",
_includeInGardenImage: false,
builds: [
{
platform: "darwin",
architecture: "amd64",
url: "https://github.com/pulumi/pulumi/releases/download/v3.39.4/pulumi-v3.39.4-darwin-x64.tar.gz",
sha256: "a563f7d7f3dbda84fae61316ef335e204606ac4e79f8e43ffb6103972b9c26ff",
extract: {
format: "tar",
targetPath: "pulumi/pulumi",
},
},
{
platform: "darwin",
architecture: "arm64",
url: "https://github.com/pulumi/pulumi/releases/download/v3.39.4/pulumi-v3.39.4-darwin-arm64.tar.gz",
sha256: "20493f365df1d73417c8159b0259624f06afe7fa5bcb15305e47edbfb7c20eca",
extract: {
format: "tar",
targetPath: "pulumi/pulumi",
},
},
{
platform: "linux",
architecture: "amd64",
url: "https://github.com/pulumi/pulumi/releases/download/v3.39.4/pulumi-v3.39.4-linux-x64.tar.gz",
sha256: "dd3ad77debfb664bc9a79cc88789a091f1f4f420780a2feb622d31cda028ade9",
extract: {
format: "tar",
targetPath: "pulumi/pulumi",
},
},
{
platform: "windows",
architecture: "amd64",
url: "https://github.com/pulumi/pulumi/releases/download/v3.39.4/pulumi-v3.39.4-windows-x64.zip",
sha256: "fdea4e4caca4be39801f7e63bb36c9826a9965a36cac37cfa1244f5110d66864",
extract: {
format: "zip",
targetPath: "pulumi/bin/pulumi.exe",
},
},
],
},
"3.24.1": {
name: "pulumi-3-24-1",
"3.25.1": {
name: "pulumi-3-25-1",
description: "The pulumi CLI, v3.24.1",
type: "binary",
_includeInGardenImage: true,
_includeInGardenImage: false,
builds: [
{
platform: "darwin",
architecture: "amd64",
url: "https://github.com/pulumi/pulumi/releases/download/v3.24.1/pulumi-v3.24.1-darwin-x64.tar.gz",
sha256: "1bfafd10f189c4e57b9961ddf899055efb55649e7403fc1bdd33c89e5a9cce1c",
url: "https://github.com/pulumi/pulumi/releases/download/v3.25.1/pulumi-v3.25.1-darwin-x64.tar.gz",
sha256: "c91ef64aedcd10a925858a21fc4b52f9a566b4f14bc0d175c0c51c7745cdd175",
extract: {
format: "tar",
targetPath: "pulumi/pulumi",
Expand All @@ -126,8 +174,8 @@ export const pulumiCliSPecs: { [version: string]: PluginToolSpec } = {
{
platform: "darwin",
architecture: "arm64",
url: "https://github.com/pulumi/pulumi/releases/download/v3.24.1/pulumi-v3.24.1-darwin-arm64.tar.gz",
sha256: "cdfd2d05beb66380b7eb2354ef45abbce17865441a465294cf8e5448a534eb7f",
url: "https://github.com/pulumi/pulumi/releases/download/v3.25.1/pulumi-v3.25.1-darwin-arm64.tar.gz",
sha256: "a5ab29db86733b5f730a0f352b407aed64b82337a222a0c7cd1492b55189e6c1",
extract: {
format: "tar",
targetPath: "pulumi/pulumi",
Expand All @@ -136,8 +184,8 @@ export const pulumiCliSPecs: { [version: string]: PluginToolSpec } = {
{
platform: "linux",
architecture: "amd64",
url: "https://github.com/pulumi/pulumi/releases/download/v3.24.1/pulumi-v3.24.1-linux-x64.tar.gz",
sha256: "9341c23c1b0266a39ebc6dab2f36b20041226143481714cb0ba8bfbf3ef7ae7e",
url: "https://github.com/pulumi/pulumi/releases/download/v3.25.1/pulumi-v3.25.1-linux-x64.tar.gz",
sha256: "71e94634492b54e09810649f3753a5b414f4a1895b012ee445c275f1a0f94c5c",
extract: {
format: "tar",
targetPath: "pulumi/pulumi",
Expand All @@ -146,7 +194,7 @@ export const pulumiCliSPecs: { [version: string]: PluginToolSpec } = {
{
platform: "windows",
architecture: "amd64",
url: "https://github.com/pulumi/pulumi/releases/download/v3.24.1/pulumi-v3.24.1-windows-x64.zip",
url: "https://github.com/pulumi/pulumi/releases/download/v3.25.1/pulumi-v3.25.1-windows-x64.zip",
sha256: "7ccaace585dfd9b44659c876ac87c33ea892cd91c34cb7ad00081cec8032a329",
extract: {
format: "zip",
Expand All @@ -160,4 +208,5 @@ export const pulumiCliSPecs: { [version: string]: PluginToolSpec } = {
export const supportedVersions = Object.keys(pulumiCliSPecs)

// Default to latest pulumi version
export const defaultPulumiVersion = "3.25.1"
export const defaultPulumiVersion = "3.40.0"
// export const defaultPulumiVersion = "3.25.1"
vvagaytsev marked this conversation as resolved.
Show resolved Hide resolved
24 changes: 20 additions & 4 deletions plugins/pulumi/commands.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,8 @@ import { PulumiModule, PulumiProvider } from "./config"
import { Profile } from "@garden-io/core/build/src/util/profiling"
import {
cancelUpdate,
getModifiedPlansDirPath,
getPlanFileName,
getPreviewDirPath,
previewStack,
PulumiParams,
Expand All @@ -30,9 +32,10 @@ import {
selectStack,
} from "./helpers"
import { dedent } from "@garden-io/sdk/util/string"
import { emptyDir } from "fs-extra"
import { copy, emptyDir } from "fs-extra"
import { ModuleConfigContext } from "@garden-io/core/build/src/config/template-contexts/module"
import { deletePulumiService } from "./handlers"
import { join } from "path"

interface PulumiParamsWithService extends PulumiParams {
service: GardenService
Expand All @@ -54,13 +57,26 @@ const pulumiCommandSpecs: PulumiCommandSpec[] = [
beforeFn: async ({ ctx, log }) => {
const previewDirPath = getPreviewDirPath(ctx)
// We clear the preview dir, so that it contains only the plans generated by this preview command.
log.info(`Clearing preview dir at ${previewDirPath}...`)
log.debug(`Clearing preview dir at ${previewDirPath}...`)
await emptyDir(previewDirPath)
},
runFn: async (params) => {
const { ctx } = params
const { ctx, module, log } = params
const previewDirPath = getPreviewDirPath(ctx)
await previewStack({ ...params, logPreview: true, previewDirPath })
const { affectedResourcesCount, planPath } = await previewStack({
...params,
logPreview: true,
previewDirPath,
})
if (affectedResourcesCount > 0) {
// We copy the plan to a subdirectory of the preview dir.
// This is to facilitate copying only those plans that aren't no-ops out of the preview dir for subsequent
// use in a deployment.
const planFileName = getPlanFileName(module, ctx.environmentName)
const modifiedPlanPath = join(getModifiedPlansDirPath(ctx), planFileName)
await copy(planPath, modifiedPlanPath)
log.debug(`Copied plan to ${modifiedPlanPath}`)
}
},
},
{
Expand Down
66 changes: 42 additions & 24 deletions plugins/pulumi/helpers.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
*/

import Bluebird from "bluebird"
import { isEmpty } from "lodash"
import { isEmpty, uniq } from "lodash"
import { safeLoad } from "js-yaml"
import { merge } from "json-merge-patch"
import { extname, join, resolve } from "path"
Expand Down Expand Up @@ -80,16 +80,19 @@ type StackStatus = "up-to-date" | "outdated" | "error"
export const stackVersionKey = "garden.io-service-version"

/**
* Used by the `garden plugins pulumi preview` command.
*
* Merges any values in the module's `pulumiVars` and `pulumiVariables`, then uses `pulumi preview` to generate
* a plan (using the merged config).
*
* If `logPreview = true`, logs the output of `pulumi preview`.
*
* Returns the path to the generated plan.
* Returns the path to the generated plan, and the number of resources affected by the plan (zero resources means the
* plan is a no-op).
*/
export async function previewStack(
params: PulumiParams & { logPreview: boolean; previewDirPath?: string }
): Promise<string> {
): Promise<{ planPath: string; affectedResourcesCount: number }> {
const { log, ctx, provider, module, logPreview, previewDirPath } = params

const configPath = await applyConfig({ ...params, previewDirPath })
Expand All @@ -106,12 +109,17 @@ export async function previewStack(
cwd: getModuleStackRoot(module),
env: defaultPulumiEnv,
})
const affectedResourcesCount = await countAffectedResources(module, planPath)
if (logPreview) {
log.info(res.stdout)
if (affectedResourcesCount > 0) {
log.info(res.stdout)
} else {
log.info(`No resources were changed in the generated plan for ${chalk.cyan(module.name)}.`)
}
} else {
log.verbose(res.stdout)
}
return planPath
return { planPath, affectedResourcesCount }
}

export async function getStackOutputs({ log, ctx, provider, module }: PulumiParams): Promise<any> {
Expand Down Expand Up @@ -268,25 +276,31 @@ export async function getStackStatusFromTag(params: PulumiParams & { serviceVers
return tagVersion === params.serviceVersion && resources && resources.length > 0 ? "up-to-date" : "outdated"
}

// Keeping this here for now, in case we want to reuse this logic
// export async function getStackStatusFromPlanPath(module: PulumiModule, planPath: string): Promise<StackStatus> {
// let plan: PulumiPlan
// try {
// plan = JSON.parse((await readFile(planPath)).toString()) as PulumiPlan
// } catch (err) {
// const errMsg = `An error occurred while reading a pulumi plan file at ${planPath}: ${err.message}`
// throw new FilesystemError(errMsg, {
// planPath,
// moduleName: module.name,
// })
// }

// // If all steps across all resource plans are of the "same" type, then the plan indicates that the
// // stack doesn't need to be updated (so we don't need to redeploy).
// const stepTypes = uniq(flatten(Object.values(plan.resourcePlans).map((p) => p.steps)))

// return stepTypes.length === 1 && stepTypes[0] === "same" ? "up-to-date" : "outdated"
// }
/**
* Reads the plan at `planPath` and counts the number of resources in it that have one or more steps that aren't of
* the `"same"` type (i.e. that aren't no-ops).
*/
export async function countAffectedResources(module: PulumiModule, planPath: string): Promise<number> {
let plan: PulumiPlan
try {
plan = JSON.parse((await readFile(planPath)).toString()) as PulumiPlan
} catch (err) {
const errMsg = `An error occurred while reading a pulumi plan file at ${planPath}: ${err.message}`
throw new FilesystemError(errMsg, {
planPath,
moduleName: module.name,
})
}

const affectedResourcesCount = Object.values(plan.resourcePlans)
.map((p) => p.steps)
.filter((steps: string[]) => {
const stepTypes = uniq(steps)
return stepTypes.length > 1 || stepTypes[0] !== "same"
}).length

return affectedResourcesCount
}

// Helpers for plugin commands

Expand Down Expand Up @@ -401,6 +415,10 @@ function getDefaultPreviewDirPath(ctx: PluginContext): string {
return join(getPluginOutputsPath(ctx, "pulumi"), "last-preview")
}

export function getModifiedPlansDirPath(ctx: PluginContext): string {
return join(getPreviewDirPath(ctx), "modified")
}

export function getPlanFileName(module: PulumiModule, environmentName: string): string {
return `${module.name}.${environmentName}.plan.json`
}
Expand Down
10 changes: 3 additions & 7 deletions scripts/compute-ext-tool-binary-shas.sh
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,10 @@

# Downloads binaries, computes and prints their SHAs. Useful when adding new tools or new versions of existing tools.
#
# Usage: ./compute-ext-tool-binary-shas <darwin-dl-url> <linux-dl-url> <win-dl-url>
# Usage: ./compute-ext-tool-binary-shas <darwin-x64-dl-url> <darwin-arm64-dl-url> <linux-dl-url> <win-dl-url>

darwin_dl_url=$1
linux_dl_url=$2
win_dl_url=$3

platforms=("Darwin" "Linux" "Windows")
urls=($1 $2 $3)
platforms=("Darwin-x64" "Darwin-arm64" "Linux" "Windows")
urls=($1 $2 $3 $4)

for i in ${!platforms[@]}; do
echo "Downloading ${platforms[$i]} binary at ${urls[$i]}..."
Expand Down