pulumi/pkg/resource/plugin/langruntime_plugin.go

82 lines
2.8 KiB
Go
Raw Normal View History

// Copyright 2016-2017, Pulumi Corporation. All rights reserved.
package plugin
import (
"strings"
"github.com/golang/glog"
"github.com/pulumi/pulumi/pkg/tokens"
lumirpc "github.com/pulumi/pulumi/sdk/proto/go"
)
2017-09-04 19:06:46 +02:00
const LanguagePluginPrefix = "pulumi-langhost-"
// langhost reflects a language host plugin, loaded dynamically for a single language/runtime pair.
type langhost struct {
ctx *Context
runtime string
plug *plugin
client lumirpc.LanguageRuntimeClient
}
// NewLanguageRuntime binds to a language's runtime plugin and then creates a gRPC connection to it. If the
// plugin could not be found, or an error occurs while creating the child process, an error is returned.
func NewLanguageRuntime(host Host, ctx *Context, runtime string, monitorAddr string) (LanguageRuntime, error) {
// Go ahead and attempt to load the plugin from the PATH.
srvexe := LanguagePluginPrefix + strings.Replace(runtime, tokens.QNameDelimiter, "_", -1)
Improve output formatting This change improves our output formatting by generally adding fewer prefixes. As shown in pulumi/pulumi#359, we were being excessively verbose in many places, including prefixing every console.out with "langhost[nodejs].stdout: ", displaying full stack traces for simple errors like missing configuration, etc. Overall, this change includes the following: * Don't prefix stdout and stderr output from the program, other than the standard "info:" prefix. I experimented with various schemes here, but they all felt gratuitous. Simply emitting the output seems fine, especially as it's closer to what would happen if you just ran the program under node. * Do NOT make writes to stderr fail the plan/deploy. Previously we assumed that any console.errors, for instance, meant that the overall program should fail. This simply isn't how stderr is treated generally and meant you couldn't use certain logging techniques and libraries, among other things. * Do make sure that stderr writes in the program end up going to stderr in the Pulumi CLI output, however, so that redirection works as it should. This required a new Infoerr log level. * Make a small fix to the planning logic so we don't attempt to print the summary if an error occurs. * Finally, add a new error type, RunError, that when thrown and uncaught does not result in a full stack trace being printed. Anyone can use this, however, we currently use it for config errors so that we can terminate with a pretty error message, rather than the monstrosity shown in pulumi/pulumi#359.
2017-09-23 14:20:11 +02:00
plug, err := newPlugin(ctx, srvexe, "nodejs", []string{monitorAddr, host.ServerAddr()})
if err != nil {
return nil, err
} else if plug == nil {
return nil, nil
}
return &langhost{
ctx: ctx,
runtime: runtime,
plug: plug,
client: lumirpc.NewLanguageRuntimeClient(plug.Conn),
}, nil
}
func (h *langhost) Runtime() string { return h.runtime }
// Run executes a program in the language runtime for planning or deployment purposes. If info.DryRun is true,
// the code must not assume that side-effects or final values resulting from resource deployments are actually
// available. If it is false, on the other hand, a real deployment is occurring and it may safely depend on these.
func (h *langhost) Run(info RunInfo) (string, error) {
2017-11-19 19:16:47 +01:00
glog.V(7).Infof("langhost[%v].Run(pwd=%v,program=%v,#args=%v,proj=%s,stack=%v,#config=%v,dryrun=%v) executing",
h.runtime, info.Pwd, info.Program, len(info.Args), info.Project, info.Stack, len(info.Config), info.DryRun)
config := make(map[string]string)
for k, v := range info.Config {
config[string(k)] = v
}
resp, err := h.client.Run(h.ctx.Request(), &lumirpc.RunRequest{
Pwd: info.Pwd,
Program: info.Program,
Args: info.Args,
2017-11-19 19:16:47 +01:00
Project: info.Project,
Stack: info.Stack,
Config: config,
DryRun: info.DryRun,
Parallel: int32(info.Parallel),
})
if err != nil {
glog.V(7).Infof("langhost[%v].Run(pwd=%v,program=%v,...,dryrun=%v) failed: err=%v",
h.runtime, info.Pwd, info.Program, info.DryRun, err)
return "", err
}
progerr := resp.GetError()
glog.V(7).Infof("langhost[%v].RunPlan(pwd=%v,program=%v,...,dryrun=%v) success: progerr=%v",
h.runtime, info.Pwd, info.Program, info.DryRun, progerr)
return progerr, nil
}
// Close tears down the underlying plugin RPC connection and process.
func (h *langhost) Close() error {
return h.plug.Close()
}