pulumi-command icon indicating copy to clipboard operation
pulumi-command copied to clipboard

Add support for using `pulumi.asset.StringAsset` in `CopyToRemote`

Open brncsk opened this issue 8 months ago • 3 comments

Using StringAssets currently (1.1.0) result in the following error:

error: command:remote:CopyToRemote resource '...': property asset value {<nil>} has a problem: asset must be a path-based file asset

brncsk avatar Jul 09 '25 10:07 brncsk

Thanks for filing this issue @brncsk.

As noted in the documentation, the CopyToRemote resource currently only supports FileAsset or FileArchive values for source. The resource is meant to model a file copy, so we did not implement a copy for a StringAsset; it is probably possible to extent the resource to do this though.

It would be helpful input for us if you could clarify how you would like CopyToRemote to work when given a StringAsset as a source - possibly with an example or two?

mjeffryes avatar Jul 25 '25 21:07 mjeffryes

Sure – I'm trying to copy a PKI certificate from @pulumi/vault like so:

const cert = new vault.pkisecret.SecretBackendCert(
  "cert",
  {
    backend: "pki",
    name: pkiSigningRole.name,
    [...]
  },
  { provider }
);

My goal is to write the contents of the cert to a file on the remote file system, so that an application (namely, RabbitMQ) can pick it up.

Ideally, I could use StringAsset for that:

// ...cont'd from above

const certAsset = new pulumi.asset.StringAsset(cert.certificate);

new command.remote.CopyToRemote("copy-cert", {
  connection: [...],
  remotePath: "/etc/ssl/private/...",
  source: certAsset
}); // <-- `error: [...] asset must be a path-based file asset`

In order to get around this limitation, I now have to do something along the lines of:

new command.remote.Command("copy-cert", {
  connection: [...],
  create: pulumi.interpolate `echo "${cert.certificate}" | sudo tee /etc/ssl/private/...`
});

brncsk avatar Jul 27 '25 15:07 brncsk

	var scriptBuf bytes.Buffer
	err = installScriptTmpl.Execute(&scriptBuf, struct {
		Packages []string
	}{
		Packages: args.Packages,
	})
	if err != nil {
		return nil, fmt.Errorf("failed to render install script: %w", err)
	}

	// Upload the script to the remote host's home directory directly from memory
	remoteScriptPath := fmt.Sprintf("~/apt-%s-install.sh", name)
	upload, err := remote.NewCopyToRemote(ctx, fmt.Sprintf("%s-upload", name), &remote.CopyToRemoteArgs{
		Connection: args.ConnectionArgs,
		Source:     pulumi.NewStringAsset(scriptBuf.String()),
		RemotePath: pulumi.String(remoteScriptPath),
	}, pulumi.Parent(component))
	if err != nil {
		return nil, fmt.Errorf("failed to upload install script: %w", err)
	}

I have a script in go template that embed. I want to upload contents to a file on the host.

Or simple case of wanting to write a config file to the host without having to use "echo {contents} | tee {path}"

kespinola avatar Sep 22 '25 18:09 kespinola