Commit graph

143 commits

Author SHA1 Message Date
joeduffy
5bf43743ab Add a rudimentary toString runtime helper
This just works around some limitations that will exist until
we do the runtime work next sprint, and achieve pulumi/lumi#169.
2017-07-17 13:43:59 -07:00
joeduffy
ee1acd365c Add a defaultIfComputed intrinsic
Until we support output-conditional code (pulumi/lumi#170), we
run into cases where we want to make a decision based on a computed
property if it is available, but can't possible know the value.  In
such cases, we get an error ("Unexpected computed value").

In fact, our generated code currently includes client side validation
of properties, since it leads to a(n admittedly only slightly) better
developer experience.  But that triggers the error for required
properties that are computed, basically hosing our ability to plan.

This change introduces a defaultIfComputed intrinsic to the lumirt
library that can be used to work around this.  It takes two arguments,
obj and def, and returns the actual property value obj if it is NOT
computed; if it is computed, def will be substituted in its stead.

The generated code changes to use this.  It's possible it will miss
validation, of course, if a computed property turns out not to match
the precondition.  But this is strictly better than the alternative
of not trying to validate any of them to begin with.
2017-07-16 15:16:48 -07:00
Luke Hoban
0b24ab7070 Serialize lambdas nested in captured objects
Adds support for serializing lambdas which are
properties of captured objects.

For example:

```
let o = {
  f: () => 12
};
let func = new aws.serverless.Function("func", {policies: [aws.iam.AWSLambdaFullAccess]}, (ev, ctx, cb) => {
    console.log(o.f());
    cb(null, null);
});
```
2017-07-12 17:43:17 -07:00
Luke Hoban
ac21b5bd82 Add test for serializeClosure 2017-07-12 15:19:20 -07:00
Luke Hoban
15be6850a2 Support cycles and avoid name collisions in closure serialization
Generate names for serialized functions as hashes of the function text, and
bind these to the actual referenced names locally to each serialized closure.
This avoids potential conflicts between different functions which are referenced
with the same name.

For example:
```
function __8c176d768f95567f8c3acd08e486a1da7299fbc1() {
  with({ f: __e61452ceb9d53f3611ed543f3822a85ad29345dd}) {
    return (() => {

return function (cb) { cb(null, f(7)); };

    })().apply(this, arguments);
  }
}
```

Also fixes the stack overflows when there are cycles in the Closure graph by
adding caches of serialized functions.

Fixes #238.
2017-07-12 12:49:04 -07:00
Luke Hoban
829b977bcf Support try/catch in Lumi and async/await in Node.js
We would like to allow developers to use async/await
on the inside (Node.js) of Lumi programs.

We now support (don't error on) usage of async/await
inside runtime callbacks in Lumi programs.  If await is
used during deployment, it will trigger an error.

Also adds support for try/catch in LumiJS, as these are
used more heavily in async/await code.

Since we target Node.js environments without native support
for async/await, we also emit runtime helpers to support TS
transpilation of async/await for Node.js pre-7.6.
2017-07-07 12:47:27 -07:00
joeduffy
24fd8e8f4a Add cancellation to interpreter
This properly unwinds the interpreter should something happen that
results in cancellation.  This occurs, for example, when the planning
engine encounters an error and decides that it doesn't need to proceed
further with evaluation before it simply goes ahead and exits.
2017-06-27 11:31:17 -07:00
joeduffy
2daea4c3d8 Clarify aspects of using the DCO 2017-06-26 14:46:34 -07:00
joeduffy
3c1041af49 Update license headers 2017-06-23 14:53:41 -07:00
joeduffy
8b57310854 Tidy up more lint
This change fixes a few things:

* Most importantly, we need to place a leading "." in the paths
  to Gometalinter, otherwise some sub-linters just silently skip
  the directory altogether.  errcheck is one such linter, which
  is a very important one!

* Use an explicit Gometalinter.json file to configure the various
  settings.  This flips on a few additional linters that aren't
  on by default (line line length checking).  Sadly, a few that
  I'd like to enable take waaaay too much time, so in the future
  we may consider a nightly job (this includes code similarity,
  unused parameters, unused functions, and others that generally
  require global analysis).

* Now that we're running more, however, linting takes a while!
  The core Lumi project now takes 26 seconds to lint on my laptop.
  That's not terrible, but it's long enough that we don't want to
  do the silly "run them twice" thing our Makefiles were previously
  doing.  Instead, we shall deploy some $$($${PIPESTATUS[1]}-1))-fu
  to rely on the fact that grep returns 1 on "zero lines".

* Finally, fix the many issues that this turned up.

I think(?) we are done, except, of course, for needing to drive
down some of the cyclomatic complexity issues (which I'm possibly
going to punt on; see pulumi/lumi#259 for more details).
2017-06-22 12:09:46 -07:00
joeduffy
7fe8052941 Fix some lint in our lint
After 233c5a8 landed, I noticed there are a few things to be fixed up:

    * Run gometalinter in all the right places.  We need to run both in
      lint and lint_quiet targets.  I've also cleaned up some of the logic
      around what to suppress so there's less repetition.

    * We currently @ meaningful commands, which is unfortunate, since it
      makes debugging Makefiles tough (especially when looking at CI build
      logs).  Going forward, we should only use @ for meaningless commands,
      like @echo.

    * The AWS project wasn't actually running tslint, because it needs to
      say `tslint './pack/**/*.ts' --exclude='./pack/node_modules/**'`.
      The current script of `tslint lib/aws/pack/...` wasn't actually
      running lint, hence we missed a lot of AWS lint issues.

    * Fix up the issues that these fixes uncovered.  Mostly err shadowing.
2017-06-21 13:24:35 -07:00
joeduffy
e5f229aad8 Use Location.Read from plugin host
This addresses CR feedback from @lukehoban; namely, that we should
be going through the Read API for location reads in the plugin host
to ensure that getters are invoked as appropriate.

I also made Location's various fields private so that we aren't
tempted to make this mistake elsewhere, effectively "forcing" us
to go through the accessor methods.
2017-06-21 08:43:05 -07:00
joeduffy
d7093188f0 Introduce an interface to read config
This change adds an engine gRPC interface, and associated implementation,
so that plugins may do interesting things that require "phoning home".
Previously, the engine would fire up plugins and talk to them directly,
but there was no way for a plugin to ask the engine to do anything.

The motivation here is so that plugins can read evaluator state, such
as config information, but this change also allows richer logging
functionality than previously possible.  We will still auto-log any
stdout/stderr writes; however, explicit errors, warnings, informational,
and even debug messages may be written over the Log API.
2017-06-20 19:45:07 -07:00
Luke Hoban
6b1fbe9ba0 Fix intrinsics tets
The previous change broke the intrinsics tests in the
case that the `lumirt` package was not installed on
the system (which is the case in Travis given our build
order).

Reverting to the previous pattern of creating a fake
`lumirt` package to run the tests in to avoid the
dependency on an externally installed `lumirt`.
2017-06-20 11:07:13 -07:00
Luke Hoban
6b7616ce1a Merge branch 'master' of https://github.com/pulumi/lumi 2017-06-20 10:30:27 -07:00
Luke Hoban
8d80871712 Fix string quoting in jsonStringify
Implements correct QuoteJSONString behaviour per ECMAScript
spec.

Also refactors intrinsic test harness to make it easier to add new
intrinsics tests going forward.
2017-06-20 10:29:53 -07:00
joeduffy
26cf93f759 Implement get functions on all resources
This change implements the `get` function for resources.  Per pulumi/lumi#83,
this allows Lumi scripts to actually read from the target environment.

For example, we can now look up a SecurityGroup from its ARN:

    let group = aws.ec2.SecurityGroup.get(
        "arn:aws:ec2:us-west-2:153052954103:security-group:sg-02150d79");

The returned object is a fully functional resource object.  So, we can then
link it up with an EC2 instance, for example, in the usual ways:

    let instance = new aws.ec2.Instance(..., {
        securityGroups: [ group ],
    });

This didn't require any changes to the RPC or provider model, since we
already implement the Get function.

There are a few loose ends; two are short term:

    1) URNs are not rehydrated.
    2) Query is not yet implemented.

