2018-05-22 21:43:36 +02:00
|
|
|
// Copyright 2016-2018, Pulumi Corporation.
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
// You may obtain a copy of the License at
|
|
|
|
//
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
//
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
// limitations under the License.
|
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-21 04:45:07 +02:00
|
|
|
|
|
|
|
package plugin
|
|
|
|
|
|
|
|
import (
|
2017-09-09 16:37:10 +02:00
|
|
|
"fmt"
|
2018-09-18 20:47:34 +02:00
|
|
|
"sync/atomic"
|
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-21 04:45:07 +02:00
|
|
|
|
|
|
|
pbempty "github.com/golang/protobuf/ptypes/empty"
|
|
|
|
"github.com/pkg/errors"
|
|
|
|
"golang.org/x/net/context"
|
|
|
|
"google.golang.org/grpc"
|
|
|
|
|
2017-09-22 04:18:21 +02:00
|
|
|
"github.com/pulumi/pulumi/pkg/diag"
|
2018-04-10 21:03:11 +02:00
|
|
|
"github.com/pulumi/pulumi/pkg/resource"
|
2017-09-22 04:18:21 +02:00
|
|
|
"github.com/pulumi/pulumi/pkg/util/rpcutil"
|
|
|
|
lumirpc "github.com/pulumi/pulumi/sdk/proto/go"
|
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-21 04:45:07 +02:00
|
|
|
)
|
|
|
|
|
2017-06-21 19:31:06 +02:00
|
|
|
// hostServer is the server side of the host RPC machinery.
|
|
|
|
type hostServer struct {
|
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-21 04:45:07 +02:00
|
|
|
host Host // the host for this RPC server.
|
|
|
|
ctx *Context // the associated plugin context.
|
2017-09-09 16:37:10 +02:00
|
|
|
addr string // the address the host is listening on.
|
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-21 04:45:07 +02:00
|
|
|
cancel chan bool // a channel that can cancel the server.
|
|
|
|
done chan error // a channel that resolves when the server completes.
|
2018-09-18 20:47:34 +02:00
|
|
|
|
|
|
|
// hostServer contains little bits of state that can't be saved in the language host.
|
|
|
|
rootUrn atomic.Value // a root resource URN that has been saved via SetRootResource
|
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-21 04:45:07 +02:00
|
|
|
}
|
|
|
|
|
2017-06-21 19:31:06 +02:00
|
|
|
// newHostServer creates a new host server wired up to the given host and context.
|
|
|
|
func newHostServer(host Host, ctx *Context) (*hostServer, error) {
|
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-21 04:45:07 +02:00
|
|
|
// New up an engine RPC server.
|
2017-06-21 19:31:06 +02:00
|
|
|
engine := &hostServer{
|
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-21 04:45:07 +02:00
|
|
|
host: host,
|
|
|
|
ctx: ctx,
|
|
|
|
cancel: make(chan bool),
|
|
|
|
}
|
|
|
|
|
|
|
|
// Fire up a gRPC server and start listening for incomings.
|
|
|
|
port, done, err := rpcutil.Serve(0, engine.cancel, []func(*grpc.Server) error{
|
|
|
|
func(srv *grpc.Server) error {
|
|
|
|
lumirpc.RegisterEngineServer(srv, engine)
|
|
|
|
return nil
|
|
|
|
},
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2017-09-21 19:56:45 +02:00
|
|
|
engine.addr = fmt.Sprintf("127.0.0.1:%d", port)
|
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-21 04:45:07 +02:00
|
|
|
engine.done = done
|
2018-09-18 20:47:34 +02:00
|
|
|
engine.rootUrn.Store("")
|
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-21 04:45:07 +02:00
|
|
|
|
|
|
|
return engine, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// Address returns the address at which the engine's RPC server may be reached.
|
2017-06-21 19:31:06 +02:00
|
|
|
func (eng *hostServer) Address() string {
|
2017-09-09 16:37:10 +02:00
|
|
|
return eng.addr
|
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-21 04:45:07 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
// Cancel signals that the engine should be terminated, awaits its termination, and returns any errors that result.
|
2017-06-21 19:31:06 +02:00
|
|
|
func (eng *hostServer) Cancel() error {
|
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-21 04:45:07 +02:00
|
|
|
eng.cancel <- true
|
|
|
|
return <-eng.done
|
|
|
|
}
|
|
|
|
|
|
|
|
// Log logs a global message in the engine, including errors and warnings.
|
2018-04-10 21:03:11 +02:00
|
|
|
func (eng *hostServer) Log(ctx context.Context, req *lumirpc.LogRequest) (*pbempty.Empty, error) {
|
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-21 04:45:07 +02:00
|
|
|
var sev diag.Severity
|
|
|
|
switch req.Severity {
|
|
|
|
case lumirpc.LogSeverity_DEBUG:
|
|
|
|
sev = diag.Debug
|
|
|
|
case lumirpc.LogSeverity_INFO:
|
|
|
|
sev = diag.Info
|
|
|
|
case lumirpc.LogSeverity_WARNING:
|
|
|
|
sev = diag.Warning
|
|
|
|
case lumirpc.LogSeverity_ERROR:
|
|
|
|
sev = diag.Error
|
|
|
|
default:
|
|
|
|
return nil, errors.Errorf("Unrecognized logging severity: %v", req.Severity)
|
|
|
|
}
|
Implement status sinks
This commit reverts most of #1853 and replaces it with functionally
identical logic, using the notion of status message-specific sinks.
In other words, where the original commit implemented ephemeral status
messages by adding an `isStatus` parameter to most of the logging
methdos in pulumi/pulumi, this implements ephemeral status messages as a
parallel logging sink, which emits _only_ ephemeral status messages.
The original commit message in that PR was:
> Allow log events to be marked "status" events
>
> This commit will introduce a field, IsStatus to LogRequest. A "status"
> logging event will be displayed in the Info column of the main
> display, but will not be printed out at the end, when resource
> operations complete.
>
> For example, for complex resource initialization, we'd like to display
> a series of intermediate results: [1/4] Service object created, for
> example. We'd like these to appear in the Info column, but not at the
> end, where they are not helpful to the user.
2018-08-31 22:12:40 +02:00
|
|
|
|
|
|
|
if req.Ephemeral {
|
|
|
|
eng.host.LogStatus(sev, resource.URN(req.Urn), req.Message, req.StreamId)
|
|
|
|
} else {
|
|
|
|
eng.host.Log(sev, resource.URN(req.Urn), req.Message, req.StreamId)
|
|
|
|
}
|
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-21 04:45:07 +02:00
|
|
|
return &pbempty.Empty{}, nil
|
|
|
|
}
|
2018-09-18 20:47:34 +02:00
|
|
|
|
|
|
|
// GetRootResource returns the current root resource's URN, which will serve as the parent of resources that are
|
|
|
|
// otherwise left unparented.
|
|
|
|
func (eng *hostServer) GetRootResource(ctx context.Context,
|
|
|
|
req *lumirpc.GetRootResourceRequest) (*lumirpc.GetRootResourceResponse, error) {
|
|
|
|
var response lumirpc.GetRootResourceResponse
|
|
|
|
response.Urn = eng.rootUrn.Load().(string)
|
|
|
|
return &response, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// SetRootResources sets the current root resource's URN. Generally only called on startup when the Stack resource is
|
|
|
|
// registered.
|
|
|
|
func (eng *hostServer) SetRootResource(ctx context.Context,
|
|
|
|
req *lumirpc.SetRootResourceRequest) (*lumirpc.SetRootResourceResponse, error) {
|
|
|
|
var response lumirpc.SetRootResourceResponse
|
|
|
|
eng.rootUrn.Store(req.GetUrn())
|
|
|
|
return &response, nil
|
|
|
|
}
|