How can I define aws resource tags in terraform conditionally? - tags

I would like to define resource tags (e.g., for a DynamoDB table) only in certain environments, but not all.
I am familiar with count trick: setting the count to 0 so that a resource will not get created. But this is a field within a resource.
tags {
count = "${var.is_production == "T" ? 1 : 0}"
MyProductionOnlyTag = "${var.prod_tag_value}"
}

A bit hacky, but you could use dynamic blocks (requires terraform => 0.12):
dynamic "tags" {
iterator = my_prod_tag_value
for_each = "${var.my_prod_tag == null ? 0 : 1 }"
content {
MyProductionOnlyTag = "${my_prod_tag_value}"
}
}
Also, when declaring var.my_prod_tag, you must explicitly allow it to be null:
variable "my_prod_tag" {
type = "string"
default = null
}

Related

Query variables in Dgraph filter

I am trying to use a variables (which is a scalar) in a #filter(ge(...)) call, but I run into an error
Given the following query
{
ua(func: uid(0xfb7f7)) {
uid
start_ua {
sua as index
}
recorded_in {
actions #filter(ge(index, sua)){
index
}
}
}
}
I get the following error
{
"errors": [
{
"code": "ErrorInvalidRequest",
"message": "Some variables are defined but not used\nDefined:[sua]\nUsed:[]\n"
}
],
"data": null
}
Now if I remove the sua as ... and the #filter(...) from the query, all works fine.
My Dgraph version is v1.0.13.
I tried replacing #filter(ge(index, sua)) with #filter(ge(index, val(sua))) but I still run into an error:
{
"errors": [
{
"code": "ErrorInvalidRequest",
"message": ": No value found for value variable \"sua\""
}
],
"data": null
}
What am I doing wrong?
Here's what the Dgraph docs say about value variables (emphasis added): https://docs.dgraph.io/query-language/#value-variables
Value variables store scalar values. Value variables are a map from the UIDs
of the enclosing block to the corresponding values.
It therefore only makes sense to use the values from a value variable in a
context that matches the same UIDs - if used in a block matching different
UIDs the value variable is undefined.
The start_ua and recorded_in are different subgraphs, which means variables defined in one are undefined in the other within the same query block.
What you can do is use multiple query blocks. Variables can be accessed across blocks:
{
block1(func: uid(0xfb7f7)) {
uid
start_ua (first: 1) {
sua as index
}
}
block2(func: uid(0xfb7f7)) {
recorded_in {
actions #filter(ge(index, val(sua))) {
index
}
}
}
}
I also added (first: 1) to the start_ua predicate, so that at most 1 node is fetched and stored the sua variable. If your data is already structured that way, then that's not needed.
val(sua) gets the value of the variable sua.

How should you query a collection via nested arrays in mongodb (Meteor)?

I'm dont think that this is a Meteor specific question, but rather around mongo and building mongo queries.
If I have the following structure,
{
username : someName,
contacts : [
{
userid : asdfae33rtqqxxx,
name : contactName,
status : friend
}
{
userid : asdfae33rtqqxxx,
name : anotherName,
status : pending
}
{
userid : asdfae33rtqqxxx,
name : contactName,
status : blocked
}
]
}
How could I pass in values from this array into a query against the users collection, to a) get the users in this array, or b) get all users in this array from the users collection with a particular status.
If this is not possible, how should I adjust my schema in order to make these sorts of queries possible?
This function will return a Meteor.users cursor based on an array of contacts and an optionally required status:
var usersByContacts = function(contacts, requiredStatus) {
var userIds = _.chain(contacts)
.map(function(c) {
if (requiredStatus) {
if (c.status === requiredStatus)
return c.userid;
} else {
return c.userid;
}
})
.compact()
.value();
return Meteor.users.find({_id: {$in: userIds}});
};
You can use it like this:
var users1 = usersByContacts(thing.contacts);
var users2 = usersByContacts(thing.contacts, 'pending');
This assumes thing has the schema referenced in your question. Also note that if you find this is a common pattern in your code, you should consider turning usersByContacts into a transform.

