pulumi/pkg/resource/urn.go
joeduffy 2362d45a5c Eliminate type redundancy
Despite our good progress moving towards having an apitype package,
where our exchange types live and can be shared among the engine and
our services, there were a few major types that were still duplciated.
Resource was the biggest example -- and indeed, the apitype varirant
was missing the new Dependencies property -- but there were others,
like Manfiest, PluginInfo, etc.  These too had semi-random omissions.

This change merges all of these types into the apitype package.  This
not only cleans up the redundancy and missing properties, but will
"force the issue" with respect to keeping them in sync and properly
versioning the information in a backwards compatible way.

The resource/stack package still exists as a simple marshaling layer
to and from the engine's core data types.

Finally, I've made the controversial change to share the actual
Deployment data structure at the apitype layer also.  This will force
us to confront differences in that data structure similarly, and will
allow us to leverage the strong typing throughout to catch issues.
2018-02-28 12:44:55 -08:00

93 lines
3.3 KiB
Go

// Copyright 2016-2017, Pulumi Corporation. All rights reserved.
package resource
import (
"strings"
"github.com/pulumi/pulumi/pkg/tokens"
"github.com/pulumi/pulumi/pkg/util/contract"
)
// URN is a friendly, but unique, URN for a resource, most often auto-assigned by Lumi. These are
// used as unique IDs for objects, and help us to perform graph diffing and resolution of resource
// objects.
//
// In theory, we could support manually assigned URIs in the future. For the time being, however,
// we have opted to simplify developers' lives by mostly automating the generation of them
// algorithmically. The one caveat where it isn't truly automatic is that a developer -- or
// resource provider -- must provide a semi-unique name part.
//
// Each resource URN is of the form:
//
// urn:pulumi:<Stack>::<Project>::<Qualified$Type$Name>::<Name>
//
// wherein each element is the following:
//
// <Stack> The stack being deployed into
// <Project> The project being evaluated
// <Qualified$Type$Name> The object type's qualified type token (including the parent type)
// <Name> The human-friendly name identifier assigned by the developer or provider
//
// In the future, we may add elements to the URN; it is more important that it is unique than it is
// human-typable.
type URN string
const (
URNPrefix = "urn:" + URNNamespaceID + ":" // the standard URN prefix
URNNamespaceID = "pulumi" // the URN namespace
URNNameDelimiter = "::" // the delimiter between URN name elements
URNTypeDelimiter = "$" // the delimiter between URN type elements
)
// NewURN creates a unique resource URN for the given resource object.
func NewURN(stack tokens.QName, proj tokens.PackageName, parentType, baseType tokens.Type, name tokens.QName) URN {
typ := string(baseType)
if parentType != "" {
typ = string(parentType) + URNTypeDelimiter + typ
}
return URN(
URNPrefix +
string(stack) +
URNNameDelimiter + string(proj) +
URNNameDelimiter + typ +
URNNameDelimiter + string(name),
)
}
// URNName returns the URN name part of a URN (i.e., strips off the prefix).
func (urn URN) URNName() string {
s := string(urn)
contract.Assertf(strings.HasPrefix(s, URNPrefix), "Urn is: '%s'", string(urn))
return s[len(URNPrefix):]
}
// Stack returns the resource stack part of a URN.
func (urn URN) Stack() tokens.QName {
return tokens.QName(strings.Split(urn.URNName(), URNNameDelimiter)[0])
}
// Project returns the project name part of a URN.
func (urn URN) Project() tokens.PackageName {
return tokens.PackageName(strings.Split(urn.URNName(), URNNameDelimiter)[1])
}
// QualifiedType returns the resource type part of a URN including the parent type
func (urn URN) QualifiedType() tokens.Type {
return tokens.Type(strings.Split(urn.URNName(), URNNameDelimiter)[2])
}
// Type returns the resource type part of a URN
func (urn URN) Type() tokens.Type {
qualifiedType := strings.Split(urn.URNName(), URNNameDelimiter)[2]
types := strings.Split(qualifiedType, URNTypeDelimiter)
lastType := types[len(types)-1]
return tokens.Type(lastType)
}
// Name returns the resource name part of a URN.
func (urn URN) Name() tokens.QName {
return tokens.QName(strings.Split(urn.URNName(), URNNameDelimiter)[3])
}