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

pulumi refresh --diff does not show a diff #7665

Closed
filip-taxamo opened this issue Jul 28, 2021 · 8 comments · Fixed by #16065
Closed

pulumi refresh --diff does not show a diff #7665

filip-taxamo opened this issue Jul 28, 2021 · 8 comments · Fixed by #16065
Assignees
Labels
area/cli UX of using the CLI (args, output, logs) kind/bug Some behavior is incorrect or out of spec
Milestone

Comments

@filip-taxamo
Copy link

I'd like to see the differences between actual values of resources' attributes and their Pulumi state.

Steps to reproduce

  1. Modify the resource managed by Pulumi not using Pulumi
  2. run:
$ pulumi refresh --diff

Expected:

A diff like:

[...]
~  opsgenie:index/user:User (update)
    [id=[...]]
    [urn=urn:pulumi:prod::opsgenie::opsgenie:index/user:User::[...]]
    timezone     : "Europe/Warsaw" => "Pacific/Honolulu"
[...]

Actual:

No diff output:

$ pulumi refresh --diff
Previewing refresh ([...])

View Live: https://app.pulumi.com/[...]

  pulumi:pulumi:Stack: (same)
    [urn=urn:pulumi:prod::opsgenie::pulumi:pulumi:Stack::opsgenie-prod]
INFO[2021-07-28T17:41:35.5841214+02:00] Client is configured with ApiUrl: api.opsgenie.com, LogLevel: info, RetryMaxCount: 10

[...] # the above INFO line repeated many times

Resources:
    ~ 2 to update
    51 unchanged
Do you want to perform this refresh?
No resources will be modified as part of this refresh; just your stack's state will be.  [Use arrows to move, enter to select, type to filter]
  yes
> no
  details

The funny thing is that the Pulumi Console shows a nice diff for the same run:

[...]
~  opsgenie:index/user:User (update)
    [id=[...]]
    [urn=urn:pulumi:prod::opsgenie::opsgenie:index/user:User::[...]]
    timezone     : "Europe/Warsaw" => "Pacific/Honolulu"
[...]
@filip-taxamo filip-taxamo added the kind/bug Some behavior is incorrect or out of spec label Jul 28, 2021
@leezen
Copy link
Contributor

leezen commented Jul 28, 2021

This sounds like it could be a rendering issue given both the console shows the diff and the CLI shows 2 to update. Will have to look into if there's a CLI display bug.

@leezen leezen added the area/cli UX of using the CLI (args, output, logs) label Jul 28, 2021
@pgavlin pgavlin changed the title pulumi preview --diff does not show a diff pulumi refresh --diff does not show a diff Feb 10, 2022
@foo-1a
Copy link

foo-1a commented May 18, 2023

any update on this? I just stumbled upon the same and we're in a situation where it's rather important being able to see the diff of a sync to remediate drift safely.

@t0yv0
Copy link
Member

t0yv0 commented Apr 8, 2024

Possibly related pulumi/pulumi-aws#3439 - possibly connected to the bridge diff code.

@zbuchheit
Copy link

zbuchheit commented Apr 9, 2024

I have a very simple repro of this to see the behavior.

Code Repro

Pulumi.yaml

name: gcp-bucket
runtime: yaml
description: A minimal Google Cloud Pulumi YAML program
resources:
  my-bucket-zbuchheit:
    properties:
      location: US
    type: gcp:storage:Bucket

Instructions to Repro

  1. Run pulumi up
  2. Make a change in the console to the resource, in my case I changed the storage class from standard to archive
  3. Run pulumi refresh --diff --preview-only
  4. Witness no diff, but resource displaying to update
Example output from `pulumi refresh --diff --preview-only`
pulumi refresh --diff --preview-only                                                                                                 
Previewing refresh (dev)

View Live: https://app.pulumi.com/zbuchheit-pulumi-corp/gcp-bucket/dev/previews/bc6b6c9d-c76f-4c68-b99c-566b087d2c58

  pulumi:pulumi:Stack: (same)
    [urn=urn:pulumi:dev::service-account::pulumi:pulumi:Stack::service-account-dev]
Resources:               
    ~ 1 to update
    1 unchanged

Additional Context