Remove nested document with condition in MongoDB

For the following JSON how do I remove the dog whose height is the least
{
_id:0
"name":"Andy",
"pets":[
{
"type":"dog","name":"max","height":120
},
{
"type":"dog","name":"rover","height":44
},
{
"type":"dog","name":"katie","height":100
},
{
"type":"cat","name":"minni"
}
]
}
The problem is the array of subdocuments is not a collection, you can't sort or do something else on it. But if you have an access to any language interface like JavaScript or else it's possible. You just need to extract list of subdocuments, sort them by height, remember the first one and then run the command to pull it from the array based on its name and height.
It can be done for example using this JavaScript code right in the MongoDB shell:
var min = 0; var name = "";
db.animals.find({ query:{"_id" : 0} }).forEach(
function(record){
var sets = record.pets;
min = sets[0].height;
sets.forEach(function(set){
if(set.height <= min)
{min=set.height;
name=set.name;}
});
print(min);
print(name);
query = {"_id": 0}
update = { "$pull" : { "pets" : { "name" : name } } };
db.animals.update(query, update);
})
I suspect the solution is not the most elegant but anyway it works.

Strategy for Modeling RBAC with NoSQL Document Store

I'm getting ready to implement stripped down version of role based access control in my application and I'm contemplating how/what to model in my document store which happens to be mongodb with mongoose.js as my "convenience lib". But this question should apply to any document store.
It seems quite common that deciding between using embedded objects vs refs is a challenge when using a document store given the competing factors of duplication vs performance and what not. I'm trying to keep the RBAC as simple as possible and not go too crazy on nested Collections/Ref IDs which would mean a ton of loops, over using mongoose's populate, etc.
Question:
I'm already leaning toward having collections for User, Permission, and Role; but does it make sense to model Operations and Resources, or, just use key/vals for these?
See code example below or jsfiddle which should help to reason about the problem. Note it's not at all the way I want to implement this but just a way to examine to relationships!
/*
Imagine this being used in a CMS ;)
User: have a role property (e.g. role:"admin" or role:"writer")
Operation: Create,Read,Update,Delete,etc.
Resource: Page,Post,User, etc.
* For simplicity, we can represent operations and resource with simple strings.
Permission: A permission is an allowable "Operation" on a "Resource"
Role: A Role is just an abstraction of a set of possible "Permissions"
*/
// I could see this as a Permission model in mongo
var adminPerms = {
create: ['pages','posts', 'users'],
update: ['posts','pages','users'],
update_others: ['posts','pages'],
delete: ['posts','pages','users'],
read:['pages','posts','users']
};
// I could see this as a Role model in mongo
var admin = {
perms: adminPerms
};
var writerPerms = {
create: ['pages','posts'],
update: ['pages','posts'],
update_others: [],
delete: [],
read:['pages','posts']
};
var writer = {
perms: writerPerms
};
// Now we can just see if that user's perms has the operation on resource defined
function hasPerms(user, operation, resource) {
var i, len, op;
if(!user || !user.role || !operation || !resource) return false;
if(typeof rolemap[user.role] !== 'undefined' &&
typeof rolemap[user.role]['perms'] !== 'undefined' &&
typeof rolemap[user.role]['perms'][operation] !== 'undefined') {
op = rolemap[user.role]['perms'][operation];
for(i=0, len=op.length; i<len; i++) {
if(op[i] === resource) {
return true;
}
}
}
return false;
}
var rolemap = {"admin":admin, "writer":writer}
var user_admin = {name:'Rob Levin', role:'admin'}
var user_jack = {name:'Jack Black', role:'writer'}
hasPerms(user_jack, 'create', 'users')
// false
hasPerms(user_admin, 'create', 'users')
// true
hasPerms(user_admin, 'update_others', 'posts')
// true
hasPerms(user_jack, 'update_others', 'posts')
// false
EDIT: Assume that roles must be editable on a per app basis so I might want to allow admin users to control access rights; this is why I want to use a database.
Regarding doing it all inside the application that won't work given the requirement to persist and possibly change. However, one compromise in this direction is I could just the role collection:
db.role.find({name:'writer'}).pretty()
{
"_id" : ObjectId("4f4c2a510785b51c7b11bc45"),
"name" : "writer",
"perms" : {
"create" : [
"posts",
"pages"
],
"update" : [
"posts",
"pages"
],
"update_others" : [ ],
"delete" : [ ],
"read" : [
"posts",
"pages"
]
}
}
And than I could make changes like removal, etc., like the following (assuming I already have a reference to a role object retrieved from mongo at point of call):
function removePerm(role, op, resource) {
if(!role || !role.perms || !role.perms[op]) {
console.log("Something not defined!");
return false;
}
var perm = role.perms[op];
for(var i=0, len=perm.length; i<len; i++) {
if(perm[i] === resource) {
perm.splice(i,1);
break;
}
}
}
I recently used mongoosejs with a user/roles/permissions need I had with Drywall.js - the actual permissions are key/value based. They can be shared by group and also overridden granularly on the administrator level.
Although it's not exactly RBAC I'm hoping that reviewing another approach helps you get closer to achieving your goal.
Project Overview:
http://jedireza.github.com/drywall/
Mongoose Schemas:
https://github.com/jedireza/drywall/tree/master/schema
Specifically Look At:
/schema/User.js
/schema/Admin.js
/schema/AdminGroup.js
/schema/Account.js
I'm interested to see what you come up with.
Your design is almost entirely dependent on the behavior of your application. What I would recommend based on the information you've provided here is to keep the data in key/values, not in the database--CRUD operations aren't going to change, so there's no reason to put that in the db. The 'resources' are classes that you've already built into your code, so you don't need to duplicate it in the db either.

