vault: Adding metrics profiling
This commit is contained in:
parent
429ad7e5cb
commit
512b3d7afd
|
@ -7,7 +7,9 @@ import (
|
|||
"log"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/armon/go-metrics"
|
||||
"github.com/hashicorp/vault/audit"
|
||||
"github.com/hashicorp/vault/logical"
|
||||
)
|
||||
|
@ -260,6 +262,7 @@ func (a *AuditBroker) IsRegistered(name string) bool {
|
|||
// LogRequest is used to ensure all the audit backends have an opportunity to
|
||||
// log the given request and that *at least one* succeeds.
|
||||
func (a *AuditBroker) LogRequest(auth *logical.Auth, req *logical.Request) error {
|
||||
defer metrics.MeasureSince([]string{"audit", "log_request"}, time.Now())
|
||||
a.l.RLock()
|
||||
defer a.l.RUnlock()
|
||||
|
||||
|
@ -282,6 +285,7 @@ func (a *AuditBroker) LogRequest(auth *logical.Auth, req *logical.Request) error
|
|||
// log the given response and that *at least one* succeeds.
|
||||
func (a *AuditBroker) LogResponse(auth *logical.Auth, req *logical.Request,
|
||||
resp *logical.Response, err error) error {
|
||||
defer metrics.MeasureSince([]string{"audit", "log_response"}, time.Now())
|
||||
a.l.RLock()
|
||||
defer a.l.RUnlock()
|
||||
|
||||
|
|
|
@ -8,7 +8,9 @@ import (
|
|||
"fmt"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/armon/go-metrics"
|
||||
"github.com/hashicorp/vault/physical"
|
||||
)
|
||||
|
||||
|
@ -203,6 +205,7 @@ func (b *AESGCMBarrier) Seal() error {
|
|||
|
||||
// Put is used to insert or update an entry
|
||||
func (b *AESGCMBarrier) Put(entry *Entry) error {
|
||||
defer metrics.MeasureSince([]string{"barrier", "put"}, time.Now())
|
||||
b.l.RLock()
|
||||
defer b.l.RUnlock()
|
||||
|
||||
|
@ -220,6 +223,7 @@ func (b *AESGCMBarrier) Put(entry *Entry) error {
|
|||
|
||||
// Get is used to fetch an entry
|
||||
func (b *AESGCMBarrier) Get(key string) (*Entry, error) {
|
||||
defer metrics.MeasureSince([]string{"barrier", "get"}, time.Now())
|
||||
b.l.RLock()
|
||||
defer b.l.RUnlock()
|
||||
|
||||
|
@ -252,6 +256,7 @@ func (b *AESGCMBarrier) Get(key string) (*Entry, error) {
|
|||
|
||||
// Delete is used to permanently delete an entry
|
||||
func (b *AESGCMBarrier) Delete(key string) error {
|
||||
defer metrics.MeasureSince([]string{"barrier", "delete"}, time.Now())
|
||||
b.l.RLock()
|
||||
defer b.l.RUnlock()
|
||||
if b.sealed {
|
||||
|
@ -264,6 +269,7 @@ func (b *AESGCMBarrier) Delete(key string) error {
|
|||
// List is used ot list all the keys under a given
|
||||
// prefix, up to the next prefix.
|
||||
func (b *AESGCMBarrier) List(prefix string) ([]string, error) {
|
||||
defer metrics.MeasureSince([]string{"barrier", "list"}, time.Now())
|
||||
b.l.RLock()
|
||||
defer b.l.RUnlock()
|
||||
if b.sealed {
|
||||
|
|
|
@ -9,7 +9,9 @@ import (
|
|||
"os"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/armon/go-metrics"
|
||||
"github.com/hashicorp/vault/audit"
|
||||
"github.com/hashicorp/vault/logical"
|
||||
"github.com/hashicorp/vault/physical"
|
||||
|
@ -152,6 +154,9 @@ type Core struct {
|
|||
// token store is used to manage authentication tokens
|
||||
tokenStore *TokenStore
|
||||
|
||||
// metricsCh is used to stop the metrics streaming
|
||||
metricsCh chan struct{}
|
||||
|
||||
logger *log.Logger
|
||||
}
|
||||
|
||||
|
@ -230,6 +235,7 @@ func (c *Core) HandleRequest(req *logical.Request) (*logical.Response, error) {
|
|||
}
|
||||
|
||||
func (c *Core) handleRequest(req *logical.Request) (*logical.Response, error) {
|
||||
defer metrics.MeasureSince([]string{"core", "handle_request"}, time.Now())
|
||||
// Validate the token
|
||||
auth, err := c.checkToken(req.Operation, req.Path, req.ClientToken)
|
||||
if err != nil {
|
||||
|
@ -321,6 +327,8 @@ func (c *Core) handleRequest(req *logical.Request) (*logical.Response, error) {
|
|||
// handleLoginRequest is used to handle a login request, which is an
|
||||
// unauthenticated request to the backend.
|
||||
func (c *Core) handleLoginRequest(req *logical.Request) (*logical.Response, error) {
|
||||
defer metrics.MeasureSince([]string{"core", "handle_login_request"}, time.Now())
|
||||
|
||||
// Create an audit trail of the request, auth is not available on login requests
|
||||
if err := c.auditBroker.LogRequest(nil, req); err != nil {
|
||||
c.logger.Printf("[ERR] core: failed to audit request (%#v): %v",
|
||||
|
@ -380,6 +388,8 @@ func (c *Core) handleLoginRequest(req *logical.Request) (*logical.Response, erro
|
|||
|
||||
func (c *Core) checkToken(
|
||||
op logical.Operation, path string, token string) (*logical.Auth, error) {
|
||||
defer metrics.MeasureSince([]string{"core", "check_token"}, time.Now())
|
||||
|
||||
// Ensure there is a client token
|
||||
if token == "" {
|
||||
return nil, fmt.Errorf("missing client token")
|
||||
|
@ -605,6 +615,8 @@ func (c *Core) SecretProgress() int {
|
|||
// this method is done with it. If you want to keep the key around, a copy
|
||||
// should be made.
|
||||
func (c *Core) Unseal(key []byte) (bool, error) {
|
||||
defer metrics.MeasureSince([]string{"core", "unseal"}, time.Now())
|
||||
|
||||
// Verify the key length
|
||||
min, max := c.barrier.KeyLength()
|
||||
max += shamir.ShareOverhead
|
||||
|
@ -689,6 +701,7 @@ func (c *Core) Unseal(key []byte) (bool, error) {
|
|||
// Seal is used to re-seal the Vault. This requires the Vault to
|
||||
// be unsealed again to perform any further operations.
|
||||
func (c *Core) Seal(token string) error {
|
||||
defer metrics.MeasureSince([]string{"core", "seal"}, time.Now())
|
||||
c.stateLock.Lock()
|
||||
defer c.stateLock.Unlock()
|
||||
if c.sealed {
|
||||
|
@ -723,6 +736,7 @@ func (c *Core) Seal(token string) error {
|
|||
// requires the Vault to be unsealed such as mount tables, logical backends,
|
||||
// credential stores, etc.
|
||||
func (c *Core) postUnseal() error {
|
||||
defer metrics.MeasureSince([]string{"core", "post_unseal"}, time.Now())
|
||||
if err := c.loadMounts(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -750,12 +764,19 @@ func (c *Core) postUnseal() error {
|
|||
if err := c.setupAudits(); err != nil {
|
||||
return err
|
||||
}
|
||||
c.metricsCh = make(chan struct{})
|
||||
go c.emitMetrics(c.metricsCh)
|
||||
return nil
|
||||
}
|
||||
|
||||
// preSeal is invoked before the barrier is sealed, allowing
|
||||
// for any state teardown required.
|
||||
func (c *Core) preSeal() error {
|
||||
defer metrics.MeasureSince([]string{"core", "pre_seal"}, time.Now())
|
||||
if c.metricsCh != nil {
|
||||
close(c.metricsCh)
|
||||
c.metricsCh = nil
|
||||
}
|
||||
if err := c.teardownAudits(); err != nil {
|
||||
return err
|
||||
}
|
||||
|
@ -776,3 +797,15 @@ func (c *Core) preSeal() error {
|
|||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// emitMetrics is used to periodically expose metrics while runnig
|
||||
func (c *Core) emitMetrics(stopCh chan struct{}) {
|
||||
for {
|
||||
select {
|
||||
case <-time.After(time.Second):
|
||||
c.expiration.emitMetrics()
|
||||
case <-stopCh:
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,6 +10,7 @@ import (
|
|||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/armon/go-metrics"
|
||||
"github.com/hashicorp/vault/logical"
|
||||
)
|
||||
|
||||
|
@ -156,6 +157,7 @@ func (m *ExpirationManager) Stop() error {
|
|||
|
||||
// Revoke is used to revoke a secret named by the given LeaseID
|
||||
func (m *ExpirationManager) Revoke(leaseID string) error {
|
||||
defer metrics.MeasureSince([]string{"expire", "revoke"}, time.Now())
|
||||
// Load the entry
|
||||
le, err := m.loadEntry(leaseID)
|
||||
if err != nil {
|
||||
|
@ -191,6 +193,7 @@ func (m *ExpirationManager) Revoke(leaseID string) error {
|
|||
// The prefix maps to that of the mount table to make this simpler
|
||||
// to reason about.
|
||||
func (m *ExpirationManager) RevokePrefix(prefix string) error {
|
||||
defer metrics.MeasureSince([]string{"expire", "revoke-prefix"}, time.Now())
|
||||
// Ensure there is a trailing slash
|
||||
if !strings.HasSuffix(prefix, "/") {
|
||||
prefix = prefix + "/"
|
||||
|
@ -217,6 +220,7 @@ func (m *ExpirationManager) RevokePrefix(prefix string) error {
|
|||
// Renew is used to renew a secret using the given leaseID
|
||||
// and a renew interval. The increment may be ignored.
|
||||
func (m *ExpirationManager) Renew(leaseID string, increment time.Duration) (*logical.Response, error) {
|
||||
defer metrics.MeasureSince([]string{"expire", "renew"}, time.Now())
|
||||
// Load the entry
|
||||
le, err := m.loadEntry(leaseID)
|
||||
if err != nil {
|
||||
|
@ -279,6 +283,7 @@ func (m *ExpirationManager) Renew(leaseID string, increment time.Duration) (*log
|
|||
// RenewToken is used to renew a token which does not need to
|
||||
// invoke a logical backend.
|
||||
func (m *ExpirationManager) RenewToken(source string, token string) (*logical.Auth, error) {
|
||||
defer metrics.MeasureSince([]string{"expire", "renew-token"}, time.Now())
|
||||
// Compute the Lease ID
|
||||
leaseID := path.Join(source, m.tokenStore.SaltID(token))
|
||||
|
||||
|
@ -324,6 +329,7 @@ func (m *ExpirationManager) RenewToken(source string, token string) (*logical.Au
|
|||
// lease. The secret gets assigned a LeaseID and the management of
|
||||
// of lease is assumed by the expiration manager.
|
||||
func (m *ExpirationManager) Register(req *logical.Request, resp *logical.Response) (string, error) {
|
||||
defer metrics.MeasureSince([]string{"expire", "register"}, time.Now())
|
||||
// Ignore if there is no leased secret
|
||||
if resp == nil || resp.Secret == nil {
|
||||
return "", nil
|
||||
|
@ -372,6 +378,7 @@ func (m *ExpirationManager) Register(req *logical.Request, resp *logical.Respons
|
|||
// The token does not get a LeaseID, but the lease management is handled by
|
||||
// the expiration manager.
|
||||
func (m *ExpirationManager) RegisterAuth(source string, auth *logical.Auth) error {
|
||||
defer metrics.MeasureSince([]string{"expire", "register-auth"}, time.Now())
|
||||
// Create a lease entry
|
||||
now := time.Now().UTC()
|
||||
leaseTotal := auth.Lease + auth.LeaseGracePeriod
|
||||
|
@ -499,6 +506,14 @@ func (m *ExpirationManager) deleteEntry(leaseID string) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
// emitMetrics is invoked periodically to emit statistics
|
||||
func (m *ExpirationManager) emitMetrics() {
|
||||
m.pendingLock.Lock()
|
||||
num := len(m.pending)
|
||||
m.pendingLock.Unlock()
|
||||
metrics.SetGauge([]string{"expire", "num_leases"}, float32(num))
|
||||
}
|
||||
|
||||
// leaseEntry is used to structure the values the expiration
|
||||
// manager stores. This is used to handle renew and revocation.
|
||||
type leaseEntry struct {
|
||||
|
|
|
@ -2,7 +2,9 @@ package vault
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/armon/go-metrics"
|
||||
"github.com/hashicorp/golang-lru"
|
||||
"github.com/hashicorp/vault/logical"
|
||||
)
|
||||
|
@ -54,6 +56,7 @@ func (c *Core) teardownPolicyStore() error {
|
|||
|
||||
// SetPolicy is used to create or update the given policy
|
||||
func (ps *PolicyStore) SetPolicy(p *Policy) error {
|
||||
defer metrics.MeasureSince([]string{"policy", "set_policy"}, time.Now())
|
||||
if p.Name == "root" {
|
||||
return fmt.Errorf("cannot update root policy")
|
||||
}
|
||||
|
@ -76,6 +79,7 @@ func (ps *PolicyStore) SetPolicy(p *Policy) error {
|
|||
|
||||
// GetPolicy is used to fetch the named policy
|
||||
func (ps *PolicyStore) GetPolicy(name string) (*Policy, error) {
|
||||
defer metrics.MeasureSince([]string{"policy", "get_policy"}, time.Now())
|
||||
// Check for cached policy
|
||||
if raw, ok := ps.lru.Get(name); ok {
|
||||
return raw.(*Policy), nil
|
||||
|
@ -111,6 +115,7 @@ func (ps *PolicyStore) GetPolicy(name string) (*Policy, error) {
|
|||
|
||||
// ListPolicies is used to list the available policies
|
||||
func (ps *PolicyStore) ListPolicies() ([]string, error) {
|
||||
defer metrics.MeasureSince([]string{"policy", "list_policies"}, time.Now())
|
||||
// Scan the view, since the policy names are the same as the
|
||||
// key names.
|
||||
return CollectKeys(ps.view)
|
||||
|
@ -118,6 +123,7 @@ func (ps *PolicyStore) ListPolicies() ([]string, error) {
|
|||
|
||||
// DeletePolicy is used to delete the named policy
|
||||
func (ps *PolicyStore) DeletePolicy(name string) error {
|
||||
defer metrics.MeasureSince([]string{"policy", "delete_policy"}, time.Now())
|
||||
if name == "root" {
|
||||
return fmt.Errorf("cannot delete root policy")
|
||||
}
|
||||
|
|
|
@ -2,9 +2,11 @@ package vault
|
|||
|
||||
import (
|
||||
"log"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/armon/go-metrics"
|
||||
"github.com/hashicorp/vault/logical"
|
||||
)
|
||||
|
||||
|
@ -124,6 +126,7 @@ func (m *RollbackManager) startRollback(path string) *rollbackState {
|
|||
|
||||
// attemptRollback invokes a RollbackOperation for the given path
|
||||
func (m *RollbackManager) attemptRollback(path string, rs *rollbackState) (err error) {
|
||||
defer metrics.MeasureSince([]string{"rollback", "attempt", strings.Replace(path, "/", "-", -1)}, time.Now())
|
||||
defer func() {
|
||||
rs.lastError = err
|
||||
rs.Done()
|
||||
|
|
|
@ -6,7 +6,9 @@ import (
|
|||
"fmt"
|
||||
"strings"
|
||||
"sync"
|
||||
"time"
|
||||
|
||||
"github.com/armon/go-metrics"
|
||||
"github.com/armon/go-radix"
|
||||
"github.com/hashicorp/vault/logical"
|
||||
)
|
||||
|
@ -157,6 +159,7 @@ func (r *Router) Route(req *logical.Request) (*logical.Response, error) {
|
|||
if !ok {
|
||||
return nil, fmt.Errorf("no handler for route '%s'", req.Path)
|
||||
}
|
||||
defer metrics.MeasureSince([]string{"route", strings.Replace(mount, "/", "-", -1)}, time.Now())
|
||||
me := raw.(*mountEntry)
|
||||
|
||||
// If the path is tainted, we reject any operation except for
|
||||
|
|
|
@ -8,6 +8,7 @@ import (
|
|||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/armon/go-metrics"
|
||||
"github.com/hashicorp/vault/logical"
|
||||
"github.com/hashicorp/vault/logical/framework"
|
||||
"github.com/mitchellh/mapstructure"
|
||||
|
@ -247,6 +248,7 @@ func (ts *TokenStore) RootToken() (*TokenEntry, error) {
|
|||
// Create is used to create a new token entry. The entry is assigned
|
||||
// a newly generated ID if not provided.
|
||||
func (ts *TokenStore) Create(entry *TokenEntry) error {
|
||||
defer metrics.MeasureSince([]string{"token", "create"}, time.Now())
|
||||
// Generate an ID if necessary
|
||||
if entry.ID == "" {
|
||||
entry.ID = generateUUID()
|
||||
|
@ -292,6 +294,7 @@ func (ts *TokenStore) Create(entry *TokenEntry) error {
|
|||
|
||||
// Lookup is used to find a token given its ID
|
||||
func (ts *TokenStore) Lookup(id string) (*TokenEntry, error) {
|
||||
defer metrics.MeasureSince([]string{"token", "lookup"}, time.Now())
|
||||
if id == "" {
|
||||
return nil, fmt.Errorf("cannot lookup blank token")
|
||||
}
|
||||
|
@ -323,6 +326,7 @@ func (ts *TokenStore) lookupSalted(saltedId string) (*TokenEntry, error) {
|
|||
// Revoke is used to invalidate a given token, any child tokens
|
||||
// will be orphaned.
|
||||
func (ts *TokenStore) Revoke(id string) error {
|
||||
defer metrics.MeasureSince([]string{"token", "revoke"}, time.Now())
|
||||
if id == "" {
|
||||
return fmt.Errorf("cannot revoke blank token")
|
||||
}
|
||||
|
@ -357,6 +361,7 @@ func (ts *TokenStore) revokeSalted(saltedId string) error {
|
|||
// RevokeTree is used to invalide a given token and all
|
||||
// child tokens.
|
||||
func (ts *TokenStore) RevokeTree(id string) error {
|
||||
defer metrics.MeasureSince([]string{"token", "revoke-tree"}, time.Now())
|
||||
// Verify the token is not blank
|
||||
if id == "" {
|
||||
return fmt.Errorf("cannot revoke blank token")
|
||||
|
@ -419,6 +424,7 @@ func (ts *TokenStore) revokeTreeSalted(saltedId string) error {
|
|||
|
||||
// RevokeAll is used to invalidate all generated tokens.
|
||||
func (ts *TokenStore) RevokeAll() error {
|
||||
defer metrics.MeasureSince([]string{"token", "revoke-all"}, time.Now())
|
||||
// Collect all the tokens
|
||||
sub := ts.view.SubView(lookupPrefix)
|
||||
tokens, err := CollectKeys(sub)
|
||||
|
|
Loading…
Reference in New Issue