One is mid-term:

    3) We probably want a URN-based lookup function.  But we will likely
       wait until we tackle pulumi/lumi#109 before adding this.

And one is long term (and subtle):

    4) These amount to I/O and are not repeatable!  A change in the target
       environment may cause a script to generate a different plan
       intermittently.  Most likely we want to apply a different kind of
       deployment "policy" for such scripts.  These are inching towards the
       scripting model of pulumi/lumi#121, which is an entirely different
       beast than the repeatable immutable infrastructure deployments.

Finally, it is worth noting that with this, we have some of the fundamental
underpinnings required to finally tackle "inference" (pulumi/lumi#142).
2017-06-19 17:29:02 -07:00
joeduffy
7f710a241f Better handle errors during config apply 2017-06-16 15:37:58 -07:00
joeduffy
34ea2e8e43 Rewrite some binop code to share more logic
Also add some logging to help diagnose some issues I was running into.
2017-06-15 17:29:51 -07:00
joeduffy
e26f934aec Propagate computed values in assignments
This change fixes an issue with the way we deal with computed values in
assignments.  Specifically, the assignment expression should resolve to
the computed value itself, but it must actually perform the assignment!
Previously, we evaluated to the right thing, but skipped the assignment.
2017-06-15 17:04:16 -07:00
Luke Hoban
ae03d69645 Wire up APIs to lambdas using output properties
We now have enough output properties implementation
working to change our API gateway examples and API
wrapper to correctly wire the API routes to the ARNs of
lambdas passed in to them.

We both wire up the lambda to the route, but also create
a permission specific to each route to assign to the
corresponding lambda - providing least privelege needed
for the API definition.

Also adds `string#toUpperCase` and fixes NewUniqueHex
to match how we are using it.
2017-06-15 16:01:00 -07:00
joeduffy
b7a3b28734 Implement array push and pop
This implements array push and pop as intrinsics.

Also:

* Tighten up some assertions while I'm in here.

* Default initialize pointer slots to Null, if not done explicitly.
2017-06-15 14:51:57 -07:00
joeduffy
2ac303f703 Fix deployment hang (pulumi/lumi#246)
The recent change to run the interpreter and planner on separate goroutines
created the need to perform rendezvous-style synchronization between them.
Although the case of an invoked function properly tore down the synchronization
by communicating the error, we seldom directly invoke functions for JavaScript
programs because the way module entrypoint code ends up in initializers.
This requires that we propagate errors correctly out of module and class
initializers, in the standard way, so that the unwind makes its way to the top.

This fixes pulumi/lumi#246.
2017-06-14 15:52:36 -07:00
joeduffy
3a899b304e Fix empty body issues
We recently changed the Resource base type to have no constructor,
rather than a manual empty constructor.  This ought to work just fine.
The LumiJS compiler indeed generates a constructor, however, it is
missing a body and when the interpreter tries to invoke it, we crash
with a nil reference panic.  The runtime actually tolerates missing
constructors entirely, although the way LumiJS binds super calls
doesn't tolerate the missing base constructor.  This change simply
generates such constructors in LumiJS with empty bodies.

In addition, I've added an error that will catch the empty body
problem during binding, since technically speaking, all functions
must have bodies.  (Our runtime happens to support the notion of
"abstract", however, so we only fire the error on concrete functions.)
2017-06-14 10:30:46 -07:00
joeduffy
a42b40f1a8 Refactor runtime functionality
This change splits the core Lumi library -- which is meant to be a pure
LumiJS library without any special status -- from the runtime library --
which is really meant to be the underpinnings of "special" functionality
that integrates with the runtime in sophisticated ways.

After this change, LumiRT is at the very bottom, and, despite it using
a subset of LumiJS, it must not trigger any functionality that would
mandate the use of the LumiJS runtime library.  Atop that, the LumiJS
library is layered.  And finally, above that, Lumi depends on LumiJS.
2017-06-13 18:11:59 -07:00
Luke Hoban
282f40d3e3 Merge branch 'master' into bforsyth927-gometalinter 2017-06-13 16:28:12 -07:00
joeduffy
01bbc23144 Only mark immediate outputs as outputs
The primary purposes of this change is to mark only immediate ouptuts
on a resource object as "output" and categories the rest as computed.

It also contains a few minor things:

    * Rebase atop the latest in master.

    * Always marshal unknows as their default value.

    * Permit computed as the existing ID property, in addition to null.

    * Tidy up some asserts.
2017-06-13 07:10:13 -07:00
joeduffy
9d73c54994 Run post-construction hooks before freezing
We need to run the post-construction hook *before* freezing an object's
readonly properties, since the hook will actually mutate the object in
the case of a deployment (it stores the output properties).  In a sense,
this hook simply becomes an extension of the object's constructor.
2017-06-13 07:10:13 -07:00
joeduffy
d1414af321 Fix a few minor things; clean stuff up
* Assert new things in new places.

* Log more interesting tidbits during evaluation.

* Invoke the OnStart hook before triggering initializers.

* Tolerate nil prev snapshots during deletion calculation.

* Handle and serialize missing resource IDs as output props.

* Return "done" flag from Rendezvous.Meet.
2017-06-13 07:10:13 -07:00
joeduffy
d277dd5800 More progress on pulumi/lumi#90
This change refactors a number of aspects of the CLI's treatment of
steps, in line with the new scheme, and a number of other miscellaneous
and minor fixes.  It also regenerates all RPC code impacted by recent renames.
2017-06-13 07:10:13 -07:00
joeduffy
6b2408e086 Rewrite plans and deployments
This change guts the deployment planning and execution process, a
necessary component of pulumi/lumi#90.

The major effect of this change is that resources are actually
connected to the live objects, instead of being snapshots taken at
inopportune moments in time.
2017-06-13 07:10:13 -07:00
Luke Hoban
9bd441be05 Support for nested lambdas and node_modules
LumiJS lambdas can now be serialized when they include calls to other LumiJS lambdas.  The chain of lambda dependencies is jointly serialized into the target Lambda.

Also, LumiJS lambdas now include `node_modules` automatically in the AWS Lambda, ensuring the the runtime execution environment more closely matches the deployment time environment.

An early version of the gh-cicd example supporting #134 is added which uses these capabilities, currently including a mocked GitHub resource provider.
2017-06-12 10:15:20 -07:00
Britton Forsyth
69e4834f63 Merge branch 'master' into gometalinter 2017-06-09 14:34:51 -07:00
Luke Hoban
e87d21cb80 Store module object on Functions
We now store the module object instead of the
symbol on function stubs.
2017-06-09 10:23:07 -07:00
Luke Hoban
7171b58459 Address PR feedback on #229 2017-06-09 10:15:03 -07:00
Luke Hoban
d77c51ff7f Allow runtime lambda to reference globals.
For lambdas which will execute at runtime,
we want to allow them to reference Node.js
global variables, like `console`.

This change makes Lumijs generated IL
incrementally more dynamic by preferring to
generate `TryLoadDynamic` over `LoadLocation`
for references to global variables (except for
references to imports).

Also introduces `console.log` in LumiJS, though
it is not yet attached to a Lumi global environment.

Fixes #174.
2017-06-08 22:06:41 -07:00
Luke Hoban
e838c6ff2d Allow lambdas to capture reference to module scope variables
The scope chain currently does not include module-scope
vairables, which are instead stored on a module object.  For
now, we are capturing this module object along with the
scope chain as part of a Lambda object so that we can use
it when evaluating variable references within a lambda
expression.

Fixes #175.
2017-06-08 15:56:50 -07:00
Luke Hoban
ae9730bad3 Only capture free variables in lambda environment
Introduces a free variable AST visitor, and uses this to limit
the environment exposed by the `serizlizeClosure` intrinsic
to only those variables that are referenced by the lambda body.

Fixes #177.
2017-06-08 11:55:24 -07:00
Britton Forsyth
3066fcda78 Implemented suggested edits 2017-06-08 11:44:16 -07:00
Britton Forsyth
7457cadf58 Fixed various additional linting issues 2017-06-08 10:21:17 -07:00
joeduffy
dce2fae4c2 Track implicated objects
This change begins to track objects that are implicated in the
creation of computed values.  This ultimately translates into the
resource URNs which are used during dependency analysis and
serialization.  This is part of pulumi/lumi#90.
2017-06-08 06:46:28 -07:00
joeduffy
ec2b964daa Do an initial pass over TODOs
This scrubs about 80% of our TODOs, as part of pulumi/lumi#212.
The remaining 20% will come shortly.
2017-06-05 18:11:51 -07:00
joeduffy
87004a124e Store both input and output properties distinctly
This changes the resource model to persist input and output properties
distinctly, so that when we diff changes, we only do so on the programmer-
specified input properties.  This eliminates problems when the outputs
differ slightly; e.g., when the provider normalizes inputs, adds its own
values, or fails to produce new values that match the inputs.

This change simultaneously makes progress on pulumi/lumi#90, by beginning
tracking the resource objects implicated in a computed property's value.

I believe this fixes both #189 and #198.
2017-06-04 19:24:48 -07:00
Luke Hoban
26a2f95c48 Support output properties on aws.apigateway APIs 2017-06-04 10:19:04 -07:00
Luke Hoban
92a9925201 Merge branch 'master' into apigateway 2017-06-03 14:58:23 -07:00
joeduffy
e2cb211d93 Enable parallel tests
This change enables parallelism for our tests.

It also introdues a `test_core` Makefile target to just run the
core engine tests, and not the providers, since they take a long time.
This is intended only as part of the inner developer loop.
2017-06-01 14:01:26 -07:00
Luke Hoban
c117b43ae4 Update serverless API programming model
Updates  the higher level AWS APIGateway programming model
in aws.serverless.API  to use an Express-like imperative API.
2017-06-01 10:54:26 -07:00
joeduffy
7f98387820 Distinguish between computed and output properties
This change introduces the notion of a computed versus an output
property on resources.  Technically, output is a subset of computed,
however it is a special kind that we want to treat differently during
the evaluation of a deployment plan.  Specifically:

* An output property is any property that is populated by the resource
  provider, not code running in the Lumi type system.  Because these
  values aren't available during planning -- since we have not yet
  performed the deployment operations -- they will be latent values in
  our runtime and generally missing at the time of a plan.  This is no
  problem and we just want to avoid marshaling them in inopportune places.

* A computed property, on the other hand, is a different beast altogehter.
  Although true one of these is missing a value -- by virtue of the fact
  that they too are latent values, bottoming out in some manner on an
  output property -- they will appear in serializable input positions.
  Not only must we treat them differently during the RPC handshake and
  in the resource providers, but we also want to guarantee they are gone
  by the time we perform any CRUD operations on a resource.  They are
  purely a planning-time-only construct.
2017-06-01 08:36:43 -07:00
joeduffy
706acb5fd8 Tolerate latent values in more places 2017-06-01 08:32:12 -07:00
joeduffy
d79c41f620 Initial support for output properties (1 of 3)
This change includes approximately 1/3rd of the change necessary
to support output properties, as per pulumi/lumi#90.

In short, the runtime now has a new hidden type, Latent<T>, which
represents a "speculative" value, whose eventual type will be T,
that we can use during evaluation in various ways.  Namely,
operations against Latent<T>s generally produce new Latent<U>s.

During planning, any Latent<T>s that end up in resource properties
are transformed into "unknown" property values.  An unknown property
value is legal only during planning-time activities, such as Check,
Name, and InspectChange.  As a result, those RPC interfaces have
been updated to include lookaside maps indicating which properties
have unknown values.  My intent is to add some helper functions to
make dealing with this circumstance more correct-by-construction.

For now, using an unresolved Latent<T> in a conditional will lead
to an error.  See pulumi/lumi#67.  Speculating beyond these -- by
supporting iterative planning and application -- is something we
want to support eventually, but it makes sense to do that as an
additive change beyond this initial support.  That is a missing 1/3.

Finally, the other missing 1/3rd which will happen much sooner
than the rest is restructuing plan application so that it will
correctly observe resolution of Latent<T> values.  Right now, the
evaluation happens in one single pass, prior to the application, and
so Latent<T>s never actually get witnessed in a resolved state.
2017-06-01 08:32:12 -07:00