Over time, I have come to view "declarative infrastructure" as unrealistic. It's right 90% of the time, but not 100% of the time -- kind of like using only CSS and HTML. One should use markup whenever possible; but not everything on a page is truly "declarative". Occasionally one needs to script an input field or a transition.
One example of this is scripting the handoff process that's part of a blue/green deploy. In practice you'll want to look at organization defined metrics. There are libraries to do this -- either internal to your organization, or provided by a metrics vendor -- and scripting the process looks like this:
(1) Setup new environment.
(2) Divert some traffic.
(3) Check metrics.
(4) If metrics are okay:
(4.1) Post message internally (IRC/Slack).
(4.2) Divert all traffic.
(4.3) Set up timed task to tear down old environment (in a day, hour, &c.).
(5) If metrics are okay:
(5.1) Post message internally (IRC/Slack), maybe to different people.
(5.2) Stop diverting traffic.
(5.3) Tear down new environment.
A large part of the work here
is declarative: (1) by itself is a big piece of it, and is fully declarative, as is the teardown in (4.3) and (5.3). However, the need for control flow in this and many other cases means that, without a library, one must drive Terraform by templating and shelling out. Not being "real code" pushes one in the direction, not of greater declarativeness (libraries can certainly have declarative interfaces, like Troposphere does), but of worse code.
Many complex and powerful features are exposed to a modern business through libraries -- AI, payments, telephony -- and software defined infrastructure can be, too. The benefits of "infrastructure as code" won't be realized until that happens.