2016-11-15 20:30:34 +01:00
|
|
|
// Copyright 2016 Marapongo, Inc. All rights reserved.
|
|
|
|
|
|
|
|
package compiler
|
|
|
|
|
|
|
|
import (
|
|
|
|
"github.com/golang/glog"
|
Sketch out more AWS backend code-generator bits and pieces
This change includes a few steps towards AWS backend code-generation:
* Add a BoundDependencies property to ast.Stack to remember the *ast.Stack
objects bound during Stack binding.
* Make a few CloudFormation properties optional (cfOutput Export/Condition).
* Rename clouds.ArchMap, clouds.ArchNames, schedulers.ArchMap, and
schedulers.ArchNames to clouds.Values, clouds.Names, schedulers.Values,
and schedulers.Names, respectively. This reads much nicer to my eyes.
* Create a new anonymous ast.Target for deployments if no specific target
was specified; this is to support quick-and-easy "one off" deployments,
as will be common when doing local development.
* Sketch out more of the AWS Cloud implementation. We actually map the
Mu Services into CloudFormation Resources; well, kinda sorta, since we
don't actually have Service-specific logic in here yet, however all of
the structure and scaffolding is now here.
2016-11-19 01:46:36 +01:00
|
|
|
"github.com/satori/go.uuid"
|
2016-11-15 20:30:34 +01:00
|
|
|
|
Add cloud target and architecture detection
This change implements most of the cloud target and architecture detection
logic, along with associated verification and a bunch of new error messages.
There are two settings for picking a cloud destination:
* Architecture: this specifies the combination of cloud (e.g., AWS, GCP, etc)
plus scheduler (e.g., none, Swarm, ECS, etc).
* Target: a named, preconfigured entity that includes both an Architecture and
an assortment of extra default configuration options.
The general idea here is that you can preconfigure a set of Targets for
named environments like "prod", "stage", etc. Those can either exist in a
single Mufile, or the Mucluster file if they are shared amongst multiple
Mufiles. This can be specified at the command line as such:
$ mu build --target=stage
Furthermore, a given environment may be annointed the default, so that
$ mu build
selects that environment without needing to say so explicitly.
It is also possible to specify an architecture at the command line for
scenarios where you aren't intending to target an existing named environment.
This is good for "anonymous" testing scenarios or even just running locally:
$ mu build --arch=aws
$ mu build --arch=aws:ecs
$ mu build --arch=local:kubernetes
$ .. and so on ..
This change does little more than plumb these settings around, verify them,
etc., however it sets us up to actually start dispating to the right backend.
2016-11-17 19:30:37 +01:00
|
|
|
"github.com/marapongo/mu/pkg/ast"
|
2016-11-18 21:40:15 +01:00
|
|
|
"github.com/marapongo/mu/pkg/compiler/backends"
|
|
|
|
"github.com/marapongo/mu/pkg/compiler/backends/clouds"
|
|
|
|
"github.com/marapongo/mu/pkg/compiler/backends/schedulers"
|
2016-11-17 17:52:54 +01:00
|
|
|
"github.com/marapongo/mu/pkg/compiler/core"
|
2016-11-15 20:30:34 +01:00
|
|
|
"github.com/marapongo/mu/pkg/diag"
|
|
|
|
"github.com/marapongo/mu/pkg/errors"
|
|
|
|
"github.com/marapongo/mu/pkg/workspace"
|
|
|
|
)
|
|
|
|
|
|
|
|
// Compiler provides an interface into the many phases of the Mu compilation process.
|
|
|
|
type Compiler interface {
|
2016-11-17 17:52:54 +01:00
|
|
|
core.Phase
|
2016-11-16 18:29:44 +01:00
|
|
|
|
2016-11-16 02:42:22 +01:00
|
|
|
// Context returns the current compiler context.
|
Add cloud target and architecture detection
This change implements most of the cloud target and architecture detection
logic, along with associated verification and a bunch of new error messages.
There are two settings for picking a cloud destination:
* Architecture: this specifies the combination of cloud (e.g., AWS, GCP, etc)
plus scheduler (e.g., none, Swarm, ECS, etc).
* Target: a named, preconfigured entity that includes both an Architecture and
an assortment of extra default configuration options.
The general idea here is that you can preconfigure a set of Targets for
named environments like "prod", "stage", etc. Those can either exist in a
single Mufile, or the Mucluster file if they are shared amongst multiple
Mufiles. This can be specified at the command line as such:
$ mu build --target=stage
Furthermore, a given environment may be annointed the default, so that
$ mu build
selects that environment without needing to say so explicitly.
It is also possible to specify an architecture at the command line for
scenarios where you aren't intending to target an existing named environment.
This is good for "anonymous" testing scenarios or even just running locally:
$ mu build --arch=aws
$ mu build --arch=aws:ecs
$ mu build --arch=local:kubernetes
$ .. and so on ..
This change does little more than plumb these settings around, verify them,
etc., however it sets us up to actually start dispating to the right backend.
2016-11-17 19:30:37 +01:00
|
|
|
Context() *core.Context
|
2016-11-16 02:42:22 +01:00
|
|
|
|
2016-11-15 20:30:34 +01:00
|
|
|
// Build detects and compiles inputs from the given location, storing build artifacts in the given destination.
|
|
|
|
Build(inp string, outp string)
|
2016-11-18 00:13:36 +01:00
|
|
|
// BuildFile uses the given Mufile directly, and stores build artifacts in the given destination.
|
|
|
|
BuildFile(mufile []byte, ext string, outp string)
|
2016-11-15 20:30:34 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// compiler is the canonical implementation of the Mu compiler.
|
|
|
|
type compiler struct {
|
Add cloud target and architecture detection
This change implements most of the cloud target and architecture detection
logic, along with associated verification and a bunch of new error messages.
There are two settings for picking a cloud destination:
* Architecture: this specifies the combination of cloud (e.g., AWS, GCP, etc)
plus scheduler (e.g., none, Swarm, ECS, etc).
* Target: a named, preconfigured entity that includes both an Architecture and
an assortment of extra default configuration options.
The general idea here is that you can preconfigure a set of Targets for
named environments like "prod", "stage", etc. Those can either exist in a
single Mufile, or the Mucluster file if they are shared amongst multiple
Mufiles. This can be specified at the command line as such:
$ mu build --target=stage
Furthermore, a given environment may be annointed the default, so that
$ mu build
selects that environment without needing to say so explicitly.
It is also possible to specify an architecture at the command line for
scenarios where you aren't intending to target an existing named environment.
This is good for "anonymous" testing scenarios or even just running locally:
$ mu build --arch=aws
$ mu build --arch=aws:ecs
$ mu build --arch=local:kubernetes
$ .. and so on ..
This change does little more than plumb these settings around, verify them,
etc., however it sets us up to actually start dispating to the right backend.
2016-11-17 19:30:37 +01:00
|
|
|
ctx *core.Context
|
2016-11-15 20:30:34 +01:00
|
|
|
opts Options
|
|
|
|
}
|
|
|
|
|
|
|
|
// NewCompiler creates a new instance of the Mu compiler, with the given initialization settings.
|
|
|
|
func NewCompiler(opts Options) Compiler {
|
2016-11-16 02:42:22 +01:00
|
|
|
return &compiler{
|
Add cloud target and architecture detection
This change implements most of the cloud target and architecture detection
logic, along with associated verification and a bunch of new error messages.
There are two settings for picking a cloud destination:
* Architecture: this specifies the combination of cloud (e.g., AWS, GCP, etc)
plus scheduler (e.g., none, Swarm, ECS, etc).
* Target: a named, preconfigured entity that includes both an Architecture and
an assortment of extra default configuration options.
The general idea here is that you can preconfigure a set of Targets for
named environments like "prod", "stage", etc. Those can either exist in a
single Mufile, or the Mucluster file if they are shared amongst multiple
Mufiles. This can be specified at the command line as such:
$ mu build --target=stage
Furthermore, a given environment may be annointed the default, so that
$ mu build
selects that environment without needing to say so explicitly.
It is also possible to specify an architecture at the command line for
scenarios where you aren't intending to target an existing named environment.
This is good for "anonymous" testing scenarios or even just running locally:
$ mu build --arch=aws
$ mu build --arch=aws:ecs
$ mu build --arch=local:kubernetes
$ .. and so on ..
This change does little more than plumb these settings around, verify them,
etc., however it sets us up to actually start dispating to the right backend.
2016-11-17 19:30:37 +01:00
|
|
|
ctx: &core.Context{},
|
2016-11-16 02:42:22 +01:00
|
|
|
opts: opts,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Add cloud target and architecture detection
This change implements most of the cloud target and architecture detection
logic, along with associated verification and a bunch of new error messages.
There are two settings for picking a cloud destination:
* Architecture: this specifies the combination of cloud (e.g., AWS, GCP, etc)
plus scheduler (e.g., none, Swarm, ECS, etc).
* Target: a named, preconfigured entity that includes both an Architecture and
an assortment of extra default configuration options.
The general idea here is that you can preconfigure a set of Targets for
named environments like "prod", "stage", etc. Those can either exist in a
single Mufile, or the Mucluster file if they are shared amongst multiple
Mufiles. This can be specified at the command line as such:
$ mu build --target=stage
Furthermore, a given environment may be annointed the default, so that
$ mu build
selects that environment without needing to say so explicitly.
It is also possible to specify an architecture at the command line for
scenarios where you aren't intending to target an existing named environment.
This is good for "anonymous" testing scenarios or even just running locally:
$ mu build --arch=aws
$ mu build --arch=aws:ecs
$ mu build --arch=local:kubernetes
$ .. and so on ..
This change does little more than plumb these settings around, verify them,
etc., however it sets us up to actually start dispating to the right backend.
2016-11-17 19:30:37 +01:00
|
|
|
func (c *compiler) Context() *core.Context {
|
2016-11-16 02:42:22 +01:00
|
|
|
return c.ctx
|
2016-11-15 20:30:34 +01:00
|
|
|
}
|
|
|
|
|
2016-11-16 01:30:10 +01:00
|
|
|
func (c *compiler) Diag() diag.Sink {
|
|
|
|
return c.opts.Diag
|
2016-11-15 20:30:34 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
func (c *compiler) Build(inp string, outp string) {
|
2016-11-16 01:30:10 +01:00
|
|
|
glog.Infof("Building target '%v' (out='%v')", inp, outp)
|
2016-11-17 22:08:20 +01:00
|
|
|
|
|
|
|
// First find the root of the current package based on the location of its Mufile.
|
2016-11-21 18:23:39 +01:00
|
|
|
w, err := workspace.New(inp, c.Diag())
|
|
|
|
if err != nil {
|
|
|
|
c.Diag().Errorf(errors.IOError.WithFile(inp), err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
mufile, err := w.DetectMufile()
|
|
|
|
if err != nil {
|
|
|
|
c.Diag().Errorf(errors.IOError.WithFile(inp), err)
|
|
|
|
return
|
|
|
|
}
|
2016-11-17 22:08:20 +01:00
|
|
|
if mufile == "" {
|
|
|
|
c.Diag().Errorf(errors.MissingMufile, inp)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// Read in the contents of the document and make it available to subsequent stages.
|
|
|
|
doc, err := diag.ReadDocument(mufile)
|
|
|
|
if err != nil {
|
|
|
|
c.Diag().Errorf(errors.CouldNotReadMufile.WithFile(mufile), err)
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
c.buildDocument(doc, outp)
|
|
|
|
}
|
|
|
|
|
2016-11-18 00:13:36 +01:00
|
|
|
func (c *compiler) BuildFile(mufile []byte, ext string, outp string) {
|
|
|
|
glog.Infof("Building in-memory %v file (bytes=%v out='%v')", ext, len(mufile), outp)
|
2016-11-20 17:20:19 +01:00
|
|
|
c.buildDocument(&diag.Document{File: workspace.Mufile + ext, Body: mufile}, outp)
|
2016-11-17 22:08:20 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
func (c *compiler) buildDocument(doc *diag.Document, outp string) {
|
|
|
|
glog.Infof("Building doc '%v' (bytes=%v out='%v')", doc.File, len(doc.Body), outp)
|
2016-11-16 01:30:10 +01:00
|
|
|
if glog.V(2) {
|
|
|
|
defer func() {
|
2016-11-17 22:08:20 +01:00
|
|
|
glog.V(2).Infof("Building doc '%v' completed w/ %v warnings and %v errors",
|
|
|
|
doc.File, c.Diag().Warnings(), c.Diag().Errors())
|
2016-11-16 01:30:10 +01:00
|
|
|
}()
|
|
|
|
}
|
2016-11-15 20:30:34 +01:00
|
|
|
|
Add cloud target and architecture detection
This change implements most of the cloud target and architecture detection
logic, along with associated verification and a bunch of new error messages.
There are two settings for picking a cloud destination:
* Architecture: this specifies the combination of cloud (e.g., AWS, GCP, etc)
plus scheduler (e.g., none, Swarm, ECS, etc).
* Target: a named, preconfigured entity that includes both an Architecture and
an assortment of extra default configuration options.
The general idea here is that you can preconfigure a set of Targets for
named environments like "prod", "stage", etc. Those can either exist in a
single Mufile, or the Mucluster file if they are shared amongst multiple
Mufiles. This can be specified at the command line as such:
$ mu build --target=stage
Furthermore, a given environment may be annointed the default, so that
$ mu build
selects that environment without needing to say so explicitly.
It is also possible to specify an architecture at the command line for
scenarios where you aren't intending to target an existing named environment.
This is good for "anonymous" testing scenarios or even just running locally:
$ mu build --arch=aws
$ mu build --arch=aws:ecs
$ mu build --arch=local:kubernetes
$ .. and so on ..
This change does little more than plumb these settings around, verify them,
etc., however it sets us up to actually start dispating to the right backend.
2016-11-17 19:30:37 +01:00
|
|
|
// Perform the front-end passes to generate a stack AST.
|
2016-11-17 22:08:20 +01:00
|
|
|
stack, ok := c.parseStack(doc)
|
Add cloud target and architecture detection
This change implements most of the cloud target and architecture detection
logic, along with associated verification and a bunch of new error messages.
There are two settings for picking a cloud destination:
* Architecture: this specifies the combination of cloud (e.g., AWS, GCP, etc)
plus scheduler (e.g., none, Swarm, ECS, etc).
* Target: a named, preconfigured entity that includes both an Architecture and
an assortment of extra default configuration options.
The general idea here is that you can preconfigure a set of Targets for
named environments like "prod", "stage", etc. Those can either exist in a
single Mufile, or the Mucluster file if they are shared amongst multiple
Mufiles. This can be specified at the command line as such:
$ mu build --target=stage
Furthermore, a given environment may be annointed the default, so that
$ mu build
selects that environment without needing to say so explicitly.
It is also possible to specify an architecture at the command line for
scenarios where you aren't intending to target an existing named environment.
This is good for "anonymous" testing scenarios or even just running locally:
$ mu build --arch=aws
$ mu build --arch=aws:ecs
$ mu build --arch=local:kubernetes
$ .. and so on ..
This change does little more than plumb these settings around, verify them,
etc., however it sets us up to actually start dispating to the right backend.
2016-11-17 19:30:37 +01:00
|
|
|
if !ok {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
|
|
|
// Perform the semantic analysis passes to validate, transform, and/or update the AST.
|
|
|
|
stack, ok = c.analyzeStack(doc, stack)
|
|
|
|
if !ok {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
|
2016-11-17 22:08:20 +01:00
|
|
|
if !c.opts.SkipCodegen {
|
|
|
|
// Figure out which cloud architecture we will be targeting during code-gen.
|
|
|
|
target, arch, ok := c.discoverTargetArch(doc, stack)
|
|
|
|
if !ok {
|
|
|
|
return
|
|
|
|
}
|
|
|
|
if glog.V(2) {
|
|
|
|
tname := "n/a"
|
|
|
|
if target != nil {
|
|
|
|
tname = target.Name
|
|
|
|
}
|
|
|
|
glog.V(2).Infof("Stack %v targets target=%v cloud=%v", stack.Name, tname, arch)
|
|
|
|
}
|
2016-11-15 20:30:34 +01:00
|
|
|
|
2016-11-18 21:40:15 +01:00
|
|
|
// Now get the backend cloud provider to process the stack from here on out.
|
2016-11-19 20:28:40 +01:00
|
|
|
be := backends.New(arch, c.Diag())
|
|
|
|
be.CodeGen(core.Compiland{target, doc, stack})
|
2016-11-16 02:42:22 +01:00
|
|
|
}
|
2016-11-17 22:08:20 +01:00
|
|
|
}
|
2016-11-16 02:42:22 +01:00
|
|
|
|
2016-11-17 22:08:20 +01:00
|
|
|
// loadAndParseStack takes a Mufile document, parses and validates it, and returns a stack AST. If anything goes wrong
|
|
|
|
// during this process, the number of errors will be non-zero, and the bool will be false.
|
|
|
|
func (c *compiler) parseStack(doc *diag.Document) (*ast.Stack, bool) {
|
2016-11-15 20:30:34 +01:00
|
|
|
// To build the Mu package, first parse the input file.
|
|
|
|
p := NewParser(c)
|
2016-11-16 02:42:22 +01:00
|
|
|
stack := p.Parse(doc)
|
|
|
|
if p.Diag().Errors() > 0 {
|
2016-11-16 18:29:44 +01:00
|
|
|
// If any errors happened during parsing, exit.
|
2016-11-17 22:08:20 +01:00
|
|
|
return stack, false
|
2016-11-15 20:30:34 +01:00
|
|
|
}
|
|
|
|
|
2016-11-16 02:42:22 +01:00
|
|
|
// Do a pass over the parse tree to ensure that all is well.
|
|
|
|
ptAnalyzer := NewPTAnalyzer(c)
|
|
|
|
ptAnalyzer.Analyze(doc, stack)
|
|
|
|
if p.Diag().Errors() > 0 {
|
2016-11-16 18:29:44 +01:00
|
|
|
// If any errors happened during parse tree analysis, exit.
|
2016-11-17 22:08:20 +01:00
|
|
|
return stack, false
|
Add cloud target and architecture detection
This change implements most of the cloud target and architecture detection
logic, along with associated verification and a bunch of new error messages.
There are two settings for picking a cloud destination:
* Architecture: this specifies the combination of cloud (e.g., AWS, GCP, etc)
plus scheduler (e.g., none, Swarm, ECS, etc).
* Target: a named, preconfigured entity that includes both an Architecture and
an assortment of extra default configuration options.
The general idea here is that you can preconfigure a set of Targets for
named environments like "prod", "stage", etc. Those can either exist in a
single Mufile, or the Mucluster file if they are shared amongst multiple
Mufiles. This can be specified at the command line as such:
$ mu build --target=stage
Furthermore, a given environment may be annointed the default, so that
$ mu build
selects that environment without needing to say so explicitly.
It is also possible to specify an architecture at the command line for
scenarios where you aren't intending to target an existing named environment.
This is good for "anonymous" testing scenarios or even just running locally:
$ mu build --arch=aws
$ mu build --arch=aws:ecs
$ mu build --arch=local:kubernetes
$ .. and so on ..
This change does little more than plumb these settings around, verify them,
etc., however it sets us up to actually start dispating to the right backend.
2016-11-17 19:30:37 +01:00
|
|
|
}
|
|
|
|
|
2016-11-17 22:08:20 +01:00
|
|
|
return stack, true
|
Add cloud target and architecture detection
This change implements most of the cloud target and architecture detection
logic, along with associated verification and a bunch of new error messages.
There are two settings for picking a cloud destination:
* Architecture: this specifies the combination of cloud (e.g., AWS, GCP, etc)
plus scheduler (e.g., none, Swarm, ECS, etc).
* Target: a named, preconfigured entity that includes both an Architecture and
an assortment of extra default configuration options.
The general idea here is that you can preconfigure a set of Targets for
named environments like "prod", "stage", etc. Those can either exist in a
single Mufile, or the Mucluster file if they are shared amongst multiple
Mufiles. This can be specified at the command line as such:
$ mu build --target=stage
Furthermore, a given environment may be annointed the default, so that
$ mu build
selects that environment without needing to say so explicitly.
It is also possible to specify an architecture at the command line for
scenarios where you aren't intending to target an existing named environment.
This is good for "anonymous" testing scenarios or even just running locally:
$ mu build --arch=aws
$ mu build --arch=aws:ecs
$ mu build --arch=local:kubernetes
$ .. and so on ..
This change does little more than plumb these settings around, verify them,
etc., however it sets us up to actually start dispating to the right backend.
2016-11-17 19:30:37 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
// discoverTargetArch uses a variety of mechanisms to discover the target architecture, returning it. If no
|
|
|
|
// architecture was discovered, an error is issued, and the bool return will be false.
|
2016-11-18 21:40:15 +01:00
|
|
|
func (c *compiler) discoverTargetArch(doc *diag.Document, stack *ast.Stack) (*ast.Target, backends.Arch, bool) {
|
Add cloud target and architecture detection
This change implements most of the cloud target and architecture detection
logic, along with associated verification and a bunch of new error messages.
There are two settings for picking a cloud destination:
* Architecture: this specifies the combination of cloud (e.g., AWS, GCP, etc)
plus scheduler (e.g., none, Swarm, ECS, etc).
* Target: a named, preconfigured entity that includes both an Architecture and
an assortment of extra default configuration options.
The general idea here is that you can preconfigure a set of Targets for
named environments like "prod", "stage", etc. Those can either exist in a
single Mufile, or the Mucluster file if they are shared amongst multiple
Mufiles. This can be specified at the command line as such:
$ mu build --target=stage
Furthermore, a given environment may be annointed the default, so that
$ mu build
selects that environment without needing to say so explicitly.
It is also possible to specify an architecture at the command line for
scenarios where you aren't intending to target an existing named environment.
This is good for "anonymous" testing scenarios or even just running locally:
$ mu build --arch=aws
$ mu build --arch=aws:ecs
$ mu build --arch=local:kubernetes
$ .. and so on ..
This change does little more than plumb these settings around, verify them,
etc., however it sets us up to actually start dispating to the right backend.
2016-11-17 19:30:37 +01:00
|
|
|
// Target and architectures settings may come from one of three places, in order of search preference:
|
|
|
|
// 1) command line arguments.
|
|
|
|
// 2) settings specific to this stack.
|
|
|
|
// 3) cluster-wide settings in a Mucluster file.
|
|
|
|
// In other words, 1 overrides 2 which overrides 3.
|
|
|
|
arch := c.opts.Arch
|
|
|
|
|
|
|
|
// If a target was specified, look it up and load up its options.
|
|
|
|
var target *ast.Target
|
|
|
|
if c.opts.Target != "" {
|
|
|
|
// First, check the stack to see if it has a targets section.
|
|
|
|
if t, exists := stack.Targets[c.opts.Target]; exists {
|
|
|
|
target = &t
|
|
|
|
} else {
|
|
|
|
// If that didn't work, see if there's a clusters file we can consult.
|
|
|
|
// TODO: support Mucluster files.
|
|
|
|
c.Diag().Errorf(errors.CloudTargetNotFound.WithDocument(doc), c.opts.Target)
|
|
|
|
return target, arch, false
|
|
|
|
}
|
2016-11-16 18:29:44 +01:00
|
|
|
}
|
|
|
|
|
Add cloud target and architecture detection
This change implements most of the cloud target and architecture detection
logic, along with associated verification and a bunch of new error messages.
There are two settings for picking a cloud destination:
* Architecture: this specifies the combination of cloud (e.g., AWS, GCP, etc)
plus scheduler (e.g., none, Swarm, ECS, etc).
* Target: a named, preconfigured entity that includes both an Architecture and
an assortment of extra default configuration options.
The general idea here is that you can preconfigure a set of Targets for
named environments like "prod", "stage", etc. Those can either exist in a
single Mufile, or the Mucluster file if they are shared amongst multiple
Mufiles. This can be specified at the command line as such:
$ mu build --target=stage
Furthermore, a given environment may be annointed the default, so that
$ mu build
selects that environment without needing to say so explicitly.
It is also possible to specify an architecture at the command line for
scenarios where you aren't intending to target an existing named environment.
This is good for "anonymous" testing scenarios or even just running locally:
$ mu build --arch=aws
$ mu build --arch=aws:ecs
$ mu build --arch=local:kubernetes
$ .. and so on ..
This change does little more than plumb these settings around, verify them,
etc., however it sets us up to actually start dispating to the right backend.
2016-11-17 19:30:37 +01:00
|
|
|
// If no target was specified or discovered yet, see if there is a default one to use.
|
|
|
|
if target == nil {
|
|
|
|
for _, t := range stack.Targets {
|
|
|
|
if t.Default {
|
|
|
|
target = &t
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if target == nil {
|
|
|
|
// If no target was found, and we don't have an architecture, error out.
|
|
|
|
if arch.Cloud == clouds.NoArch {
|
2016-11-17 22:08:20 +01:00
|
|
|
c.Diag().Errorf(errors.MissingTarget.WithDocument(doc))
|
Add cloud target and architecture detection
This change implements most of the cloud target and architecture detection
logic, along with associated verification and a bunch of new error messages.
There are two settings for picking a cloud destination:
* Architecture: this specifies the combination of cloud (e.g., AWS, GCP, etc)
plus scheduler (e.g., none, Swarm, ECS, etc).
* Target: a named, preconfigured entity that includes both an Architecture and
an assortment of extra default configuration options.
The general idea here is that you can preconfigure a set of Targets for
named environments like "prod", "stage", etc. Those can either exist in a
single Mufile, or the Mucluster file if they are shared amongst multiple
Mufiles. This can be specified at the command line as such:
$ mu build --target=stage
Furthermore, a given environment may be annointed the default, so that
$ mu build
selects that environment without needing to say so explicitly.
It is also possible to specify an architecture at the command line for
scenarios where you aren't intending to target an existing named environment.
This is good for "anonymous" testing scenarios or even just running locally:
$ mu build --arch=aws
$ mu build --arch=aws:ecs
$ mu build --arch=local:kubernetes
$ .. and so on ..
This change does little more than plumb these settings around, verify them,
etc., however it sets us up to actually start dispating to the right backend.
2016-11-17 19:30:37 +01:00
|
|
|
return target, arch, false
|
|
|
|
}
|
Sketch out more AWS backend code-generator bits and pieces
This change includes a few steps towards AWS backend code-generation:
* Add a BoundDependencies property to ast.Stack to remember the *ast.Stack
objects bound during Stack binding.
* Make a few CloudFormation properties optional (cfOutput Export/Condition).
* Rename clouds.ArchMap, clouds.ArchNames, schedulers.ArchMap, and
schedulers.ArchNames to clouds.Values, clouds.Names, schedulers.Values,
and schedulers.Names, respectively. This reads much nicer to my eyes.
* Create a new anonymous ast.Target for deployments if no specific target
was specified; this is to support quick-and-easy "one off" deployments,
as will be common when doing local development.
* Sketch out more of the AWS Cloud implementation. We actually map the
Mu Services into CloudFormation Resources; well, kinda sorta, since we
don't actually have Service-specific logic in here yet, however all of
the structure and scaffolding is now here.
2016-11-19 01:46:36 +01:00
|
|
|
|
|
|
|
// If we got here, generate an "anonymous" target, so that we at least have a name.
|
|
|
|
target = c.newAnonTarget(arch)
|
Add cloud target and architecture detection
This change implements most of the cloud target and architecture detection
logic, along with associated verification and a bunch of new error messages.
There are two settings for picking a cloud destination:
* Architecture: this specifies the combination of cloud (e.g., AWS, GCP, etc)
plus scheduler (e.g., none, Swarm, ECS, etc).
* Target: a named, preconfigured entity that includes both an Architecture and
an assortment of extra default configuration options.
The general idea here is that you can preconfigure a set of Targets for
named environments like "prod", "stage", etc. Those can either exist in a
single Mufile, or the Mucluster file if they are shared amongst multiple
Mufiles. This can be specified at the command line as such:
$ mu build --target=stage
Furthermore, a given environment may be annointed the default, so that
$ mu build
selects that environment without needing to say so explicitly.
It is also possible to specify an architecture at the command line for
scenarios where you aren't intending to target an existing named environment.
This is good for "anonymous" testing scenarios or even just running locally:
$ mu build --arch=aws
$ mu build --arch=aws:ecs
$ mu build --arch=local:kubernetes
$ .. and so on ..
This change does little more than plumb these settings around, verify them,
etc., however it sets us up to actually start dispating to the right backend.
2016-11-17 19:30:37 +01:00
|
|
|
} else {
|
|
|
|
// If a target was found, go ahead and extract and validate the target architecture.
|
|
|
|
a, ok := c.getTargetArch(doc, target, arch)
|
|
|
|
if !ok {
|
|
|
|
return target, arch, false
|
|
|
|
}
|
|
|
|
arch = a
|
|
|
|
}
|
|
|
|
|
|
|
|
return target, arch, true
|
|
|
|
}
|
|
|
|
|
Sketch out more AWS backend code-generator bits and pieces
This change includes a few steps towards AWS backend code-generation:
* Add a BoundDependencies property to ast.Stack to remember the *ast.Stack
objects bound during Stack binding.
* Make a few CloudFormation properties optional (cfOutput Export/Condition).
* Rename clouds.ArchMap, clouds.ArchNames, schedulers.ArchMap, and
schedulers.ArchNames to clouds.Values, clouds.Names, schedulers.Values,
and schedulers.Names, respectively. This reads much nicer to my eyes.
* Create a new anonymous ast.Target for deployments if no specific target
was specified; this is to support quick-and-easy "one off" deployments,
as will be common when doing local development.
* Sketch out more of the AWS Cloud implementation. We actually map the
Mu Services into CloudFormation Resources; well, kinda sorta, since we
don't actually have Service-specific logic in here yet, however all of
the structure and scaffolding is now here.
2016-11-19 01:46:36 +01:00
|
|
|
// newAnonTarget creates an anonymous target for stacks that didn't declare one.
|
|
|
|
func (c *compiler) newAnonTarget(arch backends.Arch) *ast.Target {
|
|
|
|
// TODO: ensure this is unique.
|
|
|
|
// TODO: we want to cache names somewhere (~/.mu/?) so that we can reuse temporary local stacks, etc.
|
|
|
|
return &ast.Target{
|
|
|
|
Name: uuid.NewV4().String(),
|
|
|
|
Cloud: clouds.Names[arch.Cloud],
|
|
|
|
Scheduler: schedulers.Names[arch.Scheduler],
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
Add cloud target and architecture detection
This change implements most of the cloud target and architecture detection
logic, along with associated verification and a bunch of new error messages.
There are two settings for picking a cloud destination:
* Architecture: this specifies the combination of cloud (e.g., AWS, GCP, etc)
plus scheduler (e.g., none, Swarm, ECS, etc).
* Target: a named, preconfigured entity that includes both an Architecture and
an assortment of extra default configuration options.
The general idea here is that you can preconfigure a set of Targets for
named environments like "prod", "stage", etc. Those can either exist in a
single Mufile, or the Mucluster file if they are shared amongst multiple
Mufiles. This can be specified at the command line as such:
$ mu build --target=stage
Furthermore, a given environment may be annointed the default, so that
$ mu build
selects that environment without needing to say so explicitly.
It is also possible to specify an architecture at the command line for
scenarios where you aren't intending to target an existing named environment.
This is good for "anonymous" testing scenarios or even just running locally:
$ mu build --arch=aws
$ mu build --arch=aws:ecs
$ mu build --arch=local:kubernetes
$ .. and so on ..
This change does little more than plumb these settings around, verify them,
etc., however it sets us up to actually start dispating to the right backend.
2016-11-17 19:30:37 +01:00
|
|
|
// getTargetArch gets and validates the architecture from an existing target.
|
2016-11-18 21:40:15 +01:00
|
|
|
func (c *compiler) getTargetArch(doc *diag.Document, target *ast.Target, existing backends.Arch) (backends.Arch, bool) {
|
Add cloud target and architecture detection
This change implements most of the cloud target and architecture detection
logic, along with associated verification and a bunch of new error messages.
There are two settings for picking a cloud destination:
* Architecture: this specifies the combination of cloud (e.g., AWS, GCP, etc)
plus scheduler (e.g., none, Swarm, ECS, etc).
* Target: a named, preconfigured entity that includes both an Architecture and
an assortment of extra default configuration options.
The general idea here is that you can preconfigure a set of Targets for
named environments like "prod", "stage", etc. Those can either exist in a
single Mufile, or the Mucluster file if they are shared amongst multiple
Mufiles. This can be specified at the command line as such:
$ mu build --target=stage
Furthermore, a given environment may be annointed the default, so that
$ mu build
selects that environment without needing to say so explicitly.
It is also possible to specify an architecture at the command line for
scenarios where you aren't intending to target an existing named environment.
This is good for "anonymous" testing scenarios or even just running locally:
$ mu build --arch=aws
$ mu build --arch=aws:ecs
$ mu build --arch=local:kubernetes
$ .. and so on ..
This change does little more than plumb these settings around, verify them,
etc., however it sets us up to actually start dispating to the right backend.
2016-11-17 19:30:37 +01:00
|
|
|
targetCloud := existing.Cloud
|
|
|
|
targetScheduler := existing.Scheduler
|
|
|
|
|
|
|
|
// If specified, look up the target's architecture settings.
|
|
|
|
if target.Cloud != "" {
|
Sketch out more AWS backend code-generator bits and pieces
This change includes a few steps towards AWS backend code-generation:
* Add a BoundDependencies property to ast.Stack to remember the *ast.Stack
objects bound during Stack binding.
* Make a few CloudFormation properties optional (cfOutput Export/Condition).
* Rename clouds.ArchMap, clouds.ArchNames, schedulers.ArchMap, and
schedulers.ArchNames to clouds.Values, clouds.Names, schedulers.Values,
and schedulers.Names, respectively. This reads much nicer to my eyes.
* Create a new anonymous ast.Target for deployments if no specific target
was specified; this is to support quick-and-easy "one off" deployments,
as will be common when doing local development.
* Sketch out more of the AWS Cloud implementation. We actually map the
Mu Services into CloudFormation Resources; well, kinda sorta, since we
don't actually have Service-specific logic in here yet, however all of
the structure and scaffolding is now here.
2016-11-19 01:46:36 +01:00
|
|
|
tc, ok := clouds.Values[target.Cloud]
|
Add cloud target and architecture detection
This change implements most of the cloud target and architecture detection
logic, along with associated verification and a bunch of new error messages.
There are two settings for picking a cloud destination:
* Architecture: this specifies the combination of cloud (e.g., AWS, GCP, etc)
plus scheduler (e.g., none, Swarm, ECS, etc).
* Target: a named, preconfigured entity that includes both an Architecture and
an assortment of extra default configuration options.
The general idea here is that you can preconfigure a set of Targets for
named environments like "prod", "stage", etc. Those can either exist in a
single Mufile, or the Mucluster file if they are shared amongst multiple
Mufiles. This can be specified at the command line as such:
$ mu build --target=stage
Furthermore, a given environment may be annointed the default, so that
$ mu build
selects that environment without needing to say so explicitly.
It is also possible to specify an architecture at the command line for
scenarios where you aren't intending to target an existing named environment.
This is good for "anonymous" testing scenarios or even just running locally:
$ mu build --arch=aws
$ mu build --arch=aws:ecs
$ mu build --arch=local:kubernetes
$ .. and so on ..
This change does little more than plumb these settings around, verify them,
etc., however it sets us up to actually start dispating to the right backend.
2016-11-17 19:30:37 +01:00
|
|
|
if !ok {
|
|
|
|
c.Diag().Errorf(errors.UnrecognizedCloudArch.WithDocument(doc), target.Cloud)
|
|
|
|
return existing, false
|
|
|
|
}
|
|
|
|
targetCloud = tc
|
|
|
|
}
|
|
|
|
if target.Scheduler != "" {
|
Sketch out more AWS backend code-generator bits and pieces
This change includes a few steps towards AWS backend code-generation:
* Add a BoundDependencies property to ast.Stack to remember the *ast.Stack
objects bound during Stack binding.
* Make a few CloudFormation properties optional (cfOutput Export/Condition).
* Rename clouds.ArchMap, clouds.ArchNames, schedulers.ArchMap, and
schedulers.ArchNames to clouds.Values, clouds.Names, schedulers.Values,
and schedulers.Names, respectively. This reads much nicer to my eyes.
* Create a new anonymous ast.Target for deployments if no specific target
was specified; this is to support quick-and-easy "one off" deployments,
as will be common when doing local development.
* Sketch out more of the AWS Cloud implementation. We actually map the
Mu Services into CloudFormation Resources; well, kinda sorta, since we
don't actually have Service-specific logic in here yet, however all of
the structure and scaffolding is now here.
2016-11-19 01:46:36 +01:00
|
|
|
ts, ok := schedulers.Values[target.Scheduler]
|
Add cloud target and architecture detection
This change implements most of the cloud target and architecture detection
logic, along with associated verification and a bunch of new error messages.
There are two settings for picking a cloud destination:
* Architecture: this specifies the combination of cloud (e.g., AWS, GCP, etc)
plus scheduler (e.g., none, Swarm, ECS, etc).
* Target: a named, preconfigured entity that includes both an Architecture and
an assortment of extra default configuration options.
The general idea here is that you can preconfigure a set of Targets for
named environments like "prod", "stage", etc. Those can either exist in a
single Mufile, or the Mucluster file if they are shared amongst multiple
Mufiles. This can be specified at the command line as such:
$ mu build --target=stage
Furthermore, a given environment may be annointed the default, so that
$ mu build
selects that environment without needing to say so explicitly.
It is also possible to specify an architecture at the command line for
scenarios where you aren't intending to target an existing named environment.
This is good for "anonymous" testing scenarios or even just running locally:
$ mu build --arch=aws
$ mu build --arch=aws:ecs
$ mu build --arch=local:kubernetes
$ .. and so on ..
This change does little more than plumb these settings around, verify them,
etc., however it sets us up to actually start dispating to the right backend.
2016-11-17 19:30:37 +01:00
|
|
|
if !ok {
|
|
|
|
c.Diag().Errorf(errors.UnrecognizedSchedulerArch.WithDocument(doc), target.Scheduler)
|
|
|
|
return existing, false
|
|
|
|
}
|
|
|
|
targetScheduler = ts
|
|
|
|
}
|
|
|
|
|
|
|
|
// Ensure there aren't any conflicts, comparing compiler options to target settings.
|
2016-11-18 21:40:15 +01:00
|
|
|
tarch := backends.Arch{targetCloud, targetScheduler}
|
Add cloud target and architecture detection
This change implements most of the cloud target and architecture detection
logic, along with associated verification and a bunch of new error messages.
There are two settings for picking a cloud destination:
* Architecture: this specifies the combination of cloud (e.g., AWS, GCP, etc)
plus scheduler (e.g., none, Swarm, ECS, etc).
* Target: a named, preconfigured entity that includes both an Architecture and
an assortment of extra default configuration options.
The general idea here is that you can preconfigure a set of Targets for
named environments like "prod", "stage", etc. Those can either exist in a
single Mufile, or the Mucluster file if they are shared amongst multiple
Mufiles. This can be specified at the command line as such:
$ mu build --target=stage
Furthermore, a given environment may be annointed the default, so that
$ mu build
selects that environment without needing to say so explicitly.
It is also possible to specify an architecture at the command line for
scenarios where you aren't intending to target an existing named environment.
This is good for "anonymous" testing scenarios or even just running locally:
$ mu build --arch=aws
$ mu build --arch=aws:ecs
$ mu build --arch=local:kubernetes
$ .. and so on ..
This change does little more than plumb these settings around, verify them,
etc., however it sets us up to actually start dispating to the right backend.
2016-11-17 19:30:37 +01:00
|
|
|
if targetCloud != existing.Cloud && existing.Cloud != clouds.NoArch {
|
|
|
|
c.Diag().Errorf(errors.ConflictingTargetArchSelection.WithDocument(doc), existing, target.Name, tarch)
|
|
|
|
return tarch, false
|
|
|
|
}
|
|
|
|
if targetScheduler != existing.Scheduler && existing.Scheduler != schedulers.NoArch {
|
|
|
|
c.Diag().Errorf(errors.ConflictingTargetArchSelection.WithDocument(doc), existing, target.Name, tarch)
|
|
|
|
return tarch, false
|
|
|
|
}
|
|
|
|
|
|
|
|
return tarch, true
|
|
|
|
}
|
|
|
|
|
|
|
|
// analyzeStack performs semantic analysis on a stack -- validating, transforming, and/or updating it -- and then
|
|
|
|
// returns the result. If a problem occurs, errors will have been emitted, and the bool return will be false.
|
|
|
|
func (c *compiler) analyzeStack(doc *diag.Document, stack *ast.Stack) (*ast.Stack, bool) {
|
2016-11-16 18:29:44 +01:00
|
|
|
binder := NewBinder(c)
|
|
|
|
binder.Bind(doc, stack)
|
Add cloud target and architecture detection
This change implements most of the cloud target and architecture detection
logic, along with associated verification and a bunch of new error messages.
There are two settings for picking a cloud destination:
* Architecture: this specifies the combination of cloud (e.g., AWS, GCP, etc)
plus scheduler (e.g., none, Swarm, ECS, etc).
* Target: a named, preconfigured entity that includes both an Architecture and
an assortment of extra default configuration options.
The general idea here is that you can preconfigure a set of Targets for
named environments like "prod", "stage", etc. Those can either exist in a
single Mufile, or the Mucluster file if they are shared amongst multiple
Mufiles. This can be specified at the command line as such:
$ mu build --target=stage
Furthermore, a given environment may be annointed the default, so that
$ mu build
selects that environment without needing to say so explicitly.
It is also possible to specify an architecture at the command line for
scenarios where you aren't intending to target an existing named environment.
This is good for "anonymous" testing scenarios or even just running locally:
$ mu build --arch=aws
$ mu build --arch=aws:ecs
$ mu build --arch=local:kubernetes
$ .. and so on ..
This change does little more than plumb these settings around, verify them,
etc., however it sets us up to actually start dispating to the right backend.
2016-11-17 19:30:37 +01:00
|
|
|
if c.Diag().Errors() > 0 {
|
2016-11-16 18:29:44 +01:00
|
|
|
// If any errors happened during binding, exit.
|
Add cloud target and architecture detection
This change implements most of the cloud target and architecture detection
logic, along with associated verification and a bunch of new error messages.
There are two settings for picking a cloud destination:
* Architecture: this specifies the combination of cloud (e.g., AWS, GCP, etc)
plus scheduler (e.g., none, Swarm, ECS, etc).
* Target: a named, preconfigured entity that includes both an Architecture and
an assortment of extra default configuration options.
The general idea here is that you can preconfigure a set of Targets for
named environments like "prod", "stage", etc. Those can either exist in a
single Mufile, or the Mucluster file if they are shared amongst multiple
Mufiles. This can be specified at the command line as such:
$ mu build --target=stage
Furthermore, a given environment may be annointed the default, so that
$ mu build
selects that environment without needing to say so explicitly.
It is also possible to specify an architecture at the command line for
scenarios where you aren't intending to target an existing named environment.
This is good for "anonymous" testing scenarios or even just running locally:
$ mu build --arch=aws
$ mu build --arch=aws:ecs
$ mu build --arch=local:kubernetes
$ .. and so on ..
This change does little more than plumb these settings around, verify them,
etc., however it sets us up to actually start dispating to the right backend.
2016-11-17 19:30:37 +01:00
|
|
|
return stack, false
|
2016-11-16 02:42:22 +01:00
|
|
|
}
|
2016-11-15 20:30:34 +01:00
|
|
|
|
2016-11-16 18:29:44 +01:00
|
|
|
// TODO: perform semantic analysis on the bound tree.
|
2016-11-17 16:00:52 +01:00
|
|
|
|
Add cloud target and architecture detection
This change implements most of the cloud target and architecture detection
logic, along with associated verification and a bunch of new error messages.
There are two settings for picking a cloud destination:
* Architecture: this specifies the combination of cloud (e.g., AWS, GCP, etc)
plus scheduler (e.g., none, Swarm, ECS, etc).
* Target: a named, preconfigured entity that includes both an Architecture and
an assortment of extra default configuration options.
The general idea here is that you can preconfigure a set of Targets for
named environments like "prod", "stage", etc. Those can either exist in a
single Mufile, or the Mucluster file if they are shared amongst multiple
Mufiles. This can be specified at the command line as such:
$ mu build --target=stage
Furthermore, a given environment may be annointed the default, so that
$ mu build
selects that environment without needing to say so explicitly.
It is also possible to specify an architecture at the command line for
scenarios where you aren't intending to target an existing named environment.
This is good for "anonymous" testing scenarios or even just running locally:
$ mu build --arch=aws
$ mu build --arch=aws:ecs
$ mu build --arch=local:kubernetes
$ .. and so on ..
This change does little more than plumb these settings around, verify them,
etc., however it sets us up to actually start dispating to the right backend.
2016-11-17 19:30:37 +01:00
|
|
|
return stack, true
|
2016-11-15 20:30:34 +01:00
|
|
|
}
|