Add plugin version to GRPC interface (#17088)
Add plugin version to GRPC interface
Added a version interface in the sdk/logical so that it can be shared between all plugin types, and then wired it up to RunningVersion in the mounts, auth list, and database systems.
I've tested that this works with auth, database, and secrets plugin types, with the following logic to populate RunningVersion:
If a plugin has a PluginVersion() method implemented, then that is used
If not, and the plugin is built into the Vault binary, then the go.mod version is used
Otherwise, the it will be the empty string.
My apologies for the length of this PR.
* Placeholder backend should be external
We use a placeholder backend (previously a framework.Backend) before a
GRPC plugin is lazy-loaded. This makes us later think the plugin is a
builtin plugin.
So we added a `placeholderBackend` type that overrides the
`IsExternal()` method so that later we know that the plugin is external,
and don't give it a default builtin version.
2022-09-15 23:37:59 +00:00
|
|
|
package versions
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"runtime/debug"
|
|
|
|
"strings"
|
|
|
|
"sync"
|
|
|
|
|
2022-11-23 18:36:25 +00:00
|
|
|
semver "github.com/hashicorp/go-version"
|
Add plugin version to GRPC interface (#17088)
Add plugin version to GRPC interface
Added a version interface in the sdk/logical so that it can be shared between all plugin types, and then wired it up to RunningVersion in the mounts, auth list, and database systems.
I've tested that this works with auth, database, and secrets plugin types, with the following logic to populate RunningVersion:
If a plugin has a PluginVersion() method implemented, then that is used
If not, and the plugin is built into the Vault binary, then the go.mod version is used
Otherwise, the it will be the empty string.
My apologies for the length of this PR.
* Placeholder backend should be external
We use a placeholder backend (previously a framework.Backend) before a
GRPC plugin is lazy-loaded. This makes us later think the plugin is a
builtin plugin.
So we added a `placeholderBackend` type that overrides the
`IsExternal()` method so that later we know that the plugin is external,
and don't give it a default builtin version.
2022-09-15 23:37:59 +00:00
|
|
|
"github.com/hashicorp/vault/sdk/helper/consts"
|
2022-12-07 18:29:51 +00:00
|
|
|
"github.com/hashicorp/vault/version"
|
Add plugin version to GRPC interface (#17088)
Add plugin version to GRPC interface
Added a version interface in the sdk/logical so that it can be shared between all plugin types, and then wired it up to RunningVersion in the mounts, auth list, and database systems.
I've tested that this works with auth, database, and secrets plugin types, with the following logic to populate RunningVersion:
If a plugin has a PluginVersion() method implemented, then that is used
If not, and the plugin is built into the Vault binary, then the go.mod version is used
Otherwise, the it will be the empty string.
My apologies for the length of this PR.
* Placeholder backend should be external
We use a placeholder backend (previously a framework.Backend) before a
GRPC plugin is lazy-loaded. This makes us later think the plugin is a
builtin plugin.
So we added a `placeholderBackend` type that overrides the
`IsExternal()` method so that later we know that the plugin is external,
and don't give it a default builtin version.
2022-09-15 23:37:59 +00:00
|
|
|
)
|
|
|
|
|
2022-11-23 18:36:25 +00:00
|
|
|
const (
|
|
|
|
BuiltinMetadata = "builtin"
|
|
|
|
)
|
|
|
|
|
Add plugin version to GRPC interface (#17088)
Add plugin version to GRPC interface
Added a version interface in the sdk/logical so that it can be shared between all plugin types, and then wired it up to RunningVersion in the mounts, auth list, and database systems.
I've tested that this works with auth, database, and secrets plugin types, with the following logic to populate RunningVersion:
If a plugin has a PluginVersion() method implemented, then that is used
If not, and the plugin is built into the Vault binary, then the go.mod version is used
Otherwise, the it will be the empty string.
My apologies for the length of this PR.
* Placeholder backend should be external
We use a placeholder backend (previously a framework.Backend) before a
GRPC plugin is lazy-loaded. This makes us later think the plugin is a
builtin plugin.
So we added a `placeholderBackend` type that overrides the
`IsExternal()` method so that later we know that the plugin is external,
and don't give it a default builtin version.
2022-09-15 23:37:59 +00:00
|
|
|
var (
|
|
|
|
buildInfoOnce sync.Once // once is used to ensure we only parse build info once.
|
|
|
|
buildInfo *debug.BuildInfo
|
2022-11-23 18:36:25 +00:00
|
|
|
DefaultBuiltinVersion = fmt.Sprintf("v%s+%s.vault", version.GetVersion().Version, BuiltinMetadata)
|
Add plugin version to GRPC interface (#17088)
Add plugin version to GRPC interface
Added a version interface in the sdk/logical so that it can be shared between all plugin types, and then wired it up to RunningVersion in the mounts, auth list, and database systems.
I've tested that this works with auth, database, and secrets plugin types, with the following logic to populate RunningVersion:
If a plugin has a PluginVersion() method implemented, then that is used
If not, and the plugin is built into the Vault binary, then the go.mod version is used
Otherwise, the it will be the empty string.
My apologies for the length of this PR.
* Placeholder backend should be external
We use a placeholder backend (previously a framework.Backend) before a
GRPC plugin is lazy-loaded. This makes us later think the plugin is a
builtin plugin.
So we added a `placeholderBackend` type that overrides the
`IsExternal()` method so that later we know that the plugin is external,
and don't give it a default builtin version.
2022-09-15 23:37:59 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
func GetBuiltinVersion(pluginType consts.PluginType, pluginName string) string {
|
|
|
|
buildInfoOnce.Do(func() {
|
|
|
|
buildInfo, _ = debug.ReadBuildInfo()
|
|
|
|
})
|
|
|
|
|
|
|
|
// Should never happen, means the binary was built without Go modules.
|
|
|
|
// Fall back to just the Vault version.
|
|
|
|
if buildInfo == nil {
|
|
|
|
return DefaultBuiltinVersion
|
|
|
|
}
|
|
|
|
|
|
|
|
// Vault builtin plugins are all either:
|
|
|
|
// a) An external repo within the hashicorp org - return external repo version with +builtin
|
|
|
|
// b) Within the Vault repo itself - return Vault version with +builtin.vault
|
|
|
|
//
|
|
|
|
// The repo names are predictable, but follow slightly different patterns
|
|
|
|
// for each plugin type.
|
|
|
|
t := pluginType.String()
|
|
|
|
switch pluginType {
|
|
|
|
case consts.PluginTypeDatabase:
|
|
|
|
// Database plugin built-ins are registered as e.g. "postgresql-database-plugin"
|
|
|
|
pluginName = strings.TrimSuffix(pluginName, "-database-plugin")
|
|
|
|
case consts.PluginTypeSecrets:
|
|
|
|
// Repos use "secrets", pluginType.String() is "secret".
|
|
|
|
t = "secrets"
|
|
|
|
}
|
|
|
|
pluginModulePath := fmt.Sprintf("github.com/hashicorp/vault-plugin-%s-%s", t, pluginName)
|
|
|
|
|
|
|
|
for _, dep := range buildInfo.Deps {
|
|
|
|
if dep.Path == pluginModulePath {
|
2022-11-23 18:36:25 +00:00
|
|
|
return dep.Version + "+" + BuiltinMetadata
|
Add plugin version to GRPC interface (#17088)
Add plugin version to GRPC interface
Added a version interface in the sdk/logical so that it can be shared between all plugin types, and then wired it up to RunningVersion in the mounts, auth list, and database systems.
I've tested that this works with auth, database, and secrets plugin types, with the following logic to populate RunningVersion:
If a plugin has a PluginVersion() method implemented, then that is used
If not, and the plugin is built into the Vault binary, then the go.mod version is used
Otherwise, the it will be the empty string.
My apologies for the length of this PR.
* Placeholder backend should be external
We use a placeholder backend (previously a framework.Backend) before a
GRPC plugin is lazy-loaded. This makes us later think the plugin is a
builtin plugin.
So we added a `placeholderBackend` type that overrides the
`IsExternal()` method so that later we know that the plugin is external,
and don't give it a default builtin version.
2022-09-15 23:37:59 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return DefaultBuiltinVersion
|
|
|
|
}
|
2022-11-23 18:36:25 +00:00
|
|
|
|
|
|
|
// IsBuiltinVersion checks for the "builtin" metadata identifier in a plugin's
|
|
|
|
// semantic version. Vault rejects any plugin registration requests with this
|
|
|
|
// identifier, so we can be certain it's a builtin plugin if it's present.
|
|
|
|
func IsBuiltinVersion(v string) bool {
|
|
|
|
semanticVersion, err := semver.NewSemver(v)
|
|
|
|
if err != nil {
|
|
|
|
return false
|
|
|
|
}
|
|
|
|
|
|
|
|
metadataIdentifiers := strings.Split(semanticVersion.Metadata(), ".")
|
|
|
|
for _, identifier := range metadataIdentifiers {
|
|
|
|
if identifier == BuiltinMetadata {
|
|
|
|
return true
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return false
|
|
|
|
}
|