agreeable-tomato-43927
06/23/2021, 2:50 PMconst bucketObject = new aws.s3.BucketObject("index.html", {
acl: "public-read",
contentType: "text/html",
bucket: bucket,
source: new pulumi.asset.FileAsset(pulumi.interpolate`${yarnBuild.path}/index.html`)
});
☝️this fails because FileAsset don't accept an output
const bucketObject = new aws.s3.BucketObject("index.html", {
acl: "public-read",
contentType: "text/html",
bucket: bucket,
source: pulumi.all([yarnBuild.path]).apply(([p]) => new pulumi.asset.FileAsset(`${p}/index.html`))
});
☝️this fails because p is undefined...yarnBuild.path
) as an input to the BucketObjectbrave-planet-10645
06/23/2021, 3:06 PMpulumi
.all([yarnBuild.path])
.apply(([p]) => new aws.s3.BucketObject("index.html", {
acl: "public-read",
contentType: "text/html",
bucket: bucket,
source: new pulumi.asset.FileAsset(`${p}/index.html`)
}));
bored-oyster-3147
06/23/2021, 3:25 PMbrave-planet-10645
06/23/2021, 3:28 PMagreeable-tomato-43927
06/23/2021, 3:33 PMerror: Error: failed to register new resource index.html [aws:s3/bucketObject:BucketObject]: 2 UNKNOWN: failed to compute asset hash: failed to open asset file 'undefined/index.html': open undefined/index.html: no such file or directory
Then I tried to run with:
pulumi
.all([yarnBuild.path])
.apply(([p]) => p && new aws.s3.BucketObject("index.html", {
acl: "public-read",
contentType: "text/html",
bucket: bucket,
source: new pulumi.asset.FileAsset(`${p}/index.html`)
}));
Now the deploy works but it doesn't create the BucketObject (after the deploy, there's an empty S3 bucket)brave-planet-10645
06/23/2021, 3:35 PMp && new...
in there. I'm not sure that this would work.
Where are you getting yarnBuild.path from?agreeable-tomato-43927
06/23/2021, 3:38 PMp && new...
the preview fails as p is undefined. yarnBuild is a custom dynamic provider:
export interface YarnResourceInputs {
apiUrl: pulumi.Input<string>;
}
interface YarnResourceProviderInputs {
apiUrl: string;
}
interface YarnResourceProviderOutputs {
path: string;
}
const YarnResourceProvider: pulumi.dynamic.ResourceProvider = {
async create(inputs: YarnResourceProviderInputs): Promise<pulumi.dynamic.CreateResult> {
//build frontend with "yarn build"
console.log('YarnResourceProvider:create ', inputs.apiUrl)
return { id: "123", outs: { path: './dist' }};
},
async diff(id: string, olds: YarnResourceProviderInputs, news: YarnResourceProviderInputs): Promise<pulumi.dynamic.DiffResult> {
return {changes: true, replaces: ['apiUrl']}
}
}
class YarnResource extends pulumi.dynamic.Resource {
public readonly path!: pulumi.Output<string>;
constructor(name: string, props: YarnResourceInputs, opts?: pulumi.CustomResourceOptions) {
super(YarnResourceProvider, name, props, opts);
}
}
const yarnBuild = new YarnResource('yarn-build', {apiUrl: api.url})
api.url
comes from the backend resourcebored-oyster-3147
06/23/2021, 3:52 PMpulumi.all(...)
for a single output since that is meant to be used to get multiple outputs into the same apply delegate. Why not just yarnBuild.path.apply(p => new aws.s3.BucketObject(...));
Also it doesn't look like YarnResource
is setting and/or registering path
as an output?brave-planet-10645
06/23/2021, 4:03 PMbored-oyster-3147
06/23/2021, 4:05 PMagreeable-tomato-43927
06/23/2021, 4:05 PMyarnBuild.path.apply(...)
but it fails in the preview run as yarnBuild.path == undefined
bored-oyster-3147
06/23/2021, 4:05 PMagreeable-tomato-43927
06/23/2021, 4:06 PMYarnResourceProvider
create functionbored-oyster-3147
06/23/2021, 4:07 PMYarnResource.path
. You need to set it in your YarnResource
constructor after calling the base constructor. And @brave-planet-10645 is saying that it can be string
instead of Output<string>
agreeable-tomato-43927
06/23/2021, 4:07 PMYarnResourceProvider
is supposed to run "yarn build", grab the path of the build and return it as an output to be used by the bucket resourcebrave-planet-10645
06/23/2021, 4:08 PMOutput<string>
?agreeable-tomato-43927
06/23/2021, 4:09 PMasync create(inputs: YarnResourceProviderInputs): Promise<pulumi.dynamic.CreateResult> {
//build frontend with "yarn build"
return { id: "123", outs: { path: './dist' }};
},
I'm using examples from your docs. Do I need to convert the './dist'
part to an output object? I thought Pulumi did this automaticallybrave-planet-10645
06/23/2021, 4:14 PMbored-oyster-3147
06/23/2021, 4:17 PMCreateResult
. Not a fan of magic implementations like that but my bad for confusing the discussion
I did notice that your code differs from the documentation example slightly on 1 point:
...
interface MyResourceProviderOutputs {
myNumberOutput: number;
myStringOutput: string;
}
class MyResourceProvider implements pulumi.dynamic.ResourceProvider {
async create(inputs: MyResourceProviderInputs): Promise<pulumi.dynamic.CreateResult> {
...
// Values are for an example only.
return { id: "...", outs: { myNumberOutput: 12, myStringOutput: "some value" }};
}
}
export class MyResource extends pulumi.dynamic.Resource {
public readonly myStringOutput!: pulumi.Output<string>;
public readonly myNumberOutput!: pulumi.Output<number>;
constructor(name: string, props: MyResourceInputs, opts?: pulumi.CustomResourceOptions) {
super(myprovider, name, { myStringOutput: undefined, myNumberOutput: undefined, ...props }, opts);
}
}
Maybe that object expansion in the super
call is important? They are doing something similar in all of the other SDK examples. Maybe your super
call should be super(YarnResourceProvider, name, { path: undefined, ...props }, opts);
agreeable-tomato-43927
06/23/2021, 4:52 PMbored-oyster-3147
06/23/2021, 4:55 PMbrave-planet-10645
06/24/2021, 9:23 AMimport * as pulumi from "@pulumi/pulumi";
export interface YarnResourceInputs {
apiUrl: pulumi.Input<string>;
}
interface YarnResourceProviderInputs {
apiUrl: string;
}
interface YarnResourceProviderOutputs {
path: string;
}
const YarnResourceProvider: pulumi.dynamic.ResourceProvider = {
async create(inputs: YarnResourceProviderInputs): Promise<pulumi.dynamic.CreateResult> {
//build frontend with "yarn build"
// console.log('YarnResourceProvider:create ', inputs.apiUrl)
return { id: "123", outs: { path: './dist' }};
},
async diff(id: string, olds: YarnResourceProviderInputs, news: YarnResourceProviderInputs): Promise<pulumi.dynamic.DiffResult> {
return {changes: true, replaces: ['apiUrl']}
}
}
export class YarnResource extends pulumi.dynamic.Resource {
public readonly path!: pulumi.Output<string>;
constructor(name: string, props: YarnResourceInputs, opts?: pulumi.CustomResourceOptions) {
super(YarnResourceProvider, name, {path: undefined, ...props}, opts);
}
}
And then updating the program slightly so the bucketobject isn't created in the apply, but the fileasset, you get something like this:
import * as pulumi from "@pulumi/pulumi";
import * as provider from "./provider";
import * as aws from "@pulumi/aws";
const yarn = new provider.YarnResource("yarn", {
apiUrl: "<http://thing.com|thing.com>"
});
export const path = yarn.path;
const bucket = new aws.s3.Bucket("bucket");
const file = yarn.path.apply(x => new pulumi.asset.FileAsset(x));
const bucketObject = new aws.s3.BucketObject("object", {
source: file,
bucket
})
agreeable-tomato-43927
06/24/2021, 6:03 PM