Merge pull request #28699 from hashicorp/jbardin/plugin-output-monitor

monitor plugin std outputs for unexpected data
This commit is contained in:
James Bardin 2021-05-17 12:52:53 -04:00 committed by GitHub
commit 91a8a8137c
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 38 additions and 0 deletions

View File

@ -351,6 +351,8 @@ func providerFactory(meta *providercache.CachedProvider) providers.Factory {
Cmd: exec.Command(execFile), Cmd: exec.Command(execFile),
AutoMTLS: enableProviderAutoMTLS, AutoMTLS: enableProviderAutoMTLS,
VersionedPlugins: tfplugin.VersionedPlugins, VersionedPlugins: tfplugin.VersionedPlugins,
SyncStdout: logging.PluginOutputMonitor(fmt.Sprintf("%s:stdout", meta.Provider)),
SyncStderr: logging.PluginOutputMonitor(fmt.Sprintf("%s:stderr", meta.Provider)),
} }
client := plugin.NewClient(config) client := plugin.NewClient(config)
@ -406,6 +408,8 @@ func unmanagedProviderFactory(provider addrs.Provider, reattach *plugin.Reattach
AllowedProtocols: []plugin.Protocol{plugin.ProtocolGRPC}, AllowedProtocols: []plugin.Protocol{plugin.ProtocolGRPC},
Managed: false, Managed: false,
Reattach: reattach, Reattach: reattach,
SyncStdout: logging.PluginOutputMonitor(fmt.Sprintf("%s:stdout", provider)),
SyncStderr: logging.PluginOutputMonitor(fmt.Sprintf("%s:stderr", provider)),
} }
// TODO: we probably shouldn't hardcode the protocol version // TODO: we probably shouldn't hardcode the protocol version
// here, but it'll do for now, because only one protocol // here, but it'll do for now, because only one protocol

View File

@ -163,6 +163,8 @@ func provisionerFactory(meta discovery.PluginMeta) provisioners.Factory {
Logger: logging.NewLogger("provisioner"), Logger: logging.NewLogger("provisioner"),
AllowedProtocols: []plugin.Protocol{plugin.ProtocolGRPC}, AllowedProtocols: []plugin.Protocol{plugin.ProtocolGRPC},
AutoMTLS: enableProviderAutoMTLS, AutoMTLS: enableProviderAutoMTLS,
SyncStdout: logging.PluginOutputMonitor(fmt.Sprintf("%s:stdout", meta.Name)),
SyncStderr: logging.PluginOutputMonitor(fmt.Sprintf("%s:stderr", meta.Name)),
} }
client := plugin.NewClient(cfg) client := plugin.NewClient(cfg)
return newProvisionerClient(client) return newProvisionerClient(client)

View File

@ -187,3 +187,35 @@ func isValidLogLevel(level string) bool {
return false return false
} }
// PluginOutputMonitor creates an io.Writer that will warn about any writes in
// the default logger. This is used to catch unexpected output from plugins,
// notifying them about the problem as well as surfacing the lost data for
// context.
func PluginOutputMonitor(source string) io.Writer {
return pluginOutputMonitor{
source: source,
log: logger,
}
}
// pluginOutputMonitor is an io.Writer that logs all writes as
// "unexpected data" with the source name.
type pluginOutputMonitor struct {
source string
log hclog.Logger
}
func (w pluginOutputMonitor) Write(d []byte) (int, error) {
// Limit the write size to 1024 bytes We're not expecting any data to come
// through this channel, so accidental writes will usually be stray fmt
// debugging statements and the like, but we want to provide context to the
// provider to indicate what the unexpected data might be.
n := len(d)
if n > 1024 {
d = append(d[:1024], '.', '.', '.')
}
w.log.Warn("unexpected data", w.source, strings.TrimSpace(string(d)))
return n, nil
}