2018-05-22 19:43:36 +00: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.
|
2017-08-30 01:24:12 +00:00
|
|
|
|
|
|
|
package plugin
|
|
|
|
|
|
|
|
import (
|
2022-10-04 08:58:01 +00:00
|
|
|
"context"
|
2018-06-25 05:47:54 +00:00
|
|
|
"fmt"
|
2022-04-03 14:54:59 +00:00
|
|
|
"io"
|
|
|
|
"os"
|
2021-05-14 17:41:55 +00:00
|
|
|
"path/filepath"
|
2017-08-30 01:24:12 +00:00
|
|
|
"strings"
|
|
|
|
|
2018-02-06 17:57:32 +00:00
|
|
|
"github.com/blang/semver"
|
2022-10-17 14:21:11 +00:00
|
|
|
"github.com/hashicorp/hcl/v2"
|
2022-11-01 15:15:09 +00:00
|
|
|
"google.golang.org/grpc"
|
2018-02-22 15:50:37 +00:00
|
|
|
"google.golang.org/grpc/codes"
|
2023-01-11 19:54:31 +00:00
|
|
|
"google.golang.org/grpc/credentials/insecure"
|
2024-06-17 17:10:55 +00:00
|
|
|
"google.golang.org/grpc/status"
|
2024-01-17 09:35:20 +00:00
|
|
|
"google.golang.org/protobuf/types/known/emptypb"
|
2017-08-30 01:24:12 +00:00
|
|
|
|
2024-04-25 17:30:30 +00:00
|
|
|
"github.com/pulumi/pulumi/sdk/v3/go/common/apitype"
|
2022-04-03 14:54:59 +00:00
|
|
|
"github.com/pulumi/pulumi/sdk/v3/go/common/diag/colors"
|
2023-06-28 16:02:04 +00:00
|
|
|
"github.com/pulumi/pulumi/sdk/v3/go/common/slice"
|
2021-03-17 13:20:05 +00:00
|
|
|
"github.com/pulumi/pulumi/sdk/v3/go/common/tokens"
|
2021-06-11 02:57:18 +00:00
|
|
|
"github.com/pulumi/pulumi/sdk/v3/go/common/util/cmdutil"
|
2021-03-17 13:20:05 +00:00
|
|
|
"github.com/pulumi/pulumi/sdk/v3/go/common/util/contract"
|
|
|
|
"github.com/pulumi/pulumi/sdk/v3/go/common/util/logging"
|
2022-11-01 15:15:09 +00:00
|
|
|
"github.com/pulumi/pulumi/sdk/v3/go/common/util/rpcutil"
|
2021-03-17 13:20:05 +00:00
|
|
|
"github.com/pulumi/pulumi/sdk/v3/go/common/util/rpcutil/rpcerror"
|
|
|
|
"github.com/pulumi/pulumi/sdk/v3/go/common/workspace"
|
|
|
|
pulumirpc "github.com/pulumi/pulumi/sdk/v3/proto/go"
|
2017-08-30 01:24:12 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
// langhost reflects a language host plugin, loaded dynamically for a single language/runtime pair.
|
|
|
|
type langhost struct {
|
|
|
|
ctx *Context
|
|
|
|
runtime string
|
|
|
|
plug *plugin
|
2017-12-01 21:50:32 +00:00
|
|
|
client pulumirpc.LanguageRuntimeClient
|
2017-08-30 01:24:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// 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.
|
2024-01-25 23:28:58 +00:00
|
|
|
func NewLanguageRuntime(host Host, ctx *Context, runtime, workingDirectory string, info ProgramInfo,
|
2023-03-03 16:36:39 +00:00
|
|
|
) (LanguageRuntime, error) {
|
2023-08-07 12:15:57 +00:00
|
|
|
path, err := workspace.GetPluginPath(ctx.Diag,
|
2024-04-25 17:30:30 +00:00
|
|
|
apitype.LanguagePlugin, strings.ReplaceAll(runtime, tokens.QNameDelimiter, "_"), nil, host.GetProjectPlugins())
|
2018-02-06 15:20:04 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
2023-02-15 01:06:56 +00:00
|
|
|
contract.Assertf(path != "", "unexpected empty path for language plugin %s", runtime)
|
2022-03-17 12:22:56 +00:00
|
|
|
|
2024-01-25 23:28:58 +00:00
|
|
|
args, err := buildArgsForNewPlugin(host, info.RootDirectory(), info.Options())
|
2021-05-14 17:41:55 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2018-06-25 05:47:54 +00:00
|
|
|
|
2024-01-25 23:28:58 +00:00
|
|
|
plug, err := newPlugin(ctx, workingDirectory, path, runtime,
|
2024-04-25 17:30:30 +00:00
|
|
|
apitype.LanguagePlugin, args, nil /*env*/, langRuntimePluginDialOptions(ctx, runtime))
|
2017-08-30 01:24:12 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2018-02-06 15:20:04 +00:00
|
|
|
contract.Assertf(plug != nil, "unexpected nil language plugin for %s", runtime)
|
2017-08-30 01:24:12 +00:00
|
|
|
|
|
|
|
return &langhost{
|
|
|
|
ctx: ctx,
|
|
|
|
runtime: runtime,
|
|
|
|
plug: plug,
|
2017-12-01 21:50:32 +00:00
|
|
|
client: pulumirpc.NewLanguageRuntimeClient(plug.Conn),
|
2017-08-30 01:24:12 +00:00
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
2022-11-01 15:15:09 +00:00
|
|
|
func langRuntimePluginDialOptions(ctx *Context, runtime string) []grpc.DialOption {
|
|
|
|
dialOpts := append(
|
|
|
|
rpcutil.OpenTracingInterceptorDialOptions(),
|
2023-01-11 19:54:31 +00:00
|
|
|
grpc.WithTransportCredentials(insecure.NewCredentials()),
|
2022-11-01 15:15:09 +00:00
|
|
|
rpcutil.GrpcChannelOptions(),
|
|
|
|
)
|
|
|
|
|
|
|
|
if ctx.DialOptions != nil {
|
|
|
|
metadata := map[string]interface{}{
|
|
|
|
"mode": "client",
|
|
|
|
"kind": "language",
|
|
|
|
}
|
|
|
|
if runtime != "" {
|
|
|
|
metadata["runtime"] = runtime
|
|
|
|
}
|
|
|
|
dialOpts = append(dialOpts, ctx.DialOptions(metadata)...)
|
|
|
|
}
|
|
|
|
|
|
|
|
return dialOpts
|
|
|
|
}
|
|
|
|
|
2022-10-04 08:58:01 +00:00
|
|
|
func buildArgsForNewPlugin(host Host, root string, options map[string]interface{}) ([]string, error) {
|
|
|
|
root, err := filepath.Abs(root)
|
2021-06-11 02:57:18 +00:00
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2023-06-28 16:02:04 +00:00
|
|
|
args := slice.Prealloc[string](len(options))
|
2021-06-11 02:57:18 +00:00
|
|
|
|
|
|
|
for k, v := range options {
|
|
|
|
args = append(args, fmt.Sprintf("-%s=%v", k, v))
|
|
|
|
}
|
|
|
|
|
2023-12-12 12:19:42 +00:00
|
|
|
args = append(args, "-root="+filepath.Clean(root))
|
2021-06-11 02:57:18 +00:00
|
|
|
|
|
|
|
// NOTE: positional argument for the server addresss must come last
|
|
|
|
args = append(args, host.ServerAddr())
|
|
|
|
|
|
|
|
return args, nil
|
|
|
|
}
|
|
|
|
|
2020-09-15 00:40:17 +00:00
|
|
|
func NewLanguageRuntimeClient(ctx *Context, runtime string, client pulumirpc.LanguageRuntimeClient) LanguageRuntime {
|
|
|
|
return &langhost{
|
|
|
|
ctx: ctx,
|
|
|
|
runtime: runtime,
|
|
|
|
client: client,
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-02-06 17:57:32 +00:00
|
|
|
// GetRequiredPlugins computes the complete set of anticipated plugins required by a program.
|
2024-01-25 23:28:58 +00:00
|
|
|
func (h *langhost) GetRequiredPlugins(info ProgramInfo) ([]workspace.PluginSpec, error) {
|
|
|
|
logging.V(7).Infof("langhost[%v].GetRequiredPlugins(%s) executing",
|
|
|
|
h.runtime, info)
|
Pass root and main info to language host methods (#14654)
<!---
Thanks so much for your contribution! If this is your first time
contributing, please ensure that you have read the
[CONTRIBUTING](https://github.com/pulumi/pulumi/blob/master/CONTRIBUTING.md)
documentation.
-->
# Description
<!--- Please include a summary of the change and which issue is fixed.
Please also include relevant motivation and context. -->
This is two changes rolled together in a way.
Firstly passing some of the data that we pass on language runtime
startup to also pass it to Run/GetRequiredPlugins/etc. This is needed
for matrix testing, as we only get to start the language runtime up once
for that but want to execute multiple programs with it.
I feel it's also a little more consistent as we use the language
runtimes in other contexts (codegen) where there isn't really a root
directory, and aren't any options (and if we did do options the options
for codegen are not going to be the same as for execution). It also
means we can reuse a language host for shimless and substack programs,
as before they heavily relied on their current working directory to
calculate paths, and obviosly could only take one set of options at
startup. Imagine a shimless python package + a python root program, that
would have needed two startups of the python language host to deal with,
this unblocks it so we can make the engine smarter and only use one.
Secondly renaming some of the fields we pass to
Run/GetRequiredPlugins/etc today. `Pwd` and `Program` were not very
descriptive and had pretty non-obvious documentation:
```
string pwd = 3; // the program's working directory.
string program = 4; // the path to the program to execute.
```
`pwd` will remain, although probably rename it to `working_directory` at
some point, because while today we always start programs up with the
working directory equal to the program directory that definitely is
going to change in the future (at least for MLCs and substack programs).
But the name `pwd` doesn't make it clear that this was intended to be
the working directory _and_ the directory which contains the program.
`program` was in fact nearly always ".", and if it wasn't that it was
just a filename. The engine never sent a path for `program` (although we
did have some unit tests to check how that worked for the nodejs and
python hosts).
These are now replaced by a new structure with (I think) more clearly
named and documented fields (see ProgramInfo in langauge.proto).
The engine still sends the old data for now, we need to update
dotnet/yaml/java before we break the old interface and give Virtus Labs
a chance to update [besom](https://github.com/VirtusLab/besom).
## Checklist
- [x] I have run `make tidy` to update any new dependencies
- [x] I have run `make lint` to verify my code passes the lint check
- [ ] I have formatted my code using `gofumpt`
<!--- Please provide details if the checkbox below is to be left
unchecked. -->
- [x] I have added tests that prove my fix is effective or that my
feature works
<!---
User-facing changes require a CHANGELOG entry.
-->
- [ ] I have run `make changelog` and committed the
`changelog/pending/<file>` documenting my change
<!--
If the change(s) in this PR is a modification of an existing call to the
Pulumi Cloud,
then the service should honor older versions of the CLI where this
change would not exist.
You must then bump the API version in
/pkg/backend/httpstate/client/api.go, as well as add
it to the service.
-->
- [ ] Yes, there are changes in this PR that warrants bumping the Pulumi
Cloud API version
<!-- @Pulumi employees: If yes, you must submit corresponding changes in
the service repo. -->
2023-12-10 17:30:51 +00:00
|
|
|
|
2024-01-25 23:28:58 +00:00
|
|
|
minfo, err := info.Marshal()
|
Pass root and main info to language host methods (#14654)
<!---
Thanks so much for your contribution! If this is your first time
contributing, please ensure that you have read the
[CONTRIBUTING](https://github.com/pulumi/pulumi/blob/master/CONTRIBUTING.md)
documentation.
-->
# Description
<!--- Please include a summary of the change and which issue is fixed.
Please also include relevant motivation and context. -->
This is two changes rolled together in a way.
Firstly passing some of the data that we pass on language runtime
startup to also pass it to Run/GetRequiredPlugins/etc. This is needed
for matrix testing, as we only get to start the language runtime up once
for that but want to execute multiple programs with it.
I feel it's also a little more consistent as we use the language
runtimes in other contexts (codegen) where there isn't really a root
directory, and aren't any options (and if we did do options the options
for codegen are not going to be the same as for execution). It also
means we can reuse a language host for shimless and substack programs,
as before they heavily relied on their current working directory to
calculate paths, and obviosly could only take one set of options at
startup. Imagine a shimless python package + a python root program, that
would have needed two startups of the python language host to deal with,
this unblocks it so we can make the engine smarter and only use one.
Secondly renaming some of the fields we pass to
Run/GetRequiredPlugins/etc today. `Pwd` and `Program` were not very
descriptive and had pretty non-obvious documentation:
```
string pwd = 3; // the program's working directory.
string program = 4; // the path to the program to execute.
```
`pwd` will remain, although probably rename it to `working_directory` at
some point, because while today we always start programs up with the
working directory equal to the program directory that definitely is
going to change in the future (at least for MLCs and substack programs).
But the name `pwd` doesn't make it clear that this was intended to be
the working directory _and_ the directory which contains the program.
`program` was in fact nearly always ".", and if it wasn't that it was
just a filename. The engine never sent a path for `program` (although we
did have some unit tests to check how that worked for the nodejs and
python hosts).
These are now replaced by a new structure with (I think) more clearly
named and documented fields (see ProgramInfo in langauge.proto).
The engine still sends the old data for now, we need to update
dotnet/yaml/java before we break the old interface and give Virtus Labs
a chance to update [besom](https://github.com/VirtusLab/besom).
## Checklist
- [x] I have run `make tidy` to update any new dependencies
- [x] I have run `make lint` to verify my code passes the lint check
- [ ] I have formatted my code using `gofumpt`
<!--- Please provide details if the checkbox below is to be left
unchecked. -->
- [x] I have added tests that prove my fix is effective or that my
feature works
<!---
User-facing changes require a CHANGELOG entry.
-->
- [ ] I have run `make changelog` and committed the
`changelog/pending/<file>` documenting my change
<!--
If the change(s) in this PR is a modification of an existing call to the
Pulumi Cloud,
then the service should honor older versions of the CLI where this
change would not exist.
You must then bump the API version in
/pkg/backend/httpstate/client/api.go, as well as add
it to the service.
-->
- [ ] Yes, there are changes in this PR that warrants bumping the Pulumi
Cloud API version
<!-- @Pulumi employees: If yes, you must submit corresponding changes in
the service repo. -->
2023-12-10 17:30:51 +00:00
|
|
|
if err != nil {
|
2024-01-25 23:28:58 +00:00
|
|
|
return nil, err
|
Pass root and main info to language host methods (#14654)
<!---
Thanks so much for your contribution! If this is your first time
contributing, please ensure that you have read the
[CONTRIBUTING](https://github.com/pulumi/pulumi/blob/master/CONTRIBUTING.md)
documentation.
-->
# Description
<!--- Please include a summary of the change and which issue is fixed.
Please also include relevant motivation and context. -->
This is two changes rolled together in a way.
Firstly passing some of the data that we pass on language runtime
startup to also pass it to Run/GetRequiredPlugins/etc. This is needed
for matrix testing, as we only get to start the language runtime up once
for that but want to execute multiple programs with it.
I feel it's also a little more consistent as we use the language
runtimes in other contexts (codegen) where there isn't really a root
directory, and aren't any options (and if we did do options the options
for codegen are not going to be the same as for execution). It also
means we can reuse a language host for shimless and substack programs,
as before they heavily relied on their current working directory to
calculate paths, and obviosly could only take one set of options at
startup. Imagine a shimless python package + a python root program, that
would have needed two startups of the python language host to deal with,
this unblocks it so we can make the engine smarter and only use one.
Secondly renaming some of the fields we pass to
Run/GetRequiredPlugins/etc today. `Pwd` and `Program` were not very
descriptive and had pretty non-obvious documentation:
```
string pwd = 3; // the program's working directory.
string program = 4; // the path to the program to execute.
```
`pwd` will remain, although probably rename it to `working_directory` at
some point, because while today we always start programs up with the
working directory equal to the program directory that definitely is
going to change in the future (at least for MLCs and substack programs).
But the name `pwd` doesn't make it clear that this was intended to be
the working directory _and_ the directory which contains the program.
`program` was in fact nearly always ".", and if it wasn't that it was
just a filename. The engine never sent a path for `program` (although we
did have some unit tests to check how that worked for the nodejs and
python hosts).
These are now replaced by a new structure with (I think) more clearly
named and documented fields (see ProgramInfo in langauge.proto).
The engine still sends the old data for now, we need to update
dotnet/yaml/java before we break the old interface and give Virtus Labs
a chance to update [besom](https://github.com/VirtusLab/besom).
## Checklist
- [x] I have run `make tidy` to update any new dependencies
- [x] I have run `make lint` to verify my code passes the lint check
- [ ] I have formatted my code using `gofumpt`
<!--- Please provide details if the checkbox below is to be left
unchecked. -->
- [x] I have added tests that prove my fix is effective or that my
feature works
<!---
User-facing changes require a CHANGELOG entry.
-->
- [ ] I have run `make changelog` and committed the
`changelog/pending/<file>` documenting my change
<!--
If the change(s) in this PR is a modification of an existing call to the
Pulumi Cloud,
then the service should honor older versions of the CLI where this
change would not exist.
You must then bump the API version in
/pkg/backend/httpstate/client/api.go, as well as add
it to the service.
-->
- [ ] Yes, there are changes in this PR that warrants bumping the Pulumi
Cloud API version
<!-- @Pulumi employees: If yes, you must submit corresponding changes in
the service repo. -->
2023-12-10 17:30:51 +00:00
|
|
|
}
|
|
|
|
|
2018-02-06 17:57:32 +00:00
|
|
|
resp, err := h.client.GetRequiredPlugins(h.ctx.Request(), &pulumirpc.GetRequiredPluginsRequest{
|
2024-01-16 17:06:14 +00:00
|
|
|
Project: "deprecated",
|
2024-01-25 23:28:58 +00:00
|
|
|
Pwd: info.ProgramDirectory(),
|
|
|
|
Program: info.EntryPoint(),
|
|
|
|
Info: minfo,
|
2018-02-06 17:57:32 +00:00
|
|
|
})
|
|
|
|
if err != nil {
|
2018-03-29 00:07:35 +00:00
|
|
|
rpcError := rpcerror.Convert(err)
|
2024-01-25 23:28:58 +00:00
|
|
|
logging.V(7).Infof("langhost[%v].GetRequiredPlugins(%s) failed: err=%v",
|
|
|
|
h.runtime, info, rpcError)
|
2018-02-22 15:50:37 +00:00
|
|
|
|
|
|
|
// It's possible this is just an older language host, prior to the emergence of the GetRequiredPlugins
|
|
|
|
// method. In such cases, we will silently error (with the above log left behind).
|
2018-03-29 00:07:35 +00:00
|
|
|
if rpcError.Code() == codes.Unimplemented {
|
2018-02-22 15:50:37 +00:00
|
|
|
return nil, nil
|
|
|
|
}
|
|
|
|
|
2018-03-29 00:07:35 +00:00
|
|
|
return nil, rpcError
|
2018-02-06 17:57:32 +00:00
|
|
|
}
|
|
|
|
|
2023-06-28 16:02:04 +00:00
|
|
|
results := slice.Prealloc[workspace.PluginSpec](len(resp.GetPlugins()))
|
2018-02-06 17:57:32 +00:00
|
|
|
for _, info := range resp.GetPlugins() {
|
|
|
|
var version *semver.Version
|
|
|
|
if v := info.GetVersion(); v != "" {
|
|
|
|
sv, err := semver.ParseTolerant(v)
|
|
|
|
if err != nil {
|
2024-09-09 11:11:46 +00:00
|
|
|
return nil, fmt.Errorf("illegal semver returned by language host: %s@%s: %w", info.GetName(), v, err)
|
2018-02-06 17:57:32 +00:00
|
|
|
}
|
|
|
|
version = &sv
|
|
|
|
}
|
2024-04-25 17:30:30 +00:00
|
|
|
if !apitype.IsPluginKind(info.Kind) {
|
2024-09-09 11:11:46 +00:00
|
|
|
return nil, fmt.Errorf("unrecognized plugin kind: %s", info.Kind)
|
2018-02-06 17:57:32 +00:00
|
|
|
}
|
2022-08-26 14:51:14 +00:00
|
|
|
results = append(results, workspace.PluginSpec{
|
2023-08-25 15:26:25 +00:00
|
|
|
Name: info.Name,
|
2024-04-25 17:30:30 +00:00
|
|
|
Kind: apitype.PluginKind(info.Kind),
|
2021-12-17 22:52:01 +00:00
|
|
|
Version: version,
|
2023-08-25 15:26:25 +00:00
|
|
|
PluginDownloadURL: info.Server,
|
|
|
|
Checksums: info.Checksums,
|
2018-02-06 17:57:32 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2024-01-25 23:28:58 +00:00
|
|
|
logging.V(7).Infof("langhost[%v].GetRequiredPlugins(%s) success: #versions=%d",
|
|
|
|
h.runtime, info, len(results))
|
2018-02-06 17:57:32 +00:00
|
|
|
return results, nil
|
|
|
|
}
|
|
|
|
|
2019-03-20 18:54:32 +00:00
|
|
|
// 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, bool, error) {
|
2024-01-25 23:28:58 +00:00
|
|
|
logging.V(7).Infof("langhost[%v].Run(pwd=%v,%s,#args=%v,proj=%s,stack=%v,#config=%v,dryrun=%v) executing",
|
|
|
|
h.runtime, info.Pwd, info.Info, len(info.Args), info.Project, info.Stack, len(info.Config), info.DryRun)
|
2021-05-18 16:48:08 +00:00
|
|
|
config := make(map[string]string, len(info.Config))
|
2017-08-31 21:31:33 +00:00
|
|
|
for k, v := range info.Config {
|
2018-03-02 23:23:59 +00:00
|
|
|
config[k.String()] = v
|
2017-08-31 21:31:33 +00:00
|
|
|
}
|
2021-05-18 16:48:08 +00:00
|
|
|
configSecretKeys := make([]string, len(info.ConfigSecretKeys))
|
|
|
|
for i, k := range info.ConfigSecretKeys {
|
|
|
|
configSecretKeys[i] = k.String()
|
|
|
|
}
|
2023-10-20 10:44:16 +00:00
|
|
|
configPropertyMap, err := MarshalProperties(info.ConfigPropertyMap,
|
|
|
|
MarshalOptions{RejectUnknowns: true, KeepSecrets: true, SkipInternalKeys: true})
|
|
|
|
if err != nil {
|
|
|
|
return "", false, err
|
|
|
|
}
|
Pass root and main info to language host methods (#14654)
<!---
Thanks so much for your contribution! If this is your first time
contributing, please ensure that you have read the
[CONTRIBUTING](https://github.com/pulumi/pulumi/blob/master/CONTRIBUTING.md)
documentation.
-->
# Description
<!--- Please include a summary of the change and which issue is fixed.
Please also include relevant motivation and context. -->
This is two changes rolled together in a way.
Firstly passing some of the data that we pass on language runtime
startup to also pass it to Run/GetRequiredPlugins/etc. This is needed
for matrix testing, as we only get to start the language runtime up once
for that but want to execute multiple programs with it.
I feel it's also a little more consistent as we use the language
runtimes in other contexts (codegen) where there isn't really a root
directory, and aren't any options (and if we did do options the options
for codegen are not going to be the same as for execution). It also
means we can reuse a language host for shimless and substack programs,
as before they heavily relied on their current working directory to
calculate paths, and obviosly could only take one set of options at
startup. Imagine a shimless python package + a python root program, that
would have needed two startups of the python language host to deal with,
this unblocks it so we can make the engine smarter and only use one.
Secondly renaming some of the fields we pass to
Run/GetRequiredPlugins/etc today. `Pwd` and `Program` were not very
descriptive and had pretty non-obvious documentation:
```
string pwd = 3; // the program's working directory.
string program = 4; // the path to the program to execute.
```
`pwd` will remain, although probably rename it to `working_directory` at
some point, because while today we always start programs up with the
working directory equal to the program directory that definitely is
going to change in the future (at least for MLCs and substack programs).
But the name `pwd` doesn't make it clear that this was intended to be
the working directory _and_ the directory which contains the program.
`program` was in fact nearly always ".", and if it wasn't that it was
just a filename. The engine never sent a path for `program` (although we
did have some unit tests to check how that worked for the nodejs and
python hosts).
These are now replaced by a new structure with (I think) more clearly
named and documented fields (see ProgramInfo in langauge.proto).
The engine still sends the old data for now, we need to update
dotnet/yaml/java before we break the old interface and give Virtus Labs
a chance to update [besom](https://github.com/VirtusLab/besom).
## Checklist
- [x] I have run `make tidy` to update any new dependencies
- [x] I have run `make lint` to verify my code passes the lint check
- [ ] I have formatted my code using `gofumpt`
<!--- Please provide details if the checkbox below is to be left
unchecked. -->
- [x] I have added tests that prove my fix is effective or that my
feature works
<!---
User-facing changes require a CHANGELOG entry.
-->
- [ ] I have run `make changelog` and committed the
`changelog/pending/<file>` documenting my change
<!--
If the change(s) in this PR is a modification of an existing call to the
Pulumi Cloud,
then the service should honor older versions of the CLI where this
change would not exist.
You must then bump the API version in
/pkg/backend/httpstate/client/api.go, as well as add
it to the service.
-->
- [ ] Yes, there are changes in this PR that warrants bumping the Pulumi
Cloud API version
<!-- @Pulumi employees: If yes, you must submit corresponding changes in
the service repo. -->
2023-12-10 17:30:51 +00:00
|
|
|
|
2024-01-25 23:28:58 +00:00
|
|
|
minfo, err := info.Info.Marshal()
|
Pass root and main info to language host methods (#14654)
<!---
Thanks so much for your contribution! If this is your first time
contributing, please ensure that you have read the
[CONTRIBUTING](https://github.com/pulumi/pulumi/blob/master/CONTRIBUTING.md)
documentation.
-->
# Description
<!--- Please include a summary of the change and which issue is fixed.
Please also include relevant motivation and context. -->
This is two changes rolled together in a way.
Firstly passing some of the data that we pass on language runtime
startup to also pass it to Run/GetRequiredPlugins/etc. This is needed
for matrix testing, as we only get to start the language runtime up once
for that but want to execute multiple programs with it.
I feel it's also a little more consistent as we use the language
runtimes in other contexts (codegen) where there isn't really a root
directory, and aren't any options (and if we did do options the options
for codegen are not going to be the same as for execution). It also
means we can reuse a language host for shimless and substack programs,
as before they heavily relied on their current working directory to
calculate paths, and obviosly could only take one set of options at
startup. Imagine a shimless python package + a python root program, that
would have needed two startups of the python language host to deal with,
this unblocks it so we can make the engine smarter and only use one.
Secondly renaming some of the fields we pass to
Run/GetRequiredPlugins/etc today. `Pwd` and `Program` were not very
descriptive and had pretty non-obvious documentation:
```
string pwd = 3; // the program's working directory.
string program = 4; // the path to the program to execute.
```
`pwd` will remain, although probably rename it to `working_directory` at
some point, because while today we always start programs up with the
working directory equal to the program directory that definitely is
going to change in the future (at least for MLCs and substack programs).
But the name `pwd` doesn't make it clear that this was intended to be
the working directory _and_ the directory which contains the program.
`program` was in fact nearly always ".", and if it wasn't that it was
just a filename. The engine never sent a path for `program` (although we
did have some unit tests to check how that worked for the nodejs and
python hosts).
These are now replaced by a new structure with (I think) more clearly
named and documented fields (see ProgramInfo in langauge.proto).
The engine still sends the old data for now, we need to update
dotnet/yaml/java before we break the old interface and give Virtus Labs
a chance to update [besom](https://github.com/VirtusLab/besom).
## Checklist
- [x] I have run `make tidy` to update any new dependencies
- [x] I have run `make lint` to verify my code passes the lint check
- [ ] I have formatted my code using `gofumpt`
<!--- Please provide details if the checkbox below is to be left
unchecked. -->
- [x] I have added tests that prove my fix is effective or that my
feature works
<!---
User-facing changes require a CHANGELOG entry.
-->
- [ ] I have run `make changelog` and committed the
`changelog/pending/<file>` documenting my change
<!--
If the change(s) in this PR is a modification of an existing call to the
Pulumi Cloud,
then the service should honor older versions of the CLI where this
change would not exist.
You must then bump the API version in
/pkg/backend/httpstate/client/api.go, as well as add
it to the service.
-->
- [ ] Yes, there are changes in this PR that warrants bumping the Pulumi
Cloud API version
<!-- @Pulumi employees: If yes, you must submit corresponding changes in
the service repo. -->
2023-12-10 17:30:51 +00:00
|
|
|
if err != nil {
|
2024-01-25 23:28:58 +00:00
|
|
|
return "", false, err
|
Pass root and main info to language host methods (#14654)
<!---
Thanks so much for your contribution! If this is your first time
contributing, please ensure that you have read the
[CONTRIBUTING](https://github.com/pulumi/pulumi/blob/master/CONTRIBUTING.md)
documentation.
-->
# Description
<!--- Please include a summary of the change and which issue is fixed.
Please also include relevant motivation and context. -->
This is two changes rolled together in a way.
Firstly passing some of the data that we pass on language runtime
startup to also pass it to Run/GetRequiredPlugins/etc. This is needed
for matrix testing, as we only get to start the language runtime up once
for that but want to execute multiple programs with it.
I feel it's also a little more consistent as we use the language
runtimes in other contexts (codegen) where there isn't really a root
directory, and aren't any options (and if we did do options the options
for codegen are not going to be the same as for execution). It also
means we can reuse a language host for shimless and substack programs,
as before they heavily relied on their current working directory to
calculate paths, and obviosly could only take one set of options at
startup. Imagine a shimless python package + a python root program, that
would have needed two startups of the python language host to deal with,
this unblocks it so we can make the engine smarter and only use one.
Secondly renaming some of the fields we pass to
Run/GetRequiredPlugins/etc today. `Pwd` and `Program` were not very
descriptive and had pretty non-obvious documentation:
```
string pwd = 3; // the program's working directory.
string program = 4; // the path to the program to execute.
```
`pwd` will remain, although probably rename it to `working_directory` at
some point, because while today we always start programs up with the
working directory equal to the program directory that definitely is
going to change in the future (at least for MLCs and substack programs).
But the name `pwd` doesn't make it clear that this was intended to be
the working directory _and_ the directory which contains the program.
`program` was in fact nearly always ".", and if it wasn't that it was
just a filename. The engine never sent a path for `program` (although we
did have some unit tests to check how that worked for the nodejs and
python hosts).
These are now replaced by a new structure with (I think) more clearly
named and documented fields (see ProgramInfo in langauge.proto).
The engine still sends the old data for now, we need to update
dotnet/yaml/java before we break the old interface and give Virtus Labs
a chance to update [besom](https://github.com/VirtusLab/besom).
## Checklist
- [x] I have run `make tidy` to update any new dependencies
- [x] I have run `make lint` to verify my code passes the lint check
- [ ] I have formatted my code using `gofumpt`
<!--- Please provide details if the checkbox below is to be left
unchecked. -->
- [x] I have added tests that prove my fix is effective or that my
feature works
<!---
User-facing changes require a CHANGELOG entry.
-->
- [ ] I have run `make changelog` and committed the
`changelog/pending/<file>` documenting my change
<!--
If the change(s) in this PR is a modification of an existing call to the
Pulumi Cloud,
then the service should honor older versions of the CLI where this
change would not exist.
You must then bump the API version in
/pkg/backend/httpstate/client/api.go, as well as add
it to the service.
-->
- [ ] Yes, there are changes in this PR that warrants bumping the Pulumi
Cloud API version
<!-- @Pulumi employees: If yes, you must submit corresponding changes in
the service repo. -->
2023-12-10 17:30:51 +00:00
|
|
|
}
|
|
|
|
|
2017-12-01 21:50:32 +00:00
|
|
|
resp, err := h.client.Run(h.ctx.Request(), &pulumirpc.RunRequest{
|
2023-10-20 10:44:16 +00:00
|
|
|
MonitorAddress: info.MonitorAddress,
|
|
|
|
Pwd: info.Pwd,
|
2024-01-25 23:28:58 +00:00
|
|
|
Program: info.Info.EntryPoint(),
|
2023-10-20 10:44:16 +00:00
|
|
|
Args: info.Args,
|
|
|
|
Project: info.Project,
|
|
|
|
Stack: info.Stack,
|
|
|
|
Config: config,
|
|
|
|
ConfigSecretKeys: configSecretKeys,
|
|
|
|
ConfigPropertyMap: configPropertyMap,
|
|
|
|
DryRun: info.DryRun,
|
|
|
|
QueryMode: info.QueryMode,
|
2024-08-28 13:45:17 +00:00
|
|
|
Parallel: info.Parallel,
|
2023-10-20 10:44:16 +00:00
|
|
|
Organization: info.Organization,
|
2024-01-25 23:28:58 +00:00
|
|
|
Info: minfo,
|
2024-08-29 09:14:39 +00:00
|
|
|
LoaderTarget: info.LoaderAddress,
|
2024-09-04 10:36:45 +00:00
|
|
|
AttachDebugger: info.AttachDebugger,
|
2017-08-31 21:31:33 +00:00
|
|
|
})
|
2017-08-30 01:24:12 +00:00
|
|
|
if err != nil {
|
2018-03-29 00:07:35 +00:00
|
|
|
rpcError := rpcerror.Convert(err)
|
2024-01-25 23:28:58 +00:00
|
|
|
logging.V(7).Infof("langhost[%v].Run(pwd=%v,%s,...,dryrun=%v) failed: err=%v",
|
|
|
|
h.runtime, info.Pwd, info.Info, info.DryRun, rpcError)
|
2019-03-20 18:54:32 +00:00
|
|
|
return "", false, rpcError
|
2017-08-30 01:24:12 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
progerr := resp.GetError()
|
2019-03-20 18:54:32 +00:00
|
|
|
bail := resp.GetBail()
|
2024-01-25 23:28:58 +00:00
|
|
|
logging.V(7).Infof("langhost[%v].Run(pwd=%v,%s,...,dryrun=%v) success: progerr=%v, bail=%v",
|
|
|
|
h.runtime, info.Pwd, info.Info, info.DryRun, progerr, bail)
|
2019-03-20 18:54:32 +00:00
|
|
|
return progerr, bail, nil
|
2017-08-30 01:24:12 +00:00
|
|
|
}
|
|
|
|
|
2017-12-01 21:50:32 +00:00
|
|
|
// GetPluginInfo returns this plugin's information.
|
2018-02-06 17:57:32 +00:00
|
|
|
func (h *langhost) GetPluginInfo() (workspace.PluginInfo, error) {
|
2018-05-15 22:28:00 +00:00
|
|
|
logging.V(7).Infof("langhost[%v].GetPluginInfo() executing", h.runtime)
|
2020-07-24 08:31:54 +00:00
|
|
|
|
|
|
|
plugInfo := workspace.PluginInfo{
|
|
|
|
Name: h.runtime,
|
2024-04-25 17:30:30 +00:00
|
|
|
Kind: apitype.LanguagePlugin,
|
2017-12-01 21:50:32 +00:00
|
|
|
}
|
2018-02-06 17:57:32 +00:00
|
|
|
|
2024-09-10 21:38:36 +00:00
|
|
|
if h.plug != nil {
|
|
|
|
plugInfo.Path = h.plug.Bin
|
|
|
|
}
|
2020-07-24 08:31:54 +00:00
|
|
|
|
2024-01-17 09:35:20 +00:00
|
|
|
resp, err := h.client.GetPluginInfo(h.ctx.Request(), &emptypb.Empty{})
|
2020-09-15 00:40:17 +00:00
|
|
|
if err != nil {
|
|
|
|
rpcError := rpcerror.Convert(err)
|
|
|
|
logging.V(7).Infof("langhost[%v].GetPluginInfo() failed: err=%v", h.runtime, rpcError)
|
|
|
|
return workspace.PluginInfo{}, rpcError
|
2020-07-24 08:31:54 +00:00
|
|
|
}
|
2020-09-15 00:40:17 +00:00
|
|
|
vers := resp.Version
|
2020-07-24 08:31:54 +00:00
|
|
|
|
|
|
|
if vers != "" {
|
|
|
|
sv, err := semver.ParseTolerant(vers)
|
2018-02-06 17:57:32 +00:00
|
|
|
if err != nil {
|
|
|
|
return workspace.PluginInfo{}, err
|
|
|
|
}
|
2020-07-24 08:31:54 +00:00
|
|
|
plugInfo.Version = &sv
|
2018-02-06 17:57:32 +00:00
|
|
|
}
|
|
|
|
|
2020-07-24 08:31:54 +00:00
|
|
|
return plugInfo, nil
|
2017-12-01 21:50:32 +00:00
|
|
|
}
|
|
|
|
|
2017-08-30 01:24:12 +00:00
|
|
|
// Close tears down the underlying plugin RPC connection and process.
|
|
|
|
func (h *langhost) Close() error {
|
2020-07-24 08:31:54 +00:00
|
|
|
if h.plug != nil {
|
|
|
|
return h.plug.Close()
|
|
|
|
}
|
|
|
|
return nil
|
2017-08-30 01:24:12 +00:00
|
|
|
}
|
2022-04-03 14:54:59 +00:00
|
|
|
|
2024-08-19 15:55:54 +00:00
|
|
|
func (h *langhost) InstallDependencies(request InstallDependenciesRequest) error {
|
2024-01-25 23:28:58 +00:00
|
|
|
logging.V(7).Infof("langhost[%v].InstallDependencies(%s) executing",
|
2024-08-19 15:55:54 +00:00
|
|
|
h.runtime, request)
|
Pass root and main info to language host methods (#14654)
<!---
Thanks so much for your contribution! If this is your first time
contributing, please ensure that you have read the
[CONTRIBUTING](https://github.com/pulumi/pulumi/blob/master/CONTRIBUTING.md)
documentation.
-->
# Description
<!--- Please include a summary of the change and which issue is fixed.
Please also include relevant motivation and context. -->
This is two changes rolled together in a way.
Firstly passing some of the data that we pass on language runtime
startup to also pass it to Run/GetRequiredPlugins/etc. This is needed
for matrix testing, as we only get to start the language runtime up once
for that but want to execute multiple programs with it.
I feel it's also a little more consistent as we use the language
runtimes in other contexts (codegen) where there isn't really a root
directory, and aren't any options (and if we did do options the options
for codegen are not going to be the same as for execution). It also
means we can reuse a language host for shimless and substack programs,
as before they heavily relied on their current working directory to
calculate paths, and obviosly could only take one set of options at
startup. Imagine a shimless python package + a python root program, that
would have needed two startups of the python language host to deal with,
this unblocks it so we can make the engine smarter and only use one.
Secondly renaming some of the fields we pass to
Run/GetRequiredPlugins/etc today. `Pwd` and `Program` were not very
descriptive and had pretty non-obvious documentation:
```
string pwd = 3; // the program's working directory.
string program = 4; // the path to the program to execute.
```
`pwd` will remain, although probably rename it to `working_directory` at
some point, because while today we always start programs up with the
working directory equal to the program directory that definitely is
going to change in the future (at least for MLCs and substack programs).
But the name `pwd` doesn't make it clear that this was intended to be
the working directory _and_ the directory which contains the program.
`program` was in fact nearly always ".", and if it wasn't that it was
just a filename. The engine never sent a path for `program` (although we
did have some unit tests to check how that worked for the nodejs and
python hosts).
These are now replaced by a new structure with (I think) more clearly
named and documented fields (see ProgramInfo in langauge.proto).
The engine still sends the old data for now, we need to update
dotnet/yaml/java before we break the old interface and give Virtus Labs
a chance to update [besom](https://github.com/VirtusLab/besom).
## Checklist
- [x] I have run `make tidy` to update any new dependencies
- [x] I have run `make lint` to verify my code passes the lint check
- [ ] I have formatted my code using `gofumpt`
<!--- Please provide details if the checkbox below is to be left
unchecked. -->
- [x] I have added tests that prove my fix is effective or that my
feature works
<!---
User-facing changes require a CHANGELOG entry.
-->
- [ ] I have run `make changelog` and committed the
`changelog/pending/<file>` documenting my change
<!--
If the change(s) in this PR is a modification of an existing call to the
Pulumi Cloud,
then the service should honor older versions of the CLI where this
change would not exist.
You must then bump the API version in
/pkg/backend/httpstate/client/api.go, as well as add
it to the service.
-->
- [ ] Yes, there are changes in this PR that warrants bumping the Pulumi
Cloud API version
<!-- @Pulumi employees: If yes, you must submit corresponding changes in
the service repo. -->
2023-12-10 17:30:51 +00:00
|
|
|
|
2024-08-19 15:55:54 +00:00
|
|
|
minfo, err := request.Info.Marshal()
|
Pass root and main info to language host methods (#14654)
<!---
Thanks so much for your contribution! If this is your first time
contributing, please ensure that you have read the
[CONTRIBUTING](https://github.com/pulumi/pulumi/blob/master/CONTRIBUTING.md)
documentation.
-->
# Description
<!--- Please include a summary of the change and which issue is fixed.
Please also include relevant motivation and context. -->
This is two changes rolled together in a way.
Firstly passing some of the data that we pass on language runtime
startup to also pass it to Run/GetRequiredPlugins/etc. This is needed
for matrix testing, as we only get to start the language runtime up once
for that but want to execute multiple programs with it.
I feel it's also a little more consistent as we use the language
runtimes in other contexts (codegen) where there isn't really a root
directory, and aren't any options (and if we did do options the options
for codegen are not going to be the same as for execution). It also
means we can reuse a language host for shimless and substack programs,
as before they heavily relied on their current working directory to
calculate paths, and obviosly could only take one set of options at
startup. Imagine a shimless python package + a python root program, that
would have needed two startups of the python language host to deal with,
this unblocks it so we can make the engine smarter and only use one.
Secondly renaming some of the fields we pass to
Run/GetRequiredPlugins/etc today. `Pwd` and `Program` were not very
descriptive and had pretty non-obvious documentation:
```
string pwd = 3; // the program's working directory.
string program = 4; // the path to the program to execute.
```
`pwd` will remain, although probably rename it to `working_directory` at
some point, because while today we always start programs up with the
working directory equal to the program directory that definitely is
going to change in the future (at least for MLCs and substack programs).
But the name `pwd` doesn't make it clear that this was intended to be
the working directory _and_ the directory which contains the program.
`program` was in fact nearly always ".", and if it wasn't that it was
just a filename. The engine never sent a path for `program` (although we
did have some unit tests to check how that worked for the nodejs and
python hosts).
These are now replaced by a new structure with (I think) more clearly
named and documented fields (see ProgramInfo in langauge.proto).
The engine still sends the old data for now, we need to update
dotnet/yaml/java before we break the old interface and give Virtus Labs
a chance to update [besom](https://github.com/VirtusLab/besom).
## Checklist
- [x] I have run `make tidy` to update any new dependencies
- [x] I have run `make lint` to verify my code passes the lint check
- [ ] I have formatted my code using `gofumpt`
<!--- Please provide details if the checkbox below is to be left
unchecked. -->
- [x] I have added tests that prove my fix is effective or that my
feature works
<!---
User-facing changes require a CHANGELOG entry.
-->
- [ ] I have run `make changelog` and committed the
`changelog/pending/<file>` documenting my change
<!--
If the change(s) in this PR is a modification of an existing call to the
Pulumi Cloud,
then the service should honor older versions of the CLI where this
change would not exist.
You must then bump the API version in
/pkg/backend/httpstate/client/api.go, as well as add
it to the service.
-->
- [ ] Yes, there are changes in this PR that warrants bumping the Pulumi
Cloud API version
<!-- @Pulumi employees: If yes, you must submit corresponding changes in
the service repo. -->
2023-12-10 17:30:51 +00:00
|
|
|
if err != nil {
|
2024-01-25 23:28:58 +00:00
|
|
|
return err
|
Pass root and main info to language host methods (#14654)
<!---
Thanks so much for your contribution! If this is your first time
contributing, please ensure that you have read the
[CONTRIBUTING](https://github.com/pulumi/pulumi/blob/master/CONTRIBUTING.md)
documentation.
-->
# Description
<!--- Please include a summary of the change and which issue is fixed.
Please also include relevant motivation and context. -->
This is two changes rolled together in a way.
Firstly passing some of the data that we pass on language runtime
startup to also pass it to Run/GetRequiredPlugins/etc. This is needed
for matrix testing, as we only get to start the language runtime up once
for that but want to execute multiple programs with it.
I feel it's also a little more consistent as we use the language
runtimes in other contexts (codegen) where there isn't really a root
directory, and aren't any options (and if we did do options the options
for codegen are not going to be the same as for execution). It also
means we can reuse a language host for shimless and substack programs,
as before they heavily relied on their current working directory to
calculate paths, and obviosly could only take one set of options at
startup. Imagine a shimless python package + a python root program, that
would have needed two startups of the python language host to deal with,
this unblocks it so we can make the engine smarter and only use one.
Secondly renaming some of the fields we pass to
Run/GetRequiredPlugins/etc today. `Pwd` and `Program` were not very
descriptive and had pretty non-obvious documentation:
```
string pwd = 3; // the program's working directory.
string program = 4; // the path to the program to execute.
```
`pwd` will remain, although probably rename it to `working_directory` at
some point, because while today we always start programs up with the
working directory equal to the program directory that definitely is
going to change in the future (at least for MLCs and substack programs).
But the name `pwd` doesn't make it clear that this was intended to be
the working directory _and_ the directory which contains the program.
`program` was in fact nearly always ".", and if it wasn't that it was
just a filename. The engine never sent a path for `program` (although we
did have some unit tests to check how that worked for the nodejs and
python hosts).
These are now replaced by a new structure with (I think) more clearly
named and documented fields (see ProgramInfo in langauge.proto).
The engine still sends the old data for now, we need to update
dotnet/yaml/java before we break the old interface and give Virtus Labs
a chance to update [besom](https://github.com/VirtusLab/besom).
## Checklist
- [x] I have run `make tidy` to update any new dependencies
- [x] I have run `make lint` to verify my code passes the lint check
- [ ] I have formatted my code using `gofumpt`
<!--- Please provide details if the checkbox below is to be left
unchecked. -->
- [x] I have added tests that prove my fix is effective or that my
feature works
<!---
User-facing changes require a CHANGELOG entry.
-->
- [ ] I have run `make changelog` and committed the
`changelog/pending/<file>` documenting my change
<!--
If the change(s) in this PR is a modification of an existing call to the
Pulumi Cloud,
then the service should honor older versions of the CLI where this
change would not exist.
You must then bump the API version in
/pkg/backend/httpstate/client/api.go, as well as add
it to the service.
-->
- [ ] Yes, there are changes in this PR that warrants bumping the Pulumi
Cloud API version
<!-- @Pulumi employees: If yes, you must submit corresponding changes in
the service repo. -->
2023-12-10 17:30:51 +00:00
|
|
|
}
|
|
|
|
|
2022-04-03 14:54:59 +00:00
|
|
|
resp, err := h.client.InstallDependencies(h.ctx.Request(), &pulumirpc.InstallDependenciesRequest{
|
2024-08-19 15:55:54 +00:00
|
|
|
Directory: request.Info.ProgramDirectory(),
|
|
|
|
IsTerminal: cmdutil.GetGlobalColorization() != colors.Never,
|
|
|
|
Info: minfo,
|
|
|
|
UseLanguageVersionTools: request.UseLanguageVersionTools,
|
2022-04-03 14:54:59 +00:00
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
rpcError := rpcerror.Convert(err)
|
2024-01-25 23:28:58 +00:00
|
|
|
logging.V(7).Infof("langhost[%v].InstallDependencies(%s) failed: err=%v",
|
2024-08-19 15:55:54 +00:00
|
|
|
h.runtime, request, rpcError)
|
2022-04-03 14:54:59 +00:00
|
|
|
|
|
|
|
// It's possible this is just an older language host, prior to the emergence of the InstallDependencies
|
|
|
|
// method. In such cases, we will silently error (with the above log left behind).
|
|
|
|
if rpcError.Code() == codes.Unimplemented {
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
|
|
|
return rpcError
|
|
|
|
}
|
|
|
|
|
|
|
|
for {
|
|
|
|
output, err := resp.Recv()
|
|
|
|
if err != nil {
|
|
|
|
if err == io.EOF {
|
|
|
|
break
|
|
|
|
}
|
|
|
|
rpcError := rpcerror.Convert(err)
|
2024-01-25 23:28:58 +00:00
|
|
|
logging.V(7).Infof("langhost[%v].InstallDependencies(%s) failed: err=%v",
|
2024-08-19 15:55:54 +00:00
|
|
|
h.runtime, request, rpcError)
|
2022-04-03 14:54:59 +00:00
|
|
|
return rpcError
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(output.Stdout) != 0 {
|
|
|
|
os.Stdout.Write(output.Stdout)
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(output.Stderr) != 0 {
|
|
|
|
os.Stderr.Write(output.Stderr)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2024-01-25 23:28:58 +00:00
|
|
|
logging.V(7).Infof("langhost[%v].InstallDependencies(%s) success",
|
2024-08-19 15:55:54 +00:00
|
|
|
h.runtime, request)
|
2022-04-03 14:54:59 +00:00
|
|
|
return nil
|
|
|
|
}
|
2022-08-15 13:55:04 +00:00
|
|
|
|
2024-06-17 17:10:55 +00:00
|
|
|
func (h *langhost) RuntimeOptionsPrompts(info ProgramInfo) ([]RuntimeOptionPrompt, error) {
|
|
|
|
logging.V(7).Infof("langhost[%v].RuntimeOptionsPrompts() executing", h.runtime)
|
|
|
|
|
|
|
|
minfo, err := info.Marshal()
|
|
|
|
if err != nil {
|
|
|
|
return []RuntimeOptionPrompt{}, err
|
|
|
|
}
|
|
|
|
|
|
|
|
resp, err := h.client.RuntimeOptionsPrompts(h.ctx.Request(), &pulumirpc.RuntimeOptionsRequest{
|
|
|
|
Info: minfo,
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
if status.Code(err) == codes.Unimplemented {
|
|
|
|
logging.V(7).Infof("langhost[%v].RuntimeOptionsPrompts() not implemented, returning no prompts", h.runtime)
|
|
|
|
return []RuntimeOptionPrompt{}, nil
|
|
|
|
}
|
|
|
|
rpcError := rpcerror.Convert(err)
|
|
|
|
logging.V(7).Infof("langhost[%v].RuntimeOptionsPrompts() failed: err=%v", h.runtime, rpcError)
|
|
|
|
return []RuntimeOptionPrompt{}, rpcError
|
|
|
|
}
|
|
|
|
|
|
|
|
prompts := []RuntimeOptionPrompt{}
|
|
|
|
for _, prompt := range resp.Prompts {
|
|
|
|
newPrompt, err := UnmarshallRuntimeOptionPrompt(prompt)
|
|
|
|
if err != nil {
|
|
|
|
return []RuntimeOptionPrompt{}, err
|
|
|
|
}
|
|
|
|
prompts = append(prompts, newPrompt)
|
|
|
|
}
|
|
|
|
|
|
|
|
logging.V(7).Infof("langhost[%v].RuntimeOptionsPrompts() success", h.runtime)
|
|
|
|
return prompts, nil
|
|
|
|
}
|
|
|
|
|
2024-06-06 08:21:46 +00:00
|
|
|
func (h *langhost) About(info ProgramInfo) (AboutInfo, error) {
|
2022-08-15 13:55:04 +00:00
|
|
|
logging.V(7).Infof("langhost[%v].About() executing", h.runtime)
|
2024-06-06 08:21:46 +00:00
|
|
|
minfo, err := info.Marshal()
|
|
|
|
if err != nil {
|
|
|
|
return AboutInfo{}, err
|
|
|
|
}
|
|
|
|
resp, err := h.client.About(h.ctx.Request(), &pulumirpc.AboutRequest{
|
|
|
|
Info: minfo,
|
|
|
|
})
|
2022-08-15 13:55:04 +00:00
|
|
|
if err != nil {
|
|
|
|
rpcError := rpcerror.Convert(err)
|
|
|
|
logging.V(7).Infof("langhost[%v].About() failed: err=%v", h.runtime, rpcError)
|
|
|
|
|
|
|
|
return AboutInfo{}, rpcError
|
|
|
|
}
|
|
|
|
|
|
|
|
result := AboutInfo{
|
|
|
|
Executable: resp.Executable,
|
|
|
|
Version: resp.Version,
|
|
|
|
Metadata: resp.Metadata,
|
|
|
|
}
|
|
|
|
|
|
|
|
logging.V(7).Infof("langhost[%v].About() success", h.runtime)
|
|
|
|
return result, nil
|
|
|
|
}
|
|
|
|
|
2024-01-25 23:28:58 +00:00
|
|
|
func (h *langhost) GetProgramDependencies(info ProgramInfo, transitiveDependencies bool) ([]DependencyInfo, error) {
|
|
|
|
prefix := fmt.Sprintf("langhost[%v].GetProgramDependencies(%s)", h.runtime, info.String())
|
|
|
|
minfo, err := info.Marshal()
|
Pass root and main info to language host methods (#14654)
<!---
Thanks so much for your contribution! If this is your first time
contributing, please ensure that you have read the
[CONTRIBUTING](https://github.com/pulumi/pulumi/blob/master/CONTRIBUTING.md)
documentation.
-->
# Description
<!--- Please include a summary of the change and which issue is fixed.
Please also include relevant motivation and context. -->
This is two changes rolled together in a way.
Firstly passing some of the data that we pass on language runtime
startup to also pass it to Run/GetRequiredPlugins/etc. This is needed
for matrix testing, as we only get to start the language runtime up once
for that but want to execute multiple programs with it.
I feel it's also a little more consistent as we use the language
runtimes in other contexts (codegen) where there isn't really a root
directory, and aren't any options (and if we did do options the options
for codegen are not going to be the same as for execution). It also
means we can reuse a language host for shimless and substack programs,
as before they heavily relied on their current working directory to
calculate paths, and obviosly could only take one set of options at
startup. Imagine a shimless python package + a python root program, that
would have needed two startups of the python language host to deal with,
this unblocks it so we can make the engine smarter and only use one.
Secondly renaming some of the fields we pass to
Run/GetRequiredPlugins/etc today. `Pwd` and `Program` were not very
descriptive and had pretty non-obvious documentation:
```
string pwd = 3; // the program's working directory.
string program = 4; // the path to the program to execute.
```
`pwd` will remain, although probably rename it to `working_directory` at
some point, because while today we always start programs up with the
working directory equal to the program directory that definitely is
going to change in the future (at least for MLCs and substack programs).
But the name `pwd` doesn't make it clear that this was intended to be
the working directory _and_ the directory which contains the program.
`program` was in fact nearly always ".", and if it wasn't that it was
just a filename. The engine never sent a path for `program` (although we
did have some unit tests to check how that worked for the nodejs and
python hosts).
These are now replaced by a new structure with (I think) more clearly
named and documented fields (see ProgramInfo in langauge.proto).
The engine still sends the old data for now, we need to update
dotnet/yaml/java before we break the old interface and give Virtus Labs
a chance to update [besom](https://github.com/VirtusLab/besom).
## Checklist
- [x] I have run `make tidy` to update any new dependencies
- [x] I have run `make lint` to verify my code passes the lint check
- [ ] I have formatted my code using `gofumpt`
<!--- Please provide details if the checkbox below is to be left
unchecked. -->
- [x] I have added tests that prove my fix is effective or that my
feature works
<!---
User-facing changes require a CHANGELOG entry.
-->
- [ ] I have run `make changelog` and committed the
`changelog/pending/<file>` documenting my change
<!--
If the change(s) in this PR is a modification of an existing call to the
Pulumi Cloud,
then the service should honor older versions of the CLI where this
change would not exist.
You must then bump the API version in
/pkg/backend/httpstate/client/api.go, as well as add
it to the service.
-->
- [ ] Yes, there are changes in this PR that warrants bumping the Pulumi
Cloud API version
<!-- @Pulumi employees: If yes, you must submit corresponding changes in
the service repo. -->
2023-12-10 17:30:51 +00:00
|
|
|
if err != nil {
|
2024-01-25 23:28:58 +00:00
|
|
|
return nil, err
|
Pass root and main info to language host methods (#14654)
<!---
Thanks so much for your contribution! If this is your first time
contributing, please ensure that you have read the
[CONTRIBUTING](https://github.com/pulumi/pulumi/blob/master/CONTRIBUTING.md)
documentation.
-->
# Description
<!--- Please include a summary of the change and which issue is fixed.
Please also include relevant motivation and context. -->
This is two changes rolled together in a way.
Firstly passing some of the data that we pass on language runtime
startup to also pass it to Run/GetRequiredPlugins/etc. This is needed
for matrix testing, as we only get to start the language runtime up once
for that but want to execute multiple programs with it.
I feel it's also a little more consistent as we use the language
runtimes in other contexts (codegen) where there isn't really a root
directory, and aren't any options (and if we did do options the options
for codegen are not going to be the same as for execution). It also
means we can reuse a language host for shimless and substack programs,
as before they heavily relied on their current working directory to
calculate paths, and obviosly could only take one set of options at
startup. Imagine a shimless python package + a python root program, that
would have needed two startups of the python language host to deal with,
this unblocks it so we can make the engine smarter and only use one.
Secondly renaming some of the fields we pass to
Run/GetRequiredPlugins/etc today. `Pwd` and `Program` were not very
descriptive and had pretty non-obvious documentation:
```
string pwd = 3; // the program's working directory.
string program = 4; // the path to the program to execute.
```
`pwd` will remain, although probably rename it to `working_directory` at
some point, because while today we always start programs up with the
working directory equal to the program directory that definitely is
going to change in the future (at least for MLCs and substack programs).
But the name `pwd` doesn't make it clear that this was intended to be
the working directory _and_ the directory which contains the program.
`program` was in fact nearly always ".", and if it wasn't that it was
just a filename. The engine never sent a path for `program` (although we
did have some unit tests to check how that worked for the nodejs and
python hosts).
These are now replaced by a new structure with (I think) more clearly
named and documented fields (see ProgramInfo in langauge.proto).
The engine still sends the old data for now, we need to update
dotnet/yaml/java before we break the old interface and give Virtus Labs
a chance to update [besom](https://github.com/VirtusLab/besom).
## Checklist
- [x] I have run `make tidy` to update any new dependencies
- [x] I have run `make lint` to verify my code passes the lint check
- [ ] I have formatted my code using `gofumpt`
<!--- Please provide details if the checkbox below is to be left
unchecked. -->
- [x] I have added tests that prove my fix is effective or that my
feature works
<!---
User-facing changes require a CHANGELOG entry.
-->
- [ ] I have run `make changelog` and committed the
`changelog/pending/<file>` documenting my change
<!--
If the change(s) in this PR is a modification of an existing call to the
Pulumi Cloud,
then the service should honor older versions of the CLI where this
change would not exist.
You must then bump the API version in
/pkg/backend/httpstate/client/api.go, as well as add
it to the service.
-->
- [ ] Yes, there are changes in this PR that warrants bumping the Pulumi
Cloud API version
<!-- @Pulumi employees: If yes, you must submit corresponding changes in
the service repo. -->
2023-12-10 17:30:51 +00:00
|
|
|
}
|
|
|
|
|
2022-08-15 13:55:04 +00:00
|
|
|
logging.V(7).Infof("%s executing", prefix)
|
|
|
|
resp, err := h.client.GetProgramDependencies(h.ctx.Request(), &pulumirpc.GetProgramDependenciesRequest{
|
|
|
|
TransitiveDependencies: transitiveDependencies,
|
2024-01-25 23:28:58 +00:00
|
|
|
Info: minfo,
|
2022-08-15 13:55:04 +00:00
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
rpcError := rpcerror.Convert(err)
|
|
|
|
logging.V(7).Infof("%s failed: err=%v", prefix, rpcError)
|
|
|
|
|
|
|
|
return nil, rpcError
|
|
|
|
}
|
|
|
|
|
2023-06-28 16:02:04 +00:00
|
|
|
results := slice.Prealloc[DependencyInfo](len(resp.GetDependencies()))
|
2022-08-15 13:55:04 +00:00
|
|
|
for _, dep := range resp.GetDependencies() {
|
|
|
|
results = append(results, DependencyInfo{
|
|
|
|
Name: dep.Name,
|
2024-02-09 22:18:42 +00:00
|
|
|
Version: dep.Version,
|
2022-08-15 13:55:04 +00:00
|
|
|
})
|
|
|
|
}
|
|
|
|
|
|
|
|
logging.V(7).Infof("%s success: #versions=%d", prefix, len(results))
|
|
|
|
return results, nil
|
|
|
|
}
|
2022-10-04 08:58:01 +00:00
|
|
|
|
|
|
|
func (h *langhost) RunPlugin(info RunPluginInfo) (io.Reader, io.Reader, context.CancelFunc, error) {
|
2024-01-25 23:28:58 +00:00
|
|
|
logging.V(7).Infof("langhost[%v].RunPlugin(%s) executing",
|
|
|
|
h.runtime, info.Info.String())
|
2022-10-04 08:58:01 +00:00
|
|
|
|
2024-01-25 23:28:58 +00:00
|
|
|
minfo, err := info.Info.Marshal()
|
Pass root and main info to language host methods (#14654)
<!---
Thanks so much for your contribution! If this is your first time
contributing, please ensure that you have read the
[CONTRIBUTING](https://github.com/pulumi/pulumi/blob/master/CONTRIBUTING.md)
documentation.
-->
# Description
<!--- Please include a summary of the change and which issue is fixed.
Please also include relevant motivation and context. -->
This is two changes rolled together in a way.
Firstly passing some of the data that we pass on language runtime
startup to also pass it to Run/GetRequiredPlugins/etc. This is needed
for matrix testing, as we only get to start the language runtime up once
for that but want to execute multiple programs with it.
I feel it's also a little more consistent as we use the language
runtimes in other contexts (codegen) where there isn't really a root
directory, and aren't any options (and if we did do options the options
for codegen are not going to be the same as for execution). It also
means we can reuse a language host for shimless and substack programs,
as before they heavily relied on their current working directory to
calculate paths, and obviosly could only take one set of options at
startup. Imagine a shimless python package + a python root program, that
would have needed two startups of the python language host to deal with,
this unblocks it so we can make the engine smarter and only use one.
Secondly renaming some of the fields we pass to
Run/GetRequiredPlugins/etc today. `Pwd` and `Program` were not very
descriptive and had pretty non-obvious documentation:
```
string pwd = 3; // the program's working directory.
string program = 4; // the path to the program to execute.
```
`pwd` will remain, although probably rename it to `working_directory` at
some point, because while today we always start programs up with the
working directory equal to the program directory that definitely is
going to change in the future (at least for MLCs and substack programs).
But the name `pwd` doesn't make it clear that this was intended to be
the working directory _and_ the directory which contains the program.
`program` was in fact nearly always ".", and if it wasn't that it was
just a filename. The engine never sent a path for `program` (although we
did have some unit tests to check how that worked for the nodejs and
python hosts).
These are now replaced by a new structure with (I think) more clearly
named and documented fields (see ProgramInfo in langauge.proto).
The engine still sends the old data for now, we need to update
dotnet/yaml/java before we break the old interface and give Virtus Labs
a chance to update [besom](https://github.com/VirtusLab/besom).
## Checklist
- [x] I have run `make tidy` to update any new dependencies
- [x] I have run `make lint` to verify my code passes the lint check
- [ ] I have formatted my code using `gofumpt`
<!--- Please provide details if the checkbox below is to be left
unchecked. -->
- [x] I have added tests that prove my fix is effective or that my
feature works
<!---
User-facing changes require a CHANGELOG entry.
-->
- [ ] I have run `make changelog` and committed the
`changelog/pending/<file>` documenting my change
<!--
If the change(s) in this PR is a modification of an existing call to the
Pulumi Cloud,
then the service should honor older versions of the CLI where this
change would not exist.
You must then bump the API version in
/pkg/backend/httpstate/client/api.go, as well as add
it to the service.
-->
- [ ] Yes, there are changes in this PR that warrants bumping the Pulumi
Cloud API version
<!-- @Pulumi employees: If yes, you must submit corresponding changes in
the service repo. -->
2023-12-10 17:30:51 +00:00
|
|
|
if err != nil {
|
2024-01-25 23:28:58 +00:00
|
|
|
return nil, nil, nil, err
|
Pass root and main info to language host methods (#14654)
<!---
Thanks so much for your contribution! If this is your first time
contributing, please ensure that you have read the
[CONTRIBUTING](https://github.com/pulumi/pulumi/blob/master/CONTRIBUTING.md)
documentation.
-->
# Description
<!--- Please include a summary of the change and which issue is fixed.
Please also include relevant motivation and context. -->
This is two changes rolled together in a way.
Firstly passing some of the data that we pass on language runtime
startup to also pass it to Run/GetRequiredPlugins/etc. This is needed
for matrix testing, as we only get to start the language runtime up once
for that but want to execute multiple programs with it.
I feel it's also a little more consistent as we use the language
runtimes in other contexts (codegen) where there isn't really a root
directory, and aren't any options (and if we did do options the options
for codegen are not going to be the same as for execution). It also
means we can reuse a language host for shimless and substack programs,
as before they heavily relied on their current working directory to
calculate paths, and obviosly could only take one set of options at
startup. Imagine a shimless python package + a python root program, that
would have needed two startups of the python language host to deal with,
this unblocks it so we can make the engine smarter and only use one.
Secondly renaming some of the fields we pass to
Run/GetRequiredPlugins/etc today. `Pwd` and `Program` were not very
descriptive and had pretty non-obvious documentation:
```
string pwd = 3; // the program's working directory.
string program = 4; // the path to the program to execute.
```
`pwd` will remain, although probably rename it to `working_directory` at
some point, because while today we always start programs up with the
working directory equal to the program directory that definitely is
going to change in the future (at least for MLCs and substack programs).
But the name `pwd` doesn't make it clear that this was intended to be
the working directory _and_ the directory which contains the program.
`program` was in fact nearly always ".", and if it wasn't that it was
just a filename. The engine never sent a path for `program` (although we
did have some unit tests to check how that worked for the nodejs and
python hosts).
These are now replaced by a new structure with (I think) more clearly
named and documented fields (see ProgramInfo in langauge.proto).
The engine still sends the old data for now, we need to update
dotnet/yaml/java before we break the old interface and give Virtus Labs
a chance to update [besom](https://github.com/VirtusLab/besom).
## Checklist
- [x] I have run `make tidy` to update any new dependencies
- [x] I have run `make lint` to verify my code passes the lint check
- [ ] I have formatted my code using `gofumpt`
<!--- Please provide details if the checkbox below is to be left
unchecked. -->
- [x] I have added tests that prove my fix is effective or that my
feature works
<!---
User-facing changes require a CHANGELOG entry.
-->
- [ ] I have run `make changelog` and committed the
`changelog/pending/<file>` documenting my change
<!--
If the change(s) in this PR is a modification of an existing call to the
Pulumi Cloud,
then the service should honor older versions of the CLI where this
change would not exist.
You must then bump the API version in
/pkg/backend/httpstate/client/api.go, as well as add
it to the service.
-->
- [ ] Yes, there are changes in this PR that warrants bumping the Pulumi
Cloud API version
<!-- @Pulumi employees: If yes, you must submit corresponding changes in
the service repo. -->
2023-12-10 17:30:51 +00:00
|
|
|
}
|
|
|
|
|
2022-10-04 08:58:01 +00:00
|
|
|
ctx, kill := context.WithCancel(h.ctx.Request())
|
|
|
|
|
|
|
|
resp, err := h.client.RunPlugin(ctx, &pulumirpc.RunPluginRequest{
|
2024-01-25 23:28:58 +00:00
|
|
|
Pwd: minfo.GetProgramDirectory(),
|
|
|
|
Args: info.Args,
|
|
|
|
Env: info.Env,
|
|
|
|
Info: minfo,
|
2022-10-04 08:58:01 +00:00
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
// If there was an error starting the plugin kill the context for this request to ensure any lingering
|
|
|
|
// connection terminates.
|
|
|
|
kill()
|
|
|
|
return nil, nil, nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
outr, outw := io.Pipe()
|
|
|
|
errr, errw := io.Pipe()
|
|
|
|
|
|
|
|
go func() {
|
|
|
|
for {
|
|
|
|
logging.V(10).Infoln("Waiting for plugin message")
|
|
|
|
msg, err := resp.Recv()
|
|
|
|
if err != nil {
|
|
|
|
contract.IgnoreError(outw.CloseWithError(err))
|
|
|
|
contract.IgnoreError(errw.CloseWithError(err))
|
|
|
|
break
|
|
|
|
}
|
|
|
|
|
|
|
|
logging.V(10).Infoln("Got plugin response: ", msg)
|
|
|
|
|
|
|
|
if value, ok := msg.Output.(*pulumirpc.RunPluginResponse_Stdout); ok {
|
|
|
|
n, err := outw.Write(value.Stdout)
|
2023-02-15 01:06:56 +00:00
|
|
|
contract.AssertNoErrorf(err, "failed to write to stdout pipe: %v", err)
|
|
|
|
contract.Assertf(n == len(value.Stdout), "wrote fewer bytes (%d) than expected (%d)", n, len(value.Stdout))
|
2022-10-04 08:58:01 +00:00
|
|
|
} else if value, ok := msg.Output.(*pulumirpc.RunPluginResponse_Stderr); ok {
|
|
|
|
n, err := errw.Write(value.Stderr)
|
2023-02-15 01:06:56 +00:00
|
|
|
contract.AssertNoErrorf(err, "failed to write to stderr pipe: %v", err)
|
|
|
|
contract.Assertf(n == len(value.Stderr), "wrote fewer bytes (%d) than expected (%d)", n, len(value.Stderr))
|
2022-10-04 08:58:01 +00:00
|
|
|
} else if _, ok := msg.Output.(*pulumirpc.RunPluginResponse_Exitcode); ok {
|
|
|
|
// If stdout and stderr are empty we've flushed and are returning the exit code
|
|
|
|
outw.Close()
|
|
|
|
errw.Close()
|
|
|
|
break
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}()
|
|
|
|
|
|
|
|
return outr, errr, kill, nil
|
|
|
|
}
|
2022-10-17 14:21:11 +00:00
|
|
|
|
|
|
|
func (h *langhost) GenerateProject(
|
2023-08-03 10:40:05 +00:00
|
|
|
sourceDirectory, targetDirectory, project string, strict bool,
|
|
|
|
loaderTarget string, localDependencies map[string]string,
|
2023-05-26 10:32:19 +00:00
|
|
|
) (hcl.Diagnostics, error) {
|
2022-10-17 14:21:11 +00:00
|
|
|
logging.V(7).Infof("langhost[%v].GenerateProject() executing", h.runtime)
|
2023-05-26 10:32:19 +00:00
|
|
|
resp, err := h.client.GenerateProject(h.ctx.Request(), &pulumirpc.GenerateProjectRequest{
|
2023-08-03 10:40:05 +00:00
|
|
|
SourceDirectory: sourceDirectory,
|
|
|
|
TargetDirectory: targetDirectory,
|
|
|
|
Project: project,
|
|
|
|
Strict: strict,
|
|
|
|
LoaderTarget: loaderTarget,
|
|
|
|
LocalDependencies: localDependencies,
|
2022-10-17 14:21:11 +00:00
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
rpcError := rpcerror.Convert(err)
|
|
|
|
logging.V(7).Infof("langhost[%v].GenerateProject() failed: err=%v", h.runtime, rpcError)
|
2023-05-26 10:32:19 +00:00
|
|
|
return nil, rpcError
|
|
|
|
}
|
|
|
|
|
|
|
|
// Translate the rpc diagnostics into hcl.Diagnostics.
|
|
|
|
var diags hcl.Diagnostics
|
|
|
|
for _, rpcDiag := range resp.Diagnostics {
|
|
|
|
diags = append(diags, RPCDiagnosticToHclDiagnostic(rpcDiag))
|
2022-10-17 14:21:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
logging.V(7).Infof("langhost[%v].GenerateProject() success", h.runtime)
|
2023-05-26 10:32:19 +00:00
|
|
|
return diags, nil
|
2022-10-17 14:21:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (h *langhost) GeneratePackage(
|
2024-03-26 13:10:34 +00:00
|
|
|
directory string, schema string, extraFiles map[string][]byte,
|
|
|
|
loaderTarget string, localDependencies map[string]string,
|
2024-08-07 08:16:37 +00:00
|
|
|
local bool,
|
2023-12-05 17:47:52 +00:00
|
|
|
) (hcl.Diagnostics, error) {
|
2022-10-17 14:21:11 +00:00
|
|
|
logging.V(7).Infof("langhost[%v].GeneratePackage() executing", h.runtime)
|
2023-12-05 17:47:52 +00:00
|
|
|
resp, err := h.client.GeneratePackage(h.ctx.Request(), &pulumirpc.GeneratePackageRequest{
|
2024-03-26 13:10:34 +00:00
|
|
|
Directory: directory,
|
|
|
|
Schema: schema,
|
|
|
|
ExtraFiles: extraFiles,
|
|
|
|
LoaderTarget: loaderTarget,
|
|
|
|
LocalDependencies: localDependencies,
|
2024-08-07 08:16:37 +00:00
|
|
|
Local: local,
|
2022-10-17 14:21:11 +00:00
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
rpcError := rpcerror.Convert(err)
|
|
|
|
logging.V(7).Infof("langhost[%v].GeneratePackage() failed: err=%v", h.runtime, rpcError)
|
2023-12-05 17:47:52 +00:00
|
|
|
return nil, rpcError
|
2022-10-17 14:21:11 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
logging.V(7).Infof("langhost[%v].GeneratePackage() success", h.runtime)
|
2023-12-05 17:47:52 +00:00
|
|
|
|
|
|
|
// Translate the rpc diagnostics into hcl.Diagnostics.
|
|
|
|
var diags hcl.Diagnostics
|
|
|
|
for _, rpcDiag := range resp.Diagnostics {
|
|
|
|
diags = append(diags, RPCDiagnosticToHclDiagnostic(rpcDiag))
|
|
|
|
}
|
|
|
|
|
|
|
|
return diags, nil
|
2022-10-17 14:21:11 +00:00
|
|
|
}
|
|
|
|
|
[cli/import] Fix undefined variable errors in code generation when imported resources use a parent or provider (#16786)
Fixes #15410 Fixes #13339
## Problem Context
When using `pulumi import` we generate code snippets for the resources
that were imported. Sometimes the user specifies `--parent
parentName=URN` or `--provider providerName=URN` which tweak the parent
or provider that the imported resources uses. When using `--parent` or
`--provider` the generated code emits a resource option `parent =
parentName` (in case of using `--parent`) where `parentName` is an
unbound variable.
Usually unbound variables would result in a _bind_ error such as `error:
undefined variable parentName` when type-checking the program however in
the import code generation we specify the bind option
`pcl.AllowMissingVariables` which turns that unbound variable errors
into warnings and code generation can continue to emit code.
This is all good and works as expected. However in the issues linked
above, we do get an _error_ for unbound variables in generated code even
though we specified `AllowMissingVariables`.
The problem as it turns out is when we are trying to generate code via
dynamically loaded `LangaugeRuntime` plugins. Specifically for NodeJS
and Python, we load `pulumi-language-nodejs` or `pulumi-language-python`
and call `GenerateProgram` to get the generated program. That function
`GenerateProgram` takes the text _SOURCE_ of the a bound program (one
that was bound using option `AllowMissingVariables`) and re-binds again
inside the implementation of the language plugin. The second time we
bind the program, we don't pass it the option `AllowMissingVariables`
and so it fails with `unboud variable` error.
I've verified that the issue above don't repro when doing an import for
dotnet (probably same for java/yaml) because we use the statically
linked function `codegen/{lang}/gen_program.go -> GenerateProgram`
## Solution
The problem can be solved by propagating the bind options from the CLI
to the language hosts during import so that they know how to bind the
program. I've extended the gRPC interface in `GenerateProgramRequest`
with a property `Strict` which follows the same logic from `pulumi
convert --strict` and made it such that the import command sends
`strict=false` to the language plugins when doing `GenerateProgram`.
This is consistent with `GenerateProject` that uses the same flag. When
`strict=false` we use `pcl.NonStrictBindOptions()` which includes
`AllowMissingVariables` .
## Repro
Once can test the before and after behaviour by running `pulumi up
--yes` on the following TypeScript program:
```ts
import * as pulumi from "@pulumi/pulumi";
import * as random from "@pulumi/random";
export class MyComponent extends pulumi.ComponentResource {
public readonly randomPetId: pulumi.Output<string>;
constructor(name: string, opts?: pulumi.ComponentResourceOptions) {
super("example:index:MyComponent", name, {}, opts);
const randomPet = new random.RandomPet("randomPet", {}, {
parent: this
});
this.randomPetId = randomPet.id;
this.registerOutputs({
randomPetId: randomPet.id,
});
}
}
const example = new MyComponent("example");
export const randomPetId = example.randomPetId;
```
Then running `pulumi import -f import.json` where `import.json` contains
a resource to be imported under the created component (stack=`dev`,
project=`importerrors`)
```ts
{
"nameTable": {
"parentComponent": "urn:pulumi:dev::importerrors::example:index:MyComponent::example"
},
"resources": [
{
"type": "random:index/randomPassword:RandomPassword",
"name": "randomPassword",
"id": "supersecret",
"parent": "parentComponent"
}
]
}
```
Running this locally I get the following generated code (which
previously failed to generate)
```ts
import * as pulumi from "@pulumi/pulumi";
import * as random from "@pulumi/random";
const randomPassword = new random.RandomPassword("randomPassword", {
length: 11,
lower: true,
number: true,
numeric: true,
special: true,
upper: true,
}, {
parent: parentComponent,
});
```
2024-07-25 13:53:44 +00:00
|
|
|
func (h *langhost) GenerateProgram(program map[string]string, loaderTarget string, strict bool,
|
2023-07-27 09:27:07 +00:00
|
|
|
) (map[string][]byte, hcl.Diagnostics, error) {
|
2022-10-17 14:21:11 +00:00
|
|
|
logging.V(7).Infof("langhost[%v].GenerateProgram() executing", h.runtime)
|
|
|
|
resp, err := h.client.GenerateProgram(h.ctx.Request(), &pulumirpc.GenerateProgramRequest{
|
2023-07-27 09:27:07 +00:00
|
|
|
Source: program,
|
|
|
|
LoaderTarget: loaderTarget,
|
[cli/import] Fix undefined variable errors in code generation when imported resources use a parent or provider (#16786)
Fixes #15410 Fixes #13339
## Problem Context
When using `pulumi import` we generate code snippets for the resources
that were imported. Sometimes the user specifies `--parent
parentName=URN` or `--provider providerName=URN` which tweak the parent
or provider that the imported resources uses. When using `--parent` or
`--provider` the generated code emits a resource option `parent =
parentName` (in case of using `--parent`) where `parentName` is an
unbound variable.
Usually unbound variables would result in a _bind_ error such as `error:
undefined variable parentName` when type-checking the program however in
the import code generation we specify the bind option
`pcl.AllowMissingVariables` which turns that unbound variable errors
into warnings and code generation can continue to emit code.
This is all good and works as expected. However in the issues linked
above, we do get an _error_ for unbound variables in generated code even
though we specified `AllowMissingVariables`.
The problem as it turns out is when we are trying to generate code via
dynamically loaded `LangaugeRuntime` plugins. Specifically for NodeJS
and Python, we load `pulumi-language-nodejs` or `pulumi-language-python`
and call `GenerateProgram` to get the generated program. That function
`GenerateProgram` takes the text _SOURCE_ of the a bound program (one
that was bound using option `AllowMissingVariables`) and re-binds again
inside the implementation of the language plugin. The second time we
bind the program, we don't pass it the option `AllowMissingVariables`
and so it fails with `unboud variable` error.
I've verified that the issue above don't repro when doing an import for
dotnet (probably same for java/yaml) because we use the statically
linked function `codegen/{lang}/gen_program.go -> GenerateProgram`
## Solution
The problem can be solved by propagating the bind options from the CLI
to the language hosts during import so that they know how to bind the
program. I've extended the gRPC interface in `GenerateProgramRequest`
with a property `Strict` which follows the same logic from `pulumi
convert --strict` and made it such that the import command sends
`strict=false` to the language plugins when doing `GenerateProgram`.
This is consistent with `GenerateProject` that uses the same flag. When
`strict=false` we use `pcl.NonStrictBindOptions()` which includes
`AllowMissingVariables` .
## Repro
Once can test the before and after behaviour by running `pulumi up
--yes` on the following TypeScript program:
```ts
import * as pulumi from "@pulumi/pulumi";
import * as random from "@pulumi/random";
export class MyComponent extends pulumi.ComponentResource {
public readonly randomPetId: pulumi.Output<string>;
constructor(name: string, opts?: pulumi.ComponentResourceOptions) {
super("example:index:MyComponent", name, {}, opts);
const randomPet = new random.RandomPet("randomPet", {}, {
parent: this
});
this.randomPetId = randomPet.id;
this.registerOutputs({
randomPetId: randomPet.id,
});
}
}
const example = new MyComponent("example");
export const randomPetId = example.randomPetId;
```
Then running `pulumi import -f import.json` where `import.json` contains
a resource to be imported under the created component (stack=`dev`,
project=`importerrors`)
```ts
{
"nameTable": {
"parentComponent": "urn:pulumi:dev::importerrors::example:index:MyComponent::example"
},
"resources": [
{
"type": "random:index/randomPassword:RandomPassword",
"name": "randomPassword",
"id": "supersecret",
"parent": "parentComponent"
}
]
}
```
Running this locally I get the following generated code (which
previously failed to generate)
```ts
import * as pulumi from "@pulumi/pulumi";
import * as random from "@pulumi/random";
const randomPassword = new random.RandomPassword("randomPassword", {
length: 11,
lower: true,
number: true,
numeric: true,
special: true,
upper: true,
}, {
parent: parentComponent,
});
```
2024-07-25 13:53:44 +00:00
|
|
|
Strict: strict,
|
2022-10-17 14:21:11 +00:00
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
rpcError := rpcerror.Convert(err)
|
|
|
|
logging.V(7).Infof("langhost[%v].GenerateProgram() failed: err=%v", h.runtime, rpcError)
|
|
|
|
return nil, nil, rpcError
|
|
|
|
}
|
|
|
|
|
|
|
|
// Translate the rpc diagnostics into hcl.Diagnostics.
|
|
|
|
var diags hcl.Diagnostics
|
|
|
|
for _, rpcDiag := range resp.Diagnostics {
|
|
|
|
diags = append(diags, RPCDiagnosticToHclDiagnostic(rpcDiag))
|
|
|
|
}
|
|
|
|
|
|
|
|
logging.V(7).Infof("langhost[%v].GenerateProgram() success", h.runtime)
|
|
|
|
return resp.Source, diags, nil
|
|
|
|
}
|
2023-07-27 21:39:36 +00:00
|
|
|
|
|
|
|
func (h *langhost) Pack(
|
Add SupportPack to schemas to write out in the new style (#15713)
<!---
Thanks so much for your contribution! If this is your first time
contributing, please ensure that you have read the
[CONTRIBUTING](https://github.com/pulumi/pulumi/blob/master/CONTRIBUTING.md)
documentation.
-->
# Description
<!--- Please include a summary of the change and which issue is fixed.
Please also include relevant motivation and context. -->
This adds a new flag to the schema metadata to tell codegen to use the
new proposed style of SDKs where we fill in versions and write go.mods
etc.
I've reworked pack to operate on packages assuming they're in this new
style. That is pack no longer has the responsibility to fill in any
version information.
This updates python and node codegen to write out SDKs in this new
style, and fixes their core libraries to still be buildable via pack.
There are two approaches to fixing those, I've chosen option 1 below but
could pretty easily rework for option 2.
1) Write the version information directly to the SDKs at the same time
as we edit the .version file. To simplify this I've added a new
'set-version.py' script that takes a version string an writes it to all
the relevant places (.version, package.json, etc).
2) Write "pack" in the language host to search up the directory tree for
the ".version" file and then fill in the version information as we we're
doing before with envvar tricks and copying and editing package.json.
I think 1 is simpler long term, but does force some amount of cleanup in
unrelated bits of the system right now (release makefiles need a small
edit). 2 is much more localised but keeps this complexity that
sdk/nodejs sdk/python aren't actually valid source modules.
## Checklist
- [x] I have run `make tidy` to update any new dependencies
- [x] I have run `make lint` to verify my code passes the lint check
- [x] I have formatted my code using `gofumpt`
<!--- Please provide details if the checkbox below is to be left
unchecked. -->
- [x] I have added tests that prove my fix is effective or that my
feature works
<!---
User-facing changes require a CHANGELOG entry.
-->
- [ ] I have run `make changelog` and committed the
`changelog/pending/<file>` documenting my change
<!--
If the change(s) in this PR is a modification of an existing call to the
Pulumi Cloud,
then the service should honor older versions of the CLI where this
change would not exist.
You must then bump the API version in
/pkg/backend/httpstate/client/api.go, as well as add
it to the service.
-->
- [ ] Yes, there are changes in this PR that warrants bumping the Pulumi
Cloud API version
<!-- @Pulumi employees: If yes, you must submit corresponding changes in
the service repo. -->
2024-03-22 09:25:46 +00:00
|
|
|
packageDirectory string, destinationDirectory string,
|
2023-07-27 21:39:36 +00:00
|
|
|
) (string, error) {
|
Add SupportPack to schemas to write out in the new style (#15713)
<!---
Thanks so much for your contribution! If this is your first time
contributing, please ensure that you have read the
[CONTRIBUTING](https://github.com/pulumi/pulumi/blob/master/CONTRIBUTING.md)
documentation.
-->
# Description
<!--- Please include a summary of the change and which issue is fixed.
Please also include relevant motivation and context. -->
This adds a new flag to the schema metadata to tell codegen to use the
new proposed style of SDKs where we fill in versions and write go.mods
etc.
I've reworked pack to operate on packages assuming they're in this new
style. That is pack no longer has the responsibility to fill in any
version information.
This updates python and node codegen to write out SDKs in this new
style, and fixes their core libraries to still be buildable via pack.
There are two approaches to fixing those, I've chosen option 1 below but
could pretty easily rework for option 2.
1) Write the version information directly to the SDKs at the same time
as we edit the .version file. To simplify this I've added a new
'set-version.py' script that takes a version string an writes it to all
the relevant places (.version, package.json, etc).
2) Write "pack" in the language host to search up the directory tree for
the ".version" file and then fill in the version information as we we're
doing before with envvar tricks and copying and editing package.json.
I think 1 is simpler long term, but does force some amount of cleanup in
unrelated bits of the system right now (release makefiles need a small
edit). 2 is much more localised but keeps this complexity that
sdk/nodejs sdk/python aren't actually valid source modules.
## Checklist
- [x] I have run `make tidy` to update any new dependencies
- [x] I have run `make lint` to verify my code passes the lint check
- [x] I have formatted my code using `gofumpt`
<!--- Please provide details if the checkbox below is to be left
unchecked. -->
- [x] I have added tests that prove my fix is effective or that my
feature works
<!---
User-facing changes require a CHANGELOG entry.
-->
- [ ] I have run `make changelog` and committed the
`changelog/pending/<file>` documenting my change
<!--
If the change(s) in this PR is a modification of an existing call to the
Pulumi Cloud,
then the service should honor older versions of the CLI where this
change would not exist.
You must then bump the API version in
/pkg/backend/httpstate/client/api.go, as well as add
it to the service.
-->
- [ ] Yes, there are changes in this PR that warrants bumping the Pulumi
Cloud API version
<!-- @Pulumi employees: If yes, you must submit corresponding changes in
the service repo. -->
2024-03-22 09:25:46 +00:00
|
|
|
label := fmt.Sprintf("langhost[%v].Pack(%s, %s)", h.runtime, packageDirectory, destinationDirectory)
|
2023-07-27 21:39:36 +00:00
|
|
|
logging.V(7).Infof("%s executing", label)
|
|
|
|
|
|
|
|
// Always send absolute paths to the plugin, as it may be running in a different working directory.
|
|
|
|
packageDirectory, err := filepath.Abs(packageDirectory)
|
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
destinationDirectory, err = filepath.Abs(destinationDirectory)
|
|
|
|
if err != nil {
|
|
|
|
return "", err
|
|
|
|
}
|
|
|
|
|
|
|
|
req, err := h.client.Pack(h.ctx.Request(), &pulumirpc.PackRequest{
|
|
|
|
PackageDirectory: packageDirectory,
|
|
|
|
DestinationDirectory: destinationDirectory,
|
|
|
|
})
|
|
|
|
if err != nil {
|
|
|
|
rpcError := rpcerror.Convert(err)
|
|
|
|
logging.V(7).Infof("%s failed: err=%v", label, rpcError)
|
|
|
|
return "", rpcError
|
|
|
|
}
|
|
|
|
|
|
|
|
logging.V(7).Infof("%s success: artifactPath=%s", label, req.ArtifactPath)
|
|
|
|
return req.ArtifactPath, nil
|
|
|
|
}
|