Commit graph

6502 commits

Author SHA1 Message Date
joeduffy 40eeab646f Track dependency instantiations during binding phase 2 2016-12-01 16:09:12 -08:00
joeduffy 737efdac1b Fully bind transitive dependencies
This changes the way binding dependencies works slightly, to ensure that
the full transitive closure of dependencies is bound appropriately before
hitting code-generation.  Namely, now binder.PrepareStack returns a list
of unresolved dependency Refs; the compiler is responsible for turning this
into a map from Ref to the loaded diag.Document, before calling BindStack;
then, BindStack instantiates these as necessary (template expansion, etc),
returning an array of unbound *ast.Stacks that the compiler must then bind.
2016-12-01 15:39:58 -08:00
joeduffy 11f7f4963f Go back to glog.Fail
Well, it turns out glog.Fail is slightly better than panic, because it explicitly
dumps the stacks of *all* goroutines.  This is especially good in logging scenarios.
It's really annoying that glog suppresses printing the stack trace (see here
https://github.com/golang/glog/blob/master/glog.go#L719), however this is better.
2016-12-01 11:50:19 -08:00
joeduffy 3a7fa9a983 Use panic for fail-fast
This change switches away from using glog.Fatalf, and instead uses panic,
should a fail-fast arise (due to a call to util.Fail or a failed assertion
by way of util.Assert).  This leads to a better debugging experience no
matter what flags have been passed to glog.  For example, glog.Fatal* seems
to suppress printing stack traces when --logtostderr is supplied.
2016-12-01 11:43:41 -08:00
joeduffy 334615c6b1 Move parse-tree analysis into the Parse* functions
This change moves parse-tree analysis into the Parse* functions, so that
any callers doing parsing don't need to do this as a multi-step activity.
(We had neglected to do the parse-tree analysis phase during dependency
resolution, for example, meaning services were left untyped.)
2016-12-01 11:39:03 -08:00
joeduffy f5c8c926dc Eliminate recursive dependency analysis 2016-12-01 11:14:05 -08:00
joeduffy e9ca1bf0c0 Raise template loglevel from V(5) to V(7) 2016-12-01 11:13:39 -08:00
joeduffy 80b9e05735 Rename --arch (-a) build switch to --target (-t) 2016-12-01 11:03:48 -08:00
joeduffy 85b1b5fe0a Fix a YAML problem 2016-12-01 09:13:00 -08:00
joeduffy 9f2b737715 Clean up workspace file naming
This change makes workspace file naming a little more consistent with respect
to Mufile naming.  Instead of having a .mu/ directory, under which a workspace.yaml
and/or a stacks directory might exist, we now have a Muspace.yaml (or .json) file,
and a .Mudeps/ directory.  This has nicer symmetric with respect to Mu.yaml files.
2016-11-29 20:07:27 -08:00
joeduffy c9f7d44a30 Fix a type cast problem in aws/cf provider
...and also add better diagnostics to the associated error messages, so
that the "expected" type is printed in addition to the "got" type.
2016-11-29 15:33:43 -08:00
joeduffy cb9c152104 Permit passing stack properties via the CLI
If compiling a stack that accepts properties directly, we need a way to
pass arguments to that stack at the command line.  This change permits this
using the ordinary "--" style delimiter; for example:

        $ mu build -- --name=Foo

This is super basic and doesn't handle all the edge cases, but is sufficient
for testing and prototyping purposes.
2016-11-29 15:27:02 -08:00
joeduffy 68181fd0fd Eliminate <>s in cap names
I wasn't sure at first how we'd distinguish between strings and cap names.
At first, I thought we'd need special syntax, e.g. `<vpn>`; however, now I
am leaning towards a "type inference" approach, where we will interpret the
string as a cap name rather than string if that's what the target property
expects.  Although this isn't quite as explicitly typed, that's probably a
good thing in this case, as it eliminates verbosity and weird characters.
2016-11-29 14:48:55 -08:00
joeduffy b7b1c5a715 Add readonly annotations on relevant AWS properties 2016-11-29 14:36:07 -08:00
joeduffy bccda1ee29 Nit-rename a variable 2016-11-29 14:32:02 -08:00
joeduffy 787ece1058 Log stack properties (under v=7, extreme verbosity) 2016-11-29 14:31:31 -08:00
joeduffy 2238a95502 Add the notion of "perturbing" properties
This change introduces the notion of "perturbing" properties.  Changing
one of these impacts the live service, possibly leading to downtime.  As
such, we will likely encourage blue/green deployments of them just to be
safe.  Note that this is really just a placeholder so I can keep track of
metadata as we go, since AWS CF has a similar notion to this.

