jolly-megabyte-6233
01/29/2025, 4:12 PM// USAGE EXAMPLE
const childModel = new AssetModel("test-child-1", {
name: "some-child-model",
description: "some-child-model",
externalId: "some-child-model",
})
const assetModel = new AssetModel("test-1", {
name: "some-asset-model",
description: "some-asset-model",
externalId: "some-asset-model",
properties: [
{
name: "prop-2",
externalId: "SAM-prop-1",
dataType: PropertyDataType.DOUBLE,
unit: "someNewUnit",
},
],
children: [
{
name: "asset-model-child",
externalId: "asset-model-child",
// !!! The next line is what causes the failure: `childModel.externalId` is `undefined` when pulumi runs the program
modelId: childModel.externalId.apply(externalId),
},
],
})
And here's the implementation my resource + provider (some implementation details omitted):
export interface AssetModelProviderArgs {
/** The name of the asset model */
name: string
/** An external id to reference this asset model */
externalId: string
/** The description of the asset model */
description: string
/** The properties of the asset model */
properties?: AssetModelProperty[]
/** The child asset model associations of the asset model */
children?: AssetModelChild[]
}
export interface AssetModelProperty {
/** The name of the asset model property */
name: string
/** An external id to reference this asset model property */
externalId: string
/** The data type of the asset model property */
dataType: PropertyDataType
/** The unit of the asset model property */
unit?: string
}
export interface AssetModelChild {
/** The name of the child asset model association */
name: string
/** An external id to reference this child asset model association */
externalId: string
/** The external id of the child asset model */
modelId: SitewiseId
}
export interface AssetModelProviderOuts extends AssetModelProviderArgs {
arn: string
}
const readAssetModelOuts = async (
id: string,
): Promise<AssetModelProviderOuts | undefined> => {
let readResponse: DescribeAssetModelResponse | null = null
try {
readResponse = await getSitewiseClient().assetModel.read({
assetModelId: id,
})
} catch (error) {
if (error instanceof AxiosError && error.response?.status === 404) {
return undefined
}
throw error
}
const assetModel: AssetModelProviderArgs = {
name: readResponse.assetModelName!,
externalId: readResponse.assetModelExternalId!,
description: readResponse.assetModelDescription!,
properties: (readResponse.assetModelProperties ?? []).map((property) => ({
name: property.name!,
externalId: property.externalId!,
dataType: property.dataType!,
unit: property.unit,
})),
children: (readResponse.assetModelHierarchies ?? []).map((hierarchy) => ({
name: hierarchy.name!,
externalId: hierarchy.externalId!,
modelId: uuid(hierarchy.childAssetModelId!),
})),
}
return {
...assetModel,
arn: readResponse.assetModelArn!,
}
}
export interface AssetModelArgs {
name: Input<string>
description: Input<string>
externalId: Input<string>
properties?: Input<AssetModelProviderArgs["properties"]>
children?: AsInput<AssetModelChild>[]
}
export const assetModelProvider: dynamic.ResourceProvider<
AssetModelProviderArgs,
AssetModelProviderOuts
> = {
async create(args) {
// ... details omitted
return {
id,
outs: await readAssetModelOuts(id),
}
},
async read(id, outs) {
return {
id,
props: outs ? await readAssetModelOuts(id) : undefined,
}
},
async diff(_, oldOuts, newArgs) {
// ... details omitted
return {
changes: !deepEqual(relevantOuts, relevantArgs),
stables: ["id", "arn", "externalId"],
}
},
async update(id, _, newArgs) {
// ... details omitted
return {
outs: await readAssetModelOuts(id),
}
},
async delete(id) {
// Note: This is not sufficient to delete models that contribute to a property formula in a parent.
await getSitewiseClient().assetModel.delete({ assetModelId: id })
},
}
export class AssetModel extends dynamic.Resource {
// args
public readonly name!: Output<AssetModelProviderOuts["name"]>
public readonly description!: Output<AssetModelProviderOuts["description"]>
public readonly externalId!: Output<AssetModelProviderOuts["externalId"]>
// outs
public readonly arn!: Output<AssetModelProviderOuts["arn"]>
constructor(
name: string,
args: AssetModelArgs,
opts?: CustomResourceOptions,
) {
super(assetModelProvider, `xxx:asset-model:${name}`, args, opts)
}
}
What's the issue here?
(I have checked the pulumi state JSON file and the externalId
for the child model is set at some point.)magnificent-eve-10499
01/29/2025, 5:07 PMconst assetModel = new AssetModel("test-1", {
name: "some-asset-model",
description: "some-asset-model",
externalId: "some-asset-model",
properties: [
{
name: "prop-2",
externalId: "SAM-prop-1",
dataType: PropertyDataType.DOUBLE,
unit: "someNewUnit",
},
],
children: [
{
name: "asset-model-child",
externalId: "asset-model-child",
// !!! The next line is what causes the failure: `childModel.externalId` is `undefined` when pulumi runs the program
modelId: childModel.externalId.apply(externalId),
},
],
},
{ dependsOn: [ childModel ] },
)
jolly-megabyte-6233
01/29/2025, 5:23 PMundefined
even when adding an explicit dependency,
(Besides: I was expecting that pulumi would be able to derive the dependency from the usage of an output as part of the input of a resource?)magnificent-eve-10499
01/29/2025, 9:58 PMimport * as pulumi from '@pulumi/pulumi';
import * as dockerbuild from '@pulumi/docker-build';
import { marketingcr, acrUsername, acrPassword, registryUrl } from './registries/acrRegistry';
const config = new pulumi.Config();
const imageTag = config.get('imageTag') || 'latest';
const imageNames = [
'marketing-nginx',
'marketing-mautic_web',
];
const imageBuilds: { [key: string]: dockerbuild.Image } = {};
// Wait for the ACR to be created before proceeding
marketingcr.name.apply(acrName => {
registryUrl.apply(registry => {
for (const imageName of imageNames) {
const fullImageName = pulumi.interpolate`${registry}/${imageName}:${imageTag}`;
// Define the dockerbuild.Image resource
imageBuilds[imageName] = new dockerbuild.Image(
imageName,
{
context: {
location: '../mautic',
},
push: true,
dockerfile: {
location: `../mautic/${imageName}.dockerfile`,
},
platforms: ['linux/amd64'],
registries: [{
address: registry,
username: acrUsername,
password: acrPassword,
}],
tags: [fullImageName],
});
}
});
});
// Export the image builds so they can be used elsewhere in the Pulumi stack
export { imageBuilds };
So maybe you could nest the parent in the child like:
childModel.externalId.apply(externalId => {
const assetModel = new AssetModel("test-1", {
name: "some-asset-model",
description: "some-asset-model",
externalId: "some-asset-model",
properties: [
{
name: "prop-2",
externalId: "SAM-prop-1",
dataType: PropertyDataType.DOUBLE,
unit: "someNewUnit",
},
],
children: [
{
name: "asset-model-child",
externalId: "asset-model-child",
// !!! The next line is what causes the failure: `childModel.externalId` is `undefined` when pulumi runs the program
modelId: externalId,
},
],
},
},)
)
I believe that If externalID is still undefined this way, then it doesn't exist before running this statement.