Pulumi & Terraform... infra... is not the only place where declarative happens. The driver and medium does not determine if the system is declarative. It is the developer experience which does
I could write a Prolog language host for Pulumi. Obviously that would not be imperative. It would present the exact same model as TypeScript or Go.
The engine is what matters, not the configuration format.
Yes the infra after the imperative step can have declarative layers, but the DX is still imperative. Declarative frameworks still have imperative operations underneath. You cannot argue that something is a declarative DX that is no longer a declarative input. Declarative DX is what matters. Pulumi reverses this so that the outer most layer is no longer declarative. Declarative as a term came to be because it is what the human is doing
> The engine is what matters, not the configuration format.
Code is not a configuration format...
Sorry, Lisp says otherwise.
It's clear I'm not going to modify your view of the world here, and you certainly are not going to modify mine, so I don't think there is any point in continuing this conversation.
Now let's consider another idea... can Pulumi prevent me from making arbitrary calls to an API or database to fill in the "declarative code"?
Honestly, reading the pulumi website ought to be enough to realize they think of it as programming and not something "declarative". They don't even use the word, because they aren't. They call it programming, programs, and code in many places, so they are positioning themselves differently from how you are describing them.
But by your own admission:
> You are not declaring what it looks like, you are writing instructions for how to produce declarative
If this was true, a Pulumi program would look like this:
const bucket = new aws.s3.Bucket()
if (bucket) {
// do something
} else {
// do something else
}
If you'd written anything in Pulumi you'd know that isn't how it works. The only imperative part of Pulumi is your ability to manipulate the DAG, for example: const config = pulumi.Config()
const createBucket = config.reqiureBool("createBucket")
if (createBucket) {
new aws.s3.Bucket()
}
Now, is there an imperative statement in there? Yes, but the only imperative part is your decision to include or exclude the bucket itself from the declarative end state. You do _exactly_ the same thing in Terraform but with a less intuitive syntax: resource "aws_s3_bucket" "example" {
count = 0
}
By that definition, if Pulumi is imperative, so is Terraform. It's not though, and you're wrong.Way to assume, you know how that usually turns out?
Could I condition the creation of a bucket based on the even/odd value of a different resource's hash? What about the time of day or day of week? What other arbitrary things might I be able to do in a language that Pulumi supports? How can I be sure that if I run the code on a different day, that the outputs are stable?
Let's consider another idea... can Pulumi prevent me from making arbitrary calls to an API or database to fill in the "declarative code" that creates a resource? Would something like that be imperative or declarative? Does/can the order I write Pulumi code in matter? Does it for TF? Can you interact with the outside world with custom code in TF between the creation of resources?
In the end, are you writing the desired state directly or instructions for how to construct that desired state?
I invite you to consider these questions with the others you have discussed Pulumi semantics, as I assume I am not going to have success getting you to do so here...
You can likely do some of the above with TF, as it has strayed further from declarative. What you really want for configuration is a language which is not Turing complete and does not support dynamic values within the code, only via flags / args at invocation time. In other words, same outputs from the same inputs. I think TF & Pulumi both fail on the latter
(https://www.richard-towers.com/2021/01/03/terraforming-adven...) (https://cuelang.org)
The answer to your question is that you are constructing the desired state, not instructions for how to get from the current (unknowable) state to it. Using an API to construct declarative configuration is actually an incredibly useful pattern. Terraform can do it with HCL, too.
Again, declarative vs imperative is a DX issue. All the systems underneath are using both. So if we follow your logic, that the underlying system is what matters, every experience would be both imperative and declarative. Kubernetes and Terraform both use imperative processes to implement the declarative input. Using the properties of the underlying system to describe the exposed DX makes no sense. You don't get to add imperative on declarative or declarative on imperative and claim it has the property of the system you just layered on top of. The outermost layer, the one exposed to the end user, is the type of system (declarative or imperative) that the user is using. Pulumi and client-go are both imperative interfaces on top of other systems.
Go fish...