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 }