-
Notifications
You must be signed in to change notification settings - Fork 241
Excluding targets from stack operations #14899
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
Merged
Merged
Changes from 7 commits
Commits
Show all changes
12 commits
Select commit
Hold shift + click to select a range
f843e77
Make it so
i-am-tom 7ba79ed
TypeScript
i-am-tom ad59463
Go
i-am-tom b21bb81
Linting
i-am-tom 74ee681
Close the chooser
i-am-tom c09c43f
.NET
i-am-tom 2f60903
Tags
i-am-tom 4a8ea0a
Update content/blog/excluding-targets-from-stack-operations/index.md
i-am-tom f2202a3
Update index.md
i-am-tom b216490
Update content/blog/excluding-targets-from-stack-operations/index.md
i-am-tom 059256a
Edits and messaging
meagancojocar d5a8f70
lint fix
meagancojocar File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
265 changes: 265 additions & 0 deletions
265
content/blog/excluding-targets-from-stack-operations/index.md
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,265 @@ | ||
--- | ||
title: "Excluding targets from stack operations" | ||
date: 2025-04-30 | ||
meta_desc: "You can now exclude targets from up, preview, refresh, and destroy operations" | ||
authors: | ||
- tom-harding | ||
tags: | ||
- exclude | ||
- targets | ||
--- | ||
|
||
Pulumi provides a set of top level commands for managing stack deployments. We can use commands like `up` and `destroy` to spin up and tear down production environments, or `refresh` to update our understanding of the stack’s resources. | ||
|
||
These work great, but sometimes you want to perform these operations on a subset of your infrastructure. In these cases, the `--target` flag allows you to specify the precise resources on which you want to perform your updates. On top of this, the `--target-dependents` flag can be used to select all the children of these `--target` resources automatically. This makes it easy to say, for example, “deploy this particular AWS bucket” without affecting the rest of your infrastructure. | ||
|
||
Today, we’re going to talk about an update to address the complementary feature request. While `--target` allows us to specify a subset of our infrastructure, it can be cumbersome if we want to include almost all of our resources. For this use case, we’ve introduced two new flags: `--exclude` and `--exclude-dependents`. | ||
|
||
## An example: blog post drafts | ||
|
||
Let’s imagine we want to deploy our static blog website. As part of this process, we have a bunch of HTML pages we’d like to deploy: | ||
|
||
{{% chooser language "javascript,typescript,python,go,csharp" %}} | ||
|
||
{{% choosable language javascript%}} | ||
|
||
```javascript | ||
... | ||
|
||
for (const file in await glob('posts/**/*.html')) { | ||
new aws.s3.BucketObject(`post-${file}`, { | ||
source: new pulumi.asset.FileAsset(file), | ||
... | ||
}) | ||
} | ||
|
||
... | ||
``` | ||
|
||
{{% /choosable %}} | ||
|
||
{{% choosable language typescript%}} | ||
|
||
```typescript | ||
... | ||
|
||
for (const file in await glob('posts/**/*.html')) { | ||
new aws.s3.BucketObject(`post-${file}`, { | ||
source: new pulumi.asset.FileAsset(file), | ||
... | ||
}) | ||
} | ||
|
||
... | ||
``` | ||
|
||
{{% /choosable %}} | ||
|
||
{{% choosable language python %}} | ||
|
||
```python | ||
... | ||
|
||
for file in glob("posts/**/*.html"): | ||
aws.s3.BucketObject(file, | ||
source = pulumi.FileAsset(file), | ||
.... | ||
) | ||
|
||
... | ||
``` | ||
|
||
{{% /choosable %}} | ||
|
||
{{% choosable language go %}} | ||
|
||
```go | ||
... | ||
|
||
files, err := filepath.Glob("posts/**/*.html") | ||
if err != nil { return err } | ||
|
||
for _, file := range files { | ||
_, err := s3.NewBucketObject(ctx, file, &s3.BucketObjectArgs{ | ||
Source: pulumi.FileAsset(file), | ||
... | ||
}) | ||
|
||
if err != nil { return err } | ||
} | ||
|
||
... | ||
``` | ||
|
||
{{% /choosable %}} | ||
|
||
{{% choosable language csharp %}} | ||
|
||
```csharp | ||
... | ||
|
||
var files = Directory.GetFiles("posts", "*.html"); | ||
|
||
foreach (var file in files) | ||
{ | ||
var bucketObject = new BucketObjectv2(file, new BucketObjectv2Args | ||
{ | ||
Source = new FileAsset(file), | ||
... | ||
}); | ||
} | ||
|
||
... | ||
``` | ||
|
||
{{% /choosable %}} | ||
|
||
{{% /chooser %}} | ||
|
||
This works well, but what if we have a list of draft articles that we don’t want to include in the deployment? We can optimistically assume we’ve finished more articles than we’ve started, so using `--target` to specify every article, as well as supporting resources (CSS, JavaScript, ownership controls, et cetera), would quickly become unmanageable. | ||
|
||
```shell | ||
pulumi up --target <URN>::style.css --target <URN>::post-hello.html ... | ||
``` | ||
|
||
With the `--exclude` flag, this becomes much more manageable: | ||
|
||
```shell | ||
pulumi up --exclude <URN>::post-draft-1.html --exclude <URN>::post-draft-2.html ... | ||
``` | ||
|
||
With this command, everything *not* specified using an `--exclude` tag will be included in the `up` operation, and thus we can avoid the hassle of naming every resource that *isn’t* a draft. | ||
|
||
## Next step: a draft group | ||
|
||
This is fine for a personal blog site, but can still become unmanageable when we’re dealing with multiple authors, each with multiple drafts. In this case, we might want to group our drafts under a common parent: | ||
|
||
{{% chooser language "javascript,typescript,python,go,csharp" %}} | ||
|
||
{{% choosable language javascript%}} | ||
|
||
```javascript | ||
... | ||
|
||
// A stub resource to group all our drafts | ||
const drafts = new pulumi.ComponentResource('ComponentResource', 'drafts') | ||
|
||
for (const file in await glob('drafts/**/*.html')) { | ||
new aws.s3.BucketObject(`draft-${file}`, { | ||
source: new pulumi.asset.FileAsset(`drafts/${file}`), | ||
... | ||
}, { parent: drafts }) | ||
} | ||
|
||
... | ||
``` | ||
|
||
{{% /choosable %}} | ||
|
||
{{% choosable language typescript%}} | ||
|
||
```typescript | ||
... | ||
|
||
// A stub resource to group all our drafts | ||
const drafts: pulumi.ComponentResource = | ||
new pulumi.ComponentResource('ComponentResource', 'drafts') | ||
|
||
for (const file in await glob('drafts/**/*.html')) { | ||
new aws.s3.BucketObject(`draft-${file}`, { | ||
source: new pulumi.asset.FileAsset(`drafts/${file}`), | ||
... | ||
}, { parent: drafts }) | ||
} | ||
|
||
... | ||
``` | ||
|
||
{{% /choosable %}} | ||
|
||
{{% choosable language python %}} | ||
|
||
```py | ||
... | ||
|
||
# A stub resource to group all our drafts | ||
drafts = pulumi.ComponentResource(t="ComponentResource", name="drafts") | ||
|
||
for file_path in glob("posts/**/*.html"): | ||
aws.s3.BucketObject(file_path, | ||
source = pulumi.FileAsset(file_path), | ||
opts = pulumi.ResourceOptions(parent = drafts), | ||
.... | ||
) | ||
|
||
... | ||
``` | ||
|
||
{{% /choosable %}} | ||
|
||
{{% choosable language go %}} | ||
|
||
```go | ||
drafts := &DraftGroupComponent{} | ||
err = ctx.RegisterComponentResource("ComponentResource", "drafts", drafts) | ||
if err != nil { return err } | ||
|
||
... | ||
|
||
files, err := filepath.Glob("posts/*.html") | ||
if err != nil { return err } | ||
|
||
for _, file := range files { | ||
_, err := s3.NewBucketObject(ctx, file, &s3.BucketObjectArgs{ | ||
Key: pulumi.String(file), | ||
... | ||
}, pulumi.Parent(drafts)) | ||
|
||
if err != nil { return err } | ||
} | ||
|
||
... | ||
``` | ||
|
||
{{% /choosable %}} | ||
|
||
{{% choosable language csharp %}} | ||
|
||
```csharp | ||
public class MyComponentResource : ComponentResource { ... } | ||
|
||
... | ||
|
||
var files = Directory.GetFiles("posts", "*.html"); | ||
var drafts = new MyComponentResource("drafts"); | ||
|
||
foreach (var file in files) | ||
{ | ||
var bucketObject = new BucketObjectv2(file, new BucketObjectv2Args | ||
{ | ||
Source = new FileAsset(file), | ||
... | ||
}, new CustomResourceOptions | ||
{ | ||
Parent = drafts | ||
}); | ||
} | ||
|
||
... | ||
``` | ||
|
||
{{% /choosable %}} | ||
|
||
{{% /chooser %}} | ||
|
||
In this setup, we now have a parent resource for all drafts. Using `--exclude-dependents`, we can now exclude everything under this parent resource without having to enumerate all of them individually: | ||
|
||
```shell | ||
pulumi up --exclude <URN>::ComponentResource::drafts --exclude-dependents | ||
``` | ||
|
||
This command will exclude all drafts from the `up` operation, regardless of how many we have or how they’re named. We now have a nice, scalable way to manage our drafts across production and development environments\! | ||
i-am-tom marked this conversation as resolved.
Show resolved
Hide resolved
|
||
|
||
## Next steps | ||
|
||
With these flags now available in the command line, expect to see them introduced in the automation APIs and GitHub action soon. Thanks for reading, and feel free to share any feedback on [GitHub](https://github.com/pulumi/pulumi), [X](https://twitter.com/pulumicorp), or our [Community Slack](https://slack.pulumi.com/). | ||
i-am-tom marked this conversation as resolved.
Show resolved
Hide resolved
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
id = "tom-harding" | ||
name = "Tom Harding" | ||
title = "Software Engineer" | ||
weight = 1 | ||
|
||
status = "active" | ||
|
||
[social] | ||
github = "i-am-tom" | ||
linkedin = "i-am-tom" |
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.