How can I create a `aws.sqs.QueuePolicy` with a dy...
# general
b
How can I create a
aws.sqs.QueuePolicy
with a dynamic list of statements? I'm getting:
Calling [toString] on an [Output<T>] is not supported.
Copy code
function createQueuePolicyStatement(inboundSqs: aws.sqs.Queue, topicData: TopicData[]): pulumi.Input<string> {
    const statement = (queueArn: Output<string>, topicArn: Output<string>) => {
        return queueArn.apply((qarn) => {
            return topicArn.apply((tarn) => {
                return `
                        {
                            "Effect": "Allow",
                            "Principal": "*",
                            "Action": "SQS:SendMessage",
                            "Resource": "${qarn}",
                            "Condition": {
                                "ArnEquals": {
                                "aws:SourceArn": "${tarn}"
                            }
                        }`
            });
        });
    }
    const policyStatement = `
        "Version": "2012-10-17",
        "Id": "sqspolicy",
        "Statement": [
            ${topicData.map((data) => statement(inboundSqs.arn, data.topic.arn)).join(`,`)}
        ]
    }`;
    return policyStatement;
}
w
this the line you get the error at?
Copy code
${topicData.map((data) => statement(inboundSqs.arn, data.topic.arn)).join(`,`)}
btw you dont have to nest .apply calls.
Copy code
pulumi.output({quarn: queueArn, tarn: topicArn}).apply(({quern, tarn}) => { ... })
b
The: "Statement": [ line
cool! is that the same as pulumi.all() ? (just found that)
still geting the same error with pulumi.output:
Copy code
Diagnostics:
  pulumi:pulumi:Stack (aws-prod):
            "Version": "2012-10-17",
            "Id": "sqspolicy",
            "Statement": [
                Calling [toString] on an [Output<T>] is not supported.
    To get the value of an Output<T> as an Output<string> consider either:
    1: o.apply(v => `prefix${v}suffix`)
    2: pulumi.interpolate `prefix${v}suffix`
    See <https://pulumi.io/help/outputs> for more details.
    This function may throw in a future version of @pulumi/pulumi.
            ]
        }
I got it working!
Copy code
function createQueuePolicyStatement(inboundSqs: aws.sqs.Queue, topicData: TopicData[]): pulumi.Output<string> {
    const statement = (queueArn: Output<string>, topicArn: Output<string>) => {
        return pulumi.interpolate`
                        {
                            "Effect": "Allow",
                            "Principal": "*",
                            "Action": "SQS:SendMessage",
                            "Resource": "${queueArn}",
                            "Condition": {
                                "ArnEquals": {
                                    "aws:SourceArn": "${topicArn}"
                                }
                            }
                        }`;

    }

    const policyStatement = pulumi.interpolate`
    {
        "Version": "2012-10-17",
        "Id": "sqspolicy",
        "Statement": [
            ${topicData.map((data) => statement(inboundSqs.arn, data.topic.arn))}
        ]
    }`;

    policyStatement.apply((p) => {
        console.log('policy', p.toString());
    });

    return policyStatement;
}
One thing I'm confused on -- it's adding the comma between statements automatically -- is that something interpolate is doing for me?
w
interesting
interpolate
is new to me.
not sure what you mean by adding commas though.
b
Copy code
"Statement": [
            ${topicData.map((data) => statement(inboundSqs.arn, data.topic.arn))}
        ]
the map returns an array of strings like: `[
{ ... }
,`{...}]`` the final output includes commas between each { .. }, {...}, {...}
Looking at the source, it doesn't look like interpolate is adding the comma -- Not sure what's going on.
I guess I'm just a typescript noob. String template interpolation is doing it. const x = ['blah', 'blah2']; console.log(
${x}
)
Copy code
blah,blah
Explanation template literals use the 
toString()
 method which by default joins the returned array by 
map
 with a 
,
.
w
I would recommend that you do not generate a string for the policy, but a
PolicyDocument
object instead.
would be easier to read and reason about it.
PolicyArgs
and
RolePolicyArgs
accept inputs
string
or
PolicyDocument
s . All the documetnation examples use strings.
but
PolicyDocument
s are much easier to deal with
especially as you get typechecks on the details.
b
I couldn't find `PolicyDocument`in the docs
w
yeah not documented i guess
but it is exported.
that means its supported, right?
b
Reckon so 🙂
Where is it exported from?
w
import { PolicyDocument } from "@pulumi/aws/iam"
or
import { iam  } from "@pulumi/aws"
->
iam.PolicyDocument
b
I don't see it in the type file.
got it
ws.sqs.QueuePolicy doesn't accept a PolicyDocument - only a string
Can you convert a PolicyDocument to string ?
w
JSON.stringify
should do the job
or
pulumi.output(policyDocument).apply((doc) => JSON.stringify(doc, null, 2))
b
I'll give that a shot. thanks