The command doesn't have to be pulumi refresh --diff --preview-only it really just needs to contain --diff and you will see no detailed diff in the console. I also witnessed the same behavior where the diff tab in pulumi cloud will display the diff just not locally in the cli.

Output from --json

I found it interesting the detailedDiff is showing as null here. Maybe that is expected and normal, but thought I would include it just in case.

Output from `pulumi refresh --diff --preview-only --json`
{
    "config": {
        "gcp:project": "redacted"
    },
    "steps": [
        {
            "op": "refresh",
            "urn": "urn:pulumi:dev::service-account::pulumi:pulumi:Stack::service-account-dev",
            "oldState": {
                "urn": "urn:pulumi:dev::service-account::pulumi:pulumi:Stack::service-account-dev",
                "custom": false,
                "type": "pulumi:pulumi:Stack",
                "created": "0001-01-01T00:00:00Z",
                "modified": "0001-01-01T00:00:00Z"
            },
            "newState": {
                "urn": "urn:pulumi:dev::service-account::pulumi:pulumi:Stack::service-account-dev",
                "custom": false,
                "type": "pulumi:pulumi:Stack",
                "created": "0001-01-01T00:00:00Z",
                "modified": "0001-01-01T00:00:00Z"
            },
            "detailedDiff": null
        }
    ],
    "duration": 386278166,
    "changeSummary": {
        "same": 1,
        "update": 1
    }
}

@iwahbe
Copy link
Member

iwahbe commented Apr 10, 2024

To clarify what happens with the repo from #7665 (comment):

𝛌 pulumi refresh --diff --preview-only
Previewing refresh (dev)

View Live: https://app.pulumi.com/pulumi/dev-yaml/dev/previews/49d5fe3d-cc21-49b1-b031-bdf8f3b2a3d3

  pulumi:pulumi:Stack: (same)
    [urn=urn:pulumi:dev::dev-yaml::pulumi:pulumi:Stack::dev-yaml-dev]
Resources:               
    ~ 1 to update
    1 unchanged
𝛌 pulumi refresh --preview-only       
Previewing refresh (dev)

View in Browser (Ctrl+O): https://app.pulumi.com/pulumi/dev-yaml/dev/previews/7afc727c-de6e-4223-b6f2-6e1f45d447e8

     Type                   Name              Plan       Info
     pulumi:pulumi:Stack    dev-yaml-dev                 
 ~   └─ gcp:storage:Bucket  my-bucket-iwahbe  update     [diff: ~storageClass]

Resources:
    ~ 1 to update
    1 unchanged

Both show a diff, but --diff somehow prevents the detailed diff from being shown.

@iwahbe
Copy link
Member

iwahbe commented Apr 10, 2024

To investigate further, I captured the gRPC logs for each request into with-diff.json and no-diff.json respectively.

