github.com/myhau/pulumi/pkg/v3@v3.70.2-0.20221116134521-f2775972e587/resource/deploy/providers/reference.go (about)

     1  // Copyright 2016-2018, Pulumi Corporation.
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package providers
    16  
    17  import (
    18  	"errors"
    19  	"fmt"
    20  	"strings"
    21  
    22  	"github.com/pulumi/pulumi/sdk/v3/go/common/resource"
    23  	"github.com/pulumi/pulumi/sdk/v3/go/common/resource/plugin"
    24  	"github.com/pulumi/pulumi/sdk/v3/go/common/tokens"
    25  	"github.com/pulumi/pulumi/sdk/v3/go/common/util/contract"
    26  )
    27  
    28  // A provider reference is (URN, ID) tuple that refers to a particular provider instance. A provider reference's
    29  // string representation is <URN> "::" <ID>. The URN's type portion must be of the form "pulumi:providers:<pkg>".
    30  
    31  // UnknownID is a distinguished token used to indicate that a provider's ID is not known (e.g. because we are
    32  // performing a preview).
    33  const UnknownID = plugin.UnknownStringValue
    34  
    35  // IsProviderType returns true if the supplied type token refers to a Pulumi provider.
    36  func IsProviderType(typ tokens.Type) bool {
    37  	// Tokens without a module member are definitely not provider types.
    38  	if !tokens.Token(typ).HasModuleMember() {
    39  		return false
    40  	}
    41  	return typ.Module() == "pulumi:providers" && typ.Name() != ""
    42  }
    43  
    44  // IsDefaultProvider returns true if this URN refers to a default Pulumi provider.
    45  func IsDefaultProvider(urn resource.URN) bool {
    46  	return IsProviderType(urn.Type()) && strings.HasPrefix(urn.Name().String(), "default")
    47  }
    48  
    49  // MakeProviderType returns the provider type token for the given package.
    50  func MakeProviderType(pkg tokens.Package) tokens.Type {
    51  	return tokens.Type("pulumi:providers:" + pkg)
    52  }
    53  
    54  // GetProviderPackage returns the provider package for the given type token.
    55  func GetProviderPackage(typ tokens.Type) tokens.Package {
    56  	contract.Require(IsProviderType(typ), "typ")
    57  	return tokens.Package(typ.Name())
    58  }
    59  
    60  func validateURN(urn resource.URN) error {
    61  	if !urn.IsValid() {
    62  		return fmt.Errorf("%s is not a valid URN", urn)
    63  	}
    64  	typ := urn.Type()
    65  	if typ.Module() != "pulumi:providers" {
    66  		return fmt.Errorf("invalid module in type: expected 'pulumi:providers', got '%v'", typ.Module())
    67  	}
    68  	if typ.Name() == "" {
    69  		return errors.New("provider URNs must specify a type name")
    70  	}
    71  	return nil
    72  }
    73  
    74  // Reference represents a reference to a particular provider.
    75  type Reference struct {
    76  	urn resource.URN
    77  	id  resource.ID
    78  }
    79  
    80  // URN returns the provider reference's URN.
    81  func (r Reference) URN() resource.URN {
    82  	return r.urn
    83  }
    84  
    85  // ID returns the provider reference's ID.
    86  func (r Reference) ID() resource.ID {
    87  	return r.id
    88  }
    89  
    90  // String returns the string representation of this provider reference.
    91  func (r Reference) String() string {
    92  	if r.urn == "" && r.id == "" {
    93  		return ""
    94  	}
    95  
    96  	return string(r.urn) + resource.URNNameDelimiter + string(r.id)
    97  }
    98  
    99  const denyDefaultProviderID resource.ID = "denydefaultprovider"
   100  
   101  // DenyDefaultProvider represent a default provider that cannot be created.
   102  func NewDenyDefaultProvider(name tokens.QName) Reference {
   103  	return mustNewReference(
   104  		resource.NewURN("denied", "denied", "denied", "pulumi:providers:denied", name),
   105  		denyDefaultProviderID)
   106  }
   107  
   108  // Retrieves the package of the denied provider.
   109  //
   110  // For example, if a reference to:
   111  // "urn:pulumi:stack::project::pulumi:providers:aws::default_4_35_0"
   112  // was denied, then GetDeniedDefaultProviderPkg would return "aws".
   113  //
   114  // Panics if called on a provider that is not a DenyDefaultProvider.
   115  func GetDeniedDefaultProviderPkg(ref Reference) string {
   116  	contract.Assert(IsDenyDefaultsProvider(ref))
   117  	return ref.URN().Name().String()
   118  }
   119  
   120  func IsDenyDefaultsProvider(ref Reference) bool {
   121  	return ref.id == denyDefaultProviderID
   122  }
   123  
   124  // NewReference creates a new reference for the given URN and ID.
   125  func NewReference(urn resource.URN, id resource.ID) (Reference, error) {
   126  	if err := validateURN(urn); err != nil {
   127  		return Reference{}, err
   128  	}
   129  	return Reference{urn: urn, id: id}, nil
   130  }
   131  
   132  func mustNewReference(urn resource.URN, id resource.ID) Reference {
   133  	ref, err := NewReference(urn, id)
   134  	contract.Assert(err == nil)
   135  	return ref
   136  }
   137  
   138  // ParseReference parses the URN and ID from the string representation of a provider reference. If parsing was
   139  // not possible, this function returns false.
   140  func ParseReference(s string) (Reference, error) {
   141  	// If this is not a valid URN + ID, return false. Note that we don't try terribly hard to validate the URN portion
   142  	// of the reference.
   143  	lastSep := strings.LastIndex(s, resource.URNNameDelimiter)
   144  	if lastSep == -1 {
   145  		return Reference{}, fmt.Errorf("expected '%v' in provider reference '%v'", resource.URNNameDelimiter, s)
   146  	}
   147  	urn, id := resource.URN(s[:lastSep]), resource.ID(s[lastSep+len(resource.URNNameDelimiter):])
   148  	if err := validateURN(urn); err != nil {
   149  		return Reference{}, err
   150  	}
   151  	return Reference{urn: urn, id: id}, nil
   152  }