How to create a reusable block of statement for aws_iam_policy_document? - terraform0.12+

I have a few aws_iam_policy_document like these
Policy1
data "aws_iam_policy_document" "policy1" {
statement {
actions = [
"rds:DescribeDBSnapshots"
]
resources = [
"arn:aws:rds:${var.region}:${local.account_id}:db:*
]
}
statement {
actions = [
"rds:RestoreDBInstanceFromDBSnapshot"
]
resources = [
"arn:aws:rds:${var.region}:${local.account_id}:db:*s",
"arn:aws:rds:${var.region}:${local.account_id}:snapshot:*"
]
}
}
Policy2
data "aws_iam_policy_document" "policy2" {
statement {
actions = [
"rds:DescribeDBInstances",
"rds:ModifyDBInstance"
]
resources = [
"arn:aws:rds:${var.region}:${local.account_id}:db:*",
"arn:aws:rds:${var.region}:${local.account_id}:db:*"
]
}
}
And I have a few more policies which all have some variations.
Now I want to be able insert an identical block of statement to all of these policies.
It is not tested yet but the statement will look like this:
statement {
action = [
"ssm:GetParameter"
]
resources = [
"arn:aws:ssm:${var.region}:${local.account_id}:parameter/lambda/*"
]
}
What is the most efficient way to do it? I want to avoid copy and paste the same block of statement to all policies.

I can use the source_json keyword.
Here is an example:
First of all, define the common policy in new policy document
data "aws_iam_policy_document" "common" {
statement {
action = [
"ssm:GetParameter"
]
resources = [
"arn:aws:ssm:${var.region}:${local.account_id}:parameter/lambda/*"
]
}
}
Then in the existing policy document, use source_json
data "aws_iam_policy_document" "policy1" {
source_json = "${data.aws_iam_policy_document.common.json}"
statement {
....
}
}

Related

How to perform addition in already existing json object in mongoDB?

I want to add the cost of a particular month for a specific category. This is my object stored in MongoDB :
{
"2022":{
"January":{
"Food":30,
"Traveling":0,
"Medical":0,
},
"Feburary":{
"Food":1000,
"Traveling":0,
"Medical":50,
},
"March":{
"Food":100,
"Traveling":20,
"Medical":10,
}
}
}
Now, I am making a patch request:
{
"month":"March",
"monthData":[70,45,100]
}
Now, I want my data to be updated like this:
{
"2022":{
"January":{
"Food":30,
"Traveling":0,
"Medical":0,
},
"Feburary":{
"Food":1000,
"Traveling":0,
"Medical":50,
},
"March":{
"Food":170,
"Traveling":65,
"Medical":110,
}
}
}
What query should I write using Model.findAndUpate(filter,object) so that above thing works.
Your patch request looks to me like this:
db.collection.update({},
{
"$inc": {
"2022.March.Food": 70,
"2022.March.Traveling": 45,
"2022.March.Medical": 100
}
})
Playgroud

Powershell Append PSCustomObject to nested PSCustomObject

My problem is that I have a remote API giving me a JSON with 10 levels deep nesting and I need to add another array/hashtable/PSCustomObject (whatever you want to call it) to one of them.
The JSON looks like this:
{
"result": [
"modules": [
"data": {
"segments": [
{
"routes": {
"static": [
{
"destination": "10.0.0.0",
"netmask": "255.0.0.0"
},
{
"destination": "172.16.0.0",
"netmask": "255.240.0.0"
}
]
}
}
]
}
]
]
}
The return object is a Hashtable, however when I try to access the values in dot notation, it turns into PSCustomObject:
$statics = $result.result.modules.data.segments.routes.static
It won't let me use the other notation:
$statics = $result['result']['modules']['data']['segments']['routes']['static']
Error: Cannot index into a null array
The real tricky part (for me) is to to append a new hastable to the "static" hashtable in such a way that the rest of the hashtable remains intact.
$newroute = #{
destination = "1.1.1.1."
netmask = "255.255.255.255"
}
I would have used PHP or Python but for this project I must use Powershell and I'm running into all sorts of things where PS behaves different from what I expect.
Any help is greatly appreciated!
static is an array, you can add new items to it:
$newStaticRoute = [pscustomobject]#{
destination = '192.168.0.0'
netmask = '255.255.0.0'
}
$result.result.modules.data.segments.routes.static += $newStaticRoute

