3 import "github.com/blang/semver"
5 // ProviderVersionConstraint presents a constraint for a particular
6 // provider, identified by its full name.
7 type ProviderVersionConstraint struct {
12 // ProviderVersionConstraints is a map from provider full name to its associated
13 // ProviderVersionConstraint, as produced by Config.RequiredProviders.
14 type ProviderVersionConstraints map[string]ProviderVersionConstraint
16 // RequiredProviders returns the ProviderVersionConstraints for this
19 // This includes both providers that are explicitly requested by provider
20 // blocks and those that are used implicitly by instantiating one of their
21 // resource types. In the latter case, the returned semver Range will
22 // accept any version of the provider.
23 func (c *Config) RequiredProviders() ProviderVersionConstraints {
24 ret := make(ProviderVersionConstraints, len(c.ProviderConfigs))
26 configs := c.ProviderConfigsByFullName()
28 // In order to find the *implied* dependencies (those without explicit
29 // "provider" blocks) we need to walk over all of the resources and
30 // cross-reference with the provider configs.
31 for _, rc := range c.Resources {
32 providerName := rc.ProviderFullName()
33 var providerType string
35 // Default to (effectively) no constraint whatsoever, but we might
36 // override if there's an explicit constraint in config.
37 constraint := ">=0.0.0"
39 config, ok := configs[providerName]
41 if config.Version != "" {
42 constraint = config.Version
44 providerType = config.Name
46 providerType = providerName
49 ret[providerName] = ProviderVersionConstraint{
50 ProviderType: providerType,
51 Constraint: constraint,
58 // RequiredRanges returns a semver.Range for each distinct provider type in
59 // the constraint map. If the same provider type appears more than once
60 // (e.g. because aliases are in use) then their respective constraints are
61 // combined such that they must *all* apply.
63 // The result of this method can be passed to the
64 // PluginMetaSet.ConstrainVersions method within the plugin/discovery
65 // package in order to filter down the available plugins to those which
66 // satisfy the given constraints.
68 // This function will panic if any of the constraints within cannot be
69 // parsed as semver ranges. This is guaranteed to never happen for a
70 // constraint set that was built from a configuration that passed validation.
71 func (cons ProviderVersionConstraints) RequiredRanges() map[string]semver.Range {
72 ret := make(map[string]semver.Range, len(cons))
74 for _, con := range cons {
75 spec := semver.MustParseRange(con.Constraint)
76 if existing, exists := ret[con.ProviderType]; exists {
77 ret[con.ProviderType] = existing.AND(spec)
79 ret[con.ProviderType] = spec
86 // ProviderConfigsByFullName returns a map from provider full names (as
87 // returned by ProviderConfig.FullName()) to the corresponding provider
90 // This function returns no new information than what's already in
91 // c.ProviderConfigs, but returns it in a more convenient shape. If there
92 // is more than one provider config with the same full name then the result
93 // is undefined, but that is guaranteed not to happen for any config that
94 // has passed validation.
95 func (c *Config) ProviderConfigsByFullName() map[string]*ProviderConfig {
96 ret := make(map[string]*ProviderConfig, len(c.ProviderConfigs))
98 for _, pc := range c.ProviderConfigs {
99 ret[pc.FullName()] = pc