with-diff.json
{
    "method": "/pulumirpc.ResourceProvider/GetPluginInfo",
    "request": {},
    "response": {
        "version": "v7.18.0"
    },
    "metadata": {
        "kind": "resource",
        "mode": "client",
        "name": "gcp"
    }
}
{
    "method": "/pulumirpc.ResourceProvider/Configure",
    "request": {
        "variables": {
            "gcp:config:project": "pulumi-development",
            "gcp:config:region": "us-west1"
        },
        "args": {
            "project": "pulumi-development",
            "region": "us-west1"
        },
        "acceptSecrets": true,
        "acceptResources": true,
        "sendsOldInputs": true,
        "sendsOldInputsToDelete": true
    },
    "response": {
        "supportsPreview": true
    },
    "metadata": {
        "kind": "resource",
        "mode": "client",
        "name": "gcp"
    }
}
{
    "method": "/pulumirpc.ResourceProvider/Read",
    "request": {
        "id": "my-bucket-iwahbe-dbc8024",
        "urn": "urn:pulumi:dev::dev-yaml::gcp:storage/bucket:Bucket::my-bucket-iwahbe",
        "properties": {
            "__meta": "{\"e2bfb730-ecaa-11e6-8f88-34363bc7c4c0\":{\"create\":600000000000,\"read\":240000000000,\"update\":240000000000},\"schema_version\":\"1\"}",
            "autoclass": null,
            "cors": [],
            "customPlacementConfig": null,
            "defaultEventBasedHold": false,
            "effectiveLabels": {},
            "enableObjectRetention": false,
            "encryption": null,
            "forceDestroy": false,
            "id": "my-bucket-iwahbe-dbc8024",
            "labels": {},
            "lifecycleRules": [],
            "location": "US",
            "logging": null,
            "name": "my-bucket-iwahbe-dbc8024",
            "project": "pulumi-development",
            "projectNumber": 921927215178,
            "publicAccessPrevention": "inherited",
            "pulumiLabels": {},
            "requesterPays": false,
            "retentionPolicy": null,
            "rpo": "DEFAULT",
            "selfLink": "https://www.googleapis.com/storage/v1/b/my-bucket-iwahbe-dbc8024",
            "softDeletePolicy": {
                "effectiveTime": "2024-04-10T14:45:55.883Z",
                "retentionDurationSeconds": 604800
            },
            "storageClass": "ARCHIVE",
            "uniformBucketLevelAccess": false,
            "url": "gs://my-bucket-iwahbe-dbc8024",
            "versioning": null,
            "website": null
        },
        "inputs": {
            "__defaults": [
                "forceDestroy",
                "name"
            ],
            "forceDestroy": false,
            "location": "US",
            "name": "my-bucket-iwahbe-dbc8024",
            "storageClass": "ARCHIVE"
        }
    },
    "response": {
        "id": "my-bucket-iwahbe-dbc8024",
        "properties": {
            "__meta": "{\"e2bfb730-ecaa-11e6-8f88-34363bc7c4c0\":{\"create\":600000000000,\"read\":240000000000,\"update\":240000000000},\"schema_version\":\"1\"}",
            "autoclass": null,
            "cors": [],
            "customPlacementConfig": null,
            "defaultEventBasedHold": false,
            "effectiveLabels": {},
            "enableObjectRetention": false,
            "encryption": null,
            "forceDestroy": false,
            "id": "my-bucket-iwahbe-dbc8024",
            "labels": {},
            "lifecycleRules": [],
            "location": "US",
            "logging": null,
            "name": "my-bucket-iwahbe-dbc8024",
            "project": "pulumi-development",
            "projectNumber": 921927215178,
            "publicAccessPrevention": "inherited",
            "pulumiLabels": {},
            "requesterPays": false,
            "retentionPolicy": null,
            "rpo": "DEFAULT",
            "selfLink": "https://www.googleapis.com/storage/v1/b/my-bucket-iwahbe-dbc8024",
            "softDeletePolicy": {
                "effectiveTime": "2024-04-10T14:45:55.883Z",
                "retentionDurationSeconds": 604800
            },
            "storageClass": "ARCHIVE",
            "uniformBucketLevelAccess": false,
            "url": "gs://my-bucket-iwahbe-dbc8024",
            "versioning": null,
            "website": null
        },
        "inputs": {
            "__defaults": [
                "forceDestroy",
                "name"
            ],
            "forceDestroy": false,
            "location": "US",
            "name": "my-bucket-iwahbe-dbc8024",
            "storageClass": "ARCHIVE"
        }
    },
    "metadata": {
        "kind": "resource",
        "mode": "client",
        "name": "gcp"
    }
}
no-diff.json
{
    "method": "/pulumirpc.ResourceProvider/GetPluginInfo",
    "request": {},
    "response": {
        "version": "v7.18.0"
    },
    "metadata": {
        "kind": "resource",
        "mode": "client",
        "name": "gcp"
    }
}
{
    "method": "/pulumirpc.ResourceProvider/Configure",
    "request": {
        "variables": {
            "gcp:config:project": "pulumi-development",
            "gcp:config:region": "us-west1"
        },
        "args": {
            "project": "pulumi-development",
            "region": "us-west1"
        },
        "acceptSecrets": true,
        "acceptResources": true,
        "sendsOldInputs": true,
        "sendsOldInputsToDelete": true
    },
    "response": {
        "supportsPreview": true
    },
    "metadata": {
        "kind": "resource",
        "mode": "client",
        "name": "gcp"
    }
}
{
    "method": "/pulumirpc.ResourceProvider/Read",
    "request": {
        "id": "my-bucket-iwahbe-dbc8024",
        "urn": "urn:pulumi:dev::dev-yaml::gcp:storage/bucket:Bucket::my-bucket-iwahbe",
        "properties": {
            "__meta": "{\"e2bfb730-ecaa-11e6-8f88-34363bc7c4c0\":{\"create\":600000000000,\"read\":240000000000,\"update\":240000000000},\"schema_version\":\"1\"}",
            "autoclass": null,
            "cors": [],
            "customPlacementConfig": null,
            "defaultEventBasedHold": false,
            "effectiveLabels": {},
            "enableObjectRetention": false,
            "encryption": null,
            "forceDestroy": false,
            "id": "my-bucket-iwahbe-dbc8024",
            "labels": {},
            "lifecycleRules": [],
            "location": "US",
            "logging": null,
            "name": "my-bucket-iwahbe-dbc8024",
            "project": "pulumi-development",
            "projectNumber": 921927215178,
            "publicAccessPrevention": "inherited",
            "pulumiLabels": {},
            "requesterPays": false,
            "retentionPolicy": null,
            "rpo": "DEFAULT",
            "selfLink": "https://www.googleapis.com/storage/v1/b/my-bucket-iwahbe-dbc8024",
            "softDeletePolicy": {
                "effectiveTime": "2024-04-10T14:45:55.883Z",
                "retentionDurationSeconds": 604800
            },
            "storageClass": "STANDARD",
            "uniformBucketLevelAccess": false,
            "url": "gs://my-bucket-iwahbe-dbc8024",
            "versioning": null,
            "website": null
        },
        "inputs": {
            "__defaults": [
                "forceDestroy",
                "name",
                "storageClass"
            ],
            "forceDestroy": false,
            "location": "US",
            "name": "my-bucket-iwahbe-dbc8024",
            "storageClass": "STANDARD"
        }
    },
    "response": {
        "id": "my-bucket-iwahbe-dbc8024",
        "properties": {
            "__meta": "{\"e2bfb730-ecaa-11e6-8f88-34363bc7c4c0\":{\"create\":600000000000,\"read\":240000000000,\"update\":240000000000},\"schema_version\":\"1\"}",
            "autoclass": null,
            "cors": [],
            "customPlacementConfig": null,
            "defaultEventBasedHold": false,
            "effectiveLabels": {},
            "enableObjectRetention": false,
            "encryption": null,
            "forceDestroy": false,
            "id": "my-bucket-iwahbe-dbc8024",
            "labels": {},
            "lifecycleRules": [],
            "location": "US",
            "logging": null,
            "name": "my-bucket-iwahbe-dbc8024",
            "project": "pulumi-development",
            "projectNumber": 921927215178,
            "publicAccessPrevention": "inherited",
            "pulumiLabels": {},
            "requesterPays": false,
            "retentionPolicy": null,
            "rpo": "DEFAULT",
            "selfLink": "https://www.googleapis.com/storage/v1/b/my-bucket-iwahbe-dbc8024",
            "softDeletePolicy": {
                "effectiveTime": "2024-04-10T14:45:55.883Z",
                "retentionDurationSeconds": 604800
            },
            "storageClass": "ARCHIVE",
            "uniformBucketLevelAccess": false,
            "url": "gs://my-bucket-iwahbe-dbc8024",
            "versioning": null,
            "website": null
        },
        "inputs": {
            "__defaults": [
                "forceDestroy",
                "name"
            ],
            "forceDestroy": false,
            "location": "US",
            "name": "my-bucket-iwahbe-dbc8024",
            "storageClass": "ARCHIVE"
        }
    },
    "metadata": {
        "kind": "resource",
        "mode": "client",
        "name": "gcp"
    }
}

