f

    flat-kangaroo-13810

    8 months ago
    Hi All, I have been learning Pulumi for a few weeks. I am working with dotnet deploying GCP and Kubernetes resources. I have run into an issue where when running pulumi up, the preview does not display all of the operations that I am trying to create. But when the actual update operation happens, it does the correct thing and creates all the correct items. This started occurring after I wanted to make the stack a bit easier to add DNS items for cloud-dns for GCP. I pulled the details of each record into the pulumi config in a json object, then on start up I parsed the config and generated all of the dns records. When I run Pulumi Up, the preview does not show any of the cloud dns records I am creating. If by chance I have already ran the operation once and created the records, the preview says it wants to delete the records. Does anyone happen to know why the preview would break by doing this? Example: (quick snippet on pulling dns records from config and creating them. )
    var data = config.RequireObject<Models.DNS.DNSConfigModel>("dns");
    
    foreach (Models.DNS.ZoneConfigModel zone in data.zones)
                {
                    ManagedZone requestedZone = createManagedZone(zone, new List<Resource>() {});
    
                    foreach (Models.DNS.RecordConfigModel record in zone.records)
                    {
    
                        Output.All(requestedZone.Name, ingressIp.Apply(t => t)).Apply(x =>
                        {
                            createRecordSet(x[0], record, new List<Resource>() { requestedZone }, x[1]);
                            return "";
                        });
                    }
                }
    Example: (config)
    <project>:dns:
        zones:
        - name: website-com
          projectKey: networking
          dnsName: <http://website.com|website.com>.
          description: "Zone for website-com"
          protect: true
          records:
          - name: <http://api.website.com|api.website.com>.
            isIngressEndpoint: false
            projectKey: networking
            type: CNAME
            ttl: 300
            protect: true
            rrDatas:
            - website.hosted.com.
    e

    echoing-dinner-19531

    8 months ago
    the preview does not display all of the operations that I am trying to create. But when the actual update operation happens, it does the correct thing and creates all the correct items.
    That's because your creating resources inside an Apply call.
    Output.All(requestedZone.Name, ingressIp.Apply(t => t)).Apply(x =>
    {
        createRecordSet(x[0], record, new List<Resource>() { requestedZone }, x[1]);
        return "";
    });
    The engine can't always run the code inside an Apply at preview because it doesn't have a value to pass in. We've been thinking about how we could better support cases like this see https://github.com/pulumi/pulumi/issues/5464 Also
    output.Apply(x => x)
    is a no-op, you should never need to write that.
    f

    flat-kangaroo-13810

    8 months ago
    Fraser, Thank you so much for your response. Do you suggest a better way this could be written for this situation? Or would you say the current best practices is to not create resources dynamically by config? Also thanks about the no-op, I believe I did that because it was an Input at first, so I did that to convert it to an output.
    e

    echoing-dinner-19531

    8 months ago
    There isn't a better way currently, it's a tricky problem but we do keep thinking about. Creating resources dynamically like this is mostly fine, update will handle it fine it just means your previews don't match. Up to you how much you care about that.
    f

    flat-kangaroo-13810

    8 months ago
    Ahh okay. Well thank you for the feedback. We have found that the previews are pretty important for us to maintain. In this situation, we have found that because it doesnt process the records during the preview it tries to tell us its going to delete the records if they already exist from an update. Which can be confusing for other users. So we went back to more statically typed.
    w

    worried-city-86458

    8 months ago
    What does the code for
    createManagedZone
    and
    createRecordSet
    look like? Where is
    ingressIp
    initialized? You might be able to pass the outputs directly to input properties used in these methods and thereby avoid creating the resources inside apply.
    e

    echoing-dinner-19531

    8 months ago
    We have found that the previews are pretty important for us to maintain. In this situation, we have found that because it doesnt process the records during the preview it tries to tell us its going to delete the records if they already exist from an update
    If your not changing the objects that
    requestedZone
    and
    ingressIp
    came from they should be "known" at preview time and the apply should of ran. If they we're stable in your updates and you were still seeing the apply not run that looks like a bug, and you should open an issue at https://github.com/pulumi/pulumi/issues about it. Also fools point is a good one here. If
    createRecordSet
    could take
    Output<T>
    instead of just plain
    T
    you wouldn't need the apply.
    f

    flat-kangaroo-13810

    8 months ago
    @worried-city-86458 Thats a good point. IngressIp is an output from another CustomResource. (TLDR: deploy nginx ingress in k8s on gcp, get the public ip from the service and pass that back out as an output) Sample of createRecordSet (Nuked the createManagedZone when I changed the pattern):
    private RecordSet createRecordSet(string zoneName, Models.DNS.RecordConfigModel record, InputList<Resource> dependsOn, string ingressIp="")
            {
                var recordArgs = new RecordSetArgs();
                recordArgs.Name = record.name;
                recordArgs.Type = record.type;
                recordArgs.Ttl = record.ttl;
                recordArgs.ManagedZone = zoneName;
                recordArgs.Project = _projectManager.GetProject(record.projectKey);
    
                if (record.isIngressEndpoint)
                {
                    recordArgs.Rrdatas = new List<string>() { ingressIp };
                }
                else
                {
                    recordArgs.Rrdatas = record.rrDatas;
                }
                
                var customOptions = new CustomResourceOptions();
                customOptions.DependsOn = dependsOn;
                customOptions.Protect = record.protect;
                customOptions.Parent = this;
    
                var recordRequest = new RecordSet($"{record.name.ToLower().Replace(".", "-")}{record.type.ToLower()}-record-set", recordArgs, customOptions);
    
                return recordRequest;
            }
    If your not changing the objects that  
    requestedZone
     and 
    ingressIp
     came from they should be "known" at preview time and the apply should of ran. If they we're stable in your updates and you were still seeing the apply not run that looks like a bug, and you should open an issue at https://github.com/pulumi/pulumi/issues about it.
    They do not change between runs unless we recreate the nginx-ingress or k8s cluster. Which we are not doing very often at all. A better way to explain: Before anything is created in the cloud provider, when I run "pulumi up" the preview does not show it will create the dns objects. But if you tell it to continue, it does the right thing and creates the records. If you run "pulumi up" again, the preview has not executed the code that was happening in an Output.Apply, so it doesnt think that the records should exist anymore. So it tells the user that its going to delete them if you let it continue. If you let it continue, it does the correct thing. It just no-ops because nothing actually changed now that it could execute the full code path. I understand the behavior now and can see why that happens. I will play around and see if the suggestions that you and fool have made will change that behavior. 🙂
    w

    worried-city-86458

    8 months ago
    Yeah, you can change
    zoneName
    and
    ingressIp
    parameters from
    string
    to
    Output<string>
    types, then no need for apply.
    f

    flat-kangaroo-13810

    8 months ago
    Good point, thank you fool. I will give that a try.
    Another thought:
    If your not changing the objects that  
    requestedZone
     and 
    ingressIp
     came from they should be "known" at preview time
    I am not recording the IPAddress or the Zone as actual stack outputs, but just outputs from resources that I reference in the same stack. Could that be why it might not be "known"
    e

    echoing-dinner-19531

    8 months ago
    No I think they should still be known, I'll have a look into this at some point sounds suspect.