diff --git a/CHANGELOG_PENDING.md b/CHANGELOG_PENDING.md index db039002..74f1e54f 100644 --- a/CHANGELOG_PENDING.md +++ b/CHANGELOG_PENDING.md @@ -1,5 +1,7 @@ ### Improvements +- Added support for Environment resource [#255](https://github.com/pulumi/pulumi-pulumiservice/issues/255) + ### Bug Fixes - Prevent noisy drift if agentPoolId is empty [#268](https://github.com/pulumi/pulumi-pulumiservice/issues/268) diff --git a/provider/cmd/pulumi-resource-pulumiservice/schema.json b/provider/cmd/pulumi-resource-pulumiservice/schema.json index cb14be8d..0f66f043 100644 --- a/provider/cmd/pulumi-resource-pulumiservice/schema.json +++ b/provider/cmd/pulumi-resource-pulumiservice/schema.json @@ -1240,6 +1240,47 @@ "stack", "timestamp" ] + }, + "pulumiservice:index:Environment": { + "description": "An ESC Environment.", + "properties": { + "organization": { + "description": "Organization name.", + "type": "string" + }, + "name": { + "description": "Environment name.", + "type": "string" + }, + "yaml": { + "description": "Environment's yaml file.", + "$ref": "pulumi.json#/Asset" + } + }, + "required": [ + "organization", + "name", + "yaml" + ], + "inputProperties": { + "organization": { + "description": "Organization name.", + "type": "string" + }, + "name": { + "description": "Environment name.", + "type": "string" + }, + "yaml": { + "description": "Environment's yaml file.", + "$ref": "pulumi.json#/Asset" + } + }, + "requiredInputs": [ + "organization", + "name", + "yaml" + ] } }, "language": { diff --git a/provider/go.mod b/provider/go.mod index 50bee2a1..94b80979 100644 --- a/provider/go.mod +++ b/provider/go.mod @@ -38,6 +38,7 @@ require ( github.com/gogo/protobuf v1.3.2 // indirect github.com/golang/glog v1.2.0 // indirect github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da // indirect + github.com/google/go-querystring v1.1.0 // indirect github.com/google/uuid v1.6.0 // indirect github.com/grpc-ecosystem/grpc-opentracing v0.0.0-20180507213350-8e809c8a8645 // indirect github.com/hashicorp/errwrap v1.1.0 // indirect @@ -66,7 +67,7 @@ require ( github.com/pkg/term v1.1.0 // indirect github.com/pmezard/go-difflib v1.0.0 // indirect github.com/pulumi/appdash v0.0.0-20231130102222-75f619a67231 // indirect - github.com/pulumi/esc v0.6.2 // indirect + github.com/pulumi/esc v0.8.3 // indirect github.com/rivo/uniseg v0.4.4 // indirect github.com/rogpeppe/go-internal v1.11.0 // indirect github.com/sabhiram/go-gitignore v0.0.0-20210923224102-525f6e181f06 // indirect diff --git a/provider/go.sum b/provider/go.sum index d1350bc2..1efa2d1d 100644 --- a/provider/go.sum +++ b/provider/go.sum @@ -75,8 +75,11 @@ github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da h1:oI5xCqsCo564l github.com/golang/groupcache v0.0.0-20210331224755-41bb18bfe9da/go.mod h1:cIg4eruTrX1D+g88fzRXU5OdNfaM+9IcxsU14FzY7Hc= github.com/golang/protobuf v1.5.4 h1:i7eJL8qZTpSEXOPTxNKhASYpMn+8e5Q6AdndVa1dWek= github.com/golang/protobuf v1.5.4/go.mod h1:lnTiLA8Wa4RWRcIUkrtSVa5nRhsEGBg48fD6rSs7xps= +github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.6.0 h1:ofyhxvXcZhMsU5ulbFiLKl/XBFqE1GSq7atu8tAmTRI= github.com/google/go-cmp v0.6.0/go.mod h1:17dUlkBOakJ0+DkrSSNjCkIjxS6bF9zb3elmeNGIjoY= +github.com/google/go-querystring v1.1.0 h1:AnCroh3fv4ZBgVIf1Iwtovgjaw/GiKJo8M8yD/fhyJ8= +github.com/google/go-querystring v1.1.0/go.mod h1:Kcdr2DB4koayq7X8pmAG4sNG59So17icRSOU623lUBU= github.com/google/uuid v1.6.0 h1:NIvaJDMOsjHA8n1jAhLSgzrAzy1Hgr+hNrb57e+94F0= github.com/google/uuid v1.6.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/grpc-ecosystem/grpc-opentracing v0.0.0-20180507213350-8e809c8a8645 h1:MJG/KsmcqMwFAkh8mTnAwhyKoB+sTAnY4CACC110tbU= @@ -154,8 +157,8 @@ github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZb github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pulumi/appdash v0.0.0-20231130102222-75f619a67231 h1:vkHw5I/plNdTr435cARxCW6q9gc0S/Yxz7Mkd38pOb0= github.com/pulumi/appdash v0.0.0-20231130102222-75f619a67231/go.mod h1:murToZ2N9hNJzewjHBgfFdXhZKjY3z5cYC1VXk+lbFE= -github.com/pulumi/esc v0.6.2 h1:+z+l8cuwIauLSwXQS0uoI3rqB+YG4SzsZYtHfNoXBvw= -github.com/pulumi/esc v0.6.2/go.mod h1:jNnYNjzsOgVTjCp0LL24NsCk8ZJxq4IoLQdCT0X7l8k= +github.com/pulumi/esc v0.8.3 h1:myeDL6dD/mz34zZjCL8s7d/tWHBJYxfMxDCL11MHoqc= +github.com/pulumi/esc v0.8.3/go.mod h1:v5VAPxYDa9DRwvubbzKt4ZYf5y0esWC2ccSp/AT923I= github.com/pulumi/pulumi/pkg/v3 v3.112.0 h1:vhoM6sx1eegJntIeUZENtck3VeMtK1zBiQ2E3EPOnHw= github.com/pulumi/pulumi/pkg/v3 v3.112.0/go.mod h1:GQhNr0v5E8TACF8j0p6UQqyr7mZreUpoMfVjLeu6eY0= github.com/pulumi/pulumi/sdk/v3 v3.115.3-0.20240507143413-cffdfd1fa489 h1:e7J2I8veUe9mSpzWN9kPREp7YhHUwnQz0aP0k5R45V8= diff --git a/provider/pkg/provider/environment.go b/provider/pkg/provider/environment.go new file mode 100644 index 00000000..7f7042aa --- /dev/null +++ b/provider/pkg/provider/environment.go @@ -0,0 +1,269 @@ +package provider + +import ( + "context" + "fmt" + "path" + "strings" + + esc_client "github.com/pulumi/esc/cmd/esc/cli/client" + "github.com/pulumi/pulumi/sdk/v3/go/common/resource" + "github.com/pulumi/pulumi/sdk/v3/go/common/resource/asset" + "github.com/pulumi/pulumi/sdk/v3/go/common/resource/plugin" + pulumirpc "github.com/pulumi/pulumi/sdk/v3/proto/go" + pbempty "google.golang.org/protobuf/types/known/emptypb" + "google.golang.org/protobuf/types/known/structpb" +) + +type PulumiServiceEnvironmentResource struct { + client esc_client.Client +} + +type PulumiServiceEnvironmentInput struct { + OrgName string + EnvName string + Yaml []byte +} + +func (i *PulumiServiceEnvironmentInput) ToPropertyMap() (resource.PropertyMap, error) { + propertyMap := resource.PropertyMap{} + propertyMap["organization"] = resource.NewPropertyValue(i.OrgName) + propertyMap["name"] = resource.NewPropertyValue(i.EnvName) + + yamlAsset, err := asset.FromText(strings.TrimSuffix(string(i.Yaml), "\n")) + if err != nil { + return nil, err + } + propertyMap["yaml"] = resource.NewAssetProperty(yamlAsset) + + return propertyMap, nil +} + +func ToPulumiServiceEnvironmentInput(properties *structpb.Struct) (*PulumiServiceEnvironmentInput, error) { + inputMap, err := plugin.UnmarshalProperties(properties, plugin.MarshalOptions{KeepUnknowns: true, SkipNulls: true}) + if err != nil { + return nil, err + } + + input := PulumiServiceEnvironmentInput{} + if inputMap["organization"].HasValue() && inputMap["organization"].IsString() { + input.OrgName = inputMap["organization"].StringValue() + } else { + return nil, fmt.Errorf("failed to unmarshal organization value from properties: %s", inputMap) + } + if inputMap["name"].HasValue() && inputMap["name"].IsString() { + input.EnvName = inputMap["name"].StringValue() + } else { + return nil, fmt.Errorf("failed to unmarshal environment name value from properties: %s", inputMap) + } + if inputMap["yaml"].HasValue() && inputMap["yaml"].IsAsset() { + input.Yaml = []byte(inputMap["yaml"].AssetValue().Text) + } else { + return nil, fmt.Errorf("failed to unmarshal yaml value from properties: %s", inputMap) + } + + return &input, nil +} + +func (st *PulumiServiceEnvironmentResource) Diff(req *pulumirpc.DiffRequest) (*pulumirpc.DiffResponse, error) { + olds, err := plugin.UnmarshalProperties(req.GetOlds(), plugin.MarshalOptions{}) + if err != nil { + return nil, err + } + + news, err := plugin.UnmarshalProperties(req.GetNews(), plugin.MarshalOptions{}) + if err != nil { + return nil, err + } + + diffs := olds.Diff(news) + if diffs == nil { + return &pulumirpc.DiffResponse{ + Changes: pulumirpc.DiffResponse_DIFF_NONE, + }, nil + } + + dd := plugin.NewDetailedDiffFromObjectDiff(diffs, false) + + detailedDiffs := map[string]*pulumirpc.PropertyDiff{} + replaces := []string(nil) + replaceProperties := map[string]bool{ + "organization": true, + "name": true, + } + for k, v := range dd { + if _, ok := replaceProperties[k]; ok { + v.Kind = v.Kind.AsReplace() + replaces = append(replaces, k) + } + detailedDiffs[k] = &pulumirpc.PropertyDiff{ + Kind: pulumirpc.PropertyDiff_Kind(v.Kind), + InputDiff: v.InputDiff, + } + } + + changes := pulumirpc.DiffResponse_DIFF_NONE + if len(detailedDiffs) > 0 { + changes = pulumirpc.DiffResponse_DIFF_SOME + } + return &pulumirpc.DiffResponse{ + Changes: changes, + Replaces: replaces, + DetailedDiff: detailedDiffs, + HasDetailedDiff: true, + DeleteBeforeReplace: len(replaces) > 0, + }, nil +} + +func (st *PulumiServiceEnvironmentResource) Delete(req *pulumirpc.DeleteRequest) (*pbempty.Empty, error) { + input, err := ToPulumiServiceEnvironmentInput(req.GetProperties()) + if err != nil { + return nil, err + } + + err = st.client.DeleteEnvironment(context.Background(), input.OrgName, input.EnvName) + if err != nil { + return nil, err + } + return &pbempty.Empty{}, nil +} + +func (st *PulumiServiceEnvironmentResource) Create(req *pulumirpc.CreateRequest) (*pulumirpc.CreateResponse, error) { + input, err := ToPulumiServiceEnvironmentInput(req.GetProperties()) + if err != nil { + return nil, err + } + + // First check if yaml is valid + _, diagnostics, err := st.client.CheckYAMLEnvironment(context.Background(), input.OrgName, input.Yaml) + if err != nil { + return nil, err + } + if diagnostics != nil { + return nil, fmt.Errorf("failed to create environment, yaml code failed following checks: %+v", diagnostics) + } + + // Then create environment, and update it with yaml provided. ESC API architecture doesn't let you do it in one call + err = st.client.CreateEnvironment(context.Background(), input.OrgName, input.EnvName) + if err != nil { + return nil, err + } + diagnostics, err = st.client.UpdateEnvironment(context.Background(), input.OrgName, input.EnvName, input.Yaml, "") + if err != nil { + return nil, err + } + if diagnostics != nil { + return nil, fmt.Errorf("failed to update brand new environment with pre-checked yaml, due to failing the following checks: %+v \n"+ + "This should never happen, if you're seeing this message there's likely a bug in ESC APIs", diagnostics) + } + + propertyMap, err := input.ToPropertyMap() + if err != nil { + return nil, err + } + outputProperties, err := plugin.MarshalProperties( + propertyMap, + plugin.MarshalOptions{}, + ) + if err != nil { + return nil, err + } + + return &pulumirpc.CreateResponse{ + Id: path.Join(input.OrgName, input.EnvName), + Properties: outputProperties, + }, nil +} + +func (st *PulumiServiceEnvironmentResource) Check(req *pulumirpc.CheckRequest) (*pulumirpc.CheckResponse, error) { + inputMap, err := plugin.UnmarshalProperties(req.GetNews(), plugin.MarshalOptions{}) + if err != nil { + return nil, err + } + + var failures []*pulumirpc.CheckFailure + for _, p := range []resource.PropertyKey{"organization", "name", "yaml"} { + if !inputMap[(p)].HasValue() { + failures = append(failures, &pulumirpc.CheckFailure{ + Reason: fmt.Sprintf("missing required property '%s'", p), + Property: string(p), + }) + } + } + + return &pulumirpc.CheckResponse{Inputs: req.GetNews(), Failures: failures}, nil +} + +func (st *PulumiServiceEnvironmentResource) Update(req *pulumirpc.UpdateRequest) (*pulumirpc.UpdateResponse, error) { + input, err := ToPulumiServiceEnvironmentInput(req.GetNews()) + if err != nil { + return nil, err + } + + diagnostics, err := st.client.UpdateEnvironment(context.Background(), input.OrgName, input.EnvName, input.Yaml, "") + if err != nil { + return nil, err + } + if diagnostics != nil { + return nil, fmt.Errorf("failed to update environment, yaml code failed following checks: %+v", diagnostics) + } + + propertyMap, err := input.ToPropertyMap() + if err != nil { + return nil, err + } + outputProperties, err := plugin.MarshalProperties( + propertyMap, + plugin.MarshalOptions{}, + ) + if err != nil { + return nil, err + } + + return &pulumirpc.UpdateResponse{ + Properties: outputProperties, + }, nil +} + +func (st *PulumiServiceEnvironmentResource) Read(req *pulumirpc.ReadRequest) (*pulumirpc.ReadResponse, error) { + input, err := ToPulumiServiceEnvironmentInput(req.GetProperties()) + if err != nil { + return nil, err + } + + retrievedYaml, _, err := st.client.GetEnvironment(context.Background(), input.OrgName, input.EnvName, false) + if err != nil { + return &pulumirpc.ReadResponse{Id: "", Properties: nil}, nil + } + + result := PulumiServiceEnvironmentInput{ + OrgName: input.OrgName, + EnvName: input.EnvName, + Yaml: retrievedYaml, + } + + propertyMap, err := result.ToPropertyMap() + if err != nil { + return nil, err + } + properties, err := plugin.MarshalProperties( + propertyMap, + plugin.MarshalOptions{}, + ) + if err != nil { + return nil, err + } + + return &pulumirpc.ReadResponse{ + Id: req.Id, + Properties: properties, + Inputs: properties, + }, nil +} + +func (st *PulumiServiceEnvironmentResource) Name() string { + return "pulumiservice:index:Environment" +} + +func (st *PulumiServiceEnvironmentResource) Configure(_ PulumiServiceConfig) { +} diff --git a/provider/pkg/provider/environment_test.go b/provider/pkg/provider/environment_test.go new file mode 100644 index 00000000..d27ea781 --- /dev/null +++ b/provider/pkg/provider/environment_test.go @@ -0,0 +1,154 @@ +package provider + +import ( + "context" + "fmt" + "testing" + "time" + + "github.com/pulumi/esc" + "github.com/pulumi/esc/cmd/esc/cli/client" + "github.com/pulumi/pulumi/sdk/v3/go/common/resource/plugin" + "github.com/pulumi/pulumi/sdk/v3/go/common/workspace" + pulumirpc "github.com/pulumi/pulumi/sdk/v3/proto/go" + "github.com/stretchr/testify/assert" +) + +type getEnvironmentFunc func(ctx context.Context, orgName string, envName string, decrypt bool) (yaml []byte, etag string, err error) + +type EscClientMock struct { + getEnvironmentFunc getEnvironmentFunc +} + +func (c *EscClientMock) GetEnvironment(ctx context.Context, orgName string, envName string, decrypt bool) (yaml []byte, etag string, err error) { + return c.getEnvironmentFunc(ctx, orgName, envName, decrypt) +} + +func (c *EscClientMock) CheckYAMLEnvironment(context.Context, string, []byte) (*esc.Environment, []client.EnvironmentDiagnostic, error) { + return nil, nil, nil +} + +func (c *EscClientMock) CreateEnvironment(context.Context, string, string) error { + return nil +} + +func (c *EscClientMock) DeleteEnvironment(context.Context, string, string) error { + return nil +} + +func (c *EscClientMock) GetOpenEnvironment(context.Context, string, string, string) (*esc.Environment, error) { + return nil, nil +} + +func (c *EscClientMock) GetOpenProperty(context.Context, string, string, string, string) (*esc.Value, error) { + return nil, nil +} + +func (c *EscClientMock) GetPulumiAccountDetails(context.Context) (string, []string, *workspace.TokenInformation, error) { + return "", nil, nil, nil +} + +func (c *EscClientMock) ListEnvironments(context.Context, string, string) ([]client.OrgEnvironment, string, error) { + return nil, "", nil +} + +func (c *EscClientMock) OpenEnvironment(context.Context, string, string, time.Duration) (string, []client.EnvironmentDiagnostic, error) { + return "", nil, nil +} + +func (c *EscClientMock) OpenYAMLEnvironment(context.Context, string, []byte, time.Duration) (string, []client.EnvironmentDiagnostic, error) { + return "", nil, nil +} + +func (c *EscClientMock) UpdateEnvironment(context.Context, string, string, []byte, string) ([]client.EnvironmentDiagnostic, error) { + return nil, nil +} + +func (c *EscClientMock) Insecure() bool { + return false +} + +func (c *EscClientMock) URL() string { + return "" +} + +func buildEscClientMock(getEnvironmentFunc getEnvironmentFunc) *EscClientMock { + return &EscClientMock{ + getEnvironmentFunc, + } +} + +func TestEnvironment(t *testing.T) { + t.Run("Read when the resource is not found", func(t *testing.T) { + mockedClient := buildEscClientMock( + func(ctx context.Context, orgName string, envName string, decrypt bool) (yaml []byte, etag string, err error) { + return nil, "", fmt.Errorf("not found") + }, + ) + + provider := PulumiServiceEnvironmentResource{ + client: mockedClient, + } + + input := PulumiServiceEnvironmentInput{ + OrgName: "org", + EnvName: "env", + Yaml: []byte("test-environment"), + } + + propertyMap, _ := input.ToPropertyMap() + outputProperties, _ := plugin.MarshalProperties( + propertyMap, + plugin.MarshalOptions{ + KeepUnknowns: true, + SkipNulls: true, + }, + ) + req := pulumirpc.ReadRequest{ + Id: "org/env", + Properties: outputProperties, + } + + resp, err := provider.Read(&req) + + assert.NoError(t, err) + assert.Equal(t, resp.Id, "") + assert.Nil(t, resp.Properties) + }) + + t.Run("Read when the resource is found", func(t *testing.T) { + mockedClient := buildEscClientMock( + func(ctx context.Context, orgName string, envName string, decrypt bool) (yaml []byte, etag string, err error) { + return nil, "", nil + }, + ) + + provider := PulumiServiceEnvironmentResource{ + client: mockedClient, + } + + input := PulumiServiceEnvironmentInput{ + OrgName: "org", + EnvName: "project", + Yaml: []byte("test-environment"), + } + + propertyMap, _ := input.ToPropertyMap() + outputProperties, _ := plugin.MarshalProperties( + propertyMap, + plugin.MarshalOptions{ + KeepUnknowns: true, + SkipNulls: true, + }, + ) + req := pulumirpc.ReadRequest{ + Id: "org/env", + Properties: outputProperties, + } + + resp, err := provider.Read(&req) + + assert.NoError(t, err) + assert.Equal(t, resp.Id, "org/env") + }) +} diff --git a/provider/pkg/provider/provider.go b/provider/pkg/provider/provider.go index 6e8e208e..fb39760f 100644 --- a/provider/pkg/provider/provider.go +++ b/provider/pkg/provider/provider.go @@ -19,6 +19,7 @@ import ( "encoding/json" "fmt" "net/http" + "runtime" "strings" "time" @@ -26,6 +27,8 @@ import ( "google.golang.org/grpc/status" pbempty "google.golang.org/protobuf/types/known/emptypb" + esc_client "github.com/pulumi/esc/cmd/esc/cli/client" + "github.com/pulumi/esc/cmd/esc/cli/version" "github.com/pulumi/pulumi-pulumiservice/provider/pkg/internal/pulumiapi" "github.com/pulumi/pulumi/pkg/v3/codegen/schema" "github.com/pulumi/pulumi/pkg/v3/resource/provider" @@ -120,6 +123,8 @@ func (k *pulumiserviceProvider) Configure(_ context.Context, req *pulumirpc.Conf } client, err := pulumiapi.NewClient(&httpClient, *token, *url) + escClient := esc_client.New(fmt.Sprintf("provider-pulumiservice/1 (%s; %s)", version.Version, runtime.GOOS), *url, *token, false) + if err != nil { return nil, err } @@ -161,6 +166,9 @@ func (k *pulumiserviceProvider) Configure(_ context.Context, req *pulumirpc.Conf &PulumiServiceTtlScheduleResource{ client: client, }, + &PulumiServiceEnvironmentResource{ + client: escClient, + }, } for _, sr := range k.pulumiResources { diff --git a/sdk/dotnet/Environment.cs b/sdk/dotnet/Environment.cs new file mode 100644 index 00000000..3d56abae --- /dev/null +++ b/sdk/dotnet/Environment.cs @@ -0,0 +1,104 @@ +// *** WARNING: this file was generated by pulumi. *** +// *** Do not edit by hand unless you're certain you know what you are doing! *** + +using System; +using System.Collections.Generic; +using System.Collections.Immutable; +using System.Threading.Tasks; +using Pulumi.Serialization; + +namespace Pulumi.PulumiService +{ + /// + /// An ESC Environment. + /// + [PulumiServiceResourceType("pulumiservice:index:Environment")] + public partial class Environment : global::Pulumi.CustomResource + { + /// + /// Environment name. + /// + [Output("name")] + public Output Name { get; private set; } = null!; + + /// + /// Organization name. + /// + [Output("organization")] + public Output Organization { get; private set; } = null!; + + /// + /// Environment's yaml file. + /// + [Output("yaml")] + public Output Yaml { get; private set; } = null!; + + + /// + /// Create a Environment resource with the given unique name, arguments, and options. + /// + /// + /// The unique name of the resource + /// The arguments used to populate this resource's properties + /// A bag of options that control this resource's behavior + public Environment(string name, EnvironmentArgs args, CustomResourceOptions? options = null) + : base("pulumiservice:index:Environment", name, args ?? new EnvironmentArgs(), MakeResourceOptions(options, "")) + { + } + + private Environment(string name, Input id, CustomResourceOptions? options = null) + : base("pulumiservice:index:Environment", name, null, MakeResourceOptions(options, id)) + { + } + + private static CustomResourceOptions MakeResourceOptions(CustomResourceOptions? options, Input? id) + { + var defaultOptions = new CustomResourceOptions + { + Version = Utilities.Version, + }; + var merged = CustomResourceOptions.Merge(defaultOptions, options); + // Override the ID if one was specified for consistency with other language SDKs. + merged.Id = id ?? merged.Id; + return merged; + } + /// + /// Get an existing Environment resource's state with the given name, ID, and optional extra + /// properties used to qualify the lookup. + /// + /// + /// The unique name of the resulting resource. + /// The unique provider ID of the resource to lookup. + /// A bag of options that control this resource's behavior + public static Environment Get(string name, Input id, CustomResourceOptions? options = null) + { + return new Environment(name, id, options); + } + } + + public sealed class EnvironmentArgs : global::Pulumi.ResourceArgs + { + /// + /// Environment name. + /// + [Input("name", required: true)] + public Input Name { get; set; } = null!; + + /// + /// Organization name. + /// + [Input("organization", required: true)] + public Input Organization { get; set; } = null!; + + /// + /// Environment's yaml file. + /// + [Input("yaml", required: true)] + public Input Yaml { get; set; } = null!; + + public EnvironmentArgs() + { + } + public static new EnvironmentArgs Empty => new EnvironmentArgs(); + } +} diff --git a/sdk/go/pulumiservice/init.go b/sdk/go/pulumiservice/init.go index 57867129..dbc0c5c0 100644 --- a/sdk/go/pulumiservice/init.go +++ b/sdk/go/pulumiservice/init.go @@ -31,6 +31,8 @@ func (m *module) Construct(ctx *pulumi.Context, name, typ, urn string) (r pulumi r = &DeploymentSettings{} case "pulumiservice:index:DriftSchedule": r = &DriftSchedule{} + case "pulumiservice:index:Environment": + r = &Environment{} case "pulumiservice:index:OrgAccessToken": r = &OrgAccessToken{} case "pulumiservice:index:StackTag": diff --git a/sdk/java/src/main/java/com/pulumi/pulumiservice/Environment.java b/sdk/java/src/main/java/com/pulumi/pulumiservice/Environment.java new file mode 100644 index 00000000..43c475f4 --- /dev/null +++ b/sdk/java/src/main/java/com/pulumi/pulumiservice/Environment.java @@ -0,0 +1,112 @@ +// *** WARNING: this file was generated by pulumi. *** +// *** Do not edit by hand unless you're certain you know what you are doing! *** + +package com.pulumi.pulumiservice; + +import com.pulumi.asset.AssetOrArchive; +import com.pulumi.core.Output; +import com.pulumi.core.annotations.Export; +import com.pulumi.core.annotations.ResourceType; +import com.pulumi.core.internal.Codegen; +import com.pulumi.pulumiservice.EnvironmentArgs; +import com.pulumi.pulumiservice.Utilities; +import java.lang.String; +import javax.annotation.Nullable; + +/** + * An ESC Environment. + * + */ +@ResourceType(type="pulumiservice:index:Environment") +public class Environment extends com.pulumi.resources.CustomResource { + /** + * Environment name. + * + */ + @Export(name="name", refs={String.class}, tree="[0]") + private Output name; + + /** + * @return Environment name. + * + */ + public Output name() { + return this.name; + } + /** + * Organization name. + * + */ + @Export(name="organization", refs={String.class}, tree="[0]") + private Output organization; + + /** + * @return Organization name. + * + */ + public Output organization() { + return this.organization; + } + /** + * Environment's yaml file. + * + */ + @Export(name="yaml", refs={AssetOrArchive.class}, tree="[0]") + private Output yaml; + + /** + * @return Environment's yaml file. + * + */ + public Output yaml() { + return this.yaml; + } + + /** + * + * @param name The _unique_ name of the resulting resource. + */ + public Environment(String name) { + this(name, EnvironmentArgs.Empty); + } + /** + * + * @param name The _unique_ name of the resulting resource. + * @param args The arguments to use to populate this resource's properties. + */ + public Environment(String name, EnvironmentArgs args) { + this(name, args, null); + } + /** + * + * @param name The _unique_ name of the resulting resource. + * @param args The arguments to use to populate this resource's properties. + * @param options A bag of options that control this resource's behavior. + */ + public Environment(String name, EnvironmentArgs args, @Nullable com.pulumi.resources.CustomResourceOptions options) { + super("pulumiservice:index:Environment", name, args == null ? EnvironmentArgs.Empty : args, makeResourceOptions(options, Codegen.empty())); + } + + private Environment(String name, Output id, @Nullable com.pulumi.resources.CustomResourceOptions options) { + super("pulumiservice:index:Environment", name, null, makeResourceOptions(options, id)); + } + + private static com.pulumi.resources.CustomResourceOptions makeResourceOptions(@Nullable com.pulumi.resources.CustomResourceOptions options, @Nullable Output id) { + var defaultOptions = com.pulumi.resources.CustomResourceOptions.builder() + .version(Utilities.getVersion()) + .build(); + return com.pulumi.resources.CustomResourceOptions.merge(defaultOptions, options, id); + } + + /** + * Get an existing Host resource's state with the given name, ID, and optional extra + * properties used to qualify the lookup. + * + * @param name The _unique_ name of the resulting resource. + * @param id The _unique_ provider ID of the resource to lookup. + * @param options Optional settings to control the behavior of the CustomResource. + */ + public static Environment get(String name, Output id, @Nullable com.pulumi.resources.CustomResourceOptions options) { + return new Environment(name, id, options); + } +} diff --git a/sdk/java/src/main/java/com/pulumi/pulumiservice/EnvironmentArgs.java b/sdk/java/src/main/java/com/pulumi/pulumiservice/EnvironmentArgs.java new file mode 100644 index 00000000..8221df35 --- /dev/null +++ b/sdk/java/src/main/java/com/pulumi/pulumiservice/EnvironmentArgs.java @@ -0,0 +1,166 @@ +// *** WARNING: this file was generated by pulumi. *** +// *** Do not edit by hand unless you're certain you know what you are doing! *** + +package com.pulumi.pulumiservice; + +import com.pulumi.asset.AssetOrArchive; +import com.pulumi.core.Output; +import com.pulumi.core.annotations.Import; +import com.pulumi.exceptions.MissingRequiredPropertyException; +import java.lang.String; +import java.util.Objects; + + +public final class EnvironmentArgs extends com.pulumi.resources.ResourceArgs { + + public static final EnvironmentArgs Empty = new EnvironmentArgs(); + + /** + * Environment name. + * + */ + @Import(name="name", required=true) + private Output name; + + /** + * @return Environment name. + * + */ + public Output name() { + return this.name; + } + + /** + * Organization name. + * + */ + @Import(name="organization", required=true) + private Output organization; + + /** + * @return Organization name. + * + */ + public Output organization() { + return this.organization; + } + + /** + * Environment's yaml file. + * + */ + @Import(name="yaml", required=true) + private Output yaml; + + /** + * @return Environment's yaml file. + * + */ + public Output yaml() { + return this.yaml; + } + + private EnvironmentArgs() {} + + private EnvironmentArgs(EnvironmentArgs $) { + this.name = $.name; + this.organization = $.organization; + this.yaml = $.yaml; + } + + public static Builder builder() { + return new Builder(); + } + public static Builder builder(EnvironmentArgs defaults) { + return new Builder(defaults); + } + + public static final class Builder { + private EnvironmentArgs $; + + public Builder() { + $ = new EnvironmentArgs(); + } + + public Builder(EnvironmentArgs defaults) { + $ = new EnvironmentArgs(Objects.requireNonNull(defaults)); + } + + /** + * @param name Environment name. + * + * @return builder + * + */ + public Builder name(Output name) { + $.name = name; + return this; + } + + /** + * @param name Environment name. + * + * @return builder + * + */ + public Builder name(String name) { + return name(Output.of(name)); + } + + /** + * @param organization Organization name. + * + * @return builder + * + */ + public Builder organization(Output organization) { + $.organization = organization; + return this; + } + + /** + * @param organization Organization name. + * + * @return builder + * + */ + public Builder organization(String organization) { + return organization(Output.of(organization)); + } + + /** + * @param yaml Environment's yaml file. + * + * @return builder + * + */ + public Builder yaml(Output yaml) { + $.yaml = yaml; + return this; + } + + /** + * @param yaml Environment's yaml file. + * + * @return builder + * + */ + public Builder yaml(AssetOrArchive yaml) { + return yaml(Output.of(yaml)); + } + + public EnvironmentArgs build() { + if ($.name == null) { + throw new MissingRequiredPropertyException("EnvironmentArgs", "name"); + } + if ($.organization == null) { + throw new MissingRequiredPropertyException("EnvironmentArgs", "organization"); + } + if ($.yaml == null) { + throw new MissingRequiredPropertyException("EnvironmentArgs", "yaml"); + } + return $; + } + } + +} diff --git a/sdk/nodejs/environment.ts b/sdk/nodejs/environment.ts new file mode 100644 index 00000000..2832c008 --- /dev/null +++ b/sdk/nodejs/environment.ts @@ -0,0 +1,99 @@ +// *** WARNING: this file was generated by pulumi-language-nodejs. *** +// *** Do not edit by hand unless you're certain you know what you are doing! *** + +import * as pulumi from "@pulumi/pulumi"; +import * as utilities from "./utilities"; + +/** + * An ESC Environment. + */ +export class Environment extends pulumi.CustomResource { + /** + * Get an existing Environment resource's state with the given name, ID, and optional extra + * properties used to qualify the lookup. + * + * @param name The _unique_ name of the resulting resource. + * @param id The _unique_ provider ID of the resource to lookup. + * @param opts Optional settings to control the behavior of the CustomResource. + */ + public static get(name: string, id: pulumi.Input, opts?: pulumi.CustomResourceOptions): Environment { + return new Environment(name, undefined as any, { ...opts, id: id }); + } + + /** @internal */ + public static readonly __pulumiType = 'pulumiservice:index:Environment'; + + /** + * Returns true if the given object is an instance of Environment. This is designed to work even + * when multiple copies of the Pulumi SDK have been loaded into the same process. + */ + public static isInstance(obj: any): obj is Environment { + if (obj === undefined || obj === null) { + return false; + } + return obj['__pulumiType'] === Environment.__pulumiType; + } + + /** + * Environment name. + */ + public readonly name!: pulumi.Output; + /** + * Organization name. + */ + public readonly organization!: pulumi.Output; + /** + * Environment's yaml file. + */ + public readonly yaml!: pulumi.Output; + + /** + * Create a Environment resource with the given unique name, arguments, and options. + * + * @param name The _unique_ name of the resource. + * @param args The arguments to use to populate this resource's properties. + * @param opts A bag of options that control this resource's behavior. + */ + constructor(name: string, args: EnvironmentArgs, opts?: pulumi.CustomResourceOptions) { + let resourceInputs: pulumi.Inputs = {}; + opts = opts || {}; + if (!opts.id) { + if ((!args || args.name === undefined) && !opts.urn) { + throw new Error("Missing required property 'name'"); + } + if ((!args || args.organization === undefined) && !opts.urn) { + throw new Error("Missing required property 'organization'"); + } + if ((!args || args.yaml === undefined) && !opts.urn) { + throw new Error("Missing required property 'yaml'"); + } + resourceInputs["name"] = args ? args.name : undefined; + resourceInputs["organization"] = args ? args.organization : undefined; + resourceInputs["yaml"] = args ? args.yaml : undefined; + } else { + resourceInputs["name"] = undefined /*out*/; + resourceInputs["organization"] = undefined /*out*/; + resourceInputs["yaml"] = undefined /*out*/; + } + opts = pulumi.mergeOptions(utilities.resourceOptsDefaults(), opts); + super(Environment.__pulumiType, name, resourceInputs, opts); + } +} + +/** + * The set of arguments for constructing a Environment resource. + */ +export interface EnvironmentArgs { + /** + * Environment name. + */ + name: pulumi.Input; + /** + * Organization name. + */ + organization: pulumi.Input; + /** + * Environment's yaml file. + */ + yaml: pulumi.Input; +} diff --git a/sdk/nodejs/index.ts b/sdk/nodejs/index.ts index 2ce89a37..949859e7 100644 --- a/sdk/nodejs/index.ts +++ b/sdk/nodejs/index.ts @@ -30,6 +30,11 @@ export type DriftSchedule = import("./driftSchedule").DriftSchedule; export const DriftSchedule: typeof import("./driftSchedule").DriftSchedule = null as any; utilities.lazyLoad(exports, ["DriftSchedule"], () => require("./driftSchedule")); +export { EnvironmentArgs } from "./environment"; +export type Environment = import("./environment").Environment; +export const Environment: typeof import("./environment").Environment = null as any; +utilities.lazyLoad(exports, ["Environment"], () => require("./environment")); + export { OrgAccessTokenArgs } from "./orgAccessToken"; export type OrgAccessToken = import("./orgAccessToken").OrgAccessToken; export const OrgAccessToken: typeof import("./orgAccessToken").OrgAccessToken = null as any; @@ -97,6 +102,8 @@ const _module = { return new DeploymentSettings(name, undefined, { urn }) case "pulumiservice:index:DriftSchedule": return new DriftSchedule(name, undefined, { urn }) + case "pulumiservice:index:Environment": + return new Environment(name, undefined, { urn }) case "pulumiservice:index:OrgAccessToken": return new OrgAccessToken(name, undefined, { urn }) case "pulumiservice:index:StackTag": diff --git a/sdk/nodejs/tsconfig.json b/sdk/nodejs/tsconfig.json index 5369e1e7..0f0925c9 100644 --- a/sdk/nodejs/tsconfig.json +++ b/sdk/nodejs/tsconfig.json @@ -20,6 +20,7 @@ "deploymentSchedule.ts", "deploymentSettings.ts", "driftSchedule.ts", + "environment.ts", "index.ts", "orgAccessToken.ts", "provider.ts", diff --git a/sdk/python/pulumi_pulumiservice/__init__.py b/sdk/python/pulumi_pulumiservice/__init__.py index d760f1fd..e1fc6ce9 100644 --- a/sdk/python/pulumi_pulumiservice/__init__.py +++ b/sdk/python/pulumi_pulumiservice/__init__.py @@ -11,6 +11,7 @@ from .deployment_schedule import * from .deployment_settings import * from .drift_schedule import * +from .environment import * from .org_access_token import * from .provider import * from .stack_tag import * @@ -42,6 +43,7 @@ "pulumiservice:index:DeploymentSchedule": "DeploymentSchedule", "pulumiservice:index:DeploymentSettings": "DeploymentSettings", "pulumiservice:index:DriftSchedule": "DriftSchedule", + "pulumiservice:index:Environment": "Environment", "pulumiservice:index:OrgAccessToken": "OrgAccessToken", "pulumiservice:index:StackTag": "StackTag", "pulumiservice:index:Team": "Team", diff --git a/sdk/python/pulumi_pulumiservice/environment.py b/sdk/python/pulumi_pulumiservice/environment.py new file mode 100644 index 00000000..6fb62987 --- /dev/null +++ b/sdk/python/pulumi_pulumiservice/environment.py @@ -0,0 +1,180 @@ +# coding=utf-8 +# *** WARNING: this file was generated by pulumi-language-python. *** +# *** Do not edit by hand unless you're certain you know what you are doing! *** + +import copy +import warnings +import pulumi +import pulumi.runtime +from typing import Any, Mapping, Optional, Sequence, Union, overload +from . import _utilities + +__all__ = ['EnvironmentArgs', 'Environment'] + +@pulumi.input_type +class EnvironmentArgs: + def __init__(__self__, *, + name: pulumi.Input[str], + organization: pulumi.Input[str], + yaml: pulumi.Input[Union[pulumi.Asset, pulumi.Archive]]): + """ + The set of arguments for constructing a Environment resource. + :param pulumi.Input[str] name: Environment name. + :param pulumi.Input[str] organization: Organization name. + :param pulumi.Input[Union[pulumi.Asset, pulumi.Archive]] yaml: Environment's yaml file. + """ + pulumi.set(__self__, "name", name) + pulumi.set(__self__, "organization", organization) + pulumi.set(__self__, "yaml", yaml) + + @property + @pulumi.getter + def name(self) -> pulumi.Input[str]: + """ + Environment name. + """ + return pulumi.get(self, "name") + + @name.setter + def name(self, value: pulumi.Input[str]): + pulumi.set(self, "name", value) + + @property + @pulumi.getter + def organization(self) -> pulumi.Input[str]: + """ + Organization name. + """ + return pulumi.get(self, "organization") + + @organization.setter + def organization(self, value: pulumi.Input[str]): + pulumi.set(self, "organization", value) + + @property + @pulumi.getter + def yaml(self) -> pulumi.Input[Union[pulumi.Asset, pulumi.Archive]]: + """ + Environment's yaml file. + """ + return pulumi.get(self, "yaml") + + @yaml.setter + def yaml(self, value: pulumi.Input[Union[pulumi.Asset, pulumi.Archive]]): + pulumi.set(self, "yaml", value) + + +class Environment(pulumi.CustomResource): + @overload + def __init__(__self__, + resource_name: str, + opts: Optional[pulumi.ResourceOptions] = None, + name: Optional[pulumi.Input[str]] = None, + organization: Optional[pulumi.Input[str]] = None, + yaml: Optional[pulumi.Input[Union[pulumi.Asset, pulumi.Archive]]] = None, + __props__=None): + """ + An ESC Environment. + + :param str resource_name: The name of the resource. + :param pulumi.ResourceOptions opts: Options for the resource. + :param pulumi.Input[str] name: Environment name. + :param pulumi.Input[str] organization: Organization name. + :param pulumi.Input[Union[pulumi.Asset, pulumi.Archive]] yaml: Environment's yaml file. + """ + ... + @overload + def __init__(__self__, + resource_name: str, + args: EnvironmentArgs, + opts: Optional[pulumi.ResourceOptions] = None): + """ + An ESC Environment. + + :param str resource_name: The name of the resource. + :param EnvironmentArgs args: The arguments to use to populate this resource's properties. + :param pulumi.ResourceOptions opts: Options for the resource. + """ + ... + def __init__(__self__, resource_name: str, *args, **kwargs): + resource_args, opts = _utilities.get_resource_args_opts(EnvironmentArgs, pulumi.ResourceOptions, *args, **kwargs) + if resource_args is not None: + __self__._internal_init(resource_name, opts, **resource_args.__dict__) + else: + __self__._internal_init(resource_name, *args, **kwargs) + + def _internal_init(__self__, + resource_name: str, + opts: Optional[pulumi.ResourceOptions] = None, + name: Optional[pulumi.Input[str]] = None, + organization: Optional[pulumi.Input[str]] = None, + yaml: Optional[pulumi.Input[Union[pulumi.Asset, pulumi.Archive]]] = None, + __props__=None): + opts = pulumi.ResourceOptions.merge(_utilities.get_resource_opts_defaults(), opts) + if not isinstance(opts, pulumi.ResourceOptions): + raise TypeError('Expected resource options to be a ResourceOptions instance') + if opts.id is None: + if __props__ is not None: + raise TypeError('__props__ is only valid when passed in combination with a valid opts.id to get an existing resource') + __props__ = EnvironmentArgs.__new__(EnvironmentArgs) + + if name is None and not opts.urn: + raise TypeError("Missing required property 'name'") + __props__.__dict__["name"] = name + if organization is None and not opts.urn: + raise TypeError("Missing required property 'organization'") + __props__.__dict__["organization"] = organization + if yaml is None and not opts.urn: + raise TypeError("Missing required property 'yaml'") + __props__.__dict__["yaml"] = yaml + super(Environment, __self__).__init__( + 'pulumiservice:index:Environment', + resource_name, + __props__, + opts) + + @staticmethod + def get(resource_name: str, + id: pulumi.Input[str], + opts: Optional[pulumi.ResourceOptions] = None) -> 'Environment': + """ + Get an existing Environment resource's state with the given name, id, and optional extra + properties used to qualify the lookup. + + :param str resource_name: The unique name of the resulting resource. + :param pulumi.Input[str] id: The unique provider ID of the resource to lookup. + :param pulumi.ResourceOptions opts: Options for the resource. + """ + opts = pulumi.ResourceOptions.merge(opts, pulumi.ResourceOptions(id=id)) + + __props__ = EnvironmentArgs.__new__(EnvironmentArgs) + + __props__.__dict__["name"] = None + __props__.__dict__["organization"] = None + __props__.__dict__["yaml"] = None + return Environment(resource_name, opts=opts, __props__=__props__) + + @property + @pulumi.getter + def name(self) -> pulumi.Output[str]: + """ + Environment name. + """ + return pulumi.get(self, "name") + + @property + @pulumi.getter + def organization(self) -> pulumi.Output[str]: + """ + Organization name. + """ + return pulumi.get(self, "organization") + + @property + @pulumi.getter + def yaml(self) -> pulumi.Output[Union[pulumi.Asset, pulumi.Archive]]: + """ + Environment's yaml file. + """ + return pulumi.get(self, "yaml") +