The only difference between the two is the the Read request (the response is identical):

𝛌 json-diff <(jq --sort-keys .request with-diff.json) <(jq --sort-keys .request no-diff.json)
 {
   inputs: {
     __defaults: [
       ...
       ...
+      "storageClass"
     ]
-    storageClass: "ARCHIVE"
+    storageClass: "STANDARD"
   }
   properties: {
-    storageClass: "ARCHIVE"
+    storageClass: "STANDARD"
   }
 }

This makes me pretty convinced that the problem is in https://github.com/pulumi/pulumi, not https://github.com/pulumi/pulumi-gcp.

@joeduffy
Copy link
Member

Here's my quick read (I was curious). We seem to intentionally skip showing detailed diffs for refreshes and imports:

if payload.Metadata.Op == deploy.OpRefresh || payload.Metadata.Op == deploy.OpImport {

But this seems immaterial, because DetailedDiff here is nil (which is why Zach saw what he did from --json):

if metadata.DetailedDiff != nil {

Why is that nil? It turns out, RefreshStep doesn't even implement DetailedDiff():

// RefreshStep is a step used to track the progress of a refresh operation. A refresh operation updates the an existing
// resource by reading its current state from its provider plugin. These steps are not issued by the step generator;
// instead, they are issued by the deployment executor as the optional first step in deployment execution.
type RefreshStep struct {
deployment *Deployment // the deployment that produced this refresh
old *resource.State // the old resource state, if one exists for this urn
new *resource.State // the new resource state, to be used to query the provider
done chan<- bool // the channel to use to signal completion, if any
provider plugin.Provider // the optional provider to use.
}

And the engine seems to have been taught to handle the fact that not all steps have DetailedDiffs:

pulumi/pkg/engine/events.go

Lines 350 to 355 in 29dfdca

var detailedDiff map[string]plugin.PropertyDiff
if detailedDiffer, hasDetailedDiff := step.(interface {
DetailedDiff() map[string]plugin.PropertyDiff
}); hasDetailedDiff {
detailedDiff = detailedDiffer.DetailedDiff()
}

Hence the nil.

So I guess, unless I'm mistaken or missing something, this is behaving as "intended" by the original implementation -- but if you ask me, it's surprising and should be addressed.

@justinvp justinvp added this to the 0.103 milestone Apr 11, 2024
@Frassle
Copy link
Member

Frassle commented Apr 12, 2024

So I think this might just be the shouldShow logic has a bug for diff view:
https://github.com/pulumi/pulumi/blob/master/pkg/backend/display/display.go#L202-L206

        // For logical replacement operations, only show them during progress-style updates (since this is integrated
	// into the resource status update), or if it is requested explicitly (for diffs and JSON outputs).
	if (opts.Type == DisplayDiff || opts.JSONDisplay) && !step.Logical && !opts.ShowReplacementSteps {
		return false
	}

It looks like this is trying to say "if it's a logical update only show it if we're in progress mode or we've explicitly set ShowReplacmentSteps. But the actual logic means any non-logical step gets skipped in diff or json mode.

Fixing that to instead be:

 	if (opts.Type != DisplayProgress || opts.JSONDisplay) && step.Logical {
		return opts.ShowReplacementSteps
	}

Now shows refresh updates in diff mode, but I suspect this is going to change a lot of display output for diff mode.

github-merge-queue bot pushed a commit that referenced this issue Apr 26, 2024
When displaying diff events, we currently try to hide non-logical
replacement steps unless we specifically enable showing them. However we
currently do that for all non-logical operations, regardless whether
they are replacement steps or not.

In particular a RefreshStep is non-logical, but it's also not a
replacement step. We still want to show them during the diff because
their output can be important. Especially if the user just requested a
diff it doesn't make sense to hide the diff from them at the same time.

The intention here is to only hide replacement steps, so do that.

The full diff with the display tests is here:
https://gist.github.com/tgummerer/fcd012f13669a9cdc39530cde7770260 It's
unedited, so it includes some flakyness which isn't interesting.

I looked it over, and I think it looks like what we want, but I'm
curious to hear what others think. E.g.
https://gist.github.com/tgummerer/fcd012f13669a9cdc39530cde7770260#file-testdata-diff-L558
looks more correct now, as it shows the two delete operation that
actually happened, that it didn't show before, and it still shows the
same operation (Calling this one out in particular, since it took me a
bit to understand that we still have the same operation in the diff)

Fixes #7665
@justinvp justinvp assigned tgummerer and unassigned Frassle Apr 26, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
area/cli UX of using the CLI (args, output, logs) kind/bug Some behavior is incorrect or out of spec
Projects
None yet
10 participants