I'm not in love with the name.  I considered `interrupts`, however,
I must admit I liked that `readonly` and `perturbs` are symmetric in
the number of characters (meaning stuff lines up nicely...)
2016-11-29 14:29:34 -08:00
joeduffy 182ae190f1 Use Go template whitespace trimming on AWS templates
To avoid injecting needless whitespace -- which is unfortunately meaningful
in YAML -- we need to use the new "-" trimming operators, available in Go 1.6.
2016-11-29 14:22:09 -08:00
joeduffy c1b5239667 Detect target cloud earlier on
This change detects the target cloud earlier on in the compilation process.
Prior to this change, we didn't know this information until the backend code-generation.
Clearly we need to know this at least by then, however, templates can specialize on this
information, so we actually need it sooner.  This change moves it into the frontend part.

Note that to support this we now eliminate the ability to specify target clusters in
the Mufile alone.  That "feels" right to me anyway, since Mufiles are supposed to be
agnostic to their deployment environment, other than template specialization.  Instead,
this information can come from the CLI and/or the workspace settings file.
2016-11-29 13:42:39 -08:00
joeduffy 89d9269377 Bind dependencies that have no Stacks
In some cases, a dependency will resolve to a diag.Document, rather than
a fully instantiated ast.Stack (in fact, that is the common case).  The
binder needs to detect and tolerate this situation.
2016-11-29 13:04:36 -08:00
joeduffy e68ee3523d Project more EC2 Mu Stacks
This change projects several EC2 Mu stacks that are required for Mu cluster
bootstrapping.  This includes:

        - aws/ec2/internetGateway
        - aws/ec2/route
        - aws/ec2/routeTable
        - aws/ec2/securityGroup
        - aws/ec2/subnet
        - aws/ec2/vpc
        - aws/ec2/vpcGatewayAttachment

This is still not complete, and in fact some of these reference other EC2
Stacks that do not yet exist.  But we're getting a bit closer...
2016-11-29 12:37:52 -08:00
joeduffy 9326607c46 Add the notion of readonly properties
This change adds the notion of readonly properties to stacks.  Although these
*can* be "changed", doing so implies recreation of the resources all over again.
As a result, all dependents must be recreated, in a cascading manner.
2016-11-29 12:36:02 -08:00
joeduffy f9a1cf400e Add DependsOn support in CF template generation 2016-11-29 12:23:46 -08:00
joeduffy fb1a6ec4d2 Add a "require" template function
The "require" template function simply checks a condition and, if it
is false, issues an error and quits template processing immediately.
This is useful for concisely encoding validation logic.
2016-11-29 12:12:53 -08:00
joeduffy 6d3296b65f Permit explicit listing of properties to map
In some cases, we actually want to suppress auto-mapping for all or
most of the properties.  In those cases, it's easier to specify those
that we *do* want rather than the ones we *do not* want.  Now with
properties, skipProperties, and extraProperties, we have all the
necessary flexibility to control auto-mapping for CF templates.
2016-11-29 12:04:05 -08:00
joeduffy 4b58c862a4 Add a "has" template function
The new "has" function lets templates conveniently check the existence of
keys in property bag-like maps.  For example:

        {{if has .Properties "something"}}
                ...
        {{end}}
