Merge branch 'master' into gometalinter
This commit is contained in:
commit
69e4834f63
7
Makefile
7
Makefile
|
@ -21,13 +21,6 @@ banner_all:
|
|||
@echo "\033[1;37mLumi (Full)\033[0m"
|
||||
@echo "\033[1;37m============\033[0m"
|
||||
|
||||
.PHONY: build
|
||||
build:
|
||||
@echo "\033[0;32mBUILD:\033[0m"
|
||||
@go version
|
||||
@go build ${PROJECT}/cmd/lumi
|
||||
@go build ${PROJECT}/cmd/lumidl
|
||||
|
||||
.PHONY: install
|
||||
install:
|
||||
@echo "\033[0;32mINSTALL:\033[0m"
|
||||
|
|
|
@ -1023,11 +1023,14 @@ export class Transformer {
|
|||
contract.assert(!!idsym, `Expected an ID symbol for '${id.ident}', but it is missing`);
|
||||
tok = await this.resolveTokenFromSymbol(idsym);
|
||||
// note that we intentionally leave object blank, since the token is fully qualified.
|
||||
if ((idsym.flags & ts.SymbolFlags.Alias) === 0) {
|
||||
// Mark as dynamic unless this is an alias to a module import.
|
||||
isDynamic = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (isDynamic) {
|
||||
// If the target type is `dynamic`, we cannot perform static lookups; devolve into a dynamic load.
|
||||
contract.assert(!!object);
|
||||
return this.withLocation(node, <ast.TryLoadDynamicExpression>{
|
||||
kind: ast.tryLoadDynamicExpressionKind,
|
||||
object: object,
|
||||
|
|
|
@ -1215,10 +1215,10 @@
|
|||
"right": {
|
||||
"kind": "TryLoadDynamicExpression",
|
||||
"object": {
|
||||
"kind": "LoadLocationExpression",
|
||||
"kind": "TryLoadDynamicExpression",
|
||||
"name": {
|
||||
"kind": "Token",
|
||||
"tok": "basic/arrays:index:a2",
|
||||
"kind": "StringLiteral",
|
||||
"value": "a2",
|
||||
"loc": {
|
||||
"file": "index.ts",
|
||||
"start": {
|
||||
|
@ -1303,10 +1303,10 @@
|
|||
"left": {
|
||||
"kind": "TryLoadDynamicExpression",
|
||||
"object": {
|
||||
"kind": "LoadLocationExpression",
|
||||
"kind": "TryLoadDynamicExpression",
|
||||
"name": {
|
||||
"kind": "Token",
|
||||
"tok": "basic/arrays:index:a2",
|
||||
"kind": "StringLiteral",
|
||||
"value": "a2",
|
||||
"loc": {
|
||||
"file": "index.ts",
|
||||
"start": {
|
||||
|
@ -1436,10 +1436,10 @@
|
|||
"right": {
|
||||
"kind": "TryLoadDynamicExpression",
|
||||
"object": {
|
||||
"kind": "LoadLocationExpression",
|
||||
"kind": "TryLoadDynamicExpression",
|
||||
"name": {
|
||||
"kind": "Token",
|
||||
"tok": "basic/arrays:index:a2",
|
||||
"kind": "StringLiteral",
|
||||
"value": "a2",
|
||||
"loc": {
|
||||
"file": "index.ts",
|
||||
"start": {
|
||||
|
@ -1524,10 +1524,10 @@
|
|||
"left": {
|
||||
"kind": "TryLoadDynamicExpression",
|
||||
"object": {
|
||||
"kind": "LoadLocationExpression",
|
||||
"kind": "TryLoadDynamicExpression",
|
||||
"name": {
|
||||
"kind": "Token",
|
||||
"tok": "basic/arrays:index:a2",
|
||||
"kind": "StringLiteral",
|
||||
"value": "a2",
|
||||
"loc": {
|
||||
"file": "index.ts",
|
||||
"start": {
|
||||
|
@ -1657,10 +1657,10 @@
|
|||
"right": {
|
||||
"kind": "TryLoadDynamicExpression",
|
||||
"object": {
|
||||
"kind": "LoadLocationExpression",
|
||||
"kind": "TryLoadDynamicExpression",
|
||||
"name": {
|
||||
"kind": "Token",
|
||||
"tok": "basic/arrays:index:a2",
|
||||
"kind": "StringLiteral",
|
||||
"value": "a2",
|
||||
"loc": {
|
||||
"file": "index.ts",
|
||||
"start": {
|
||||
|
@ -1745,10 +1745,10 @@
|
|||
"left": {
|
||||
"kind": "TryLoadDynamicExpression",
|
||||
"object": {
|
||||
"kind": "LoadLocationExpression",
|
||||
"kind": "TryLoadDynamicExpression",
|
||||
"name": {
|
||||
"kind": "Token",
|
||||
"tok": "basic/arrays:index:a2",
|
||||
"kind": "StringLiteral",
|
||||
"value": "a2",
|
||||
"loc": {
|
||||
"file": "index.ts",
|
||||
"start": {
|
||||
|
@ -2004,10 +2004,10 @@
|
|||
"right": {
|
||||
"kind": "TryLoadDynamicExpression",
|
||||
"object": {
|
||||
"kind": "LoadLocationExpression",
|
||||
"kind": "TryLoadDynamicExpression",
|
||||
"name": {
|
||||
"kind": "Token",
|
||||
"tok": "basic/arrays:index:a3",
|
||||
"kind": "StringLiteral",
|
||||
"value": "a3",
|
||||
"loc": {
|
||||
"file": "index.ts",
|
||||
"start": {
|
||||
|
@ -2121,10 +2121,10 @@
|
|||
"right": {
|
||||
"kind": "TryLoadDynamicExpression",
|
||||
"object": {
|
||||
"kind": "LoadLocationExpression",
|
||||
"kind": "TryLoadDynamicExpression",
|
||||
"name": {
|
||||
"kind": "Token",
|
||||
"tok": "basic/arrays:index:a3",
|
||||
"kind": "StringLiteral",
|
||||
"value": "a3",
|
||||
"loc": {
|
||||
"file": "index.ts",
|
||||
"start": {
|
||||
|
@ -2238,10 +2238,10 @@
|
|||
"right": {
|
||||
"kind": "TryLoadDynamicExpression",
|
||||
"object": {
|
||||
"kind": "LoadLocationExpression",
|
||||
"kind": "TryLoadDynamicExpression",
|
||||
"name": {
|
||||
"kind": "Token",
|
||||
"tok": "basic/arrays:index:a3",
|
||||
"kind": "StringLiteral",
|
||||
"value": "a3",
|
||||
"loc": {
|
||||
"file": "index.ts",
|
||||
"start": {
|
||||
|
@ -2859,10 +2859,10 @@
|
|||
"right": {
|
||||
"kind": "TryLoadDynamicExpression",
|
||||
"object": {
|
||||
"kind": "LoadLocationExpression",
|
||||
"kind": "TryLoadDynamicExpression",
|
||||
"name": {
|
||||
"kind": "Token",
|
||||
"tok": "basic/arrays:index:a6",
|
||||
"kind": "StringLiteral",
|
||||
"value": "a6",
|
||||
"loc": {
|
||||
"file": "index.ts",
|
||||
"start": {
|
||||
|
@ -2978,10 +2978,10 @@
|
|||
"object": {
|
||||
"kind": "TryLoadDynamicExpression",
|
||||
"object": {
|
||||
"kind": "LoadLocationExpression",
|
||||
"kind": "TryLoadDynamicExpression",
|
||||
"name": {
|
||||
"kind": "Token",
|
||||
"tok": "basic/arrays:index:a6",
|
||||
"kind": "StringLiteral",
|
||||
"value": "a6",
|
||||
"loc": {
|
||||
"file": "index.ts",
|
||||
"start": {
|
||||
|
@ -3125,10 +3125,10 @@
|
|||
"object": {
|
||||
"kind": "TryLoadDynamicExpression",
|
||||
"object": {
|
||||
"kind": "LoadLocationExpression",
|
||||
"kind": "TryLoadDynamicExpression",
|
||||
"name": {
|
||||
"kind": "Token",
|
||||
"tok": "basic/arrays:index:a6",
|
||||
"kind": "StringLiteral",
|
||||
"value": "a6",
|
||||
"loc": {
|
||||
"file": "index.ts",
|
||||
"start": {
|
||||
|
@ -3272,10 +3272,10 @@
|
|||
"object": {
|
||||
"kind": "TryLoadDynamicExpression",
|
||||
"object": {
|
||||
"kind": "LoadLocationExpression",
|
||||
"kind": "TryLoadDynamicExpression",
|
||||
"name": {
|
||||
"kind": "Token",
|
||||
"tok": "basic/arrays:index:a6",
|
||||
"kind": "StringLiteral",
|
||||
"value": "a6",
|
||||
"loc": {
|
||||
"file": "index.ts",
|
||||
"start": {
|
||||
|
@ -3417,10 +3417,10 @@
|
|||
"right": {
|
||||
"kind": "TryLoadDynamicExpression",
|
||||
"object": {
|
||||
"kind": "LoadLocationExpression",
|
||||
"kind": "TryLoadDynamicExpression",
|
||||
"name": {
|
||||
"kind": "Token",
|
||||
"tok": "basic/arrays:index:a6",
|
||||
"kind": "StringLiteral",
|
||||
"value": "a6",
|
||||
"loc": {
|
||||
"file": "index.ts",
|
||||
"start": {
|
||||
|
@ -3536,10 +3536,10 @@
|
|||
"object": {
|
||||
"kind": "TryLoadDynamicExpression",
|
||||
"object": {
|
||||
"kind": "LoadLocationExpression",
|
||||
"kind": "TryLoadDynamicExpression",
|
||||
"name": {
|
||||
"kind": "Token",
|
||||
"tok": "basic/arrays:index:a6",
|
||||
"kind": "StringLiteral",
|
||||
"value": "a6",
|
||||
"loc": {
|
||||
"file": "index.ts",
|
||||
"start": {
|
||||
|
@ -3683,10 +3683,10 @@
|
|||
"object": {
|
||||
"kind": "TryLoadDynamicExpression",
|
||||
"object": {
|
||||
"kind": "LoadLocationExpression",
|
||||
"kind": "TryLoadDynamicExpression",
|
||||
"name": {
|
||||
"kind": "Token",
|
||||
"tok": "basic/arrays:index:a6",
|
||||
"kind": "StringLiteral",
|
||||
"value": "a6",
|
||||
"loc": {
|
||||
"file": "index.ts",
|
||||
"start": {
|
||||
|
@ -3830,10 +3830,10 @@
|
|||
"object": {
|
||||
"kind": "TryLoadDynamicExpression",
|
||||
"object": {
|
||||
"kind": "LoadLocationExpression",
|
||||
"kind": "TryLoadDynamicExpression",
|
||||
"name": {
|
||||
"kind": "Token",
|
||||
"tok": "basic/arrays:index:a6",
|
||||
"kind": "StringLiteral",
|
||||
"value": "a6",
|
||||
"loc": {
|
||||
"file": "index.ts",
|
||||
"start": {
|
||||
|
@ -4189,10 +4189,10 @@
|
|||
"right": {
|
||||
"kind": "TryLoadDynamicExpression",
|
||||
"object": {
|
||||
"kind": "LoadLocationExpression",
|
||||
"kind": "TryLoadDynamicExpression",
|
||||
"name": {
|
||||
"kind": "Token",
|
||||
"tok": "basic/arrays:index:a6",
|
||||
"kind": "StringLiteral",
|
||||
"value": "a6",
|
||||
"loc": {
|
||||
"file": "index.ts",
|
||||
"start": {
|
||||
|
@ -4308,10 +4308,10 @@
|
|||
"object": {
|
||||
"kind": "TryLoadDynamicExpression",
|
||||
"object": {
|
||||
"kind": "LoadLocationExpression",
|
||||
"kind": "TryLoadDynamicExpression",
|
||||
"name": {
|
||||
"kind": "Token",
|
||||
"tok": "basic/arrays:index:a6",
|
||||
"kind": "StringLiteral",
|
||||
"value": "a6",
|
||||
"loc": {
|
||||
"file": "index.ts",
|
||||
"start": {
|
||||
|
@ -4455,10 +4455,10 @@
|
|||
"object": {
|
||||
"kind": "TryLoadDynamicExpression",
|
||||
"object": {
|
||||
"kind": "LoadLocationExpression",
|
||||
"kind": "TryLoadDynamicExpression",
|
||||
"name": {
|
||||
"kind": "Token",
|
||||
"tok": "basic/arrays:index:a6",
|
||||
"kind": "StringLiteral",
|
||||
"value": "a6",
|
||||
"loc": {
|
||||
"file": "index.ts",
|
||||
"start": {
|
||||
|
@ -4602,10 +4602,10 @@
|
|||
"object": {
|
||||
"kind": "TryLoadDynamicExpression",
|
||||
"object": {
|
||||
"kind": "LoadLocationExpression",
|
||||
"kind": "TryLoadDynamicExpression",
|
||||
"name": {
|
||||
"kind": "Token",
|
||||
"tok": "basic/arrays:index:a6",
|
||||
"kind": "StringLiteral",
|
||||
"value": "a6",
|
||||
"loc": {
|
||||
"file": "index.ts",
|
||||
"start": {
|
||||
|
@ -4747,10 +4747,10 @@
|
|||
"right": {
|
||||
"kind": "TryLoadDynamicExpression",
|
||||
"object": {
|
||||
"kind": "LoadLocationExpression",
|
||||
"kind": "TryLoadDynamicExpression",
|
||||
"name": {
|
||||
"kind": "Token",
|
||||
"tok": "basic/arrays:index:a6",
|
||||
"kind": "StringLiteral",
|
||||
"value": "a6",
|
||||
"loc": {
|
||||
"file": "index.ts",
|
||||
"start": {
|
||||
|
@ -4866,10 +4866,10 @@
|
|||
"object": {
|
||||
"kind": "TryLoadDynamicExpression",
|
||||
"object": {
|
||||
"kind": "LoadLocationExpression",
|
||||
"kind": "TryLoadDynamicExpression",
|
||||
"name": {
|
||||
"kind": "Token",
|
||||
"tok": "basic/arrays:index:a6",
|
||||
"kind": "StringLiteral",
|
||||
"value": "a6",
|
||||
"loc": {
|
||||
"file": "index.ts",
|
||||
"start": {
|
||||
|
@ -5013,10 +5013,10 @@
|
|||
"object": {
|
||||
"kind": "TryLoadDynamicExpression",
|
||||
"object": {
|
||||
"kind": "LoadLocationExpression",
|
||||
"kind": "TryLoadDynamicExpression",
|
||||
"name": {
|
||||
"kind": "Token",
|
||||
"tok": "basic/arrays:index:a6",
|
||||
"kind": "StringLiteral",
|
||||
"value": "a6",
|
||||
"loc": {
|
||||
"file": "index.ts",
|
||||
"start": {
|
||||
|
@ -5160,10 +5160,10 @@
|
|||
"object": {
|
||||
"kind": "TryLoadDynamicExpression",
|
||||
"object": {
|
||||
"kind": "LoadLocationExpression",
|
||||
"kind": "TryLoadDynamicExpression",
|
||||
"name": {
|
||||
"kind": "Token",
|
||||
"tok": "basic/arrays:index:a6",
|
||||
"kind": "StringLiteral",
|
||||
"value": "a6",
|
||||
"loc": {
|
||||
"file": "index.ts",
|
||||
"start": {
|
||||
|
|
|
@ -942,10 +942,10 @@
|
|||
"expression": {
|
||||
"kind": "InvokeFunctionExpression",
|
||||
"function": {
|
||||
"kind": "LoadLocationExpression",
|
||||
"kind": "TryLoadDynamicExpression",
|
||||
"name": {
|
||||
"kind": "Token",
|
||||
"tok": "basic/undefined:index:f",
|
||||
"kind": "StringLiteral",
|
||||
"value": "f",
|
||||
"loc": {
|
||||
"file": "index.ts",
|
||||
"start": {
|
||||
|
@ -1237,10 +1237,10 @@
|
|||
"expression": {
|
||||
"kind": "InvokeFunctionExpression",
|
||||
"function": {
|
||||
"kind": "LoadLocationExpression",
|
||||
"kind": "TryLoadDynamicExpression",
|
||||
"name": {
|
||||
"kind": "Token",
|
||||
"tok": "basic/undefined:index:g",
|
||||
"kind": "StringLiteral",
|
||||
"value": "g",
|
||||
"loc": {
|
||||
"file": "index.ts",
|
||||
"start": {
|
||||
|
|
|
@ -1023,10 +1023,10 @@
|
|||
},
|
||||
"operator": "=",
|
||||
"right": {
|
||||
"kind": "LoadLocationExpression",
|
||||
"kind": "TryLoadDynamicExpression",
|
||||
"name": {
|
||||
"kind": "Token",
|
||||
"tok": "basic/props:index:modprop",
|
||||
"kind": "StringLiteral",
|
||||
"value": "modprop",
|
||||
"loc": {
|
||||
"file": "index.ts",
|
||||
"start": {
|
||||
|
@ -1256,10 +1256,10 @@
|
|||
"kind": "BinaryOperatorExpression",
|
||||
"operator": "!=",
|
||||
"left": {
|
||||
"kind": "LoadLocationExpression",
|
||||
"kind": "TryLoadDynamicExpression",
|
||||
"name": {
|
||||
"kind": "Token",
|
||||
"tok": "basic/props:index:c",
|
||||
"kind": "StringLiteral",
|
||||
"value": "c",
|
||||
"loc": {
|
||||
"file": "index.ts",
|
||||
"start": {
|
||||
|
@ -1389,10 +1389,10 @@
|
|||
"right": {
|
||||
"kind": "LoadLocationExpression",
|
||||
"object": {
|
||||
"kind": "LoadLocationExpression",
|
||||
"kind": "TryLoadDynamicExpression",
|
||||
"name": {
|
||||
"kind": "Token",
|
||||
"tok": "basic/props:index:c",
|
||||
"kind": "StringLiteral",
|
||||
"value": "c",
|
||||
"loc": {
|
||||
"file": "index.ts",
|
||||
"start": {
|
||||
|
@ -1568,10 +1568,10 @@
|
|||
"tok": "f"
|
||||
},
|
||||
"value": {
|
||||
"kind": "LoadLocationExpression",
|
||||
"kind": "TryLoadDynamicExpression",
|
||||
"name": {
|
||||
"kind": "Token",
|
||||
"tok": "basic/props:index:modprop",
|
||||
"kind": "StringLiteral",
|
||||
"value": "modprop",
|
||||
"loc": {
|
||||
"file": "index.ts",
|
||||
"start": {
|
||||
|
@ -1664,10 +1664,10 @@
|
|||
"value": {
|
||||
"kind": "LoadLocationExpression",
|
||||
"object": {
|
||||
"kind": "LoadLocationExpression",
|
||||
"kind": "TryLoadDynamicExpression",
|
||||
"name": {
|
||||
"kind": "Token",
|
||||
"tok": "basic/props:index:c",
|
||||
"kind": "StringLiteral",
|
||||
"value": "c",
|
||||
"loc": {
|
||||
"file": "index.ts",
|
||||
"start": {
|
||||
|
@ -1770,10 +1770,10 @@
|
|||
"property": {
|
||||
"kind": "InvokeFunctionExpression",
|
||||
"function": {
|
||||
"kind": "LoadLocationExpression",
|
||||
"kind": "TryLoadDynamicExpression",
|
||||
"name": {
|
||||
"kind": "Token",
|
||||
"tok": "basic/props:index:j",
|
||||
"kind": "StringLiteral",
|
||||
"value": "j",
|
||||
"loc": {
|
||||
"file": "index.ts",
|
||||
"start": {
|
||||
|
@ -1965,10 +1965,10 @@
|
|||
"right": {
|
||||
"kind": "LoadLocationExpression",
|
||||
"object": {
|
||||
"kind": "LoadLocationExpression",
|
||||
"kind": "TryLoadDynamicExpression",
|
||||
"name": {
|
||||
"kind": "Token",
|
||||
"tok": "basic/props:index:c",
|
||||
"kind": "StringLiteral",
|
||||
"value": "c",
|
||||
"loc": {
|
||||
"file": "index.ts",
|
||||
"start": {
|
||||
|
@ -2065,10 +2065,10 @@
|
|||
"left": {
|
||||
"kind": "LoadLocationExpression",
|
||||
"object": {
|
||||
"kind": "LoadLocationExpression",
|
||||
"kind": "TryLoadDynamicExpression",
|
||||
"name": {
|
||||
"kind": "Token",
|
||||
"tok": "basic/props:index:c",
|
||||
"kind": "StringLiteral",
|
||||
"value": "c",
|
||||
"loc": {
|
||||
"file": "index.ts",
|
||||
"start": {
|
||||
|
|
|
@ -1164,10 +1164,10 @@
|
|||
"function": {
|
||||
"kind": "LoadLocationExpression",
|
||||
"object": {
|
||||
"kind": "LoadLocationExpression",
|
||||
"kind": "TryLoadDynamicExpression",
|
||||
"name": {
|
||||
"kind": "Token",
|
||||
"tok": "basic/super:index:b",
|
||||
"kind": "StringLiteral",
|
||||
"value": "b",
|
||||
"loc": {
|
||||
"file": "index.ts",
|
||||
"start": {
|
||||
|
@ -1262,10 +1262,10 @@
|
|||
"kind": "BinaryOperatorExpression",
|
||||
"operator": "!=",
|
||||
"left": {
|
||||
"kind": "LoadLocationExpression",
|
||||
"kind": "TryLoadDynamicExpression",
|
||||
"name": {
|
||||
"kind": "Token",
|
||||
"tok": "basic/super:index:bgx",
|
||||
"kind": "StringLiteral",
|
||||
"value": "bgx",
|
||||
"loc": {
|
||||
"file": "index.ts",
|
||||
"start": {
|
||||
|
@ -1363,10 +1363,10 @@
|
|||
}
|
||||
},
|
||||
"right": {
|
||||
"kind": "LoadLocationExpression",
|
||||
"kind": "TryLoadDynamicExpression",
|
||||
"name": {
|
||||
"kind": "Token",
|
||||
"tok": "basic/super:index:bgx",
|
||||
"kind": "StringLiteral",
|
||||
"value": "bgx",
|
||||
"loc": {
|
||||
"file": "index.ts",
|
||||
"start": {
|
||||
|
@ -1581,10 +1581,10 @@
|
|||
"function": {
|
||||
"kind": "LoadLocationExpression",
|
||||
"object": {
|
||||
"kind": "LoadLocationExpression",
|
||||
"kind": "TryLoadDynamicExpression",
|
||||
"name": {
|
||||
"kind": "Token",
|
||||
"tok": "basic/super:index:c",
|
||||
"kind": "StringLiteral",
|
||||
"value": "c",
|
||||
"loc": {
|
||||
"file": "index.ts",
|
||||
"start": {
|
||||
|
@ -1679,10 +1679,10 @@
|
|||
"kind": "BinaryOperatorExpression",
|
||||
"operator": "!=",
|
||||
"left": {
|
||||
"kind": "LoadLocationExpression",
|
||||
"kind": "TryLoadDynamicExpression",
|
||||
"name": {
|
||||
"kind": "Token",
|
||||
"tok": "basic/super:index:cgx",
|
||||
"kind": "StringLiteral",
|
||||
"value": "cgx",
|
||||
"loc": {
|
||||
"file": "index.ts",
|
||||
"start": {
|
||||
|
@ -1780,10 +1780,10 @@
|
|||
}
|
||||
},
|
||||
"right": {
|
||||
"kind": "LoadLocationExpression",
|
||||
"kind": "TryLoadDynamicExpression",
|
||||
"name": {
|
||||
"kind": "Token",
|
||||
"tok": "basic/super:index:cgx",
|
||||
"kind": "StringLiteral",
|
||||
"value": "cgx",
|
||||
"loc": {
|
||||
"file": "index.ts",
|
||||
"start": {
|
||||
|
@ -1910,10 +1910,10 @@
|
|||
"function": {
|
||||
"kind": "LoadLocationExpression",
|
||||
"object": {
|
||||
"kind": "LoadLocationExpression",
|
||||
"kind": "TryLoadDynamicExpression",
|
||||
"name": {
|
||||
"kind": "Token",
|
||||
"tok": "basic/super:index:c",
|
||||
"kind": "StringLiteral",
|
||||
"value": "c",
|
||||
"loc": {
|
||||
"file": "index.ts",
|
||||
"start": {
|
||||
|
@ -2008,10 +2008,10 @@
|
|||
"kind": "BinaryOperatorExpression",
|
||||
"operator": "!=",
|
||||
"left": {
|
||||
"kind": "LoadLocationExpression",
|
||||
"kind": "TryLoadDynamicExpression",
|
||||
"name": {
|
||||
"kind": "Token",
|
||||
"tok": "basic/super:index:cgy",
|
||||
"kind": "StringLiteral",
|
||||
"value": "cgy",
|
||||
"loc": {
|
||||
"file": "index.ts",
|
||||
"start": {
|
||||
|
@ -2109,10 +2109,10 @@
|
|||
}
|
||||
},
|
||||
"right": {
|
||||
"kind": "LoadLocationExpression",
|
||||
"kind": "TryLoadDynamicExpression",
|
||||
"name": {
|
||||
"kind": "Token",
|
||||
"tok": "basic/super:index:cgy",
|
||||
"kind": "StringLiteral",
|
||||
"value": "cgy",
|
||||
"loc": {
|
||||
"file": "index.ts",
|
||||
"start": {
|
||||
|
|
|
@ -4,6 +4,6 @@
|
|||
set -e # bail on errors
|
||||
|
||||
echo Compiling:
|
||||
go build -o lumi-analyzer-contoso_infosec
|
||||
go build -i -o lumi-analyzer-contoso_infosec
|
||||
echo Done.
|
||||
|
||||
|
|
1
examples/scenarios/aws/beanstalk/.gitignore
vendored
1
examples/scenarios/aws/beanstalk/.gitignore
vendored
|
@ -1,4 +1,3 @@
|
|||
.lumi/
|
||||
bin/
|
||||
node_modules/
|
||||
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"name": "beanstalk",
|
||||
"main": ".lumi/bin/index.js",
|
||||
"version": "0.1",
|
||||
"typings": ".lumi/bin/index.d.ts",
|
||||
"scripts": {
|
||||
"build": "lumijs"
|
||||
|
|
1
examples/scenarios/aws/cpuwatch/.gitignore
vendored
1
examples/scenarios/aws/cpuwatch/.gitignore
vendored
|
@ -1,4 +1,3 @@
|
|||
.lumi/
|
||||
bin/
|
||||
node_modules/
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "cpuwatch",
|
||||
"main": "bin/index.js",
|
||||
"typings": "bin/index.d.ts",
|
||||
"version": "0.1",
|
||||
"typings": ".lumi/bin/index.d.ts",
|
||||
"scripts": {
|
||||
"build": "lumijs"
|
||||
},
|
||||
|
|
2
examples/scenarios/aws/minimal/.gitignore
vendored
2
examples/scenarios/aws/minimal/.gitignore
vendored
|
@ -1,3 +1,3 @@
|
|||
bin/
|
||||
.lumi/
|
||||
node_modules/
|
||||
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
name: aws/minimal
|
||||
description: A minimal AWS blueprint that consists solely of creating a single VPC resource.
|
||||
description: An empty Lumi script.
|
||||
dependencies:
|
||||
lumi: "*"
|
||||
aws: "*"
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
import * as lumi from "@lumi/lumi";
|
||||
import * as aws from "@lumi/aws";
|
||||
|
||||
let vpc = new aws.ec2.VPC({ cidrBlock: "10.0.0.0/16" });
|
||||
|
||||
|
|
16
examples/scenarios/aws/minimal/package.json
Normal file
16
examples/scenarios/aws/minimal/package.json
Normal file
|
@ -0,0 +1,16 @@
|
|||
{
|
||||
"name": "minimal",
|
||||
"version": "0.1",
|
||||
"typings": ".lumi/bin/index.d.ts",
|
||||
"scripts": {
|
||||
"build": "lumijs"
|
||||
},
|
||||
"devDependencies": {
|
||||
"typescript": "^2.1.4"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@lumi/lumi": "*",
|
||||
"@lumi/aws": "*"
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
{
|
||||
"compilerOptions": {
|
||||
"outDir": "bin",
|
||||
"outDir": ".lumi/bin",
|
||||
"target": "es6",
|
||||
"module": "commonjs",
|
||||
"moduleResolution": "node",
|
||||
|
|
|
@ -16,7 +16,9 @@
|
|||
"strictNullChecks": true
|
||||
},
|
||||
"files": [
|
||||
"index.ts"
|
||||
"index.ts",
|
||||
"infra.ts",
|
||||
"swarm.ts"
|
||||
]
|
||||
}
|
||||
|
||||
|
|
1
examples/scenarios/aws/serverless/.gitignore
vendored
1
examples/scenarios/aws/serverless/.gitignore
vendored
|
@ -1,4 +1,3 @@
|
|||
.lumi/
|
||||
bin/
|
||||
node_modules/
|
||||
|
||||
|
|
|
@ -2,5 +2,6 @@ name: serverless
|
|||
description: Basic example of a serverless AWS application.
|
||||
dependencies:
|
||||
lumi: "*"
|
||||
lumijs: "*"
|
||||
aws: "*"
|
||||
|
||||
|
|
|
@ -49,34 +49,17 @@ let music = new aws.dynamodb.Table("music", {
|
|||
],
|
||||
})
|
||||
|
||||
// TODO[pulumi/lumi#174] Until we have global definitions available in Lumi for these APIs that are expected
|
||||
// by runtime code, we'll declare variables that should be available on the global scope of the lambda to keep
|
||||
// TypeScript type checking happy.
|
||||
let console: any
|
||||
|
||||
function createLambda() {
|
||||
// TODO[pulumi/lumi#175] Currently, we can only capture local variables, not module scope variables,
|
||||
// so we keep this inside a helper function.
|
||||
let hello = "Hello, world!"
|
||||
let num = 3
|
||||
let obj = { x: 42 }
|
||||
let mus = music
|
||||
|
||||
let lambda = new aws.serverless.Function(
|
||||
"mylambda",
|
||||
[aws.iam.AWSLambdaFullAccess],
|
||||
(event, context, callback) => {
|
||||
console.log(hello);
|
||||
console.log(obj.x);
|
||||
console.log("Music table hash key is: " + mus.hashKey);
|
||||
console.log("Invoked function: " + context.invokedFunctionArn);
|
||||
callback(null, "Succeeed with " + context.getRemainingTimeInMillis() + "ms remaining.");
|
||||
}
|
||||
);
|
||||
return lambda;
|
||||
}
|
||||
|
||||
let lambda = createLambda();
|
||||
let hello = "Hello, world!"
|
||||
let lambda = new aws.serverless.Function(
|
||||
"mylambda",
|
||||
[aws.iam.AWSLambdaFullAccess],
|
||||
(event, context, callback) => {
|
||||
console.log(hello);
|
||||
console.log("Music table hash key is: " + music.hashKey);
|
||||
console.log("Invoked function: " + context.invokedFunctionArn);
|
||||
callback(null, "Succeeed with " + context.getRemainingTimeInMillis() + "ms remaining.");
|
||||
}
|
||||
);
|
||||
|
||||
let api = new aws.serverless.API("frontend")
|
||||
api.route("GET", "/bambam", lambda)
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "serverless",
|
||||
"main": "bin/index.js",
|
||||
"typings": "bin/index.d.ts",
|
||||
"version": "0.1",
|
||||
"typings": ".lumi/bin/index.d.ts",
|
||||
"scripts": {
|
||||
"build": "lumijs"
|
||||
},
|
||||
|
@ -9,6 +9,7 @@
|
|||
"typescript": "^2.1.4"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"@lumi/lumi": "*",
|
||||
"@lumi/aws": "*"
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1,4 +1,3 @@
|
|||
.lumi/
|
||||
bin/
|
||||
node_modules/
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "webserver",
|
||||
"main": "bin/index.js",
|
||||
"typings": "bin/index.d.ts",
|
||||
"version": "0.1",
|
||||
"typings": ".lumi/bin/index.d.ts",
|
||||
"scripts": {
|
||||
"build": "lumijs"
|
||||
},
|
||||
|
|
1
examples/scenarios/aws/webserver/.gitignore
vendored
1
examples/scenarios/aws/webserver/.gitignore
vendored
|
@ -1,4 +1,3 @@
|
|||
.lumi/
|
||||
bin/
|
||||
node_modules/
|
||||
|
||||
|
|
|
@ -1,7 +1,7 @@
|
|||
{
|
||||
"name": "webserver",
|
||||
"main": "bin/index.js",
|
||||
"typings": "bin/index.d.ts",
|
||||
"version": "0.1",
|
||||
"typings": ".lumi/bin/index.d.ts",
|
||||
"scripts": {
|
||||
"build": "lumijs"
|
||||
},
|
||||
|
|
|
@ -34,7 +34,7 @@ build:
|
|||
@cd pack/ && lumi pack verify # ensure the pack verifies
|
||||
@cp -R pack/.lumi/bin/ bin/ # copy the pack to our bin dir
|
||||
@go version
|
||||
@cd provider/ && go build -o ../bin/lumi-resource-aws # compile the resource provider
|
||||
@cd provider/ && go build -i -o ../bin/lumi-resource-aws # compile the resource provider
|
||||
|
||||
.PHONY: install
|
||||
install:
|
||||
|
|
|
@ -13,12 +13,15 @@
|
|||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
|
||||
/* tslint:disable: ordered-imports */
|
||||
import { jsonStringify, sha1hash, printf } from "@lumi/lumi/runtime";
|
||||
import { Deployment, RestAPI, Stage } from "../apigateway";
|
||||
import { Permission } from "../lambda";
|
||||
import { Function } from "./function";
|
||||
import { region } from "../config";
|
||||
|
||||
|
||||
export interface Route {
|
||||
method: string;
|
||||
path: string;
|
||||
|
@ -75,6 +78,10 @@ function createPathSpec(lambdaARN: string): SwaggerOperation {
|
|||
};
|
||||
}
|
||||
|
||||
function createSourceARN(region: string, account: string, apiid: string, functionName: string): string {
|
||||
return "arn:aws:execute-api:"+region+":"+account+":"+apiid+"/*/*/"+ functionName;
|
||||
}
|
||||
|
||||
// API is a higher level abstraction for working with AWS APIGateway reources.
|
||||
export class API {
|
||||
public api: RestAPI;
|
||||
|
@ -111,7 +118,19 @@ export class API {
|
|||
default:
|
||||
throw new Error("Method not supported: " + method);
|
||||
}
|
||||
|
||||
let apiName = "";
|
||||
if(this.api.apiName !== undefined) {
|
||||
apiName = this.api.apiName;
|
||||
}
|
||||
let invokePermission = new Permission(this.apiName + "_invoke_" + sha1hash(method + path), {
|
||||
action: "lambda:invokeFunction",
|
||||
function: lambda.lambda,
|
||||
principal: "apigateway.amazonaws.com",
|
||||
sourceARN: createSourceARN("us-east-1", "490047557317", apiName, "webapi-test-func"),
|
||||
});
|
||||
// TODO[pulumi/lumi#90]: Once we suport output properties, we can use `lambda.lambda.arn` as input
|
||||
|
||||
// to constructing this apigateway lambda invocation uri.
|
||||
// this.swaggerSpec.paths[path][swaggerMethod] = createPathSpec(lambda.lambda.arn);
|
||||
this.swaggerSpec.paths[path][swaggerMethod] = createPathSpec(
|
||||
|
|
|
@ -103,8 +103,8 @@ func (arn ARN) Parse() (Parts, error) {
|
|||
if len(ps) > 5 {
|
||||
parts.Resource = ps[5]
|
||||
}
|
||||
if len(ps) > 6 {
|
||||
parts.Resource = parts.Resource + ":" + ps[6]
|
||||
for i := 6; i < len(ps); i++ {
|
||||
parts.Resource = parts.Resource + ":" + ps[i]
|
||||
}
|
||||
return parts, nil
|
||||
}
|
||||
|
|
|
@ -29,12 +29,12 @@ func Test(t *testing.T) {
|
|||
cleanupFunctions(ctx)
|
||||
cleanupRoles(ctx)
|
||||
|
||||
functionProvider := NewFunctionProvider(ctx)
|
||||
roleProvider := iamprovider.NewRoleProvider(ctx)
|
||||
sourceARN := rpc.ARN("arn:aws:s3:::elasticbeanstalk-us-east-1-111111111111")
|
||||
|
||||
resources := map[string]testutil.Resource{
|
||||
"role": {Provider: roleProvider, Token: iam.RoleToken},
|
||||
"f": {Provider: functionProvider, Token: FunctionToken},
|
||||
"role": {Provider: iamprovider.NewRoleProvider(ctx), Token: iam.RoleToken},
|
||||
"f": {Provider: NewFunctionProvider(ctx), Token: FunctionToken},
|
||||
"permission": {Provider: NewPermissionProvider(ctx), Token: PermissionToken},
|
||||
}
|
||||
steps := []testutil.Step{
|
||||
testutil.Step{
|
||||
|
@ -80,6 +80,19 @@ func Test(t *testing.T) {
|
|||
}
|
||||
},
|
||||
},
|
||||
testutil.ResourceGenerator{
|
||||
Name: "permission",
|
||||
Creator: func(ctx testutil.Context) interface{} {
|
||||
return &lambda.Permission{
|
||||
Name: aws.String(RESOURCEPREFIX),
|
||||
Function: ctx.GetResourceID("f"),
|
||||
Action: "lambda:InvokeFunction",
|
||||
Principal: "s3.amazonaws.com",
|
||||
SourceAccount: aws.String("111111111111"),
|
||||
SourceARN: &sourceARN,
|
||||
}
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
|
||||
|
|
237
lib/aws/provider/lambda/permission.go
Normal file
237
lib/aws/provider/lambda/permission.go
Normal file
|
@ -0,0 +1,237 @@
|
|||
// Licensed to Pulumi Corporation ("Pulumi") under one or more
|
||||
// contributor license agreements. See the NOTICE file distributed with
|
||||
// this work for additional information regarding copyright ownership.
|
||||
// Pulumi licenses this file to You under the Apache License, Version 2.0
|
||||
// (the "License"); you may not use this file except in compliance with
|
||||
// the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package lambda
|
||||
|
||||
import (
|
||||
"crypto/sha1"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"reflect"
|
||||
"regexp"
|
||||
"strings"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws"
|
||||
awslambda "github.com/aws/aws-sdk-go/service/lambda"
|
||||
"github.com/pulumi/lumi/pkg/resource"
|
||||
"github.com/pulumi/lumi/pkg/util/contract"
|
||||
"github.com/pulumi/lumi/sdk/go/pkg/lumirpc"
|
||||
"golang.org/x/net/context"
|
||||
|
||||
"github.com/pulumi/lumi/lib/aws/provider/arn"
|
||||
"github.com/pulumi/lumi/lib/aws/provider/awsctx"
|
||||
awscommon "github.com/pulumi/lumi/lib/aws/rpc"
|
||||
"github.com/pulumi/lumi/lib/aws/rpc/lambda"
|
||||
)
|
||||
|
||||
const PermissionToken = lambda.PermissionToken
|
||||
|
||||
const (
|
||||
maxStatementID = 100
|
||||
actionRegexp = "(lambda:[*]|lambda:[a-zA-Z]+|[*])"
|
||||
sourceAccountRegexp = "\\d{12}"
|
||||
sourceARNRegexp = "arn:aws:([a-zA-Z0-9\\-])+:([a-z]{2}-[a-z]+-\\d{1})?:(\\d{12})?:(.*)"
|
||||
)
|
||||
|
||||
type policy struct {
|
||||
Version string
|
||||
ID string `json:"Id"`
|
||||
Statement []statement
|
||||
}
|
||||
|
||||
type statement struct {
|
||||
Sid string
|
||||
Effect string
|
||||
Principal principal
|
||||
Action string
|
||||
Resource string
|
||||
Condition condition
|
||||
}
|
||||
|
||||
type principal struct {
|
||||
Service string
|
||||
}
|
||||
|
||||
type condition struct {
|
||||
ArnLike *arnLike `json:"ArnLike,omitempty"`
|
||||
StringEquals *stringEquals `json:"StringEquals,omitempty"`
|
||||
}
|
||||
|
||||
type arnLike struct {
|
||||
AWSSourceArn *string `json:"AWS:SourceArn,omitempty"`
|
||||
}
|
||||
|
||||
type stringEquals struct {
|
||||
AWSSourceAccount *string `json:"AWS:SourceAccount,omitempty"`
|
||||
}
|
||||
|
||||
// NewPermissionID returns an AWS APIGateway Deployment ARN ID for the given restAPIID and deploymentID
|
||||
func NewPermissionID(region, account, functionName, statementID string) resource.ID {
|
||||
return arn.NewID("lambda", region, account, "function:"+functionName+":policy:"+statementID)
|
||||
}
|
||||
|
||||
// ParsePermissionID parses an AWS APIGateway Deployment ARN ID to extract the restAPIID and deploymentID
|
||||
func ParsePermissionID(id resource.ID) (string, string, error) {
|
||||
res, err := arn.ParseResourceName(id)
|
||||
if err != nil {
|
||||
return "", "", err
|
||||
}
|
||||
parts := strings.Split(res, ":")
|
||||
if len(parts) != 3 || parts[1] != "policy" {
|
||||
return "", "", fmt.Errorf("expected Permission ARN of the form %v: %v",
|
||||
"arn:aws:lambda:region:account:function:function-name:policy:statement-id", id)
|
||||
}
|
||||
return parts[0], parts[2], nil
|
||||
}
|
||||
|
||||
// NewPermissionProvider creates a provider that handles Lambda permission operations.
|
||||
func NewPermissionProvider(ctx *awsctx.Context) lumirpc.ResourceProviderServer {
|
||||
ops := &permissionProvider{ctx}
|
||||
return lambda.NewPermissionProvider(ops)
|
||||
}
|
||||
|
||||
type permissionProvider struct {
|
||||
ctx *awsctx.Context
|
||||
}
|
||||
|
||||
// Check validates that the given property bag is valid for a resource of the given type.
|
||||
func (p *permissionProvider) Check(ctx context.Context, obj *lambda.Permission) ([]error, error) {
|
||||
var failures []error
|
||||
if matched, err := regexp.MatchString(actionRegexp, obj.Action); err != nil || !matched {
|
||||
failures = append(failures,
|
||||
resource.NewFieldError(reflect.TypeOf(obj), lambda.Permission_Action,
|
||||
fmt.Errorf("did not match regexp %v", actionRegexp)))
|
||||
}
|
||||
if obj.SourceAccount != nil {
|
||||
if matched, err := regexp.MatchString(sourceAccountRegexp, *obj.SourceAccount); err != nil || !matched {
|
||||
fmt.Printf("adding failure because source account didn't match\n")
|
||||
failures = append(failures,
|
||||
resource.NewFieldError(reflect.TypeOf(obj), lambda.Permission_SourceAccount,
|
||||
fmt.Errorf("did not match regexp %v", sourceAccountRegexp)))
|
||||
}
|
||||
}
|
||||
if obj.SourceARN != nil {
|
||||
if matched, err := regexp.MatchString(sourceARNRegexp, string(*obj.SourceARN)); err != nil || !matched {
|
||||
failures = append(failures,
|
||||
resource.NewFieldError(reflect.TypeOf(obj), lambda.Permission_SourceARN,
|
||||
fmt.Errorf("did not match regexp %v", sourceARNRegexp)))
|
||||
}
|
||||
}
|
||||
return failures, nil
|
||||
}
|
||||
|
||||
// Create allocates a new instance of the provided resource and returns its unique ID afterwards. (The input ID
|
||||
// must be blank.) If this call fails, the resource must not have been created (i.e., it is "transacational").
|
||||
func (p *permissionProvider) Create(ctx context.Context, obj *lambda.Permission) (resource.ID, error) {
|
||||
// Auto-generate a name in part based on the resource name.
|
||||
statementID := resource.NewUniqueHex(*obj.Name+"-", maxStatementID, sha1.Size)
|
||||
functionName, err := arn.ParseResourceName(obj.Function)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
fmt.Printf("Creating Lambda Permission '%v' with statement ID '%v'\n", *obj.Name, statementID)
|
||||
create := &awslambda.AddPermissionInput{
|
||||
Action: aws.String(obj.Action),
|
||||
FunctionName: aws.String(functionName),
|
||||
Principal: aws.String(obj.Principal),
|
||||
SourceAccount: obj.SourceAccount,
|
||||
StatementId: aws.String(statementID),
|
||||
}
|
||||
if obj.SourceARN != nil {
|
||||
create.SourceArn = aws.String(string(*obj.SourceARN))
|
||||
}
|
||||
_, err = p.ctx.Lambda().AddPermission(create)
|
||||
if err != nil {
|
||||
return "", err
|
||||
}
|
||||
|
||||
return NewPermissionID(p.ctx.Region(), p.ctx.AccountID(), functionName, statementID), nil
|
||||
}
|
||||
|
||||
// Get reads the instance state identified by ID, returning a populated resource object, or an error if not found.
|
||||
func (p *permissionProvider) Get(ctx context.Context, id resource.ID) (*lambda.Permission, error) {
|
||||
functionName, statementID, err := ParsePermissionID(id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
resp, err := p.ctx.Lambda().GetPolicy(&awslambda.GetPolicyInput{
|
||||
FunctionName: aws.String(functionName),
|
||||
})
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
contract.Assert(resp != nil)
|
||||
contract.Assert(resp.Policy != nil)
|
||||
policy := policy{}
|
||||
err = json.Unmarshal([]byte(*resp.Policy), &policy)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, statement := range policy.Statement {
|
||||
if statement.Sid == statementID {
|
||||
permission := &lambda.Permission{
|
||||
Action: statement.Action,
|
||||
Function: resource.ID(statement.Resource),
|
||||
Principal: statement.Principal.Service,
|
||||
}
|
||||
// The statements generated by `lambda.AddPermission` will contain up to two Condition elements
|
||||
// of the following two forms, corresponding to the optional SourceARN and SourceAccount properites.
|
||||
// "ArnLike": { "AWS:SourceArn": "<arn>" }
|
||||
// or:
|
||||
// "StringEquals": { "AWS:SourceAccount": "<account-id>" }
|
||||
condition := statement.Condition
|
||||
if condition.ArnLike != nil && condition.ArnLike.AWSSourceArn != nil {
|
||||
sourceARN := awscommon.ARN(*condition.ArnLike.AWSSourceArn)
|
||||
permission.SourceARN = &sourceARN
|
||||
}
|
||||
if condition.StringEquals != nil && condition.StringEquals.AWSSourceAccount != nil {
|
||||
permission.SourceAccount = condition.StringEquals.AWSSourceAccount
|
||||
}
|
||||
return permission, nil
|
||||
}
|
||||
}
|
||||
return nil, fmt.Errorf("No statement found for id '%v'", id)
|
||||
}
|
||||
|
||||
// InspectChange checks what impacts a hypothetical update will have on the resource's properties.
|
||||
func (p *permissionProvider) InspectChange(ctx context.Context, id resource.ID,
|
||||
old *lambda.Permission, new *lambda.Permission, diff *resource.ObjectDiff) ([]string, error) {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// Update updates an existing resource with new values. Only those values in the provided property bag are updated
|
||||
// to new values. The resource ID is returned and may be different if the resource had to be recreated.
|
||||
func (p *permissionProvider) Update(ctx context.Context, id resource.ID,
|
||||
old *lambda.Permission, new *lambda.Permission, diff *resource.ObjectDiff) error {
|
||||
contract.Failf("No properties of Permission resource are updatable.")
|
||||
return nil
|
||||
}
|
||||
|
||||
// Delete tears down an existing resource with the given ID. If it fails, the resource is assumed to still exist.
|
||||
func (p *permissionProvider) Delete(ctx context.Context, id resource.ID) error {
|
||||
functionName, statementID, err := ParsePermissionID(id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
fmt.Printf("Deleting Lambda Permission '%v'\n", statementID)
|
||||
_, err = p.ctx.Lambda().RemovePermission(&awslambda.RemovePermissionInput{
|
||||
FunctionName: aws.String(functionName),
|
||||
StatementId: aws.String(statementID),
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
|
@ -56,6 +56,7 @@ func NewProvider() (*Provider, error) {
|
|||
elasticbeanstalk.ApplicationVersionToken: elasticbeanstalk.NewApplicationVersionProvider(ctx),
|
||||
elasticbeanstalk.EnvironmentToken: elasticbeanstalk.NewEnvironmentProvider(ctx),
|
||||
lambda.FunctionToken: lambda.NewFunctionProvider(ctx),
|
||||
lambda.PermissionToken: lambda.NewPermissionProvider(ctx),
|
||||
iam.RoleToken: iam.NewRoleProvider(ctx),
|
||||
s3.BucketToken: s3.NewBucketProvider(ctx),
|
||||
s3.ObjectToken: s3.NewObjectProvider(ctx),
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
package testutil
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
structpb "github.com/golang/protobuf/ptypes/struct"
|
||||
|
@ -35,18 +36,25 @@ type Step []ResourceGenerator
|
|||
func ProviderTest(t *testing.T, resources map[string]Resource, steps []Step) {
|
||||
|
||||
p := &providerTest{
|
||||
resources: resources,
|
||||
ids: map[string]resource.ID{},
|
||||
props: map[string]*structpb.Struct{},
|
||||
resources: resources,
|
||||
namesInCreationOrder: []string{},
|
||||
ids: map[string]resource.ID{},
|
||||
props: map[string]*structpb.Struct{},
|
||||
}
|
||||
|
||||
// For each step, create or update all listed resources
|
||||
for _, step := range steps {
|
||||
for _, res := range step {
|
||||
provider := resources[res.Name].Provider
|
||||
token := resources[res.Name].Token
|
||||
currentResource, ok := resources[res.Name]
|
||||
if !ok {
|
||||
t.Fatalf("expected resource to have been pre-declared: %v", res.Name)
|
||||
}
|
||||
provider := currentResource.Provider
|
||||
token := currentResource.Token
|
||||
if id, ok := p.ids[res.Name]; !ok {
|
||||
id, props := createResource(t, res.Creator(p), provider, token)
|
||||
p.ids[res.Name] = resource.ID(id)
|
||||
p.namesInCreationOrder = append(p.namesInCreationOrder, res.Name)
|
||||
p.props[res.Name] = props
|
||||
if id == "" {
|
||||
t.Fatal("expected to succesfully create resource")
|
||||
|
@ -61,7 +69,10 @@ func ProviderTest(t *testing.T, resources map[string]Resource, steps []Step) {
|
|||
}
|
||||
}
|
||||
}
|
||||
for name, id := range p.ids {
|
||||
// Delete resources in the opposite order they were created
|
||||
for i := len(p.namesInCreationOrder) - 1; i >= 0; i-- {
|
||||
name := p.namesInCreationOrder[i]
|
||||
id := p.ids[name]
|
||||
provider := resources[name].Provider
|
||||
token := resources[name].Token
|
||||
ok := deleteResource(t, string(id), provider, token)
|
||||
|
@ -97,9 +108,10 @@ func ProviderTestSimple(t *testing.T, provider lumirpc.ResourceProviderServer, t
|
|||
}
|
||||
|
||||
type providerTest struct {
|
||||
resources map[string]Resource
|
||||
ids map[string]resource.ID
|
||||
props map[string]*structpb.Struct
|
||||
resources map[string]Resource
|
||||
namesInCreationOrder []string
|
||||
ids map[string]resource.ID
|
||||
props map[string]*structpb.Struct
|
||||
}
|
||||
|
||||
func (p *providerTest) GetResourceID(name string) resource.ID {
|
||||
|
@ -113,6 +125,7 @@ var _ Context = &providerTest{}
|
|||
|
||||
func createResource(t *testing.T, res interface{}, provider lumirpc.ResourceProviderServer, token tokens.Type) (string, *structpb.Struct) {
|
||||
props := resource.MarshalProperties(nil, resource.NewPropertyMap(res), resource.MarshalOptions{})
|
||||
fmt.Printf("[Provider Test]: Checking %v\n", token)
|
||||
checkResp, err := provider.Check(nil, &lumirpc.CheckRequest{
|
||||
Type: string(token),
|
||||
Properties: props,
|
||||
|
@ -121,6 +134,7 @@ func createResource(t *testing.T, res interface{}, provider lumirpc.ResourceProv
|
|||
return "", nil
|
||||
}
|
||||
assert.Equal(t, 0, len(checkResp.Failures), "expected no check failures")
|
||||
fmt.Printf("[Provider Test]: Creating %v\n", token)
|
||||
resp, err := provider.Create(nil, &lumirpc.CreateRequest{
|
||||
Type: string(token),
|
||||
Properties: props,
|
||||
|
@ -132,11 +146,23 @@ func createResource(t *testing.T, res interface{}, provider lumirpc.ResourceProv
|
|||
return "", nil
|
||||
}
|
||||
id := resp.Id
|
||||
fmt.Printf("[Provider Test]: Getting %v with id %v\n", token, id)
|
||||
getResp, err := provider.Get(nil, &lumirpc.GetRequest{
|
||||
Type: string(token),
|
||||
Id: id,
|
||||
})
|
||||
if !assert.NoError(t, err, "expected no error reading resource") {
|
||||
return "", nil
|
||||
}
|
||||
if !assert.NotNil(t, getResp, "expected a non-nil response reading the resources") {
|
||||
return "", nil
|
||||
}
|
||||
return id, props
|
||||
}
|
||||
|
||||
func updateResource(t *testing.T, id string, lastProps *structpb.Struct, res interface{}, provider lumirpc.ResourceProviderServer, token tokens.Type) (bool, *structpb.Struct) {
|
||||
newProps := resource.MarshalProperties(nil, resource.NewPropertyMap(res), resource.MarshalOptions{})
|
||||
fmt.Printf("[Provider Test]: Checking %v\n", token)
|
||||
checkResp, err := provider.Check(nil, &lumirpc.CheckRequest{
|
||||
Type: string(token),
|
||||
Properties: newProps,
|
||||
|
@ -145,6 +171,7 @@ func updateResource(t *testing.T, id string, lastProps *structpb.Struct, res int
|
|||
return false, nil
|
||||
}
|
||||
assert.Equal(t, 0, len(checkResp.Failures), "expected no check failures")
|
||||
fmt.Printf("[Provider Test]: Updating %v with id %v\n", token, id)
|
||||
_, err = provider.Update(nil, &lumirpc.UpdateRequest{
|
||||
Type: string(token),
|
||||
Id: id,
|
||||
|
@ -158,6 +185,7 @@ func updateResource(t *testing.T, id string, lastProps *structpb.Struct, res int
|
|||
}
|
||||
|
||||
func deleteResource(t *testing.T, id string, provider lumirpc.ResourceProviderServer, token tokens.Type) bool {
|
||||
fmt.Printf("[Provider Test]: Deleting %v with id %v\n", token, id)
|
||||
_, err := provider.Delete(nil, &lumirpc.DeleteRequest{
|
||||
Type: string(token),
|
||||
Id: id,
|
||||
|
|
|
@ -49,14 +49,15 @@ func (p *AccountProvider) Check(
|
|||
ctx context.Context, req *lumirpc.CheckRequest) (*lumirpc.CheckResponse, error) {
|
||||
contract.Assert(req.GetType() == string(AccountToken))
|
||||
obj, _, err := p.Unmarshal(req.GetProperties())
|
||||
if err == nil {
|
||||
if failures, err := p.ops.Check(ctx, obj); err != nil {
|
||||
return nil, err
|
||||
} else if len(failures) > 0 {
|
||||
err = resource.NewCheckError(failures)
|
||||
}
|
||||
if err != nil {
|
||||
return resource.NewCheckResponse(err), nil
|
||||
}
|
||||
return resource.NewCheckResponse(err), nil
|
||||
if failures, err := p.ops.Check(ctx, obj); err != nil {
|
||||
return nil, err
|
||||
} else if len(failures) > 0 {
|
||||
return resource.NewCheckResponse(resource.NewCheckError(failures)), nil
|
||||
}
|
||||
return resource.NewCheckResponse(nil), nil
|
||||
}
|
||||
|
||||
func (p *AccountProvider) Name(
|
||||
|
|
|
@ -49,14 +49,15 @@ func (p *APIKeyProvider) Check(
|
|||
ctx context.Context, req *lumirpc.CheckRequest) (*lumirpc.CheckResponse, error) {
|
||||
contract.Assert(req.GetType() == string(APIKeyToken))
|
||||
obj, _, err := p.Unmarshal(req.GetProperties())
|
||||
if err == nil {
|
||||
if failures, err := p.ops.Check(ctx, obj); err != nil {
|
||||
return nil, err
|
||||
} else if len(failures) > 0 {
|
||||
err = resource.NewCheckError(failures)
|
||||
}
|
||||
if err != nil {
|
||||
return resource.NewCheckResponse(err), nil
|
||||
}
|
||||
return resource.NewCheckResponse(err), nil
|
||||
if failures, err := p.ops.Check(ctx, obj); err != nil {
|
||||
return nil, err
|
||||
} else if len(failures) > 0 {
|
||||
return resource.NewCheckResponse(resource.NewCheckError(failures)), nil
|
||||
}
|
||||
return resource.NewCheckResponse(nil), nil
|
||||
}
|
||||
|
||||
func (p *APIKeyProvider) Name(
|
||||
|
|
|
@ -49,14 +49,15 @@ func (p *AuthorizerProvider) Check(
|
|||
ctx context.Context, req *lumirpc.CheckRequest) (*lumirpc.CheckResponse, error) {
|
||||
contract.Assert(req.GetType() == string(AuthorizerToken))
|
||||
obj, _, err := p.Unmarshal(req.GetProperties())
|
||||
if err == nil {
|
||||
if failures, err := p.ops.Check(ctx, obj); err != nil {
|
||||
return nil, err
|
||||
} else if len(failures) > 0 {
|
||||
err = resource.NewCheckError(failures)
|
||||
}
|
||||
if err != nil {
|
||||
return resource.NewCheckResponse(err), nil
|
||||
}
|
||||
return resource.NewCheckResponse(err), nil
|
||||
if failures, err := p.ops.Check(ctx, obj); err != nil {
|
||||
return nil, err
|
||||
} else if len(failures) > 0 {
|
||||
return resource.NewCheckResponse(resource.NewCheckError(failures)), nil
|
||||
}
|
||||
return resource.NewCheckResponse(nil), nil
|
||||
}
|
||||
|
||||
func (p *AuthorizerProvider) Name(
|
||||
|
|
|
@ -49,14 +49,15 @@ func (p *BasePathMappingProvider) Check(
|
|||
ctx context.Context, req *lumirpc.CheckRequest) (*lumirpc.CheckResponse, error) {
|
||||
contract.Assert(req.GetType() == string(BasePathMappingToken))
|
||||
obj, _, err := p.Unmarshal(req.GetProperties())
|
||||
if err == nil {
|
||||
if failures, err := p.ops.Check(ctx, obj); err != nil {
|
||||
return nil, err
|
||||
} else if len(failures) > 0 {
|
||||
err = resource.NewCheckError(failures)
|
||||
}
|
||||
if err != nil {
|
||||
return resource.NewCheckResponse(err), nil
|
||||
}
|
||||
return resource.NewCheckResponse(err), nil
|
||||
if failures, err := p.ops.Check(ctx, obj); err != nil {
|
||||
return nil, err
|
||||
} else if len(failures) > 0 {
|
||||
return resource.NewCheckResponse(resource.NewCheckError(failures)), nil
|
||||
}
|
||||
return resource.NewCheckResponse(nil), nil
|
||||
}
|
||||
|
||||
func (p *BasePathMappingProvider) Name(
|
||||
|
|
|
@ -49,14 +49,15 @@ func (p *ClientCertificateProvider) Check(
|
|||
ctx context.Context, req *lumirpc.CheckRequest) (*lumirpc.CheckResponse, error) {
|
||||
contract.Assert(req.GetType() == string(ClientCertificateToken))
|
||||
obj, _, err := p.Unmarshal(req.GetProperties())
|
||||
if err == nil {
|
||||
if failures, err := p.ops.Check(ctx, obj); err != nil {
|
||||
return nil, err
|
||||
} else if len(failures) > 0 {
|
||||
err = resource.NewCheckError(failures)
|
||||
}
|
||||
if err != nil {
|
||||
return resource.NewCheckResponse(err), nil
|
||||
}
|
||||
return resource.NewCheckResponse(err), nil
|
||||
if failures, err := p.ops.Check(ctx, obj); err != nil {
|
||||
return nil, err
|
||||
} else if len(failures) > 0 {
|
||||
return resource.NewCheckResponse(resource.NewCheckError(failures)), nil
|
||||
}
|
||||
return resource.NewCheckResponse(nil), nil
|
||||
}
|
||||
|
||||
func (p *ClientCertificateProvider) Name(
|
||||
|
|
|
@ -49,14 +49,15 @@ func (p *DeploymentProvider) Check(
|
|||
ctx context.Context, req *lumirpc.CheckRequest) (*lumirpc.CheckResponse, error) {
|
||||
contract.Assert(req.GetType() == string(DeploymentToken))
|
||||
obj, _, err := p.Unmarshal(req.GetProperties())
|
||||
if err == nil {
|
||||
if failures, err := p.ops.Check(ctx, obj); err != nil {
|
||||
return nil, err
|
||||
} else if len(failures) > 0 {
|
||||
err = resource.NewCheckError(failures)
|
||||
}
|
||||
if err != nil {
|
||||
return resource.NewCheckResponse(err), nil
|
||||
}
|
||||
return resource.NewCheckResponse(err), nil
|
||||
if failures, err := p.ops.Check(ctx, obj); err != nil {
|
||||
return nil, err
|
||||
} else if len(failures) > 0 {
|
||||
return resource.NewCheckResponse(resource.NewCheckError(failures)), nil
|
||||
}
|
||||
return resource.NewCheckResponse(nil), nil
|
||||
}
|
||||
|
||||
func (p *DeploymentProvider) Name(
|
||||
|
|
|
@ -97,14 +97,15 @@ func (p *MethodProvider) Check(
|
|||
ctx context.Context, req *lumirpc.CheckRequest) (*lumirpc.CheckResponse, error) {
|
||||
contract.Assert(req.GetType() == string(MethodToken))
|
||||
obj, _, err := p.Unmarshal(req.GetProperties())
|
||||
if err == nil {
|
||||
if failures, err := p.ops.Check(ctx, obj); err != nil {
|
||||
return nil, err
|
||||
} else if len(failures) > 0 {
|
||||
err = resource.NewCheckError(failures)
|
||||
}
|
||||
if err != nil {
|
||||
return resource.NewCheckResponse(err), nil
|
||||
}
|
||||
return resource.NewCheckResponse(err), nil
|
||||
if failures, err := p.ops.Check(ctx, obj); err != nil {
|
||||
return nil, err
|
||||
} else if len(failures) > 0 {
|
||||
return resource.NewCheckResponse(resource.NewCheckError(failures)), nil
|
||||
}
|
||||
return resource.NewCheckResponse(nil), nil
|
||||
}
|
||||
|
||||
func (p *MethodProvider) Name(
|
||||
|
|
|
@ -49,14 +49,15 @@ func (p *ModelProvider) Check(
|
|||
ctx context.Context, req *lumirpc.CheckRequest) (*lumirpc.CheckResponse, error) {
|
||||
contract.Assert(req.GetType() == string(ModelToken))
|
||||
obj, _, err := p.Unmarshal(req.GetProperties())
|
||||
if err == nil {
|
||||
if failures, err := p.ops.Check(ctx, obj); err != nil {
|
||||
return nil, err
|
||||
} else if len(failures) > 0 {
|
||||
err = resource.NewCheckError(failures)
|
||||
}
|
||||
if err != nil {
|
||||
return resource.NewCheckResponse(err), nil
|
||||
}
|
||||
return resource.NewCheckResponse(err), nil
|
||||
if failures, err := p.ops.Check(ctx, obj); err != nil {
|
||||
return nil, err
|
||||
} else if len(failures) > 0 {
|
||||
return resource.NewCheckResponse(resource.NewCheckError(failures)), nil
|
||||
}
|
||||
return resource.NewCheckResponse(nil), nil
|
||||
}
|
||||
|
||||
func (p *ModelProvider) Name(
|
||||
|
|
|
@ -49,14 +49,15 @@ func (p *ResourceProvider) Check(
|
|||
ctx context.Context, req *lumirpc.CheckRequest) (*lumirpc.CheckResponse, error) {
|
||||
contract.Assert(req.GetType() == string(ResourceToken))
|
||||
obj, _, err := p.Unmarshal(req.GetProperties())
|
||||
if err == nil {
|
||||
if failures, err := p.ops.Check(ctx, obj); err != nil {
|
||||
return nil, err
|
||||
} else if len(failures) > 0 {
|
||||
err = resource.NewCheckError(failures)
|
||||
}
|
||||
if err != nil {
|
||||
return resource.NewCheckResponse(err), nil
|
||||
}
|
||||
return resource.NewCheckResponse(err), nil
|
||||
if failures, err := p.ops.Check(ctx, obj); err != nil {
|
||||
return nil, err
|
||||
} else if len(failures) > 0 {
|
||||
return resource.NewCheckResponse(resource.NewCheckError(failures)), nil
|
||||
}
|
||||
return resource.NewCheckResponse(nil), nil
|
||||
}
|
||||
|
||||
func (p *ResourceProvider) Name(
|
||||
|
|
|
@ -49,14 +49,15 @@ func (p *RestAPIProvider) Check(
|
|||
ctx context.Context, req *lumirpc.CheckRequest) (*lumirpc.CheckResponse, error) {
|
||||
contract.Assert(req.GetType() == string(RestAPIToken))
|
||||
obj, _, err := p.Unmarshal(req.GetProperties())
|
||||
if err == nil {
|
||||
if failures, err := p.ops.Check(ctx, obj); err != nil {
|
||||
return nil, err
|
||||
} else if len(failures) > 0 {
|
||||
err = resource.NewCheckError(failures)
|
||||
}
|
||||
if err != nil {
|
||||
return resource.NewCheckResponse(err), nil
|
||||
}
|
||||
return resource.NewCheckResponse(err), nil
|
||||
if failures, err := p.ops.Check(ctx, obj); err != nil {
|
||||
return nil, err
|
||||
} else if len(failures) > 0 {
|
||||
return resource.NewCheckResponse(resource.NewCheckError(failures)), nil
|
||||
}
|
||||
return resource.NewCheckResponse(nil), nil
|
||||
}
|
||||
|
||||
func (p *RestAPIProvider) Name(
|
||||
|
|
|
@ -49,14 +49,15 @@ func (p *StageProvider) Check(
|
|||
ctx context.Context, req *lumirpc.CheckRequest) (*lumirpc.CheckResponse, error) {
|
||||
contract.Assert(req.GetType() == string(StageToken))
|
||||
obj, _, err := p.Unmarshal(req.GetProperties())
|
||||
if err == nil {
|
||||
if failures, err := p.ops.Check(ctx, obj); err != nil {
|
||||
return nil, err
|
||||
} else if len(failures) > 0 {
|
||||
err = resource.NewCheckError(failures)
|
||||
}
|
||||
if err != nil {
|
||||
return resource.NewCheckResponse(err), nil
|
||||
}
|
||||
return resource.NewCheckResponse(err), nil
|
||||
if failures, err := p.ops.Check(ctx, obj); err != nil {
|
||||
return nil, err
|
||||
} else if len(failures) > 0 {
|
||||
return resource.NewCheckResponse(resource.NewCheckError(failures)), nil
|
||||
}
|
||||
return resource.NewCheckResponse(nil), nil
|
||||
}
|
||||
|
||||
func (p *StageProvider) Name(
|
||||
|
|
|
@ -93,14 +93,15 @@ func (p *UsagePlanProvider) Check(
|
|||
ctx context.Context, req *lumirpc.CheckRequest) (*lumirpc.CheckResponse, error) {
|
||||
contract.Assert(req.GetType() == string(UsagePlanToken))
|
||||
obj, _, err := p.Unmarshal(req.GetProperties())
|
||||
if err == nil {
|
||||
if failures, err := p.ops.Check(ctx, obj); err != nil {
|
||||
return nil, err
|
||||
} else if len(failures) > 0 {
|
||||
err = resource.NewCheckError(failures)
|
||||
}
|
||||
if err != nil {
|
||||
return resource.NewCheckResponse(err), nil
|
||||
}
|
||||
return resource.NewCheckResponse(err), nil
|
||||
if failures, err := p.ops.Check(ctx, obj); err != nil {
|
||||
return nil, err
|
||||
} else if len(failures) > 0 {
|
||||
return resource.NewCheckResponse(resource.NewCheckError(failures)), nil
|
||||
}
|
||||
return resource.NewCheckResponse(nil), nil
|
||||
}
|
||||
|
||||
func (p *UsagePlanProvider) Name(
|
||||
|
|
|
@ -49,14 +49,15 @@ func (p *UsagePlanKeyProvider) Check(
|
|||
ctx context.Context, req *lumirpc.CheckRequest) (*lumirpc.CheckResponse, error) {
|
||||
contract.Assert(req.GetType() == string(UsagePlanKeyToken))
|
||||
obj, _, err := p.Unmarshal(req.GetProperties())
|
||||
if err == nil {
|
||||
if failures, err := p.ops.Check(ctx, obj); err != nil {
|
||||
return nil, err
|
||||
} else if len(failures) > 0 {
|
||||
err = resource.NewCheckError(failures)
|
||||
}
|
||||
if err != nil {
|
||||
return resource.NewCheckResponse(err), nil
|
||||
}
|
||||
return resource.NewCheckResponse(err), nil
|
||||
if failures, err := p.ops.Check(ctx, obj); err != nil {
|
||||
return nil, err
|
||||
} else if len(failures) > 0 {
|
||||
return resource.NewCheckResponse(resource.NewCheckError(failures)), nil
|
||||
}
|
||||
return resource.NewCheckResponse(nil), nil
|
||||
}
|
||||
|
||||
func (p *UsagePlanKeyProvider) Name(
|
||||
|
|
|
@ -51,14 +51,15 @@ func (p *ActionTargetProvider) Check(
|
|||
ctx context.Context, req *lumirpc.CheckRequest) (*lumirpc.CheckResponse, error) {
|
||||
contract.Assert(req.GetType() == string(ActionTargetToken))
|
||||
obj, _, err := p.Unmarshal(req.GetProperties())
|
||||
if err == nil {
|
||||
if failures, err := p.ops.Check(ctx, obj); err != nil {
|
||||
return nil, err
|
||||
} else if len(failures) > 0 {
|
||||
err = resource.NewCheckError(failures)
|
||||
}
|
||||
if err != nil {
|
||||
return resource.NewCheckResponse(err), nil
|
||||
}
|
||||
return resource.NewCheckResponse(err), nil
|
||||
if failures, err := p.ops.Check(ctx, obj); err != nil {
|
||||
return nil, err
|
||||
} else if len(failures) > 0 {
|
||||
return resource.NewCheckResponse(resource.NewCheckError(failures)), nil
|
||||
}
|
||||
return resource.NewCheckResponse(nil), nil
|
||||
}
|
||||
|
||||
func (p *ActionTargetProvider) Name(
|
||||
|
@ -222,14 +223,15 @@ func (p *AlarmProvider) Check(
|
|||
ctx context.Context, req *lumirpc.CheckRequest) (*lumirpc.CheckResponse, error) {
|
||||
contract.Assert(req.GetType() == string(AlarmToken))
|
||||
obj, _, err := p.Unmarshal(req.GetProperties())
|
||||
if err == nil {
|
||||
if failures, err := p.ops.Check(ctx, obj); err != nil {
|
||||
return nil, err
|
||||
} else if len(failures) > 0 {
|
||||
err = resource.NewCheckError(failures)
|
||||
}
|
||||
if err != nil {
|
||||
return resource.NewCheckResponse(err), nil
|
||||
}
|
||||
return resource.NewCheckResponse(err), nil
|
||||
if failures, err := p.ops.Check(ctx, obj); err != nil {
|
||||
return nil, err
|
||||
} else if len(failures) > 0 {
|
||||
return resource.NewCheckResponse(resource.NewCheckError(failures)), nil
|
||||
}
|
||||
return resource.NewCheckResponse(nil), nil
|
||||
}
|
||||
|
||||
func (p *AlarmProvider) Name(
|
||||
|
|
|
@ -87,14 +87,15 @@ func (p *TableProvider) Check(
|
|||
ctx context.Context, req *lumirpc.CheckRequest) (*lumirpc.CheckResponse, error) {
|
||||
contract.Assert(req.GetType() == string(TableToken))
|
||||
obj, _, err := p.Unmarshal(req.GetProperties())
|
||||
if err == nil {
|
||||
if failures, err := p.ops.Check(ctx, obj); err != nil {
|
||||
return nil, err
|
||||
} else if len(failures) > 0 {
|
||||
err = resource.NewCheckError(failures)
|
||||
}
|
||||
if err != nil {
|
||||
return resource.NewCheckResponse(err), nil
|
||||
}
|
||||
return resource.NewCheckResponse(err), nil
|
||||
if failures, err := p.ops.Check(ctx, obj); err != nil {
|
||||
return nil, err
|
||||
} else if len(failures) > 0 {
|
||||
return resource.NewCheckResponse(resource.NewCheckError(failures)), nil
|
||||
}
|
||||
return resource.NewCheckResponse(nil), nil
|
||||
}
|
||||
|
||||
func (p *TableProvider) Name(
|
||||
|
|
|
@ -49,14 +49,15 @@ func (p *InstanceProvider) Check(
|
|||
ctx context.Context, req *lumirpc.CheckRequest) (*lumirpc.CheckResponse, error) {
|
||||
contract.Assert(req.GetType() == string(InstanceToken))
|
||||
obj, _, err := p.Unmarshal(req.GetProperties())
|
||||
if err == nil {
|
||||
if failures, err := p.ops.Check(ctx, obj); err != nil {
|
||||
return nil, err
|
||||
} else if len(failures) > 0 {
|
||||
err = resource.NewCheckError(failures)
|
||||
}
|
||||
if err != nil {
|
||||
return resource.NewCheckResponse(err), nil
|
||||
}
|
||||
return resource.NewCheckResponse(err), nil
|
||||
if failures, err := p.ops.Check(ctx, obj); err != nil {
|
||||
return nil, err
|
||||
} else if len(failures) > 0 {
|
||||
return resource.NewCheckResponse(resource.NewCheckError(failures)), nil
|
||||
}
|
||||
return resource.NewCheckResponse(nil), nil
|
||||
}
|
||||
|
||||
func (p *InstanceProvider) Name(
|
||||
|
|
|
@ -49,14 +49,15 @@ func (p *InternetGatewayProvider) Check(
|
|||
ctx context.Context, req *lumirpc.CheckRequest) (*lumirpc.CheckResponse, error) {
|
||||
contract.Assert(req.GetType() == string(InternetGatewayToken))
|
||||
obj, _, err := p.Unmarshal(req.GetProperties())
|
||||
if err == nil {
|
||||
if failures, err := p.ops.Check(ctx, obj); err != nil {
|
||||
return nil, err
|
||||
} else if len(failures) > 0 {
|
||||
err = resource.NewCheckError(failures)
|
||||
}
|
||||
if err != nil {
|
||||
return resource.NewCheckResponse(err), nil
|
||||
}
|
||||
return resource.NewCheckResponse(err), nil
|
||||
if failures, err := p.ops.Check(ctx, obj); err != nil {
|
||||
return nil, err
|
||||
} else if len(failures) > 0 {
|
||||
return resource.NewCheckResponse(resource.NewCheckError(failures)), nil
|
||||
}
|
||||
return resource.NewCheckResponse(nil), nil
|
||||
}
|
||||
|
||||
func (p *InternetGatewayProvider) Name(
|
||||
|
|
|
@ -49,14 +49,15 @@ func (p *RouteProvider) Check(
|
|||
ctx context.Context, req *lumirpc.CheckRequest) (*lumirpc.CheckResponse, error) {
|
||||
contract.Assert(req.GetType() == string(RouteToken))
|
||||
obj, _, err := p.Unmarshal(req.GetProperties())
|
||||
if err == nil {
|
||||
if failures, err := p.ops.Check(ctx, obj); err != nil {
|
||||
return nil, err
|
||||
} else if len(failures) > 0 {
|
||||
err = resource.NewCheckError(failures)
|
||||
}
|
||||
if err != nil {
|
||||
return resource.NewCheckResponse(err), nil
|
||||
}
|
||||
return resource.NewCheckResponse(err), nil
|
||||
if failures, err := p.ops.Check(ctx, obj); err != nil {
|
||||
return nil, err
|
||||
} else if len(failures) > 0 {
|
||||
return resource.NewCheckResponse(resource.NewCheckError(failures)), nil
|
||||
}
|
||||
return resource.NewCheckResponse(nil), nil
|
||||
}
|
||||
|
||||
func (p *RouteProvider) Name(
|
||||
|
|
|
@ -49,14 +49,15 @@ func (p *RouteTableProvider) Check(
|
|||
ctx context.Context, req *lumirpc.CheckRequest) (*lumirpc.CheckResponse, error) {
|
||||
contract.Assert(req.GetType() == string(RouteTableToken))
|
||||
obj, _, err := p.Unmarshal(req.GetProperties())
|
||||
if err == nil {
|
||||
if failures, err := p.ops.Check(ctx, obj); err != nil {
|
||||
return nil, err
|
||||
} else if len(failures) > 0 {
|
||||
err = resource.NewCheckError(failures)
|
||||
}
|
||||
if err != nil {
|
||||
return resource.NewCheckResponse(err), nil
|
||||
}
|
||||
return resource.NewCheckResponse(err), nil
|
||||
if failures, err := p.ops.Check(ctx, obj); err != nil {
|
||||
return nil, err
|
||||
} else if len(failures) > 0 {
|
||||
return resource.NewCheckResponse(resource.NewCheckError(failures)), nil
|
||||
}
|
||||
return resource.NewCheckResponse(nil), nil
|
||||
}
|
||||
|
||||
func (p *RouteTableProvider) Name(
|
||||
|
|
|
@ -49,14 +49,15 @@ func (p *SecurityGroupProvider) Check(
|
|||
ctx context.Context, req *lumirpc.CheckRequest) (*lumirpc.CheckResponse, error) {
|
||||
contract.Assert(req.GetType() == string(SecurityGroupToken))
|
||||
obj, _, err := p.Unmarshal(req.GetProperties())
|
||||
if err == nil {
|
||||
if failures, err := p.ops.Check(ctx, obj); err != nil {
|
||||
return nil, err
|
||||
} else if len(failures) > 0 {
|
||||
err = resource.NewCheckError(failures)
|
||||
}
|
||||
if err != nil {
|
||||
return resource.NewCheckResponse(err), nil
|
||||
}
|
||||
return resource.NewCheckResponse(err), nil
|
||||
if failures, err := p.ops.Check(ctx, obj); err != nil {
|
||||
return nil, err
|
||||
} else if len(failures) > 0 {
|
||||
return resource.NewCheckResponse(resource.NewCheckError(failures)), nil
|
||||
}
|
||||
return resource.NewCheckResponse(nil), nil
|
||||
}
|
||||
|
||||
func (p *SecurityGroupProvider) Name(
|
||||
|
|
|
@ -49,14 +49,15 @@ func (p *SecurityGroupEgressProvider) Check(
|
|||
ctx context.Context, req *lumirpc.CheckRequest) (*lumirpc.CheckResponse, error) {
|
||||
contract.Assert(req.GetType() == string(SecurityGroupEgressToken))
|
||||
obj, _, err := p.Unmarshal(req.GetProperties())
|
||||
if err == nil {
|
||||
if failures, err := p.ops.Check(ctx, obj); err != nil {
|
||||
return nil, err
|
||||
} else if len(failures) > 0 {
|
||||
err = resource.NewCheckError(failures)
|
||||
}
|
||||
if err != nil {
|
||||
return resource.NewCheckResponse(err), nil
|
||||
}
|
||||
return resource.NewCheckResponse(err), nil
|
||||
if failures, err := p.ops.Check(ctx, obj); err != nil {
|
||||
return nil, err
|
||||
} else if len(failures) > 0 {
|
||||
return resource.NewCheckResponse(resource.NewCheckError(failures)), nil
|
||||
}
|
||||
return resource.NewCheckResponse(nil), nil
|
||||
}
|
||||
|
||||
func (p *SecurityGroupEgressProvider) Name(
|
||||
|
|
|
@ -49,14 +49,15 @@ func (p *SecurityGroupIngressProvider) Check(
|
|||
ctx context.Context, req *lumirpc.CheckRequest) (*lumirpc.CheckResponse, error) {
|
||||
contract.Assert(req.GetType() == string(SecurityGroupIngressToken))
|
||||
obj, _, err := p.Unmarshal(req.GetProperties())
|
||||
if err == nil {
|
||||
if failures, err := p.ops.Check(ctx, obj); err != nil {
|
||||
return nil, err
|
||||
} else if len(failures) > 0 {
|
||||
err = resource.NewCheckError(failures)
|
||||
}
|
||||
if err != nil {
|
||||
return resource.NewCheckResponse(err), nil
|
||||
}
|
||||
return resource.NewCheckResponse(err), nil
|
||||
if failures, err := p.ops.Check(ctx, obj); err != nil {
|
||||
return nil, err
|
||||
} else if len(failures) > 0 {
|
||||
return resource.NewCheckResponse(resource.NewCheckError(failures)), nil
|
||||
}
|
||||
return resource.NewCheckResponse(nil), nil
|
||||
}
|
||||
|
||||
func (p *SecurityGroupIngressProvider) Name(
|
||||
|
|
|
@ -49,14 +49,15 @@ func (p *SubnetProvider) Check(
|
|||
ctx context.Context, req *lumirpc.CheckRequest) (*lumirpc.CheckResponse, error) {
|
||||
contract.Assert(req.GetType() == string(SubnetToken))
|
||||
obj, _, err := p.Unmarshal(req.GetProperties())
|
||||
if err == nil {
|
||||
if failures, err := p.ops.Check(ctx, obj); err != nil {
|
||||
return nil, err
|
||||
} else if len(failures) > 0 {
|
||||
err = resource.NewCheckError(failures)
|
||||
}
|
||||
if err != nil {
|
||||
return resource.NewCheckResponse(err), nil
|
||||
}
|
||||
return resource.NewCheckResponse(err), nil
|
||||
if failures, err := p.ops.Check(ctx, obj); err != nil {
|
||||
return nil, err
|
||||
} else if len(failures) > 0 {
|
||||
return resource.NewCheckResponse(resource.NewCheckError(failures)), nil
|
||||
}
|
||||
return resource.NewCheckResponse(nil), nil
|
||||
}
|
||||
|
||||
func (p *SubnetProvider) Name(
|
||||
|
|
|
@ -49,14 +49,15 @@ func (p *VPCProvider) Check(
|
|||
ctx context.Context, req *lumirpc.CheckRequest) (*lumirpc.CheckResponse, error) {
|
||||
contract.Assert(req.GetType() == string(VPCToken))
|
||||
obj, _, err := p.Unmarshal(req.GetProperties())
|
||||
if err == nil {
|
||||
if failures, err := p.ops.Check(ctx, obj); err != nil {
|
||||
return nil, err
|
||||
} else if len(failures) > 0 {
|
||||
err = resource.NewCheckError(failures)
|
||||
}
|
||||
if err != nil {
|
||||
return resource.NewCheckResponse(err), nil
|
||||
}
|
||||
return resource.NewCheckResponse(err), nil
|
||||
if failures, err := p.ops.Check(ctx, obj); err != nil {
|
||||
return nil, err
|
||||
} else if len(failures) > 0 {
|
||||
return resource.NewCheckResponse(resource.NewCheckError(failures)), nil
|
||||
}
|
||||
return resource.NewCheckResponse(nil), nil
|
||||
}
|
||||
|
||||
func (p *VPCProvider) Name(
|
||||
|
|
|
@ -49,14 +49,15 @@ func (p *VPCGatewayAttachmentProvider) Check(
|
|||
ctx context.Context, req *lumirpc.CheckRequest) (*lumirpc.CheckResponse, error) {
|
||||
contract.Assert(req.GetType() == string(VPCGatewayAttachmentToken))
|
||||
obj, _, err := p.Unmarshal(req.GetProperties())
|
||||
if err == nil {
|
||||
if failures, err := p.ops.Check(ctx, obj); err != nil {
|
||||
return nil, err
|
||||
} else if len(failures) > 0 {
|
||||
err = resource.NewCheckError(failures)
|
||||
}
|
||||
if err != nil {
|
||||
return resource.NewCheckResponse(err), nil
|
||||
}
|
||||
return resource.NewCheckResponse(err), nil
|
||||
if failures, err := p.ops.Check(ctx, obj); err != nil {
|
||||
return nil, err
|
||||
} else if len(failures) > 0 {
|
||||
return resource.NewCheckResponse(resource.NewCheckError(failures)), nil
|
||||
}
|
||||
return resource.NewCheckResponse(nil), nil
|
||||
}
|
||||
|
||||
func (p *VPCGatewayAttachmentProvider) Name(
|
||||
|
|
|
@ -49,14 +49,15 @@ func (p *VPCPeeringConnectionProvider) Check(
|
|||
ctx context.Context, req *lumirpc.CheckRequest) (*lumirpc.CheckResponse, error) {
|
||||
contract.Assert(req.GetType() == string(VPCPeeringConnectionToken))
|
||||
obj, _, err := p.Unmarshal(req.GetProperties())
|
||||
if err == nil {
|
||||
if failures, err := p.ops.Check(ctx, obj); err != nil {
|
||||
return nil, err
|
||||
} else if len(failures) > 0 {
|
||||
err = resource.NewCheckError(failures)
|
||||
}
|
||||
if err != nil {
|
||||
return resource.NewCheckResponse(err), nil
|
||||
}
|
||||
return resource.NewCheckResponse(err), nil
|
||||
if failures, err := p.ops.Check(ctx, obj); err != nil {
|
||||
return nil, err
|
||||
} else if len(failures) > 0 {
|
||||
return resource.NewCheckResponse(resource.NewCheckError(failures)), nil
|
||||
}
|
||||
return resource.NewCheckResponse(nil), nil
|
||||
}
|
||||
|
||||
func (p *VPCPeeringConnectionProvider) Name(
|
||||
|
|
|
@ -49,14 +49,15 @@ func (p *ApplicationProvider) Check(
|
|||
ctx context.Context, req *lumirpc.CheckRequest) (*lumirpc.CheckResponse, error) {
|
||||
contract.Assert(req.GetType() == string(ApplicationToken))
|
||||
obj, _, err := p.Unmarshal(req.GetProperties())
|
||||
if err == nil {
|
||||
if failures, err := p.ops.Check(ctx, obj); err != nil {
|
||||
return nil, err
|
||||
} else if len(failures) > 0 {
|
||||
err = resource.NewCheckError(failures)
|
||||
}
|
||||
if err != nil {
|
||||
return resource.NewCheckResponse(err), nil
|
||||
}
|
||||
return resource.NewCheckResponse(err), nil
|
||||
if failures, err := p.ops.Check(ctx, obj); err != nil {
|
||||
return nil, err
|
||||
} else if len(failures) > 0 {
|
||||
return resource.NewCheckResponse(resource.NewCheckError(failures)), nil
|
||||
}
|
||||
return resource.NewCheckResponse(nil), nil
|
||||
}
|
||||
|
||||
func (p *ApplicationProvider) Name(
|
||||
|
|
|
@ -49,14 +49,15 @@ func (p *ApplicationVersionProvider) Check(
|
|||
ctx context.Context, req *lumirpc.CheckRequest) (*lumirpc.CheckResponse, error) {
|
||||
contract.Assert(req.GetType() == string(ApplicationVersionToken))
|
||||
obj, _, err := p.Unmarshal(req.GetProperties())
|
||||
if err == nil {
|
||||
if failures, err := p.ops.Check(ctx, obj); err != nil {
|
||||
return nil, err
|
||||
} else if len(failures) > 0 {
|
||||
err = resource.NewCheckError(failures)
|
||||
}
|
||||
if err != nil {
|
||||
return resource.NewCheckResponse(err), nil
|
||||
}
|
||||
return resource.NewCheckResponse(err), nil
|
||||
if failures, err := p.ops.Check(ctx, obj); err != nil {
|
||||
return nil, err
|
||||
} else if len(failures) > 0 {
|
||||
return resource.NewCheckResponse(resource.NewCheckError(failures)), nil
|
||||
}
|
||||
return resource.NewCheckResponse(nil), nil
|
||||
}
|
||||
|
||||
func (p *ApplicationVersionProvider) Name(
|
||||
|
|
|
@ -49,14 +49,15 @@ func (p *EnvironmentProvider) Check(
|
|||
ctx context.Context, req *lumirpc.CheckRequest) (*lumirpc.CheckResponse, error) {
|
||||
contract.Assert(req.GetType() == string(EnvironmentToken))
|
||||
obj, _, err := p.Unmarshal(req.GetProperties())
|
||||
if err == nil {
|
||||
if failures, err := p.ops.Check(ctx, obj); err != nil {
|
||||
return nil, err
|
||||
} else if len(failures) > 0 {
|
||||
err = resource.NewCheckError(failures)
|
||||
}
|
||||
if err != nil {
|
||||
return resource.NewCheckResponse(err), nil
|
||||
}
|
||||
return resource.NewCheckResponse(err), nil
|
||||
if failures, err := p.ops.Check(ctx, obj); err != nil {
|
||||
return nil, err
|
||||
} else if len(failures) > 0 {
|
||||
return resource.NewCheckResponse(resource.NewCheckError(failures)), nil
|
||||
}
|
||||
return resource.NewCheckResponse(nil), nil
|
||||
}
|
||||
|
||||
func (p *EnvironmentProvider) Name(
|
||||
|
|
|
@ -49,14 +49,15 @@ func (p *GroupProvider) Check(
|
|||
ctx context.Context, req *lumirpc.CheckRequest) (*lumirpc.CheckResponse, error) {
|
||||
contract.Assert(req.GetType() == string(GroupToken))
|
||||
obj, _, err := p.Unmarshal(req.GetProperties())
|
||||
if err == nil {
|
||||
if failures, err := p.ops.Check(ctx, obj); err != nil {
|
||||
return nil, err
|
||||
} else if len(failures) > 0 {
|
||||
err = resource.NewCheckError(failures)
|
||||
}
|
||||
if err != nil {
|
||||
return resource.NewCheckResponse(err), nil
|
||||
}
|
||||
return resource.NewCheckResponse(err), nil
|
||||
if failures, err := p.ops.Check(ctx, obj); err != nil {
|
||||
return nil, err
|
||||
} else if len(failures) > 0 {
|
||||
return resource.NewCheckResponse(resource.NewCheckError(failures)), nil
|
||||
}
|
||||
return resource.NewCheckResponse(nil), nil
|
||||
}
|
||||
|
||||
func (p *GroupProvider) Name(
|
||||
|
|
|
@ -63,14 +63,15 @@ func (p *PolicyProvider) Check(
|
|||
ctx context.Context, req *lumirpc.CheckRequest) (*lumirpc.CheckResponse, error) {
|
||||
contract.Assert(req.GetType() == string(PolicyToken))
|
||||
obj, _, err := p.Unmarshal(req.GetProperties())
|
||||
if err == nil {
|
||||
if failures, err := p.ops.Check(ctx, obj); err != nil {
|
||||
return nil, err
|
||||
} else if len(failures) > 0 {
|
||||
err = resource.NewCheckError(failures)
|
||||
}
|
||||
if err != nil {
|
||||
return resource.NewCheckResponse(err), nil
|
||||
}
|
||||
return resource.NewCheckResponse(err), nil
|
||||
if failures, err := p.ops.Check(ctx, obj); err != nil {
|
||||
return nil, err
|
||||
} else if len(failures) > 0 {
|
||||
return resource.NewCheckResponse(resource.NewCheckError(failures)), nil
|
||||
}
|
||||
return resource.NewCheckResponse(nil), nil
|
||||
}
|
||||
|
||||
func (p *PolicyProvider) Name(
|
||||
|
|
|
@ -51,14 +51,15 @@ func (p *RoleProvider) Check(
|
|||
ctx context.Context, req *lumirpc.CheckRequest) (*lumirpc.CheckResponse, error) {
|
||||
contract.Assert(req.GetType() == string(RoleToken))
|
||||
obj, _, err := p.Unmarshal(req.GetProperties())
|
||||
if err == nil {
|
||||
if failures, err := p.ops.Check(ctx, obj); err != nil {
|
||||
return nil, err
|
||||
} else if len(failures) > 0 {
|
||||
err = resource.NewCheckError(failures)
|
||||
}
|
||||
if err != nil {
|
||||
return resource.NewCheckResponse(err), nil
|
||||
}
|
||||
return resource.NewCheckResponse(err), nil
|
||||
if failures, err := p.ops.Check(ctx, obj); err != nil {
|
||||
return nil, err
|
||||
} else if len(failures) > 0 {
|
||||
return resource.NewCheckResponse(resource.NewCheckError(failures)), nil
|
||||
}
|
||||
return resource.NewCheckResponse(nil), nil
|
||||
}
|
||||
|
||||
func (p *RoleProvider) Name(
|
||||
|
|
|
@ -63,14 +63,15 @@ func (p *UserProvider) Check(
|
|||
ctx context.Context, req *lumirpc.CheckRequest) (*lumirpc.CheckResponse, error) {
|
||||
contract.Assert(req.GetType() == string(UserToken))
|
||||
obj, _, err := p.Unmarshal(req.GetProperties())
|
||||
if err == nil {
|
||||
if failures, err := p.ops.Check(ctx, obj); err != nil {
|
||||
return nil, err
|
||||
} else if len(failures) > 0 {
|
||||
err = resource.NewCheckError(failures)
|
||||
}
|
||||
if err != nil {
|
||||
return resource.NewCheckResponse(err), nil
|
||||
}
|
||||
return resource.NewCheckResponse(err), nil
|
||||
if failures, err := p.ops.Check(ctx, obj); err != nil {
|
||||
return nil, err
|
||||
} else if len(failures) > 0 {
|
||||
return resource.NewCheckResponse(resource.NewCheckError(failures)), nil
|
||||
}
|
||||
return resource.NewCheckResponse(nil), nil
|
||||
}
|
||||
|
||||
func (p *UserProvider) Name(
|
||||
|
|
|
@ -49,14 +49,15 @@ func (p *KeyProvider) Check(
|
|||
ctx context.Context, req *lumirpc.CheckRequest) (*lumirpc.CheckResponse, error) {
|
||||
contract.Assert(req.GetType() == string(KeyToken))
|
||||
obj, _, err := p.Unmarshal(req.GetProperties())
|
||||
if err == nil {
|
||||
if failures, err := p.ops.Check(ctx, obj); err != nil {
|
||||
return nil, err
|
||||
} else if len(failures) > 0 {
|
||||
err = resource.NewCheckError(failures)
|
||||
}
|
||||
if err != nil {
|
||||
return resource.NewCheckResponse(err), nil
|
||||
}
|
||||
return resource.NewCheckResponse(err), nil
|
||||
if failures, err := p.ops.Check(ctx, obj); err != nil {
|
||||
return nil, err
|
||||
} else if len(failures) > 0 {
|
||||
return resource.NewCheckResponse(resource.NewCheckError(failures)), nil
|
||||
}
|
||||
return resource.NewCheckResponse(nil), nil
|
||||
}
|
||||
|
||||
func (p *KeyProvider) Name(
|
||||
|
|
|
@ -63,14 +63,15 @@ func (p *FunctionProvider) Check(
|
|||
ctx context.Context, req *lumirpc.CheckRequest) (*lumirpc.CheckResponse, error) {
|
||||
contract.Assert(req.GetType() == string(FunctionToken))
|
||||
obj, _, err := p.Unmarshal(req.GetProperties())
|
||||
if err == nil {
|
||||
if failures, err := p.ops.Check(ctx, obj); err != nil {
|
||||
return nil, err
|
||||
} else if len(failures) > 0 {
|
||||
err = resource.NewCheckError(failures)
|
||||
}
|
||||
if err != nil {
|
||||
return resource.NewCheckResponse(err), nil
|
||||
}
|
||||
return resource.NewCheckResponse(err), nil
|
||||
if failures, err := p.ops.Check(ctx, obj); err != nil {
|
||||
return nil, err
|
||||
} else if len(failures) > 0 {
|
||||
return resource.NewCheckResponse(resource.NewCheckError(failures)), nil
|
||||
}
|
||||
return resource.NewCheckResponse(nil), nil
|
||||
}
|
||||
|
||||
func (p *FunctionProvider) Name(
|
||||
|
|
|
@ -51,14 +51,15 @@ func (p *PermissionProvider) Check(
|
|||
ctx context.Context, req *lumirpc.CheckRequest) (*lumirpc.CheckResponse, error) {
|
||||
contract.Assert(req.GetType() == string(PermissionToken))
|
||||
obj, _, err := p.Unmarshal(req.GetProperties())
|
||||
if err == nil {
|
||||
if failures, err := p.ops.Check(ctx, obj); err != nil {
|
||||
return nil, err
|
||||
} else if len(failures) > 0 {
|
||||
err = resource.NewCheckError(failures)
|
||||
}
|
||||
if err != nil {
|
||||
return resource.NewCheckResponse(err), nil
|
||||
}
|
||||
return resource.NewCheckResponse(err), nil
|
||||
if failures, err := p.ops.Check(ctx, obj); err != nil {
|
||||
return nil, err
|
||||
} else if len(failures) > 0 {
|
||||
return resource.NewCheckResponse(resource.NewCheckError(failures)), nil
|
||||
}
|
||||
return resource.NewCheckResponse(nil), nil
|
||||
}
|
||||
|
||||
func (p *PermissionProvider) Name(
|
||||
|
|
|
@ -49,14 +49,15 @@ func (p *BucketProvider) Check(
|
|||
ctx context.Context, req *lumirpc.CheckRequest) (*lumirpc.CheckResponse, error) {
|
||||
contract.Assert(req.GetType() == string(BucketToken))
|
||||
obj, _, err := p.Unmarshal(req.GetProperties())
|
||||
if err == nil {
|
||||
if failures, err := p.ops.Check(ctx, obj); err != nil {
|
||||
return nil, err
|
||||
} else if len(failures) > 0 {
|
||||
err = resource.NewCheckError(failures)
|
||||
}
|
||||
if err != nil {
|
||||
return resource.NewCheckResponse(err), nil
|
||||
}
|
||||
return resource.NewCheckResponse(err), nil
|
||||
if failures, err := p.ops.Check(ctx, obj); err != nil {
|
||||
return nil, err
|
||||
} else if len(failures) > 0 {
|
||||
return resource.NewCheckResponse(resource.NewCheckError(failures)), nil
|
||||
}
|
||||
return resource.NewCheckResponse(nil), nil
|
||||
}
|
||||
|
||||
func (p *BucketProvider) Name(
|
||||
|
|
|
@ -48,14 +48,15 @@ func (p *ObjectProvider) Check(
|
|||
ctx context.Context, req *lumirpc.CheckRequest) (*lumirpc.CheckResponse, error) {
|
||||
contract.Assert(req.GetType() == string(ObjectToken))
|
||||
obj, _, err := p.Unmarshal(req.GetProperties())
|
||||
if err == nil {
|
||||
if failures, err := p.ops.Check(ctx, obj); err != nil {
|
||||
return nil, err
|
||||
} else if len(failures) > 0 {
|
||||
err = resource.NewCheckError(failures)
|
||||
}
|
||||
if err != nil {
|
||||
return resource.NewCheckResponse(err), nil
|
||||
}
|
||||
return resource.NewCheckResponse(err), nil
|
||||
if failures, err := p.ops.Check(ctx, obj); err != nil {
|
||||
return nil, err
|
||||
} else if len(failures) > 0 {
|
||||
return resource.NewCheckResponse(resource.NewCheckError(failures)), nil
|
||||
}
|
||||
return resource.NewCheckResponse(nil), nil
|
||||
}
|
||||
|
||||
func (p *ObjectProvider) Name(
|
||||
|
|
|
@ -49,14 +49,15 @@ func (p *TopicProvider) Check(
|
|||
ctx context.Context, req *lumirpc.CheckRequest) (*lumirpc.CheckResponse, error) {
|
||||
contract.Assert(req.GetType() == string(TopicToken))
|
||||
obj, _, err := p.Unmarshal(req.GetProperties())
|
||||
if err == nil {
|
||||
if failures, err := p.ops.Check(ctx, obj); err != nil {
|
||||
return nil, err
|
||||
} else if len(failures) > 0 {
|
||||
err = resource.NewCheckError(failures)
|
||||
}
|
||||
if err != nil {
|
||||
return resource.NewCheckResponse(err), nil
|
||||
}
|
||||
return resource.NewCheckResponse(err), nil
|
||||
if failures, err := p.ops.Check(ctx, obj); err != nil {
|
||||
return nil, err
|
||||
} else if len(failures) > 0 {
|
||||
return resource.NewCheckResponse(resource.NewCheckError(failures)), nil
|
||||
}
|
||||
return resource.NewCheckResponse(nil), nil
|
||||
}
|
||||
|
||||
func (p *TopicProvider) Name(
|
||||
|
|
|
@ -49,14 +49,15 @@ func (p *QueueProvider) Check(
|
|||
ctx context.Context, req *lumirpc.CheckRequest) (*lumirpc.CheckResponse, error) {
|
||||
contract.Assert(req.GetType() == string(QueueToken))
|
||||
obj, _, err := p.Unmarshal(req.GetProperties())
|
||||
if err == nil {
|
||||
if failures, err := p.ops.Check(ctx, obj); err != nil {
|
||||
return nil, err
|
||||
} else if len(failures) > 0 {
|
||||
err = resource.NewCheckError(failures)
|
||||
}
|
||||
if err != nil {
|
||||
return resource.NewCheckResponse(err), nil
|
||||
}
|
||||
return resource.NewCheckResponse(err), nil
|
||||
if failures, err := p.ops.Check(ctx, obj); err != nil {
|
||||
return nil, err
|
||||
} else if len(failures) > 0 {
|
||||
return resource.NewCheckResponse(resource.NewCheckError(failures)), nil
|
||||
}
|
||||
return resource.NewCheckResponse(nil), nil
|
||||
}
|
||||
|
||||
func (p *QueueProvider) Name(
|
||||
|
|
|
@ -1,3 +1,5 @@
|
|||
name: lumijs
|
||||
description: The LumiJS runtime library.
|
||||
dependencies:
|
||||
lumi: "*"
|
||||
|
||||
|
|
25
lib/lumijs/lib/console.ts
Normal file
25
lib/lumijs/lib/console.ts
Normal file
|
@ -0,0 +1,25 @@
|
|||
// Licensed to Pulumi Corporation ("Pulumi") under one or more
|
||||
// contributor license agreements. See the NOTICE file distributed with
|
||||
// this work for additional information regarding copyright ownership.
|
||||
// Pulumi licenses this file to You under the Apache License, Version 2.0
|
||||
// (the "License"); you may not use this file except in compliance with
|
||||
// the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
import { printf } from "@lumi/lumi/runtime"
|
||||
|
||||
export class Console {
|
||||
log(message: any) {
|
||||
printf(message);
|
||||
printf("\n");
|
||||
}
|
||||
}
|
||||
|
||||
export let console = new Console();
|
|
@ -17,4 +17,5 @@
|
|||
|
||||
export * from "./errors";
|
||||
export * from "./types";
|
||||
export * from "./console";
|
||||
|
||||
|
|
|
@ -111,7 +111,6 @@ export class API {
|
|||
let restAPI = new aws.apigateway.RestAPI(prefix, { body: body });
|
||||
let deployment = new aws.apigateway.Deployment(prefix + "-deployment", {
|
||||
restAPI: restAPI,
|
||||
stageName: "Stage",
|
||||
});
|
||||
let stage = new aws.apigateway.Stage(prefix + "-primary-stage", {
|
||||
deployment: deployment,
|
||||
|
|
107
pkg/compiler/binder/freevars.go
Normal file
107
pkg/compiler/binder/freevars.go
Normal file
|
@ -0,0 +1,107 @@
|
|||
// Licensed to Pulumi Corporation ("Pulumi") under one or more
|
||||
// contributor license agreements. See the NOTICE file distributed with
|
||||
// this work for additional information regarding copyright ownership.
|
||||
// Pulumi licenses this file to You under the Apache License, Version 2.0
|
||||
// (the "License"); you may not use this file except in compliance with
|
||||
// the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package binder
|
||||
|
||||
import (
|
||||
"github.com/pulumi/lumi/pkg/compiler/ast"
|
||||
"github.com/pulumi/lumi/pkg/tokens"
|
||||
"github.com/pulumi/lumi/pkg/util/contract"
|
||||
)
|
||||
|
||||
// FreeVars computes the free variables referenced inside a function body.
|
||||
// The free variables for a function will be either simple identifier tokens or tokens
|
||||
// referencing module-scope variables.
|
||||
func FreeVars(fnc ast.Function) []tokens.Token {
|
||||
visitor := &freeVarsVisitor{
|
||||
freeVars: map[tokens.Token]bool{},
|
||||
}
|
||||
|
||||
ast.Walk(visitor, fnc)
|
||||
|
||||
params := fnc.GetParameters()
|
||||
if params != nil {
|
||||
for _, lv := range *params {
|
||||
visitor.removeLocalVariable(lv)
|
||||
}
|
||||
}
|
||||
|
||||
var vars []tokens.Token
|
||||
for k := range visitor.freeVars {
|
||||
vars = append(vars, k)
|
||||
}
|
||||
return vars
|
||||
}
|
||||
|
||||
type freeVarsVisitor struct {
|
||||
freeVars map[tokens.Token]bool
|
||||
}
|
||||
|
||||
var _ ast.Visitor = (*freeVarsVisitor)(nil)
|
||||
|
||||
func (visitor *freeVarsVisitor) Visit(node ast.Node) ast.Visitor {
|
||||
return visitor
|
||||
}
|
||||
|
||||
// We walk the AST and process each node after visiting it in depth first order. There are two cases we care about:
|
||||
// 1) After visiting a leaf node which is a reference to a local variable (`n.Object == nil``), we add it to our set.
|
||||
// 2) After visiting a LocalVariableDeclaration or a Lambda, we remove the declared variables from our set.
|
||||
func (visitor *freeVarsVisitor) After(node ast.Node) {
|
||||
switch n := node.(type) {
|
||||
case *ast.LoadLocationExpression:
|
||||
if n.Object == nil {
|
||||
visitor.addToken(n.Name.Tok)
|
||||
}
|
||||
case *ast.LoadDynamicExpression:
|
||||
if n.Object == nil {
|
||||
switch e := n.Name.(type) {
|
||||
case *ast.StringLiteral:
|
||||
visitor.addToken(tokens.Token(e.Value))
|
||||
default:
|
||||
contract.Failf("expected LoadDynamicExpression with Object == nil to have a StringLiteral expression")
|
||||
}
|
||||
}
|
||||
case *ast.TryLoadDynamicExpression:
|
||||
if n.Object == nil {
|
||||
switch e := n.Name.(type) {
|
||||
case *ast.StringLiteral:
|
||||
visitor.addToken(tokens.Token(e.Value))
|
||||
default:
|
||||
contract.Failf("expected LoadDynamicExpression with Object == nil to have a StringLiteral expression")
|
||||
}
|
||||
}
|
||||
case *ast.LambdaExpression:
|
||||
if n.Parameters != nil {
|
||||
for _, param := range *n.Parameters {
|
||||
visitor.removeLocalVariable(param)
|
||||
}
|
||||
}
|
||||
case *ast.Block:
|
||||
for _, stmt := range n.Statements {
|
||||
switch s := stmt.(type) {
|
||||
case *ast.LocalVariableDeclaration:
|
||||
visitor.removeLocalVariable(s.Local)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (visitor *freeVarsVisitor) addToken(tok tokens.Token) {
|
||||
visitor.freeVars[tok] = true
|
||||
}
|
||||
|
||||
func (visitor *freeVarsVisitor) removeLocalVariable(lv *ast.LocalVariable) {
|
||||
delete(visitor.freeVars, tokens.Token(lv.Name.Ident))
|
||||
}
|
192
pkg/compiler/binder/freevars_test.go
Normal file
192
pkg/compiler/binder/freevars_test.go
Normal file
|
@ -0,0 +1,192 @@
|
|||
// Licensed to Pulumi Corporation ("Pulumi") under one or more
|
||||
// contributor license agreements. See the NOTICE file distributed with
|
||||
// this work for additional information regarding copyright ownership.
|
||||
// Pulumi licenses this file to You under the Apache License, Version 2.0
|
||||
// (the "License"); you may not use this file except in compliance with
|
||||
// the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package binder
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/pulumi/lumi/pkg/compiler/ast"
|
||||
"github.com/pulumi/lumi/pkg/compiler/types"
|
||||
"github.com/pulumi/lumi/pkg/tokens"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func makeLocalVariable(name string) *ast.LocalVariable {
|
||||
return &ast.LocalVariable{
|
||||
DefinitionNode: ast.DefinitionNode{
|
||||
Name: &ast.Identifier{
|
||||
Ident: tokens.Name(name),
|
||||
},
|
||||
},
|
||||
VariableNode: ast.VariableNode{
|
||||
Type: &ast.TypeToken{
|
||||
Tok: types.Object.TypeToken(),
|
||||
},
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func expressionRef(expr ast.Expression) *ast.Expression {
|
||||
return &expr
|
||||
}
|
||||
|
||||
func TestFreeVars_Parameter(t *testing.T) {
|
||||
// function(foo) foo
|
||||
fun := ast.ModuleMethod{
|
||||
FunctionNode: ast.FunctionNode{
|
||||
Parameters: &[]*ast.LocalVariable{
|
||||
makeLocalVariable("foo"),
|
||||
},
|
||||
Body: &ast.ExpressionStatement{
|
||||
Expression: &ast.LoadLocationExpression{
|
||||
Name: &ast.Token{
|
||||
Tok: tokens.Token("foo"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
freeVars := FreeVars(&fun)
|
||||
assert.Len(t, freeVars, 0, "expected no free variables")
|
||||
}
|
||||
|
||||
func TestFreeVars_Dynamic(t *testing.T) {
|
||||
// function(foo) foo
|
||||
fun := ast.ModuleMethod{
|
||||
FunctionNode: ast.FunctionNode{
|
||||
Parameters: &[]*ast.LocalVariable{},
|
||||
Body: &ast.ExpressionStatement{
|
||||
Expression: &ast.LoadDynamicExpression{
|
||||
Name: &ast.StringLiteral{
|
||||
Value: "foo",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
freeVars := FreeVars(&fun)
|
||||
assert.Len(t, freeVars, 1, "expected one free variable")
|
||||
assert.Equal(t, tokens.Name("foo"), freeVars[0].Name())
|
||||
}
|
||||
|
||||
func TestFreeVars_LocalVariable(t *testing.T) {
|
||||
// function(foo) { var bar; foo; bar; baz; }
|
||||
fun := ast.ModuleMethod{
|
||||
FunctionNode: ast.FunctionNode{
|
||||
Parameters: &[]*ast.LocalVariable{
|
||||
makeLocalVariable("foo"),
|
||||
},
|
||||
Body: &ast.Block{
|
||||
Statements: []ast.Statement{
|
||||
&ast.LocalVariableDeclaration{
|
||||
Local: makeLocalVariable("bar"),
|
||||
},
|
||||
&ast.ExpressionStatement{
|
||||
Expression: &ast.LoadLocationExpression{
|
||||
Name: &ast.Token{
|
||||
Tok: tokens.Token("foo"),
|
||||
},
|
||||
},
|
||||
},
|
||||
&ast.ExpressionStatement{
|
||||
Expression: &ast.LoadLocationExpression{
|
||||
Name: &ast.Token{
|
||||
Tok: tokens.Token("bar"),
|
||||
},
|
||||
},
|
||||
},
|
||||
&ast.ExpressionStatement{
|
||||
Expression: &ast.TryLoadDynamicExpression{
|
||||
Name: &ast.StringLiteral{
|
||||
Value: "baz",
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
freeVars := FreeVars(&fun)
|
||||
assert.Len(t, freeVars, 1, "expected one free variable")
|
||||
assert.Equal(t, tokens.Name("baz"), freeVars[0].Name())
|
||||
}
|
||||
|
||||
func TestFreeVars_Member(t *testing.T) {
|
||||
// function(foo) foo.bar
|
||||
fun := ast.ModuleMethod{
|
||||
FunctionNode: ast.FunctionNode{
|
||||
Parameters: &[]*ast.LocalVariable{
|
||||
makeLocalVariable("foo"),
|
||||
},
|
||||
Body: &ast.ExpressionStatement{
|
||||
Expression: &ast.LoadLocationExpression{
|
||||
Object: expressionRef(&ast.LoadLocationExpression{
|
||||
Name: &ast.Token{
|
||||
Tok: tokens.Token("foo"),
|
||||
},
|
||||
}),
|
||||
Name: &ast.Token{
|
||||
Tok: tokens.Token("bar"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
freeVars := FreeVars(&fun)
|
||||
assert.Len(t, freeVars, 0, "expected no free variables")
|
||||
}
|
||||
|
||||
func TestFreeVars_Lambda(t *testing.T) {
|
||||
// function(foo) ((bar) => bar)(foo)
|
||||
fun := ast.ModuleMethod{
|
||||
FunctionNode: ast.FunctionNode{
|
||||
Parameters: &[]*ast.LocalVariable{
|
||||
makeLocalVariable("foo"),
|
||||
},
|
||||
Body: &ast.ExpressionStatement{
|
||||
Expression: &ast.InvokeFunctionExpression{
|
||||
Function: &ast.LambdaExpression{
|
||||
FunctionNode: ast.FunctionNode{
|
||||
Parameters: &[]*ast.LocalVariable{
|
||||
makeLocalVariable("bar"),
|
||||
},
|
||||
Body: &ast.ExpressionStatement{
|
||||
Expression: &ast.LoadLocationExpression{
|
||||
Name: &ast.Token{
|
||||
Tok: tokens.Token("bar"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
CallExpressionNode: ast.CallExpressionNode{
|
||||
Arguments: &[]*ast.CallArgument{
|
||||
&ast.CallArgument{
|
||||
Expr: &ast.LoadLocationExpression{
|
||||
Name: &ast.Token{
|
||||
Tok: tokens.Token("foo"),
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
},
|
||||
}
|
||||
freeVars := FreeVars(&fun)
|
||||
assert.Len(t, freeVars, 0, "expected no free variables")
|
||||
}
|
|
@ -1730,22 +1730,23 @@ func (e *evaluator) evalLoadDynamicCore(node ast.Node, objexpr *ast.Expression,
|
|||
}, nil
|
||||
}
|
||||
|
||||
func (e *evaluator) getDynamicNameAddr(key tokens.Name, lval bool) *rt.Pointer {
|
||||
var pv *rt.Pointer
|
||||
|
||||
// If there's no object, look in the current localsment.
|
||||
pkey := rt.PropertyKey(key)
|
||||
globals := e.getModuleGlobals(e.ctx.Currmodule)
|
||||
if loc := e.locals.Lookup(key); loc != nil {
|
||||
pv = e.locals.GetValueAddr(loc, true) // create a slot, we know the declaration exists.
|
||||
} else {
|
||||
// If it didn't exist in the lexical scope, check the module's globals.
|
||||
pv = globals.Properties().GetAddr(pkey) // look for a global by this name, but don't allocate one.
|
||||
func getDynamicNameAddrCore(locals rt.Environment, globals *rt.Object, key tokens.Name) *rt.Pointer {
|
||||
if loc := locals.Lookup(key); loc != nil {
|
||||
return locals.GetValueAddr(loc, true) // create a slot, we know the declaration exists.
|
||||
}
|
||||
// If it didn't exist in the lexical scope, check the module's globals.
|
||||
pkey := rt.PropertyKey(key)
|
||||
return globals.Properties().GetAddr(pkey) // look for a global by this name, but don't allocate one.
|
||||
}
|
||||
|
||||
// Finally, if neither of those existed, and this is the target of a load, allocate a slot.
|
||||
func (e *evaluator) getDynamicNameAddr(key tokens.Name, lval bool) *rt.Pointer {
|
||||
globals := e.getModuleGlobals(e.ctx.Currmodule)
|
||||
pv := getDynamicNameAddrCore(e.locals, globals, key)
|
||||
|
||||
// If not found and this is the target of a load, allocate a slot.
|
||||
if pv == nil && lval {
|
||||
if e.fnc != nil && e.fnc.SpecialModInit() && e.locals.Activation() {
|
||||
pkey := rt.PropertyKey(key)
|
||||
pv = globals.Properties().GetInitAddr(pkey)
|
||||
} else {
|
||||
loc := symbols.NewSpecialVariableSym(key, types.Dynamic)
|
||||
|
@ -1870,7 +1871,8 @@ func (e *evaluator) evalLambdaExpression(node *ast.LambdaExpression) (*rt.Object
|
|||
// To create a lambda object we will simply produce a function object that can invoke it. Lambdas also uniquely
|
||||
// capture the current environment, including the this variable.
|
||||
sig := e.ctx.RequireType(node).(*symbols.FunctionType)
|
||||
obj := rt.NewFunctionObjectFromLambda(node, sig, e.locals)
|
||||
moduleObject := e.getModuleGlobals(e.ctx.Currmodule)
|
||||
obj := rt.NewFunctionObjectFromLambda(node, sig, e.locals, moduleObject)
|
||||
return obj, nil
|
||||
}
|
||||
|
||||
|
|
|
@ -19,14 +19,15 @@ import (
|
|||
"crypto/sha1"
|
||||
"encoding/hex"
|
||||
"fmt"
|
||||
"sort"
|
||||
"strconv"
|
||||
"strings"
|
||||
|
||||
"github.com/pulumi/lumi/pkg/compiler/ast"
|
||||
"github.com/pulumi/lumi/pkg/compiler/binder"
|
||||
"github.com/pulumi/lumi/pkg/compiler/symbols"
|
||||
"github.com/pulumi/lumi/pkg/compiler/types"
|
||||
"github.com/pulumi/lumi/pkg/eval/rt"
|
||||
"github.com/pulumi/lumi/pkg/tokens"
|
||||
"github.com/pulumi/lumi/pkg/util/contract"
|
||||
)
|
||||
|
||||
|
@ -108,21 +109,24 @@ func serializeClosure(intrin *rt.Intrinsic, e *evaluator, this *rt.Object, args
|
|||
return e.NewException(intrin.Tree(), "Expected argument 'func' to be a lambda expression.")
|
||||
}
|
||||
|
||||
// TODO[pulumi/lumi#177]: We are using the full environment available at execution time here, we should
|
||||
// instead capture only the free variables referenced in the function itself.
|
||||
|
||||
// Insert environment variables into a PropertyMap with stable ordering
|
||||
envPropMap := rt.NewPropertyMap()
|
||||
slots := stub.Env.Slots()
|
||||
var keys []*symbols.LocalVariable
|
||||
for key := range slots {
|
||||
keys = append(keys, key)
|
||||
}
|
||||
sort.SliceStable(keys, func(i, j int) bool {
|
||||
return keys[i].Name() < keys[j].Name()
|
||||
})
|
||||
for _, key := range keys {
|
||||
envPropMap.Set(rt.PropertyKey(key.Name()), slots[key].Obj())
|
||||
for _, tok := range binder.FreeVars(stub.Func) {
|
||||
var name tokens.Name
|
||||
contract.Assertf(tok.Simple() || (tok.HasModule() && tok.HasModuleMember() && !tok.HasClassMember()),
|
||||
"Expected free variable to be simple name or reference to top-level module name")
|
||||
if tok.Simple() {
|
||||
name = tok.Name()
|
||||
} else {
|
||||
name = tokens.Name(tok.ModuleMember().Name())
|
||||
}
|
||||
pv := getDynamicNameAddrCore(stub.Env, stub.Module, name)
|
||||
if pv != nil {
|
||||
envPropMap.Set(rt.PropertyKey(name), pv.Obj())
|
||||
}
|
||||
// Else the variable was not found, so we skip serializing it.
|
||||
// This will be true for references to globals which are not known to Lumi but
|
||||
// will be available within the runtime environment.
|
||||
}
|
||||
envObj := e.alloc.New(intrin.Tree(), types.Dynamic, envPropMap, nil)
|
||||
|
||||
|
|
|
@ -404,7 +404,6 @@ func NewNullObject() *Object {
|
|||
|
||||
// NewStringObject creates a new primitive number object.
|
||||
func NewStringObject(v string) *Object {
|
||||
|
||||
// Add a `length` property to the object
|
||||
arrayProps := NewPropertyMap()
|
||||
lengthGetter := NewBuiltinIntrinsic(
|
||||
|
@ -413,9 +412,7 @@ func NewStringObject(v string) *Object {
|
|||
)
|
||||
arrayProps.InitAddr(PropertyKey("length"), nil, true, lengthGetter, nil)
|
||||
|
||||
stringProto := StringPrototypeObject()
|
||||
|
||||
return NewObject(types.String, v, arrayProps, stringProto)
|
||||
return NewObject(types.String, v, arrayProps, StringPrototypeObject())
|
||||
}
|
||||
|
||||
// stringProto is a cached reference to the String prototype object
|
||||
|
@ -455,21 +452,23 @@ func NewFunctionObjectFromSymbol(fnc symbols.Function, this *Object) *Object {
|
|||
}
|
||||
|
||||
// NewFunctionObjectFromLambda creates a new function object with very specific underlying parts.
|
||||
func NewFunctionObjectFromLambda(fnc ast.Function, sig *symbols.FunctionType, env Environment) *Object {
|
||||
func NewFunctionObjectFromLambda(fnc ast.Function, sig *symbols.FunctionType, env Environment, module *Object) *Object {
|
||||
return NewFunctionObject(FuncStub{
|
||||
Func: fnc,
|
||||
Sig: sig,
|
||||
Env: env,
|
||||
Func: fnc,
|
||||
Sig: sig,
|
||||
Env: env,
|
||||
Module: module,
|
||||
})
|
||||
}
|
||||
|
||||
// FuncStub is a stub that captures a symbol plus an optional instance 'this' object.
|
||||
type FuncStub struct {
|
||||
Func ast.Function // the function whose body AST to evaluate.
|
||||
Sym symbols.Function // an optional function symbol that this AST belongs to.
|
||||
Sig *symbols.FunctionType // the function type representing this function's signature.
|
||||
This *Object // an optional "this" pointer to bind when invoking this function.
|
||||
Env Environment // an optional environment to evaluate this function inside.
|
||||
Func ast.Function // the function whose body AST to evaluate.
|
||||
Sym symbols.Function // an optional function symbol that this AST belongs to.
|
||||
Sig *symbols.FunctionType // the function type representing this function's signature.
|
||||
This *Object // an optional "this" pointer to bind when invoking this function.
|
||||
Env Environment // an optional environment to evaluate this function inside.
|
||||
Module *Object // an optional module object to use for module variable lookups inside this function.
|
||||
}
|
||||
|
||||
// NewPointerObject allocates a new pointer-like object that wraps the given reference.
|
||||
|
@ -638,18 +637,33 @@ func (o *Object) PropertyValues() *PropertyMap {
|
|||
func adjustPointerForThis(parent *Object, this *Object, prop *Pointer) *Pointer {
|
||||
if parent != this {
|
||||
if value := prop.Obj(); value != nil {
|
||||
if _, isfunc := value.Type().(*symbols.FunctionType); isfunc {
|
||||
contract.Assert(prop.Readonly()) // otherwise, writes to the resulting pointer could go missing.
|
||||
switch vt := value.Type().(type) {
|
||||
case *symbols.FunctionType:
|
||||
// Function stubs must be adjusted so that `this` is correct.
|
||||
stub := value.FunctionValue()
|
||||
contract.Assert(stub.This == parent)
|
||||
value = NewFunctionObject(FuncStub{
|
||||
Func: stub.Func,
|
||||
Sym: stub.Sym,
|
||||
Sig: stub.Sig,
|
||||
This: this,
|
||||
Env: stub.Env,
|
||||
Func: stub.Func,
|
||||
Sym: stub.Sym,
|
||||
Sig: stub.Sig,
|
||||
This: this,
|
||||
Env: stub.Env,
|
||||
Module: stub.Module,
|
||||
})
|
||||
prop = NewPointer(value, true, prop.Getter(), prop.Setter())
|
||||
prop = NewPointer(value, prop.Readonly(), prop.Getter(), prop.Setter())
|
||||
case *symbols.ComputedType:
|
||||
// Computed stubs must be adjusted so that any self-references are correct.
|
||||
stub := value.ComputedValue()
|
||||
var sources []*Object
|
||||
for _, source := range stub.Sources {
|
||||
if source == parent {
|
||||
sources = append(sources, this)
|
||||
} else {
|
||||
sources = append(sources, source)
|
||||
}
|
||||
}
|
||||
value = NewComputedObject(vt.Element, stub.Expr, sources)
|
||||
prop = NewPointer(value, prop.Readonly(), prop.Getter(), prop.Setter())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -673,7 +687,7 @@ func (intrin *Intrinsic) SpecialModInit() bool { return false }
|
|||
func (intrin *Intrinsic) Tree() diag.Diagable { return intrin.node }
|
||||
func (intrin *Intrinsic) Function() ast.Function { return intrin.node }
|
||||
func (intrin *Intrinsic) Signature() *symbols.FunctionType { return intrin.sig }
|
||||
func (intrin *Intrinsic) String() string { return string(intrin.Name()) }
|
||||
func (intrin *Intrinsic) String() string { return string(intrin.Token()) }
|
||||
|
||||
func (intrin *Intrinsic) UnderlyingSymbol() symbols.Function { return intrin.fnc }
|
||||
|
||||
|
|
|
@ -42,16 +42,14 @@ const DefaultDeploymentReftag = "#ref"
|
|||
|
||||
// Deployment is a serializable vertex within a LumiGL graph, specifically for resource snapshots.
|
||||
type Deployment struct {
|
||||
ID *ID `json:"id,omitempty"` // the provider ID for this resource, if any.
|
||||
Type tokens.Type `json:"type"` // this resource's full type token.
|
||||
Inputs DeploymentProperties `json:"inputs,omitempty"` // the input properties from the program.
|
||||
Outputs DeploymentProperties `json:"outputs,omitempty"` // the output properties from the resource provider.
|
||||
ID *ID `json:"id,omitempty"` // the provider ID for this resource, if any.
|
||||
Type tokens.Type `json:"type"` // this resource's full type token.
|
||||
Inputs map[string]interface{} `json:"inputs,omitempty"` // the input properties from the program.
|
||||
Outputs map[string]interface{} `json:"outputs,omitempty"` // the output properties from the resource provider.
|
||||
}
|
||||
|
||||
// DeploymentProperties is a property map from resource key to the underlying property value.
|
||||
type DeploymentProperties map[string]interface{}
|
||||
|
||||
func serializeDeploymentRecord(snap Snapshot, reftag string) *DeploymentRecord {
|
||||
// SerializeDeploymentRecord serializes an entire snapshot using the given reftag for cross-resource references.
|
||||
func SerializeDeploymentRecord(snap Snapshot, reftag string) *DeploymentRecord {
|
||||
// Initialize the reftag if needed, and only serialize if overridden.
|
||||
var refp *string
|
||||
if reftag == "" {
|
||||
|
@ -68,7 +66,7 @@ func serializeDeploymentRecord(snap Snapshot, reftag string) *DeploymentRecord {
|
|||
m := res.URN()
|
||||
contract.Assertf(string(m) != "", "Unexpected empty resource URN")
|
||||
contract.Assertf(!resm.Has(m), "Unexpected duplicate resource URN '%v'", m)
|
||||
resm.Add(m, serializeDeployment(res, reftag))
|
||||
resm.Add(m, SerializeDeployment(res, reftag))
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -87,8 +85,8 @@ func serializeDeploymentRecord(snap Snapshot, reftag string) *DeploymentRecord {
|
|||
}
|
||||
}
|
||||
|
||||
// serializeDeployment turns a resource into a LumiGL data structure suitable for serialization.
|
||||
func serializeDeployment(res Resource, reftag string) *Deployment {
|
||||
// SerializeDeployment turns a resource into a LumiGL data structure suitable for serialization.
|
||||
func SerializeDeployment(res Resource, reftag string) *Deployment {
|
||||
contract.Assert(res != nil)
|
||||
|
||||
// Only serialize the ID if it is non-empty.
|
||||
|
@ -98,8 +96,14 @@ func serializeDeployment(res Resource, reftag string) *Deployment {
|
|||
}
|
||||
|
||||
// Serialize all input and output properties recursively, and add them if non-empty.
|
||||
inputs := serializeDeploymentProperties(res.Inputs(), reftag)
|
||||
outputs := serializeDeploymentProperties(res.Outputs(), reftag)
|
||||
var inputs map[string]interface{}
|
||||
if inp := res.Inputs(); inp != nil {
|
||||
inputs = SerializeDeploymentProperties(inp, reftag)
|
||||
}
|
||||
var outputs map[string]interface{}
|
||||
if outp := res.Outputs(); outp != nil {
|
||||
outputs = SerializeDeploymentProperties(outp, reftag)
|
||||
}
|
||||
|
||||
return &Deployment{
|
||||
ID: idp,
|
||||
|
@ -109,22 +113,19 @@ func serializeDeployment(res Resource, reftag string) *Deployment {
|
|||
}
|
||||
}
|
||||
|
||||
// serializeDeploymentProperties serializes a resource property bag so that it's suitable for serialization.
|
||||
func serializeDeploymentProperties(props PropertyMap, reftag string) DeploymentProperties {
|
||||
var dst DeploymentProperties
|
||||
// SerializeDeploymentProperties serializes a resource property bag so that it's suitable for serialization.
|
||||
func SerializeDeploymentProperties(props PropertyMap, reftag string) map[string]interface{} {
|
||||
dst := make(map[string]interface{})
|
||||
for _, k := range StablePropertyKeys(props) {
|
||||
if v := serializeDeploymentProperty(props[k], reftag); v != nil {
|
||||
if dst == nil {
|
||||
dst = make(DeploymentProperties)
|
||||
}
|
||||
if v := SerializeDeploymentProperty(props[k], reftag); v != nil {
|
||||
dst[string(k)] = v
|
||||
}
|
||||
}
|
||||
return dst
|
||||
}
|
||||
|
||||
// serializeDeploymentProperty serializes a resource property value so that it's suitable for serialization.
|
||||
func serializeDeploymentProperty(prop PropertyValue, reftag string) interface{} {
|
||||
// SerializeDeploymentProperty serializes a resource property value so that it's suitable for serialization.
|
||||
func SerializeDeploymentProperty(prop PropertyValue, reftag string) interface{} {
|
||||
contract.Assert(!prop.IsComputed())
|
||||
|
||||
// Skip nulls and "outputs"; the former needn't be serialized, and the latter happens if there is an output
|
||||
|
@ -135,21 +136,17 @@ func serializeDeploymentProperty(prop PropertyValue, reftag string) interface{}
|
|||
|
||||
// For arrays, make sure to recurse.
|
||||
if prop.IsArray() {
|
||||
var arr []interface{}
|
||||
for _, elem := range prop.ArrayValue() {
|
||||
if v := serializeDeploymentProperty(elem, reftag); v != nil {
|
||||
arr = append(arr, v)
|
||||
}
|
||||
srcarr := prop.ArrayValue()
|
||||
dstarr := make([]interface{}, len(srcarr))
|
||||
for i, elem := range prop.ArrayValue() {
|
||||
dstarr[i] = SerializeDeploymentProperty(elem, reftag)
|
||||
}
|
||||
if len(arr) > 0 {
|
||||
return arr
|
||||
}
|
||||
return nil
|
||||
return dstarr
|
||||
}
|
||||
|
||||
// Also for objects, recurse and use naked properties.
|
||||
if prop.IsObject() {
|
||||
return serializeDeploymentProperties(prop.ObjectValue(), reftag)
|
||||
return SerializeDeploymentProperties(prop.ObjectValue(), reftag)
|
||||
}
|
||||
|
||||
// Morph resources into their equivalent `{ "#ref": "<URN>" }` form.
|
||||
|
@ -163,15 +160,17 @@ func serializeDeploymentProperty(prop PropertyValue, reftag string) interface{}
|
|||
return prop.V
|
||||
}
|
||||
|
||||
func deserializeDeploymentProperties(props DeploymentProperties, reftag string) PropertyMap {
|
||||
// DeserializeDeploymentProperties deserializes an entire map of deployment properties into a resource property map.
|
||||
func DeserializeDeploymentProperties(props map[string]interface{}, reftag string) PropertyMap {
|
||||
result := make(PropertyMap)
|
||||
for k, prop := range props {
|
||||
result[PropertyKey(k)] = deserializeDeploymentProperty(prop, reftag)
|
||||
result[PropertyKey(k)] = DeserializeDeploymentProperty(prop, reftag)
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func deserializeDeploymentProperty(v interface{}, reftag string) PropertyValue {
|
||||
// DeserializeDeploymentProperty deserializes a single deployment property into a resource property value.
|
||||
func DeserializeDeploymentProperty(v interface{}, reftag string) PropertyValue {
|
||||
if v != nil {
|
||||
switch w := v.(type) {
|
||||
case bool:
|
||||
|
@ -183,7 +182,7 @@ func deserializeDeploymentProperty(v interface{}, reftag string) PropertyValue {
|
|||
case []interface{}:
|
||||
var arr []PropertyValue
|
||||
for _, elem := range w {
|
||||
arr = append(arr, deserializeDeploymentProperty(elem, reftag))
|
||||
arr = append(arr, DeserializeDeploymentProperty(elem, reftag))
|
||||
}
|
||||
return NewArrayProperty(arr)
|
||||
case map[string]interface{}:
|
||||
|
@ -197,7 +196,7 @@ func deserializeDeploymentProperty(v interface{}, reftag string) PropertyValue {
|
|||
}
|
||||
|
||||
// Otherwise, this is an arbitrary object value.
|
||||
obj := deserializeDeploymentProperties(DeploymentProperties(w), reftag)
|
||||
obj := DeserializeDeploymentProperties(w, reftag)
|
||||
return NewObjectProperty(obj)
|
||||
default:
|
||||
contract.Failf("Unrecognized property type: %v", reflect.ValueOf(v))
|
||||
|
|
127
pkg/resource/deployment_test.go
Normal file
127
pkg/resource/deployment_test.go
Normal file
|
@ -0,0 +1,127 @@
|
|||
// Licensed to Pulumi Corporation ("Pulumi") under one or more
|
||||
// contributor license agreements. See the NOTICE file distributed with
|
||||
// this work for additional information regarding copyright ownership.
|
||||
// Pulumi licenses this file to You under the Apache License, Version 2.0
|
||||
// (the "License"); you may not use this file except in compliance with
|
||||
// the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package resource
|
||||
|
||||
import (
|
||||
"testing"
|
||||
|
||||
"github.com/stretchr/testify/assert"
|
||||
|
||||
"github.com/pulumi/lumi/pkg/tokens"
|
||||
)
|
||||
|
||||
// TestDeploymentSerialization creates a basic
|
||||
func TestDeploymentSerialization(t *testing.T) {
|
||||
res := NewResource(
|
||||
ID("test-resource-x"),
|
||||
NewURN(tokens.QName("test"), tokens.Module("resource/test"), tokens.Type("Test"), tokens.QName("resource-x")),
|
||||
tokens.Type("Test"),
|
||||
NewPropertyMapFromMap(map[string]interface{}{
|
||||
"in-nil": nil,
|
||||
"in-bool": true,
|
||||
"in-float64": float64(1.5),
|
||||
"in-string": "lumilumilo",
|
||||
"in-array": []interface{}{"a", true, float64(32)},
|
||||
"in-empty-array": []interface{}{},
|
||||
"in-map": map[string]interface{}{
|
||||
"a": true,
|
||||
"b": float64(88),
|
||||
"c": "c-see-saw",
|
||||
"d": "d-dee-daw",
|
||||
},
|
||||
"in-empty-map": map[string]interface{}{},
|
||||
}),
|
||||
NewPropertyMapFromMap(map[string]interface{}{
|
||||
"out-nil": nil,
|
||||
"out-bool": false,
|
||||
"out-float64": float64(76),
|
||||
"out-string": "loyolumiloom",
|
||||
"out-array": []interface{}{false, "zzxx"},
|
||||
"out-empty-array": []interface{}{},
|
||||
"out-map": map[string]interface{}{
|
||||
"x": false,
|
||||
"y": "z-zee-zaw",
|
||||
"z": float64(999.9),
|
||||
},
|
||||
"out-empty-map": map[string]interface{}{},
|
||||
}),
|
||||
)
|
||||
|
||||
dep := SerializeDeployment(res, DefaultDeploymentReftag)
|
||||
|
||||
// assert some things about the deployment record:
|
||||
assert.NotNil(t, dep)
|
||||
assert.NotNil(t, dep.ID)
|
||||
assert.Equal(t, ID("test-resource-x"), *dep.ID)
|
||||
assert.Equal(t, tokens.Type("Test"), dep.Type)
|
||||
|
||||
// assert some things about the inputs:
|
||||
assert.NotNil(t, dep.Inputs)
|
||||
assert.Nil(t, dep.Inputs["in-nil"])
|
||||
assert.NotNil(t, dep.Inputs["in-bool"])
|
||||
assert.True(t, dep.Inputs["in-bool"].(bool))
|
||||
assert.NotNil(t, dep.Inputs["in-float64"])
|
||||
assert.Equal(t, float64(1.5), dep.Inputs["in-float64"].(float64))
|
||||
assert.NotNil(t, dep.Inputs["in-string"])
|
||||
assert.Equal(t, "lumilumilo", dep.Inputs["in-string"].(string))
|
||||
assert.NotNil(t, dep.Inputs["in-array"])
|
||||
assert.Equal(t, 3, len(dep.Inputs["in-array"].([]interface{})))
|
||||
assert.Equal(t, "a", dep.Inputs["in-array"].([]interface{})[0])
|
||||
assert.Equal(t, true, dep.Inputs["in-array"].([]interface{})[1])
|
||||
assert.Equal(t, float64(32), dep.Inputs["in-array"].([]interface{})[2])
|
||||
assert.NotNil(t, dep.Inputs["in-empty-array"])
|
||||
assert.Equal(t, 0, len(dep.Inputs["in-empty-array"].([]interface{})))
|
||||
assert.NotNil(t, dep.Inputs["in-map"])
|
||||
inmap := dep.Inputs["in-map"].(map[string]interface{})
|
||||
assert.Equal(t, 4, len(inmap))
|
||||
assert.NotNil(t, inmap["a"])
|
||||
assert.Equal(t, true, inmap["a"].(bool))
|
||||
assert.NotNil(t, inmap["b"])
|
||||
assert.Equal(t, float64(88), inmap["b"].(float64))
|
||||
assert.NotNil(t, inmap["c"])
|
||||
assert.Equal(t, "c-see-saw", inmap["c"].(string))
|
||||
assert.NotNil(t, inmap["d"])
|
||||
assert.Equal(t, "d-dee-daw", inmap["d"].(string))
|
||||
assert.NotNil(t, dep.Inputs["in-empty-map"])
|
||||
assert.Equal(t, 0, len(dep.Inputs["in-empty-map"].(map[string]interface{})))
|
||||
|
||||
// assert some things about the outputs:
|
||||
assert.NotNil(t, dep.Outputs)
|
||||
assert.Nil(t, dep.Outputs["out-nil"])
|
||||
assert.NotNil(t, dep.Outputs["out-bool"])
|
||||
assert.False(t, dep.Outputs["out-bool"].(bool))
|
||||
assert.NotNil(t, dep.Outputs["out-float64"])
|
||||
assert.Equal(t, float64(76), dep.Outputs["out-float64"].(float64))
|
||||
assert.NotNil(t, dep.Outputs["out-string"])
|
||||
assert.Equal(t, "loyolumiloom", dep.Outputs["out-string"].(string))
|
||||
assert.NotNil(t, dep.Outputs["out-array"])
|
||||
assert.Equal(t, 2, len(dep.Outputs["out-array"].([]interface{})))
|
||||
assert.Equal(t, false, dep.Outputs["out-array"].([]interface{})[0])
|
||||
assert.Equal(t, "zzxx", dep.Outputs["out-array"].([]interface{})[1])
|
||||
assert.NotNil(t, dep.Outputs["out-empty-array"])
|
||||
assert.Equal(t, 0, len(dep.Outputs["out-empty-array"].([]interface{})))
|
||||
assert.NotNil(t, dep.Outputs["out-map"])
|
||||
outmap := dep.Outputs["out-map"].(map[string]interface{})
|
||||
assert.Equal(t, 3, len(outmap))
|
||||
assert.NotNil(t, outmap["x"])
|
||||
assert.Equal(t, false, outmap["x"].(bool))
|
||||
assert.NotNil(t, outmap["y"])
|
||||
assert.Equal(t, "z-zee-zaw", outmap["y"].(string))
|
||||
assert.NotNil(t, outmap["z"])
|
||||
assert.Equal(t, float64(999.9), outmap["z"].(float64))
|
||||
assert.NotNil(t, dep.Outputs["out-empty-map"])
|
||||
assert.Equal(t, 0, len(dep.Outputs["out-empty-map"].(map[string]interface{})))
|
||||
}
|
|
@ -41,7 +41,7 @@ func SerializeEnvfile(env *Env, snap Snapshot, reftag string) *Envfile {
|
|||
// If snap is nil, that's okay, we will just create an empty deployment; otherwise, serialize the whole snapshot.
|
||||
var latest *DeploymentRecord
|
||||
if snap != nil {
|
||||
latest = serializeDeploymentRecord(snap, reftag)
|
||||
latest = SerializeDeploymentRecord(snap, reftag)
|
||||
}
|
||||
|
||||
var config *ConfigMap
|
||||
|
@ -78,8 +78,8 @@ func DeserializeEnvfile(ctx *Context, envfile *Envfile) (*Env, Snapshot) {
|
|||
for _, kvp := range latest.Resources.Iter() {
|
||||
// Deserialize the resource properties, if they exist.
|
||||
res := kvp.Value
|
||||
inputs := deserializeDeploymentProperties(res.Inputs, reftag)
|
||||
outputs := deserializeDeploymentProperties(res.Outputs, reftag)
|
||||
inputs := DeserializeDeploymentProperties(res.Inputs, reftag)
|
||||
outputs := DeserializeDeploymentProperties(res.Outputs, reftag)
|
||||
|
||||
// And now just produce a resource object using the information available.
|
||||
var id ID
|
||||
|
|
|
@ -176,11 +176,11 @@ func (p *plan) Provider(res Resource) (Provider, error) {
|
|||
func (p *plan) Apply(prog Progress) (Snapshot, Step, State, error) {
|
||||
// First go ahead and propagate IDs for unchanged resources.
|
||||
for old, new := range p.unchanged {
|
||||
contract.Assert(old.HasID())
|
||||
contract.Assert(!new.HasID())
|
||||
contract.Assert(HasID(old))
|
||||
contract.Assert(!HasID(new))
|
||||
id := old.ID()
|
||||
new.SetID(id)
|
||||
new.SetOutputsFrom(old)
|
||||
CopyOutputs(old, new)
|
||||
p.ctx.IDURN[id] = new.URN()
|
||||
}
|
||||
|
||||
|
@ -284,7 +284,7 @@ func newPlan(ctx *Context, old Snapshot, new Snapshot, analyzers []tokens.QName)
|
|||
for _, old := range pb.OldRes {
|
||||
m := old.URN()
|
||||
pb.Olds[m] = old
|
||||
contract.Assert(old.HasID())
|
||||
contract.Assert(HasID(old))
|
||||
// Keep track of which dependents exist for all resources.
|
||||
for dep := range old.Inputs().AllResources() {
|
||||
pb.Depends[dep] = append(pb.Depends[dep], m)
|
||||
|
@ -680,7 +680,7 @@ func (s *step) Apply() (State, error) {
|
|||
// Invoke the Create RPC function for this provider:
|
||||
contract.Assert(s.old == nil)
|
||||
contract.Assert(s.new != nil)
|
||||
contract.Assertf(!s.new.HasID(), "Resources being created must not have IDs already")
|
||||
contract.Assertf(!HasID(s.new), "Resources being created must not have IDs already")
|
||||
rst, err := prov.Create(s.new)
|
||||
if err != nil {
|
||||
return rst, err
|
||||
|
@ -698,7 +698,7 @@ func (s *step) Apply() (State, error) {
|
|||
// Invoke the Delete RPC function for this provider:
|
||||
contract.Assert(s.old != nil)
|
||||
contract.Assert(s.new == nil)
|
||||
contract.Assertf(s.old.HasID(), "Resources being deleted must have IDs")
|
||||
contract.Assertf(HasID(s.old), "Resources being deleted must have IDs")
|
||||
if rst, err := prov.Delete(s.old); err != nil {
|
||||
return rst, err
|
||||
}
|
||||
|
@ -708,7 +708,7 @@ func (s *step) Apply() (State, error) {
|
|||
contract.Assert(s.old != nil)
|
||||
contract.Assert(s.new != nil)
|
||||
contract.Assert(s.old.Type() == s.new.Type())
|
||||
contract.Assertf(s.old.HasID(), "Resources being updated must have IDs")
|
||||
contract.Assertf(HasID(s.old), "Resources being updated must have IDs")
|
||||
id := s.old.ID()
|
||||
if rst, err := prov.Update(s.old, s.new); err != nil {
|
||||
return rst, err
|
||||
|
@ -724,7 +724,7 @@ func (s *step) Apply() (State, error) {
|
|||
contract.Assert(s.old != nil)
|
||||
contract.Assert(s.new != nil)
|
||||
contract.Assert(s.old.Type() == s.new.Type())
|
||||
contract.Assertf(s.old.HasID(), "Resources being replaced must have IDs")
|
||||
contract.Assertf(HasID(s.old), "Resources being replaced must have IDs")
|
||||
|
||||
// There is nothing to do for OpReplace nodes; they are here to represent logical steps in the graph, and mostly
|
||||
// for visualization purposes; there will be true OpReplaceCreate and OpReplaceDelete nodes in the graph.
|
||||
|
|
|
@ -57,21 +57,16 @@ type PropertyValue struct {
|
|||
|
||||
// Computed represents the absence of a property value, because it will be computed at some point in the future. It
|
||||
// contains a property value which represents the underlying expected type of the eventual property value.
|
||||
type Computed PropertyValue
|
||||
|
||||
// Eventual reflects the eventual type of property value that a computed property will contain.
|
||||
func (v Computed) Eventual() PropertyValue {
|
||||
return PropertyValue(v)
|
||||
type Computed struct {
|
||||
Sources []URN // the resources whose state contribute to this value.
|
||||
Element PropertyValue // the eventual value (type) of the computed property.
|
||||
}
|
||||
|
||||
// Output is a property value that will eventually be computed by the resource provider. If an output property is
|
||||
// encountered, it means the resource has not yet been created, and so the output value is unavailable. Note that an
|
||||
// output property is a special case of computed, but carries additional semantic meaning.
|
||||
type Output PropertyValue
|
||||
|
||||
// Eventual reflects the eventual type of property value that an output property will contain.
|
||||
func (v Output) Eventual() PropertyValue {
|
||||
return PropertyValue(v)
|
||||
type Output struct {
|
||||
Element PropertyValue // the eventual value (type) of the output property.
|
||||
}
|
||||
|
||||
type ReqError struct {
|
||||
|
@ -453,8 +448,13 @@ func NewResourceProperty(v URN) PropertyValue { return PropertyValue{v}
|
|||
func NewComputedProperty(v Computed) PropertyValue { return PropertyValue{v} }
|
||||
func NewOutputProperty(v Output) PropertyValue { return PropertyValue{v} }
|
||||
|
||||
func MakeComputed(v PropertyValue) PropertyValue { return NewComputedProperty(Computed(v)) }
|
||||
func MakeOutput(v PropertyValue) PropertyValue { return NewOutputProperty(Output(v)) }
|
||||
func MakeComputed(v PropertyValue, sources []URN) PropertyValue {
|
||||
return NewComputedProperty(Computed{Element: v, Sources: sources})
|
||||
}
|
||||
|
||||
func MakeOutput(v PropertyValue) PropertyValue {
|
||||
return NewOutputProperty(Output{Element: v})
|
||||
}
|
||||
|
||||
// NewPropertyValue turns a value into a property value, provided it is of a legal "JSON-like" kind.
|
||||
func NewPropertyValue(v interface{}) PropertyValue {
|
||||
|
@ -610,10 +610,10 @@ func (v PropertyValue) CanBool() bool {
|
|||
return true
|
||||
}
|
||||
if v.IsComputed() {
|
||||
return v.ComputedValue().Eventual().CanBool()
|
||||
return v.ComputedValue().Element.CanBool()
|
||||
}
|
||||
if v.IsOutput() {
|
||||
return v.OutputValue().Eventual().CanBool()
|
||||
return v.OutputValue().Element.CanBool()
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
@ -624,10 +624,10 @@ func (v PropertyValue) CanNumber() bool {
|
|||
return true
|
||||
}
|
||||
if v.IsComputed() {
|
||||
return v.ComputedValue().Eventual().CanNumber()
|
||||
return v.ComputedValue().Element.CanNumber()
|
||||
}
|
||||
if v.IsOutput() {
|
||||
return v.OutputValue().Eventual().CanNumber()
|
||||
return v.OutputValue().Element.CanNumber()
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
@ -638,10 +638,10 @@ func (v PropertyValue) CanString() bool {
|
|||
return true
|
||||
}
|
||||
if v.IsComputed() {
|
||||
return v.ComputedValue().Eventual().CanString()
|
||||
return v.ComputedValue().Element.CanString()
|
||||
}
|
||||
if v.IsOutput() {
|
||||
return v.OutputValue().Eventual().CanString()
|
||||
return v.OutputValue().Element.CanString()
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
@ -652,10 +652,10 @@ func (v PropertyValue) CanArray() bool {
|
|||
return true
|
||||
}
|
||||
if v.IsComputed() {
|
||||
return v.ComputedValue().Eventual().CanArray()
|
||||
return v.ComputedValue().Element.CanArray()
|
||||
}
|
||||
if v.IsOutput() {
|
||||
return v.OutputValue().Eventual().CanArray()
|
||||
return v.OutputValue().Element.CanArray()
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
@ -666,10 +666,10 @@ func (v PropertyValue) CanObject() bool {
|
|||
return true
|
||||
}
|
||||
if v.IsComputed() {
|
||||
return v.ComputedValue().Eventual().CanObject()
|
||||
return v.ComputedValue().Element.CanObject()
|
||||
}
|
||||
if v.IsOutput() {
|
||||
return v.OutputValue().Eventual().CanObject()
|
||||
return v.OutputValue().Element.CanObject()
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
@ -680,10 +680,10 @@ func (v PropertyValue) CanResource() bool {
|
|||
return true
|
||||
}
|
||||
if v.IsComputed() {
|
||||
return v.ComputedValue().Eventual().CanResource()
|
||||
return v.ComputedValue().Element.CanResource()
|
||||
}
|
||||
if v.IsOutput() {
|
||||
return v.OutputValue().Eventual().CanResource()
|
||||
return v.OutputValue().Element.CanResource()
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
@ -710,9 +710,9 @@ func (v PropertyValue) TypeString() string {
|
|||
} else if v.IsResource() {
|
||||
return "resource"
|
||||
} else if v.IsComputed() {
|
||||
return "computed<" + v.ComputedValue().Eventual().TypeString() + ">"
|
||||
return "computed<" + v.ComputedValue().Element.TypeString() + ">"
|
||||
} else if v.IsOutput() {
|
||||
return "output<" + v.OutputValue().Eventual().TypeString() + ">"
|
||||
return "output<" + v.OutputValue().Element.TypeString() + ">"
|
||||
}
|
||||
contract.Failf("Unrecognized PropertyValue type")
|
||||
return ""
|
||||
|
|
|
@ -179,6 +179,9 @@ func TestArrayPropertyValueDiffs(t *testing.T) {
|
|||
assert.Equal(t, d5a1.ArrayValue()[i], update.Old)
|
||||
assert.Equal(t, d5a2.ArrayValue()[i], update.New)
|
||||
}
|
||||
// from nil to empty array:
|
||||
d6 := NewNullProperty().Diff(NewArrayProperty([]PropertyValue{}))
|
||||
assert.NotNil(t, d6)
|
||||
}
|
||||
|
||||
func TestObjectPropertyValueDiffs(t *testing.T) {
|
||||
|
|
|
@ -16,62 +16,18 @@
|
|||
package resource
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/hex"
|
||||
"reflect"
|
||||
|
||||
"github.com/golang/glog"
|
||||
|
||||
"github.com/pulumi/lumi/pkg/compiler/symbols"
|
||||
"github.com/pulumi/lumi/pkg/compiler/types"
|
||||
"github.com/pulumi/lumi/pkg/compiler/types/predef"
|
||||
"github.com/pulumi/lumi/pkg/eval/heapstate"
|
||||
"github.com/pulumi/lumi/pkg/eval/rt"
|
||||
"github.com/pulumi/lumi/pkg/tokens"
|
||||
"github.com/pulumi/lumi/pkg/util/contract"
|
||||
)
|
||||
|
||||
// ID is a unique resource identifier; it is managed by the provider and is mostly opaque to Lumi.
|
||||
type ID string
|
||||
|
||||
func MaybeID(s *string) *ID {
|
||||
var ret *ID
|
||||
if s != nil {
|
||||
id := ID(*s)
|
||||
ret = &id
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
func (id ID) String() string { return string(id) }
|
||||
func (id *ID) StringPtr() *string {
|
||||
if id == nil {
|
||||
return nil
|
||||
}
|
||||
ids := (*id).String()
|
||||
return &ids
|
||||
}
|
||||
func IDStrings(ids []ID) []string {
|
||||
ss := make([]string, len(ids))
|
||||
for i, id := range ids {
|
||||
ss[i] = id.String()
|
||||
}
|
||||
return ss
|
||||
}
|
||||
|
||||
// Resource is an instance of a resource with an ID, type, and bag of state.
|
||||
type Resource interface {
|
||||
ID() ID // the resource's unique ID assigned by the provider (or blank if uncreated).
|
||||
URN() URN // the resource's object urn, a human-friendly, unique name for the resource.
|
||||
Type() tokens.Type // the resource's type.
|
||||
Inputs() PropertyMap // the resource's input properties (as specified by the program).
|
||||
Outputs() PropertyMap // the resource's output properties (as specified by the resource provider).
|
||||
HasID() bool // returns true if the resource has been assigned an ID.
|
||||
SetID(id ID) // assignes an ID to this resource, for those under creation.
|
||||
HasURN() bool // returns true if the resource has been assigned URN.
|
||||
SetURN(m URN) // assignes a URN to this resource, for those under creation.
|
||||
SetOutputsFrom(src Resource) // copy all output properties from one resource to another.
|
||||
ShallowClone() Resource // make a shallow clone of the resource.
|
||||
ID() ID // the resource's unique ID assigned by the provider (or blank if uncreated).
|
||||
SetID(id ID) // assignes an ID to this resource, for those under creation.
|
||||
URN() URN // the resource's object urn, a human-friendly, unique name for the resource.
|
||||
SetURN(m URN) // assignes a URN to this resource, for those under creation.
|
||||
Type() tokens.Type // the resource's type.
|
||||
Inputs() PropertyMap // the resource's input properties (as specified by the program).
|
||||
Outputs() PropertyMap // the resource's output properties (as specified by the resource provider).
|
||||
}
|
||||
|
||||
// State is returned when an error has occurred during a resource provider operation. It indicates whether the
|
||||
|
@ -83,208 +39,29 @@ const (
|
|||
StateUnknown
|
||||
)
|
||||
|
||||
// IsResourceVertex returns true if the heap graph vertex has an object whose type is the standard resource class.
|
||||
func IsResourceVertex(v *heapstate.ObjectVertex) bool {
|
||||
return predef.IsResourceType(v.Obj().Type())
|
||||
// HasID returns true if the given resource has been assigned an ID.
|
||||
func HasID(r Resource) bool {
|
||||
return r.ID() != ""
|
||||
}
|
||||
|
||||
type resource struct {
|
||||
id ID // the resource's unique ID, assigned by the resource provider (or blank if uncreated).
|
||||
urn URN // the resource's object urn, a human-friendly, unique name for the resource.
|
||||
t tokens.Type // the resource's type.
|
||||
inputs PropertyMap // the resource's input properties (as specified by the program).
|
||||
outputs PropertyMap // the resource's output properties (as specified by the resource provider).
|
||||
// HasURN returns true if the given resource has been assigned a URN.
|
||||
func HasURN(r Resource) bool {
|
||||
return r.URN() != ""
|
||||
}
|
||||
|
||||
func (r *resource) ID() ID { return r.id }
|
||||
func (r *resource) URN() URN { return r.urn }
|
||||
func (r *resource) Type() tokens.Type { return r.t }
|
||||
func (r *resource) Inputs() PropertyMap { return r.inputs }
|
||||
func (r *resource) Outputs() PropertyMap { return r.outputs }
|
||||
|
||||
func (r *resource) HasID() bool { return (string(r.id) != "") }
|
||||
func (r *resource) SetID(id ID) {
|
||||
contract.Requiref(!r.HasID(), "id", "empty")
|
||||
glog.V(9).Infof("Assigning ID=%v to resource w/ URN=%v", id, r.urn)
|
||||
r.id = id
|
||||
}
|
||||
|
||||
func (r *resource) HasURN() bool { return (string(r.urn) != "") }
|
||||
func (r *resource) SetURN(m URN) {
|
||||
contract.Requiref(!r.HasURN(), "urn", "empty")
|
||||
r.urn = m
|
||||
}
|
||||
|
||||
// SetOutputsFrom copies all output properties from a src resource to the instance.
|
||||
func (r *resource) SetOutputsFrom(src Resource) {
|
||||
src.Outputs().ShallowCloneInto(r.Outputs())
|
||||
// CopyOutputs copies all output properties from a src resource to the instance.
|
||||
func CopyOutputs(src Resource, dst Resource) {
|
||||
src.Outputs().ShallowCloneInto(dst.Outputs())
|
||||
}
|
||||
|
||||
// ShallowClone clones a resource object so that any modifications to it are not reflected in the original. Note that
|
||||
// the property map is only shallowly cloned so any mutations deep within it may get reflected in the original.
|
||||
func (r *resource) ShallowClone() Resource {
|
||||
func ShallowClone(r Resource) Resource {
|
||||
return &resource{
|
||||
id: r.id,
|
||||
urn: r.urn,
|
||||
t: r.t,
|
||||
inputs: r.inputs.ShallowClone(),
|
||||
outputs: r.outputs.ShallowClone(),
|
||||
id: r.ID(),
|
||||
urn: r.URN(),
|
||||
t: r.Type(),
|
||||
inputs: r.Inputs().ShallowClone(),
|
||||
outputs: r.Outputs().ShallowClone(),
|
||||
}
|
||||
}
|
||||
|
||||
// NewResource creates a new resource from the information provided.
|
||||
func NewResource(id ID, urn URN, t tokens.Type, inputs PropertyMap, outputs PropertyMap) Resource {
|
||||
if inputs == nil {
|
||||
inputs = make(PropertyMap)
|
||||
}
|
||||
if outputs == nil {
|
||||
outputs = make(PropertyMap)
|
||||
}
|
||||
return &resource{
|
||||
id: id,
|
||||
urn: urn,
|
||||
t: t,
|
||||
inputs: inputs,
|
||||
outputs: outputs,
|
||||
}
|
||||
}
|
||||
|
||||
// NewObjectResource creates a new resource object out of the runtime object provided. The context is used to resolve
|
||||
// dependencies between resources and must contain all references that could be encountered.
|
||||
func NewObjectResource(ctx *Context, obj *rt.Object) Resource {
|
||||
t := obj.Type()
|
||||
contract.Assert(predef.IsResourceType(t))
|
||||
|
||||
// Extract the urn. This must already exist.
|
||||
urn, hasm := ctx.ObjURN[obj]
|
||||
contract.Assertf(!hasm, "Object already assigned a urn '%v'; double allocation detected", urn)
|
||||
|
||||
// Do a deep copy of the resource properties. This ensures property serializability.
|
||||
props := cloneObject(ctx, obj)
|
||||
|
||||
// Finally allocate and return the resource object; note that ID is left blank until the provider assignes one.
|
||||
return NewResource("", urn, t.TypeToken(), props, nil)
|
||||
}
|
||||
|
||||
// cloneObject creates a property map out of a runtime object. The result is fully serializable in the sense that it
|
||||
// can be stored in a JSON or YAML file, serialized over an RPC interface, etc. In particular, any references to other
|
||||
// resources are replaced with their urn equivalents, which the runtime understands.
|
||||
func cloneObject(ctx *Context, obj *rt.Object) PropertyMap {
|
||||
contract.Assert(obj != nil)
|
||||
|
||||
// Walk the object's properties and serialize them in a stable order.
|
||||
src := obj.PropertyValues()
|
||||
dest := make(PropertyMap)
|
||||
for _, k := range src.Stable() {
|
||||
obj := src.Get(k)
|
||||
if v, ok := cloneObjectProperty(ctx, obj); ok {
|
||||
dest[PropertyKey(k)] = v
|
||||
}
|
||||
}
|
||||
return dest
|
||||
}
|
||||
|
||||
// cloneObjectProperty creates a single property value out of a runtime object. It returns false if the property could
|
||||
// not be stored in a property (e.g., it is a function or other unrecognized or unserializable runtime object).
|
||||
func cloneObjectProperty(ctx *Context, obj *rt.Object) (PropertyValue, bool) {
|
||||
t := obj.Type()
|
||||
|
||||
// Serialize resource references as URNs.
|
||||
if predef.IsResourceType(t) {
|
||||
// For resources, simply look up the urn from the resource map.
|
||||
urn, hasm := ctx.ObjURN[obj]
|
||||
contract.Assertf(hasm, "Missing object reference; possible out of order dependency walk")
|
||||
return NewResourceProperty(urn), true
|
||||
}
|
||||
|
||||
// Serialize simple primitive types with their primitive equivalents.
|
||||
switch t {
|
||||
case types.Null:
|
||||
return NewNullProperty(), true
|
||||
case types.Bool:
|
||||
return NewBoolProperty(obj.BoolValue()), true
|
||||
case types.Number:
|
||||
return NewNumberProperty(obj.NumberValue()), true
|
||||
case types.String:
|
||||
return NewStringProperty(obj.StringValue()), true
|
||||
case types.Object, types.Dynamic:
|
||||
obj := cloneObject(ctx, obj) // an object literal, clone it
|
||||
return NewObjectProperty(obj), true
|
||||
}
|
||||
|
||||
// Serialize arrays, maps, and object instances in the obvious way.
|
||||
// TODO: handle symbols.MapType.
|
||||
switch t.(type) {
|
||||
case *symbols.ArrayType:
|
||||
var result []PropertyValue
|
||||
for _, e := range *obj.ArrayValue() {
|
||||
if v, ok := cloneObjectProperty(ctx, e.Obj()); ok {
|
||||
result = append(result, v)
|
||||
}
|
||||
}
|
||||
return NewArrayProperty(result), true
|
||||
case *symbols.Class:
|
||||
obj := cloneObject(ctx, obj) // a class, just deep clone it
|
||||
return NewObjectProperty(obj), true
|
||||
}
|
||||
|
||||
// If a computed value, we can propagate an unknown value, but only for certain cases.
|
||||
if t.Computed() {
|
||||
// If this is an output property, then this property will turn into an output. Otherwise, it will be marked
|
||||
// completed. An output property is permitted in more places by virtue of the fact that it is expected not to
|
||||
// exist during resource create operations, whereas all computed properties should have been resolved by then.
|
||||
var makeProperty func(PropertyValue) PropertyValue
|
||||
if !obj.ComputedValue().Expr {
|
||||
makeProperty = MakeOutput
|
||||
} else {
|
||||
makeProperty = MakeComputed
|
||||
}
|
||||
// TODO[pulumi/lumi#90]: track the resource URNs that are implicated.
|
||||
|
||||
future := t.(*symbols.ComputedType).Element
|
||||
switch future {
|
||||
case types.Null:
|
||||
return makeProperty(NewNullProperty()), true
|
||||
case types.Bool:
|
||||
return makeProperty(NewBoolProperty(false)), true
|
||||
case types.Number:
|
||||
return makeProperty(NewNumberProperty(0)), true
|
||||
case types.String:
|
||||
return makeProperty(NewStringProperty("")), true
|
||||
case types.Object, types.Dynamic:
|
||||
return makeProperty(NewObjectProperty(make(PropertyMap))), true
|
||||
}
|
||||
switch future.(type) {
|
||||
case *symbols.ArrayType:
|
||||
return makeProperty(NewArrayProperty(nil)), true
|
||||
case *symbols.Class:
|
||||
return makeProperty(NewObjectProperty(make(PropertyMap))), true
|
||||
}
|
||||
}
|
||||
|
||||
// We can safely skip serializing functions, however, anything else is unexpected at this point.
|
||||
_, isfunc := t.(*symbols.FunctionType)
|
||||
contract.Assertf(isfunc, "Unrecognized resource property object type '%v' (%v)", t, reflect.TypeOf(t))
|
||||
return PropertyValue{}, false
|
||||
}
|
||||
|
||||
// NewUniqueHex generates a new "random" hex string for use by resource providers. It has the given optional prefix and
|
||||
// the total length is capped to the maxlen. Note that capping to maxlen necessarily increases the risk of collisions.
|
||||
func NewUniqueHex(prefix string, randlen, maxlen int) string {
|
||||
bs := make([]byte, randlen)
|
||||
n, err := rand.Read(bs)
|
||||
contract.Assert(err == nil)
|
||||
contract.Assert(n == len(bs))
|
||||
|
||||
str := prefix + hex.EncodeToString(bs)
|
||||
if len(str) > maxlen {
|
||||
str = str[:maxlen]
|
||||
}
|
||||
return str
|
||||
}
|
||||
|
||||
// NewUniqueHexID generates a new "random" hex ID for use by resource providers. It has the given optional prefix and
|
||||
// the total length is capped to the maxlen. Note that capping to maxlen necessarily increases the risk of collisions.
|
||||
func NewUniqueHexID(prefix string, randlen, maxlen int) ID {
|
||||
return ID(NewUniqueHex(prefix, randlen, maxlen))
|
||||
}
|
||||
|
|
|
@ -16,6 +16,8 @@
|
|||
package resource
|
||||
|
||||
import (
|
||||
"github.com/pulumi/lumi/pkg/compiler/types/predef"
|
||||
"github.com/pulumi/lumi/pkg/eval/heapstate"
|
||||
"github.com/pulumi/lumi/pkg/graph"
|
||||
"github.com/pulumi/lumi/pkg/util/contract"
|
||||
)
|
||||
|
@ -127,3 +129,8 @@ func (e *resourceEdge) From() graph.Vertex {
|
|||
return e.from
|
||||
}
|
||||
func (e *resourceEdge) FromObj() *resourceVertex { return e.from }
|
||||
|
||||
// IsResourceVertex returns true if the heap graph vertex has an object whose type is the standard resource class.
|
||||
func IsResourceVertex(v *heapstate.ObjectVertex) bool {
|
||||
return predef.IsResourceType(v.Obj().Type())
|
||||
}
|
||||
|
|
80
pkg/resource/resource_id.go
Normal file
80
pkg/resource/resource_id.go
Normal file
|
@ -0,0 +1,80 @@
|
|||
// Licensed to Pulumi Corporation ("Pulumi") under one or more
|
||||
// contributor license agreements. See the NOTICE file distributed with
|
||||
// this work for additional information regarding copyright ownership.
|
||||
// Pulumi licenses this file to You under the Apache License, Version 2.0
|
||||
// (the "License"); you may not use this file except in compliance with
|
||||
// the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package resource
|
||||
|
||||
import (
|
||||
"crypto/rand"
|
||||
"encoding/hex"
|
||||
|
||||
"github.com/pulumi/lumi/pkg/util/contract"
|
||||
)
|
||||
|
||||
// ID is a unique resource identifier; it is managed by the provider and is mostly opaque to Lumi.
|
||||
type ID string
|
||||
|
||||
// String converts a resource ID into a string.
|
||||
func (id ID) String() string {
|
||||
return string(id)
|
||||
}
|
||||
|
||||
// StringPtr converts an optional ID into an optional string.
|
||||
func (id *ID) StringPtr() *string {
|
||||
if id == nil {
|
||||
return nil
|
||||
}
|
||||
ids := (*id).String()
|
||||
return &ids
|
||||
}
|
||||
|
||||
// IDStrings turns an array of resource IDs into an array of strings.
|
||||
func IDStrings(ids []ID) []string {
|
||||
ss := make([]string, len(ids))
|
||||
for i, id := range ids {
|
||||
ss[i] = id.String()
|
||||
}
|
||||
return ss
|
||||
}
|
||||
|
||||
// MaybeID turns an optional string into an optional resource ID.
|
||||
func MaybeID(s *string) *ID {
|
||||
var ret *ID
|
||||
if s != nil {
|
||||
id := ID(*s)
|
||||
ret = &id
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
// NewUniqueHex generates a new "random" hex string for use by resource providers. It has the given optional prefix and
|
||||
// the total length is capped to the maxlen. Note that capping to maxlen necessarily increases the risk of collisions.
|
||||
func NewUniqueHex(prefix string, randlen, maxlen int) string {
|
||||
bs := make([]byte, randlen)
|
||||
n, err := rand.Read(bs)
|
||||
contract.Assert(err == nil)
|
||||
contract.Assert(n == len(bs))
|
||||
|
||||
str := prefix + hex.EncodeToString(bs)
|
||||
if len(str) > maxlen {
|
||||
str = str[:maxlen]
|
||||
}
|
||||
return str
|
||||
}
|
||||
|
||||
// NewUniqueHexID generates a new "random" hex ID for use by resource providers. It has the given optional prefix and
|
||||
// the total length is capped to the maxlen. Note that capping to maxlen necessarily increases the risk of collisions.
|
||||
func NewUniqueHexID(prefix string, randlen, maxlen int) ID {
|
||||
return ID(NewUniqueHex(prefix, randlen, maxlen))
|
||||
}
|
198
pkg/resource/resource_object.go
Normal file
198
pkg/resource/resource_object.go
Normal file
|
@ -0,0 +1,198 @@
|
|||
// Licensed to Pulumi Corporation ("Pulumi") under one or more
|
||||
// contributor license agreements. See the NOTICE file distributed with
|
||||
// this work for additional information regarding copyright ownership.
|
||||
// Pulumi licenses this file to You under the Apache License, Version 2.0
|
||||
// (the "License"); you may not use this file except in compliance with
|
||||
// the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package resource
|
||||
|
||||
import (
|
||||
"reflect"
|
||||
|
||||
"github.com/golang/glog"
|
||||
|
||||
"github.com/pulumi/lumi/pkg/compiler/symbols"
|
||||
"github.com/pulumi/lumi/pkg/compiler/types"
|
||||
"github.com/pulumi/lumi/pkg/compiler/types/predef"
|
||||
"github.com/pulumi/lumi/pkg/eval/rt"
|
||||
"github.com/pulumi/lumi/pkg/tokens"
|
||||
"github.com/pulumi/lumi/pkg/util/contract"
|
||||
)
|
||||
|
||||
type objectResource struct {
|
||||
ctx *Context // the resource context this object is associated with.
|
||||
id ID // the resource's unique ID, assigned by the resource provider (or blank if uncreated).
|
||||
urn URN // the resource's object urn, a human-friendly, unique name for the resource.
|
||||
obj *rt.Object // the resource's live object reference.
|
||||
outputs PropertyMap // the resource's output properties (as specified by the resource provider).
|
||||
}
|
||||
|
||||
// NewObjectResource creates a new resource object out of the runtime object provided. The context is used to resolve
|
||||
// dependencies between resources and must contain all references that could be encountered.
|
||||
func NewObjectResource(ctx *Context, obj *rt.Object) Resource {
|
||||
contract.Assertf(predef.IsResourceType(obj.Type()), "Expected a resource type")
|
||||
return &objectResource{
|
||||
ctx: ctx,
|
||||
obj: obj,
|
||||
outputs: make(PropertyMap),
|
||||
}
|
||||
}
|
||||
|
||||
func (r *objectResource) ID() ID { return r.id }
|
||||
func (r *objectResource) URN() URN { return r.urn }
|
||||
func (r *objectResource) Type() tokens.Type { return r.obj.Type().TypeToken() }
|
||||
func (r *objectResource) Inputs() PropertyMap { return cloneResource(r.ctx, r.obj) }
|
||||
func (r *objectResource) Outputs() PropertyMap { return r.outputs }
|
||||
|
||||
func (r *objectResource) SetID(id ID) {
|
||||
contract.Requiref(!HasID(r), "id", "empty")
|
||||
glog.V(9).Infof("Assigning ID=%v to resource w/ URN=%v", id, r.urn)
|
||||
r.id = id
|
||||
}
|
||||
|
||||
func (r *objectResource) SetURN(m URN) {
|
||||
contract.Requiref(!HasURN(r), "urn", "empty")
|
||||
r.urn = m
|
||||
}
|
||||
|
||||
// cloneResource creates a property map out of a resource's runtime object.
|
||||
func cloneResource(ctx *Context, resobj *rt.Object) PropertyMap {
|
||||
return cloneObject(ctx, resobj, resobj)
|
||||
}
|
||||
|
||||
// cloneObject creates a property map out of a runtime object. The result is fully serializable in the sense that it
|
||||
// can be stored in a JSON or YAML file, serialized over an RPC interface, etc. In particular, any references to other
|
||||
// resources are replaced with their urn equivalents, which the runtime understands.
|
||||
func cloneObject(ctx *Context, resobj *rt.Object, obj *rt.Object) PropertyMap {
|
||||
contract.Assert(obj != nil)
|
||||
props := obj.PropertyValues()
|
||||
return cloneObjectProperties(ctx, resobj, props)
|
||||
}
|
||||
|
||||
// cloneObjectProperty creates a single property value out of a runtime object. It returns false if the property could
|
||||
// not be stored in a property (e.g., it is a function or other unrecognized or unserializable runtime object).
|
||||
func cloneObjectProperty(ctx *Context, resobj *rt.Object, obj *rt.Object) (PropertyValue, bool) {
|
||||
t := obj.Type()
|
||||
|
||||
// Serialize resource references as URNs.
|
||||
if predef.IsResourceType(t) {
|
||||
// For resources, simply look up the urn from the resource map.
|
||||
urn, hasm := ctx.ObjURN[obj]
|
||||
contract.Assertf(hasm, "Missing object reference for %v; possible out of order dependency walk", obj)
|
||||
return NewResourceProperty(urn), true
|
||||
}
|
||||
|
||||
// Serialize simple primitive types with their primitive equivalents.
|
||||
switch t {
|
||||
case types.Null:
|
||||
return NewNullProperty(), true
|
||||
case types.Bool:
|
||||
return NewBoolProperty(obj.BoolValue()), true
|
||||
case types.Number:
|
||||
return NewNumberProperty(obj.NumberValue()), true
|
||||
case types.String:
|
||||
return NewStringProperty(obj.StringValue()), true
|
||||
case types.Object, types.Dynamic:
|
||||
result := cloneObject(ctx, resobj, obj) // an object literal, clone it
|
||||
return NewObjectProperty(result), true
|
||||
}
|
||||
|
||||
// Serialize arrays, maps, and object instances in the obvious way.
|
||||
switch t.(type) {
|
||||
case *symbols.ArrayType:
|
||||
// Make a new array, clone each element, and return the result.
|
||||
var result []PropertyValue
|
||||
for _, e := range *obj.ArrayValue() {
|
||||
if v, ok := cloneObjectProperty(ctx, obj, e.Obj()); ok {
|
||||
result = append(result, v)
|
||||
}
|
||||
}
|
||||
return NewArrayProperty(result), true
|
||||
case *symbols.MapType:
|
||||
// Make a new map, clone each property value, and return the result.
|
||||
props := obj.PropertyValues()
|
||||
result := cloneObjectProperties(ctx, resobj, props)
|
||||
return NewObjectProperty(result), true
|
||||
case *symbols.Class:
|
||||
// Make a new object that contains a deep clone of the source.
|
||||
result := cloneObject(ctx, resobj, obj)
|
||||
return NewObjectProperty(result), true
|
||||
}
|
||||
|
||||
// If a computed value, we can propagate an unknown value, but only for certain cases.
|
||||
if t.Computed() {
|
||||
// If this is an output property, then this property will turn into an output. Otherwise, it will be marked
|
||||
// completed. An output property is permitted in more places by virtue of the fact that it is expected not to
|
||||
// exist during resource create operations, whereas all computed properties should have been resolved by then.
|
||||
comp := obj.ComputedValue()
|
||||
outprop := (!comp.Expr && len(comp.Sources) == 1 && comp.Sources[0] == resobj)
|
||||
var makeProperty func(PropertyValue) PropertyValue
|
||||
if outprop {
|
||||
// For output properties, we need not track any URNs.
|
||||
makeProperty = func(v PropertyValue) PropertyValue {
|
||||
return MakeOutput(v)
|
||||
}
|
||||
} else {
|
||||
// For all other properties, we need to look up and store the URNs for all resource dependencies.
|
||||
var urns []URN
|
||||
for _, src := range comp.Sources {
|
||||
// For all inter-resource references, materialize a URN. Skip this for intra-resource references!
|
||||
if src != resobj {
|
||||
urn, hasm := ctx.ObjURN[src]
|
||||
contract.Assertf(hasm,
|
||||
"Missing computed reference from %v to %v; possible out of order dependency walk", resobj, src)
|
||||
urns = append(urns, urn)
|
||||
}
|
||||
}
|
||||
makeProperty = func(v PropertyValue) PropertyValue {
|
||||
return MakeComputed(v, urns)
|
||||
}
|
||||
}
|
||||
|
||||
future := t.(*symbols.ComputedType).Element
|
||||
switch future {
|
||||
case types.Null:
|
||||
return makeProperty(NewNullProperty()), true
|
||||
case types.Bool:
|
||||
return makeProperty(NewBoolProperty(false)), true
|
||||
case types.Number:
|
||||
return makeProperty(NewNumberProperty(0)), true
|
||||
case types.String:
|
||||
return makeProperty(NewStringProperty("")), true
|
||||
case types.Object, types.Dynamic:
|
||||
return makeProperty(NewObjectProperty(make(PropertyMap))), true
|
||||
}
|
||||
switch future.(type) {
|
||||
case *symbols.ArrayType:
|
||||
return makeProperty(NewArrayProperty(nil)), true
|
||||
case *symbols.Class:
|
||||
return makeProperty(NewObjectProperty(make(PropertyMap))), true
|
||||
}
|
||||
}
|
||||
|
||||
// We can safely skip serializing functions, however, anything else is unexpected at this point.
|
||||
_, isfunc := t.(*symbols.FunctionType)
|
||||
contract.Assertf(isfunc, "Unrecognized resource property object type '%v' (%v)", t, reflect.TypeOf(t))
|
||||
return PropertyValue{}, false
|
||||
}
|
||||
|
||||
// cloneObjectProperties copies a resource's properties.
|
||||
func cloneObjectProperties(ctx *Context, resobj *rt.Object, props *rt.PropertyMap) PropertyMap {
|
||||
// Walk the object's properties and serialize them in a stable order.
|
||||
result := make(PropertyMap)
|
||||
for _, k := range props.Stable() {
|
||||
if v, ok := cloneObjectProperty(ctx, resobj, props.Get(k)); ok {
|
||||
result[PropertyKey(k)] = v
|
||||
}
|
||||
}
|
||||
return result
|
||||
}
|
68
pkg/resource/resource_value.go
Normal file
68
pkg/resource/resource_value.go
Normal file
|
@ -0,0 +1,68 @@
|
|||
// Licensed to Pulumi Corporation ("Pulumi") under one or more
|
||||
// contributor license agreements. See the NOTICE file distributed with
|
||||
// this work for additional information regarding copyright ownership.
|
||||
// Pulumi licenses this file to You under the Apache License, Version 2.0
|
||||
// (the "License"); you may not use this file except in compliance with
|
||||
// the License. You may obtain a copy of the License at
|
||||
//
|
||||
// http://www.apache.org/licenses/LICENSE-2.0
|
||||
//
|
||||
// Unless required by applicable law or agreed to in writing, software
|
||||
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
// See the License for the specific language governing permissions and
|
||||
// limitations under the License.
|
||||
|
||||
package resource
|
||||
|
||||
import (
|
||||
"github.com/golang/glog"
|
||||
|
||||
"github.com/pulumi/lumi/pkg/tokens"
|
||||
"github.com/pulumi/lumi/pkg/util/contract"
|
||||
)
|
||||
|
||||
// resource is a structure containing state associated with a resource. This resource may have been serialized and
|
||||
// deserialized, or snapshotted from a live graph of resource objects. The value's state is not, however, associated
|
||||
// with any runtime objects in memory that may be actively involved in ongoing computations.
|
||||
type resource struct {
|
||||
id ID // the resource's unique ID, assigned by the resource provider (or blank if uncreated).
|
||||
urn URN // the resource's object urn, a human-friendly, unique name for the resource.
|
||||
t tokens.Type // the resource's type.
|
||||
inputs PropertyMap // the resource's input properties (as specified by the program).
|
||||
outputs PropertyMap // the resource's output properties (as specified by the resource provider).
|
||||
}
|
||||
|
||||
// NewResource creates a new resource value from existing resource state information.
|
||||
func NewResource(id ID, urn URN, t tokens.Type, inputs PropertyMap, outputs PropertyMap) Resource {
|
||||
if inputs == nil {
|
||||
inputs = make(PropertyMap)
|
||||
}
|
||||
if outputs == nil {
|
||||
outputs = make(PropertyMap)
|
||||
}
|
||||
return &resource{
|
||||
id: id,
|
||||
urn: urn,
|
||||
t: t,
|
||||
inputs: inputs,
|
||||
outputs: outputs,
|
||||
}
|
||||
}
|
||||
|
||||
func (r *resource) ID() ID { return r.id }
|
||||
func (r *resource) URN() URN { return r.urn }
|
||||
func (r *resource) Type() tokens.Type { return r.t }
|
||||
func (r *resource) Inputs() PropertyMap { return r.inputs }
|
||||
func (r *resource) Outputs() PropertyMap { return r.outputs }
|
||||
|
||||
func (r *resource) SetID(id ID) {
|
||||
contract.Requiref(!HasID(r), "id", "empty")
|
||||
glog.V(9).Infof("Assigning ID=%v to resource w/ URN=%v", id, r.urn)
|
||||
r.id = id
|
||||
}
|
||||
|
||||
func (r *resource) SetURN(m URN) {
|
||||
contract.Requiref(!HasURN(r), "urn", "empty")
|
||||
r.urn = m
|
||||
}
|
|
@ -140,13 +140,13 @@ func MarshalPropertyValue(ctx *Context, v PropertyValue, opts MarshalOptions) (*
|
|||
},
|
||||
}, true
|
||||
} else if v.IsComputed() {
|
||||
e := v.ComputedValue().Eventual()
|
||||
e := v.ComputedValue().Element
|
||||
contract.Assert(!e.IsComputed())
|
||||
w, known := MarshalPropertyValue(ctx, e, opts)
|
||||
contract.Assert(known)
|
||||
return w, false
|
||||
} else if v.IsOutput() {
|
||||
e := v.OutputValue().Eventual()
|
||||
e := v.OutputValue().Element
|
||||
contract.Assert(!e.IsComputed())
|
||||
w, known := MarshalPropertyValue(ctx, e, opts)
|
||||
contract.Assert(known)
|
||||
|
|
|
@ -54,7 +54,7 @@ func NewGraphSnapshot(ctx *Context, ns tokens.QName, pkg tokens.Package, args co
|
|||
// If the old snapshot is non-nil, we need to register old IDs so they will be found below.
|
||||
if old != nil {
|
||||
for _, res := range old.Resources() {
|
||||
contract.Assert(res.HasID())
|
||||
contract.Assert(HasID(res))
|
||||
ctx.URNOldIDs[res.URN()] = res.ID()
|
||||
}
|
||||
}
|
||||
|
@ -97,6 +97,11 @@ func (s *snapshot) ResourceByObject(obj *rt.Object) Resource { return s.ctx.ObjR
|
|||
func createResources(ctx *Context, ns tokens.QName, heap *heapstate.Heap, resobjs []*rt.Object) ([]Resource, error) {
|
||||
var resources []Resource
|
||||
for _, resobj := range resobjs {
|
||||
// Make sure the URN doesn't already exist for this object.
|
||||
if urn, has := ctx.ObjURN[resobj]; has {
|
||||
contract.Failf("Object already assigned a URN '%v'; double allocation detected", urn)
|
||||
}
|
||||
|
||||
// Create an object resource without a URN.
|
||||
res := NewObjectResource(ctx, resobj)
|
||||
|
||||
|
|
|
@ -270,14 +270,15 @@ func (g *RPCGenerator) EmitResource(w *bufio.Writer, module tokens.Module, pkg *
|
|||
writefmtln(w, " ctx context.Context, req *lumirpc.CheckRequest) (*lumirpc.CheckResponse, error) {")
|
||||
writefmtln(w, " contract.Assert(req.GetType() == string(%vToken))", name)
|
||||
writefmtln(w, " obj, _, err := p.Unmarshal(req.GetProperties())")
|
||||
writefmtln(w, " if err == nil {")
|
||||
writefmtln(w, " if failures, err := p.ops.Check(ctx, obj); err != nil {")
|
||||
writefmtln(w, " return nil, err")
|
||||
writefmtln(w, " } else if len(failures) > 0 {")
|
||||
writefmtln(w, " err = resource.NewCheckError(failures)")
|
||||
writefmtln(w, " }")
|
||||
writefmtln(w, " if err != nil {")
|
||||
writefmtln(w, " return resource.NewCheckResponse(err), nil")
|
||||
writefmtln(w, " }")
|
||||
writefmtln(w, " return resource.NewCheckResponse(err), nil")
|
||||
writefmtln(w, " if failures, err := p.ops.Check(ctx, obj); err != nil {")
|
||||
writefmtln(w, " return nil, err")
|
||||
writefmtln(w, " } else if len(failures) > 0 {")
|
||||
writefmtln(w, " return resource.NewCheckResponse(resource.NewCheckError(failures)), nil")
|
||||
writefmtln(w, " }")
|
||||
writefmtln(w, " return resource.NewCheckResponse(nil), nil")
|
||||
writefmtln(w, "}")
|
||||
writefmtln(w, "")
|
||||
writefmtln(w, "func (p *%vProvider) Name(", name)
|
||||
|
|
Loading…
Reference in a new issue