AppSync: pipeline resolver #return null result

I'm successfully using a pipeline resolver to persist a parent/child relationship, except when the list of child items is empty and I #return early.
I'm guessing the issue is around my response mappers and use of $ctx.prev vs $ctx.result but I can't figure it out.
The pipeline looks like this:
BEFORE template: {}
Function 1:
request = PutItem the parent
response = $utils.toJson($ctx.result)
Function 2:
request = TransactWriteItems (foreach UpdateItem) the children
response = $utils.toJson($ctx.prev.result)
AFTER template: $utils.toJson($ctx.prev.result)
When I call the mutation with
{"parentAttribute":"foo", "children": [{"childAttribute": "bar"}]}
I get a good response like:
{
"data": {
"createFoo": {
"parentAttribute": "foo",
"children": [
{
"childAttribute": "bar"
}
]
}
}
}
If no children, Function 2 request mapper does #return to avoid "TransactWriteItems must have at least one operation" error.
In this scenario I am hoping for the above response to the mutation, just with children: []
Instead, I get:
{
"data": {
"createFoo": null
}
}
The data has been written correctly; if I query it I get back the parent with empty list of children.
How do I get this pipeline to execute so that it returns the combined parent+child data whether the child array is populated or not?
Detail
The schema is something like:
type Foo {
id: String!
attr1: String
bars: [Bar]
}
type Bar {
id: String!
attr2: String
}
type Mutation {
createFoo(foo: Foo): Foo
}
And a dynamodb representation like this:
pk
sk
attr1
attr2
FOO#1
METADATA#FOO#1
Lorem
FOO#1
BAR#1
Ipsum
While the pipeline looks like:
before.vtl
{}
createParent-request.vtl
{
"version" : "2017-02-28",
"operation" : "PutItem",
"key" : {
"pk" : $util.dynamodb.toDynamoDBJson(...),
"sk" : $util.dynamodb.toDynamoDBJson(...)
},
"attributeValues" : {
"data" : $util.dynamodb.toDynamoDBJson(...)
}
}
createParent-response.vtl
#if($ctx.error)
$utils.error($ctx.error.message, $ctx.error.type)
#end
$utils.toJson($ctx.result)
createChildren-request.vtl
#if($ctx.args.fooInput.children.size() > 0)
{
"version": "2018-05-29",
"operation": "TransactWriteItems",
"transactItems": [
#foreach( $child in $ctx.args.fooInput.children )
{
"table": "${table}",
"operation": "UpdateItem",
"key": {
"pk" : $util.dynamodb.toDynamoDBJson(...),
"sk" : $util.dynamodb.toDynamoDBJson(...)
},
"update": {
"expression": "SET #data = :data",
"expressionNames": {
"#data": "data"
},
"expressionValues": {
":data":
$util.dynamodb.toDynamoDBJson(...)
}
}
}
#if( $foreach.hasNext ),#end
#end
]
}
#else
#return
#end
createChildren-response.vtl
#if($ctx.error)
$utils.error($ctx.error.message, $ctx.error.type)
#end
$utils.toJson($ctx.prev.result)
after.vtl
#if($ctx.error)
$utils.error($ctx.error.message, $ctx.error.type)
#end
$utils.toJson($ctx.prev.result)
I figured it out. For the expected behaviour, one needs the 'after' mapper to return the necessary JSON to populate the overall mutation response. In my example above, after.vtl needs to return a parent and nothing else matters (in particular, the result of the individual function response mappers).
I ended up putting the output of the 'create parent' operation into ctx.stash then returning ctx.stash in after.vtl, setting the other resolvers to {}.
Note that, if your response has subtypes (with their own resolvers) and you return it sparse, AppSync will call the resolver. In the context of my example, it's enough to return the parent without any children and then the normal query resolver for "get children of a parent" will execute to populate the final response.

