I'm looking into using beforeUpdate in a ResourceH...
# general
f
I'm looking into using beforeUpdate in a ResourceHookBinding to start an AWS EC2 instance before I run a command on it. However, to start the instance I need the IID, and the IID is an output of an aws.EC2 resource. It looks like the only way I can feed the aws.EC2 resource ID in to the hook as a resolved value is to make it an input of the resource I have attached the hook to. It would be useful if hooks could get access to the outputs of the parent resource, as the resource I'm attaching my hook to is a child of the aws.ec2 resource.
n
I'm not sure about your specific case, but something like this should work
Copy code
// Convert a pulumi.Output to a promise of the same type.
export function promiseOf<T>(output: pulumi.Output<T>): Promise<T> {
  return new Promise((resolve) => output.apply(resolve));
}
const ec2Instance = new aws.ec2.Instance('instance');
const beforeHook = new pulumi.ResourceHook('before', async (_args) => {
  const id = await promiseOf(ec2Instance.id);
  console.log(`Instance ID: ${id}`);
});
const cmd = new command.local.Command(
  'curl',
  {
    create: 'echo "hello"',
    update: 'echo "hello again"',
    triggers: [new Date()],
  },
  {
    hooks: {
      beforeCreate: [beforeHook],
      beforeUpdate: [beforeHook],
    },
    dependsOn: [ec2Instance],
  },
);
e
The outputs are sent to hooks:
Copy code
export interface ResourceHookArgs {
    /**
     * The URN of the resource that triggered the hook.
     */
    urn: URN;
    /**
     * The ID of the resource that triggered the hook.
     */
    id: ID;
    /**
     * The name of the resource that triggered the hook.
     */
    name: string;
    /**
     * The type of the resource that triggered the hook.
     */
    type: string;
    /**
     * The new inputs of the resource that triggered the hook.
     */
    newInputs?: Record<string, any>;
    /**
     * The old inputs of the resource that triggered the hook.
     */
    oldInputs?: Record<string, any>;
    /**
     * The new outputs of the resource that triggered the hook.
     */
    newOutputs?: Record<string, any>;
    /**
     * The old outputs of the resource that triggered the hook.
     */
    oldOutputs?: Record<string, any>;
}
and if you need the outputs of a different resource then Cory's suggestion covers you
f
FWIW I'm using the Python API. I tried something like that in Python, using output.apply() to get the value of the id, but it appears that the lambda/function I'm passing to output.apply() is not getting called before the update happens. It's would appear Pulumi is not waiting for my output.apply()
Copy code
def start_instance( iid_input: pulumi.Output[str], region:str, args ):
    def do_start_instance( iid:str, region:str ):
        ec2 = boto3.client("ec2', region_name=region)
        ec2.start_instances( InstanceIds=[iid] )
    iid_input.apply( lambda value, r=region: do_start_instance( value, r ) )
e
applys run asynchronously, you'll need to do a similar trick to the typescript to push it into a promise and await that.
I think this is the same:
Copy code
def promise_of(output: pulumi.Output):
    fut = Future()
    output.apply(fut.set_result)
    return fut
f
AFAIK that would require that I'm using asyncio?
e
Pretty sure hooks are all asyncio functions anyway
1
f
I'll give that a go, thanks!
e
Copy code
ResourceHookFunction = Callable[
    [ResourceHookArgs],
    Union[None, Awaitable[None]],
]
So I think you can just tag it async and use await inside it
f
Just wanted to chime in that this worked great. Thanks!