2016-11-29 11:43:20 -08:00
joeduffy 9a962b2014 Add skipProperties and extraProperties to aws/cf extension provider
Most properties in CF templates are auto-mapped by the aws/cf extension
provider.  However, sometimes we want to inject extra properties that are
outside of that auto-mapping (like our convenient shortcut for supplying
name to mean adding a "Name=v" tag).  And sometimes we want to skip auto-
mapping for certain properties (like our capability-based approach to
passing service references, versus string IDs).
2016-11-29 11:31:58 -08:00
joeduffy d722cc284f Inject the availability zone from cluster settings 2016-11-28 16:30:32 -08:00
joeduffy f511d30a37 Project the AWS::EC2::VPC resource type into Mu 2016-11-28 16:28:23 -08:00
joeduffy 6f572a6a5b Add an initial whack at a cluster Mufile
This change adds a super simple initial whack at a basic cluster topology
comprised of VPC, subnet, internet gateway, attachments, and route tables.
This is actually written in Mu itself, and I am committing this early, since
there are quite a few features required before we can actually make progress
getting this up and running.
2016-11-28 16:18:38 -08:00
joeduffy 9acfd18dc2 Add the target architecture to the rendering context
This allows templates to switch on the target cloud and do the right thing.
2016-11-28 15:15:49 -08:00
joeduffy 5233b2bcbe Add a "panic" template function
This introduces a "panic" template function, so that templates may abandon
evaluation if something unexpected occurs.  It accepts a string, indicating
the error, and optional arguments, if the string is to be formatted.

For example:

        {{if eq .Target "aws"}}
                ...
        {{else}}
                {{panic "Unrecognized cloud target: %v" .Target}}
        {{end}}
2016-11-28 14:56:43 -08:00
joeduffy 63ddbc6e7a Add an "include" template function
This lets YAML files include others, often conditionally, based on things
like the cloud target.  For example, I am currently using this to define the
overall cluster stack by doing things like:

        name: mu/cluster
        services:
        {{if eq .Target "aws"}}
                {{include "Mu-aws.yaml" | indent 4}}
        {{else}}
                ...
        {{end}}
2016-11-28 14:54:41 -08:00
joeduffy 1302fc8a47 Add rudimentary template expansion
This change performs template expansion both for root stack documents in
addition to the transitive closure of dependencies.  There are many ongoing
design and implementation questions about how this should actually work;
please see marapongo/mu#7 for a discussion of them.
2016-11-25 12:58:29 -08:00
joeduffy ffae234af0 Add a Mu.yaml to the MongoDB/Twilio example 2016-11-23 16:28:00 -08:00
joeduffy 6e77e0f462 Sketch out some cross-cloud abstraction thinking 2016-11-23 16:20:40 -08:00
joeduffy e37aa602c9 Add an aws/dynamodb/table type 2016-11-23 16:07:26 -08:00
joeduffy bbfbe61d43 Mention ln -s for the Mu runtime/library 2016-11-23 14:22:42 -08:00
joeduffy c1c43c7907 Use /usr/local/mu as the default install path 2016-11-23 14:18:18 -08:00
joeduffy 0d6208bb00 Simplify cf/template extension provider
For now, we can simply auto-map the Mu properties to CF properties,
eliminating the need to manually map them in the templates.  Eventually
we'll want more sophistication here to control various aspects of the CF
templates, but this eliminates a lot of tedious manual work in the meantime.
2016-11-23 14:16:35 -08:00
joeduffy a1660c1298 Add building and testing instructions 2016-11-23 12:41:30 -08:00
joeduffy 925ee92c60 Annotate a bunch of TODOs with work item numbers 2016-11-23 12:30:02 -08:00
joeduffy d26c1e395a Implement diag.Diagable on ast.Workspace and ast.Stack
The only two AST nodes that track any semblance of location right now
are ast.Workspace and ast.Stack.  This is simply because, using the standard
JSON and YAML parsers, we aren't given any information about the resulting
unmarshaled node locations.  To fix that, we'll need to crack open the parsers
and get our hands dirty.  In the meantime, we can crudely implement diag.Diagable
on ast.Workspace and ast.Stack, however, to simply return their diag.Documents.
2016-11-23 07:54:40 -08:00
joeduffy 2b385b2e20 Prepare for better diagnostics
This change adds a new Diagable interface from which you can obtain
a diagnostic's location information (Document and Location).  A new
At function replaces WithDocument, et al., and will be used soon to
permit all arbitrary AST nodes to report back their position.
2016-11-23 07:44:03 -08:00
joeduffy e02921dc35 Finish dependency and type binding
This change completes the implementation of dependency and type binding.
The top-level change here is that, during the first semantic analysis AST walk,
we gather up all unknown dependencies.  Then the compiler resolves them, caching
the lookups to ensure that we don't load the same stack twice.  Finally, during
the second and final semantic analysis AST walk, we populate the bound nodes
by looking up what the compiler resolved for us.
2016-11-23 07:26:45 -08:00
joeduffy c478ffbe40 Preserve blank ""s in RefParts
This changes the logic when parsing RefParts so that we can actually
round-trip them faithfully when required.  To do this, by default we
preserve blank ""s in the RefPart fields that are legally omitted from
the Ref string.  Then, there is a Defaults() method that can populate
the missing fields with the defaults if desired.
2016-11-22 17:24:49 -08:00
joeduffy 12eb91bcbb Fix a typo that crept in 2016-11-22 17:07:10 -08:00
joeduffy c84512510a Implement dependency versions
This change implements dependency versions, including semantic analysis, per the
checkin 83030685c3.

