Is there a way to tell, from within the code, whet...
# getting-started
c
Is there a way to tell, from within the code, whether a given resource needs to be updated or not? For example, say I have a bunch of ec2 instances created with
new aws.ec2.Instance()
and some of them didn't have any changes, some needed to be updated, and some were going to be newly created. It there a way I can get a list of just the new or updated instances by looking at some property of each
Instance
object?
l
No. You use
pulumi preview
for this. You can get its output in JSON format (
--json
) for easier manipulation.
c
Unfortunately, that doesn't really help. I was hoping there would be some way to do that within the code. The pulumi internals must know that since that's how it deals with changing `Input`s, and
dependsOn
, right? If those things don't change for a given resource, then it won't be modified. So there must be some way (during runtime of
pulumi up
) to know whether an
Input
or
Resource
has changed.
l
The code runs before the provider plugin does its diff-the-state-with-the-cloud work. Your code runs and builds a desired state tree in Pulumi engine. Pulumi then compares that tree to what is in state. So Pulumi doesn't know if something needs to be updated until after your code has finished running.
So it is simply not possible.
This is an unavoidable side-effect of the declarative model. Even though Pulumi projects are written in imperative languages, they are not imperative programs, at least as far as changing the cloud goes.
c
But if I do
someResource.someAttribute.apply((x) => { /* do stuff here */})
, then within body of the function passed to
apply
,
x
is a concrete value, a string or whatever it is on the resource. That must happen after the provider plugin runs, right? And I can create further resources inside that function, and at that point, it must be known whether
someResource
was updated or not, no?
l
Yes at that point. But also at that point, the change has already happened.
c
The change for the first resource has already happened, but that's fine. That's what I'm interested in.
I want to use that info to decide things for other resources.
l
Maybe automation-api will get you what you need? In general, a single project won't allow what you're talking about. That's just how declarative works. You don't get to react when making changes: you must know everything up front, and declare the changes.
c
Of course you get to react to changes with pulumi... I'm already doing it.
For example, I can declare an ec2 instance, wait for it to come up, run a remote command on it, get the stdout of that command and create other resources dynamically based on the content of the stdout string.
l
You can do that inside an
apply()
, true. But: don't do that.
c
First, that's way different from "it is simply not possible". Second, it wouldn't necessarily need to happen inside an
apply()
. Every resource that has inputs must actually wait until they've been concretely resolved for real before the resource can be actually created. That's all I'm looking for.
l
The way to put code into that phase of execution is via
apply()
.
c
or just use the stdout of the command as an input to a resource that depends on it.
l
The stdout isn't available at tree-generation time. Only after execution. Hence apply.
An Output wrapping the stdout is available, but the content isn't
And if you use that stdout to do more, then the outputs from that "more" won't be available under after another run of the engine. It gets so confusing, so quickly.
Strong recommend against doing that. Use automation-api, it simplifies things greatly.
c
Are you saying this is impossible?
Copy code
const cmd = new command.remote.Command("foo", {connection, create: "hostname"});
const thing2 = new otherResource("bar", {someAttribute: cmd.stdout});
isn't that pretty standard? Using the output of one resource as the input for another? I'm not using
apply()
explicitly there.
l
I don't mean to say anything is impossible. I'm saying that I recommend against doing this:
Copy code
const cmd = new command.remote.Command("foo", {connection, create: "hostname"});
cmd.stdout.apply((t) => {
  if (t.match(/go for it/) {
    const thing2 = new otherResource("bar", {someAttribute: t});
  }
});
Your snippet doesn't decide anything: it declares two resources, unconditionally. My snippet decides whether or not to create a resource based on the output of another resource. This isn't declarative and I think it's a bad idea. The same problem can be solved safer by using automation-api.
c
I'm not saying it has to be done with
apply()
I think you keep saying that. I'm not necessarily opposed to it, I'm just saying that obviously resources depend on the output of other resources all the time, and those outputs have to be concretely known prior to the downstream resources actually being created. There's nothing different between knowing the output of an attribute of an upstream resource before actually creating the downstream resource and knowing whether the upstream resource changed.
l
I'm sorry, I think I'm confusing matters, and I know I'm getting confused. I'll leave it with one point: • In order to keep your code as maintainable as possible, the tree of resources created should be known completely before Pulumi starts interacting with providers. Having your tree shape change during the deployment phase will make your code more complicated and its outputs less predictable. It will make debugging very, very difficult. It will make writing unit tests (not integration tests) all but impossible. And it can be easily avoided by making a different, simpler architectural decision.
c
What I'm talking about wouldn't necessarily change the tree shape.
l
Okay. Well to go back to your original question, is there a way to get a list of resources (or specifically, EC2 instances) that have been created, updated or changed: not during the project's execution, no. You can do this only by examining the change tree, which is available only after the project has complete (via preview or up). You can use automation-api to do this inside your program, for example via the Stack.preview().changeSummary property.
I don't think you can even do it for a single resource: I don't know of any way to compare before with after. It might be possible though, I've just never tried to find out how, as it has never been a problem I've needed to solve.
c
What you are asking for is currently not possible in the way you are asking for. As @little-cartoon-10569 suggested you could use the
--json
flag to get the list of steps and figure out the operation based on the type token, in your case, the EC2 instance resource. However, I realize this is not what you are looking for exactly. There just isn't a programmatic way to do that right now. Not even with the Automation SDK. Perhaps https://github.com/pulumi/pulumi/issues/1691 might provide you with what you are looking for, in which case, feel free to +1 it. However, it's at a per-resource level. One idea that you might be able to try is, create a dynamic provider and make it depend on your EC2 instance resource. That dependency would then allow you to implement custom logic in the callbacks based on some property changes in the dependent resource. For example, you could depend on the ID property of all of your instances in this dynamic provider and detect changes in inputs via the callbacks in the dynamic provider. I am not sure how effective this will be in practice, to be honest.