Picking an array of hashes from a hash

I have a hash coming back from an XML datasource that looks like this:
{...,
'records' :{
'record' :[
{'availability' :{'$t' :'available'}, ...},
{'availability' :{'$t' :'available'}, ...}
]
}
};
I'd like to get all the record hashes into an array so I can filter() it and do some other operations. However, when I have this statement in my pre block,
raw_records = raw.pick("$..record");
the array that gets returned is an array of two empty strings:
var raw_records = ['', ''];
The odd thing is that I can pick out just availability with expected results:
availability = raw.pick("$..availability.$t");
producing
var availability = ['available', 'available'];
What's wrong with my first pick()?
EDIT: Here is a more complete version that should help with reproducing the problem. It's slightly different, since I'm using the JSON version of the web service now:
global {
datasource hbll <- "https://svc.lib.byu.edu/services/catalog/v1/search/?field=isbn&format=json&terms=";
}
rule new_rule {
select when pageview "amazon.com/.*/?dp/(.*)/" setting (isbn)
pre {
//This is the array with two empty strings...
raw = datasource:hbll(isbn);
myfilter = function(x) { x.pick("availability") eq "available"; };
records = raw.filter(myfilter);
len = records.length();
availability = records.pick("$..availability");
middleman = len > 1 => availability[0] | availability;
available = middleman eq "available" => true | false;
url_list = records.pick("$..url");
url = len > 1 => url_list[0] | url_list;
msg = <<
<p>This book is available for checkout at the BYU Library.</p>
More information
>>;
}
notify("BYU Harold B. Lee Library", msg) with sticky=true;
}
I'm going to need a more complete example. The test app and results I got are below:
ruleset a8x167 {
meta {
name "Pick - Array of Hashes"
description <<
Testing
>>
author "Sam Curren"
logging on
}
dispatch {}
global {
raw = {
'records' :{
'record' :[
{'availability' :{'$t' :'available'}},
{'availability' :{'$t' :'available'}}
]
}
};
}
rule test {
select when pageview ".*" setting ()
pre {
raw_records = raw.pick("$..record");
availability = raw.pick("$..availability.$t");
}
notify("Hello World", "This is a sample rule.");
}
}
And Results:
var raw_records = [{'availability' :{'$t' :'available'}}, {'availability' :{'$t' :'available'}}];
var availability = ['available', 'available'];