How can I return the element I'm looking for inside a nested array?

I have a database like this:
[
{
"universe":"comics",
"saga":[
{
"name":"x-men",
"characters":[
{
"character":"wolverine",
"picture":"618035022351.png"
},
{
"character":"cyclops",
"picture":"618035022352.png"
}
]
}
]
},
{
"universe":"dc",
"saga":[
{
"name":"spiderman",
"characters":[
{
"character":"venom",
"picture":"618035022353.png"
}
]
}
]
}
]
and with this code I manage to update one of the objects in my array. specifically the object where character: wolverine
db.mydb.findOneAndUpdate({
"universe": "comics",
"saga.name": "x-men",
"saga.characters.character": "wolverine"
}, {
$set: {
"saga.$[].characters.$[].character": "lobezno",
"saga.$[].characters.$[].picture": "618035022354.png",
}
}, {
new: false
}
)
it returns all my document, I need ONLY the document matched
I would like to return the object that I have updated without having to make more queries to the database.
Note
I have been told that my code does not work well as it should, apparently my query to update this bad, I would like to know how to fix it and get the object that matches these search criteria.
In other words how can I get this output:
{
"character":"wolverine",
"picture":"618035022351.png"
}
in a single query using filters
{
"universe": "comics",
"saga.name": "x-men",
"saga.characters.character": "wolverine"
}
My MongoDB knowledge prevents me from correcting this.
Use the shell method findAndModify to suit your needs.
But you cannot use the positional character $ more than once while projecting in MongoDb, so you may have to keep track of it yourself at client-side.
Use arrayFilters to update deeply nested sub-document, instead of positional all operator $[].
Below is a working query -
var query = {
universe: 'comics'
};
var update = {
$set: {
'saga.$[outer].characters.$[inner].character': 'lobezno',
'saga.$[outer].characters.$[inner].picture': '618035022354.png',
}
};
var fields = {
'saga.characters': 1
};
var updateFilter = {
arrayFilters: [
{
'outer.name': 'x-men'
},
{
'inner.character': 'wolverine'
}
]
};
db.collection.findAndModify({
query,
update,
fields,
arrayFilters: updateFilter.arrayFilters
new: true
});
If I understand your question correctly, your updating is working as expected and your issue is that it returns the whole document and you don't want to query the database to just to return these two fields.
Why don't you just extract the fields from the document returned from your update? You are not going to the database when doing that.
var extractElementFromResult = null;
if(result != null) {
extractElementFromResult = result.saga
.filter(item => item.name == "x-men")[0]
.characters
.filter(item => item.character == "wolverine")[0];
}

Sails Waterline "Or" clause not working

I tried a lot of time to figure out getting an OR clause working in sails without success.
I am using Sails-MySql adapter.
Have anyone of you done anything like this already? I would appreciate some help.
Basically this is what I want to do:
Do an OR clause on a set of fields along with an AND on another set of fields.
Something like this:
FdbDevice
.find()
.where(or:
[
{ deviceCategory: “cardiology valve bioprosthesis” },
{ deviceCategory: “nephrology haemodialysis catheter” }
]
})
.where(
{ catalogNumber : “Z286004” },
{ modelNumber: “Z286004” }
)
.exec
In this particular case, here is how I would do it:
// Each element in the array is treated as 'or'
var possibleDeviceCategories = [
'cardiology valve bioprosthesis',
'nephrology haemodialysis catheter'
];
FdbDevice
.find({
deviceCategory: possibleDeviceCategories,
catalogNumber: 'Z286004',
modelNumber: 'Z286004'
})
.exec(cb);
Check out the docs for more informations about the Waterline's query language.
you can try something like that, into the find:
FdbDevice
.find({or:
[
{ deviceCategory: “cardiology valve bioprosthesis” },
{ deviceCategory: “nephrology haemodialysis catheter” }
]
})
.where(
{ catalogNumber : “Z286004” },
{ modelNumber: “Z286004” }
)