Unable to set VM startup script metadata via Google Cloud Workflows

97 Views Asked by At

I'm trying to use Cloud Workflows to modify the metadata of an existing VM. Basically, the VM has some expensive proprietary software on it, and I'm wanting to run it headless via a workflow whenever new data comes in. Licensing restrictions mean I can't use images/templates etc. I have a function that creates the script and uploads to a bucket, so I just need to set the metadata before I start the VM via the workflow.

Example:

startupscript.sh (living in gs://(bucket)/startupscript.sh):
echo "hello world from startup script" > helloworld.txt && gsutil cp helloworld.txt gs://<bucket>

Create demo VM:
gcloud compute instances create workflow-metadata-setting-test --project=*** --zone=us-central1-c --machine-type=e2-micro --scopes=https://www.googleapis.com/auth/servicecontrol,https://www.googleapis.com/auth/service.management.readonly,https://www.googleapis.com/auth/logging.write,https://www.googleapis.com/auth/monitoring.write,https://www.googleapis.com/auth/trace.append,https://www.googleapis.com/auth/devstorage.read_write

workflow.yaml:

get_vm_fingerprint:
  params: [project, zone, instance]
  steps:
    - get_instance:
        call: googleapis.compute.v1.instances.get
        args:
          instance: ${instance}
          project: ${project}
          zone: ${zone}
        result: instance
    - extract_result:
        return: ${instance.metadata.fingerprint}

main:
  params: [event]
  steps:
    - init:
        assign:
          - project: ${sys.get_env("GOOGLE_CLOUD_PROJECT_ID")}
          - zone: us-central1-c
          - instance: "workflow-metadata-setting-test"

    - getFingerprint:
        call: get_vm_fingerprint
        args:
          instance: ${instance}
          project: ${project}
          zone: ${zone}
        result: fingerprint

    - setMetadata:
        call: googleapis.compute.beta.instances.setMetadata
        args:
            instance: ${instance}
            project: ${project}
            zone: ${zone}
            body:
                fingerprint: ${fingerprint}
                items:
                    key: startup-script-url
                    value: gs://<bucket>/startupscript.sh
        result: setMetadataResult

    - start_machine:
        call: googleapis.compute.v1.instances.start
        args:
          instance: ${instance}
          project: ${project}
          zone: ${zone}

    - return_result:
        return: ${setMetadataResult}

In theory, there should be a file called "helloworld.txt" living in gs://(bucket) after running this workflow, however, there is not. If you got into the VM details via the console, the metadata is shown as "None"

However, I do get a successful completion message displayed from setMetadataResult (I've added *** and ... for anonymity reasons):

{
  "endTime": "2023-08-09T21:17:28.983-07:00",
  "id": "7738306016998709***",
  "insertTime": "2023-08-09T21:17:28.535-07:00",
  "kind": "compute#operation",
  "name": "operation-1691641047461-60289dfb8ad83-297311a8-8a14****",
  "operationType": "setMetadata",
  "progress": 100,
  "selfLink": "https://www.googleapis.com/compute/beta/projects/.../operations/operation-1691641047461-60289dfb8ad83-297311a8-8a14****",
  "startTime": "2023-08-09T21:17:28.641-07:00",
  "status": "DONE",
  "targetId": "860253131759589****",
  "targetLink": "https://www.googleapis.com/compute/beta/projects/.../instances/workflow-test",
  "user": "****[email protected]",
  "zone": "https://www.googleapis.com/compute/beta/projects/..."
}

Does this work for anyone else? I don't know if its a permissions thing (if it were, I'd be expecting a different response to what I get), or a bug. I can set the startup-script-url metadata via console and via gcloud CLI, but just not via workflow...

Cheers!

1

There are 1 best solutions below

0
MJB On

After much trial and error, I noticed on https://cloud.google.com/compute/docs/reference/rest/v1/instances/setMetadata that items should be a list, not a dict. It started working by simply adding a '-' and appropriate indenting:

    - setMetadata:
        call: googleapis.compute.beta.instances.setMetadata
        args:
            instance: ${instance}
            project: ${project}
            zone: ${zone}
            body:
                fingerprint: ${fingerprint}
                items:
                    - key: startup-script-url
                      value: gs://<bucket>/startupscript.sh
        result: setMetadataResult