There's quite a bit in here but at a top-level this parses and validates dependency
references of the form

        [[proto://]base.url]namespace/.../name[@version]

and verifies that the components are correct, as well as binding them to symbols.

These references can appear in two places at the moment:

* Service types.
* Cluster dependencies.

As part of this change, a number of supporting changes have been made:

* Parse Workspaces using a full-blown parser, parser analysis, and semantic analysis.
  This allows us to share logic around the validation of common AST types.  This also
  moves some of the logic around loading workspace.yaml files back to the parser, where
  it can be unified with the way we load Mu.yaml files.

* New ast.Version and ast.VersionSpec types.  The former represents a precise version
  -- either a specific semantic version or a short or long Git SHA hash -- and the
  latter represents a range -- either a Version, "latest", or a semantic range.

* New ast.Ref and ast.RefParts types.  The former is an unparsed string that is
  thought to contain a Ref, while the latter is a validated Ref that has been parsed
  into its components (Proto, Base, Name, and Version).

* Added some type assertions to ensure certain structs implement certain interfaces,
  to speed up finding errors.  (And remove the coercions that zero-fill vtbl slots.)

* Be consistent about prefixing error types with Error or Warning.

* Organize the core compiler driver's logic into three methods, FE, sema, and BE.

* A bunch of tests for some of the above ...  more to come in an upcoming change.
2016-11-22 16:58:23 -08:00
joeduffy 83030685c3 Articulate how dependency versioning works
I've gone backwards and forwards on the design for dependency version
management.  However, I think what's written in this commit represents
a pretty sane "sweet spot" between all available options.

In a nutshell, anytime reference to a stack type in your Mufile is a
full-blown StackRef; in other words, it has a protocol (e.g., "https://"),
a base URL (e.g., "hub.mu.com/"), a name (e.g., "aws/s3/bucket"), and a
version ("@^1.0.6").  Each reference carries all of these components.

For convenience, you may omit the components.  In that case, Mu chooses
reasonable defaults:

* "https://" as the default protocol (or "git://"; this is TBD).
* "hub.mu.com/" as the default base URL.
* "@latest" as the default version number.

Note that a version can be "latest" to mean "tip", a specific SHA hash
to pin to a precise version, or a semantic version number/range.

I had originally shied away from specifying versions inline as you reference
stacks in your Mufile, and was leaning towards an explicit dependencies
section, however I was swayed for two reasons:

1. It's very common to only consume a given stack once in a file.  Needing
   to specify it in two places each time is verbose and violates DRY.

2. We have decided that each Mufile stands on its own and forms the unit
   of distribution.  I had previously thought we might move dependencies
   out of Mufiles into a "package manager" specification.  Lacking that,
   there is even less reason to call them out in a dedicated section.

Now, managing all these embedded version numbers across multiple stacks in
a single workspace would have been annoying.  (Many edits for a single
version bump.)  Instead, I've added provisions for storing this in your
workspace.yaml file.  The way it works is if any StackRef lacks a version
number, before defaulting to "@latest" we check the workspace.yaml file and,
if a default is found in there, we will use it.  For example:

        dependencies:
                aws/s3/bucket: ^1.0.6

The provision for pinning an entire namespace is also preserved.  E.g.:

        dependencies:
                aws/...: ^1.0.6
2016-11-22 13:22:29 -08:00
joeduffy 6f99088e2b Add scaffolding for the AWS ECS scheduler backend
Right now, the AWS ECS scheduler simply passes through to the underlying
AWS cloud provider.  However, now we have the necessary hooks to start
incrementally recognizing stack types and emitting specialized code for
them (e.g., starting with mu/container).
2016-11-22 12:37:14 -08:00