Skip to content

Commit 3c1c9f8

Browse files
Ensure "initialized" service registration tag is also present whenever Vault is unsealed, on both Consul and K8s (#8990)
* Add the initialized tag to Consul registration for parity with k8s (and for easy automated testing). Ensure that whenever we flag Vault as unsealed, we also flag it as initialized. * Update API docs. Co-authored-by: Jason O'Donnell <[email protected]>
1 parent e8baa21 commit 3c1c9f8

File tree

4 files changed

+64
-67
lines changed

4 files changed

+64
-67
lines changed

serviceregistration/consul/consul_service_registration.go

Lines changed: 26 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -72,8 +72,12 @@ type serviceRegistration struct {
7272
notifyActiveCh chan struct{}
7373
notifySealedCh chan struct{}
7474
notifyPerfStandbyCh chan struct{}
75+
notifyInitializedCh chan struct{}
7576

76-
isActive, isSealed, isPerfStandby *atomicB.Bool
77+
isActive *atomicB.Bool
78+
isSealed *atomicB.Bool
79+
isPerfStandby *atomicB.Bool
80+
isInitialized *atomicB.Bool
7781
}
7882

7983
// NewConsulServiceRegistration constructs a Consul-based ServiceRegistration.
@@ -210,10 +214,12 @@ func NewServiceRegistration(conf map[string]string, logger log.Logger, state sr.
210214
notifyActiveCh: make(chan struct{}),
211215
notifySealedCh: make(chan struct{}),
212216
notifyPerfStandbyCh: make(chan struct{}),
217+
notifyInitializedCh: make(chan struct{}),
213218

214219
isActive: atomicB.NewBool(state.IsActive),
215220
isSealed: atomicB.NewBool(state.IsSealed),
216221
isPerfStandby: atomicB.NewBool(state.IsPerformanceStandby),
222+
isInitialized: atomicB.NewBool(state.IsInitialized),
217223
}
218224
return c, nil
219225
}
@@ -269,9 +275,15 @@ func (c *serviceRegistration) NotifySealedStateChange(isSealed bool) error {
269275
}
270276

271277
func (c *serviceRegistration) NotifyInitializedStateChange(isInitialized bool) error {
272-
// This is not implemented because to date, Consul service registration has
273-
// never reported out on whether Vault was initialized. We may someday want to
274-
// do this, but it has not yet been requested.
278+
c.isInitialized.Store(isInitialized)
279+
select {
280+
case c.notifyInitializedCh <- struct{}{}:
281+
default:
282+
// NOTE: If this occurs Vault's initialized status could be out of
283+
// sync with Consul until checkTimer expires.
284+
c.logger.Warn("concurrent initalize state change notify dropped")
285+
}
286+
275287
return nil
276288
}
277289

@@ -329,7 +341,10 @@ func (c *serviceRegistration) runEventDemuxer(waitGroup *sync.WaitGroup, shutdow
329341
// Run check timer immediately upon a seal state change notification
330342
checkTimer.Reset(0)
331343
case <-c.notifyPerfStandbyCh:
332-
// Run check timer immediately upon a seal state change notification
344+
// Run check timer immediately upon a perfstandby state change notification
345+
checkTimer.Reset(0)
346+
case <-c.notifyInitializedCh:
347+
// Run check timer immediately upon an initialized state change notification
333348
checkTimer.Reset(0)
334349
case <-reconcileTimer.C:
335350
// Unconditionally rearm the reconcileTimer
@@ -428,7 +443,7 @@ func (c *serviceRegistration) reconcileConsul(registeredServiceID string) (servi
428443
}
429444
}
430445

431-
tags := c.fetchServiceTags(c.isActive.Load(), c.isPerfStandby.Load())
446+
tags := c.fetchServiceTags(c.isActive.Load(), c.isPerfStandby.Load(), c.isInitialized.Load())
432447

433448
var reregister bool
434449

@@ -505,7 +520,7 @@ func (c *serviceRegistration) runCheck(sealed bool) error {
505520
}
506521

507522
// fetchServiceTags returns all of the relevant tags for Consul.
508-
func (c *serviceRegistration) fetchServiceTags(active bool, perfStandby bool) []string {
523+
func (c *serviceRegistration) fetchServiceTags(active, perfStandby, initialized bool) []string {
509524
activeTag := "standby"
510525
if active {
511526
activeTag = "active"
@@ -517,6 +532,10 @@ func (c *serviceRegistration) fetchServiceTags(active bool, perfStandby bool) []
517532
result = append(c.serviceTags, "performance-standby")
518533
}
519534

535+
if initialized {
536+
result = append(result, "initialized")
537+
}
538+
520539
return result
521540
}
522541

serviceregistration/consul/consul_service_registration_test.go

Lines changed: 31 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,6 @@ import (
1212
log "github.com/hashicorp/go-hclog"
1313
"github.com/hashicorp/vault/helper/testhelpers/consul"
1414
"github.com/hashicorp/vault/sdk/helper/logging"
15-
"github.com/hashicorp/vault/sdk/helper/strutil"
1615
"github.com/hashicorp/vault/sdk/physical"
1716
"github.com/hashicorp/vault/sdk/physical/inmem"
1817
sr "github.com/hashicorp/vault/serviceregistration"
@@ -145,65 +144,10 @@ func TestConsul_ServiceRegistration(t *testing.T) {
145144

146145
waitForServices(t, map[string][]string{
147146
"consul": []string{},
148-
"vault": []string{"active"},
147+
"vault": []string{"active", "initialized"},
149148
})
150149
}
151150

152-
func TestConsul_ServiceTags(t *testing.T) {
153-
consulConfig := map[string]string{
154-
"path": "seaTech/",
155-
"service": "astronomy",
156-
"service_tags": "deadbeef, cafeefac, deadc0de, feedface",
157-
"redirect_addr": "http://127.0.0.2:8200",
158-
"check_timeout": "6s",
159-
"address": "127.0.0.2",
160-
"scheme": "https",
161-
"token": "deadbeef-cafeefac-deadc0de-feedface",
162-
"max_parallel": "4",
163-
"disable_registration": "false",
164-
}
165-
logger := logging.NewVaultLogger(log.Debug)
166-
167-
shutdownCh := make(chan struct{})
168-
defer func() {
169-
close(shutdownCh)
170-
}()
171-
172-
be, err := NewServiceRegistration(consulConfig, logger, sr.State{})
173-
if err != nil {
174-
t.Fatal(err)
175-
}
176-
if err := be.Run(shutdownCh, &sync.WaitGroup{}, ""); err != nil {
177-
t.Fatal(err)
178-
}
179-
180-
c, ok := be.(*serviceRegistration)
181-
if !ok {
182-
t.Fatalf("failed to create physical Consul backend")
183-
}
184-
185-
expected := []string{"deadbeef", "cafeefac", "deadc0de", "feedface"}
186-
actual := c.fetchServiceTags(false, false)
187-
if !strutil.EquivalentSlices(actual, append(expected, "standby")) {
188-
t.Fatalf("bad: expected:%s actual:%s", append(expected, "standby"), actual)
189-
}
190-
191-
actual = c.fetchServiceTags(true, false)
192-
if !strutil.EquivalentSlices(actual, append(expected, "active")) {
193-
t.Fatalf("bad: expected:%s actual:%s", append(expected, "active"), actual)
194-
}
195-
196-
actual = c.fetchServiceTags(false, true)
197-
if !strutil.EquivalentSlices(actual, append(expected, "performance-standby")) {
198-
t.Fatalf("bad: expected:%s actual:%s", append(expected, "performance-standby"), actual)
199-
}
200-
201-
actual = c.fetchServiceTags(true, true)
202-
if !strutil.EquivalentSlices(actual, append(expected, "performance-standby")) {
203-
t.Fatalf("bad: expected:%s actual:%s", append(expected, "performance-standby"), actual)
204-
}
205-
}
206-
207151
func TestConsul_ServiceAddress(t *testing.T) {
208152
tests := []struct {
209153
consulConfig map[string]string
@@ -418,34 +362,63 @@ func TestConsul_serviceTags(t *testing.T) {
418362
tests := []struct {
419363
active bool
420364
perfStandby bool
365+
initialized bool
421366
tags []string
422367
}{
423368
{
424369
active: true,
425370
perfStandby: false,
371+
initialized: false,
426372
tags: []string{"active"},
427373
},
428374
{
429375
active: false,
430376
perfStandby: false,
377+
initialized: false,
431378
tags: []string{"standby"},
432379
},
433380
{
434381
active: false,
435382
perfStandby: true,
383+
initialized: false,
436384
tags: []string{"performance-standby"},
437385
},
438386
{
439387
active: true,
440388
perfStandby: true,
389+
initialized: false,
441390
tags: []string{"performance-standby"},
442391
},
392+
{
393+
active: true,
394+
perfStandby: false,
395+
initialized: true,
396+
tags: []string{"active", "initialized"},
397+
},
398+
{
399+
active: false,
400+
perfStandby: false,
401+
initialized: true,
402+
tags: []string{"standby", "initialized"},
403+
},
404+
{
405+
active: false,
406+
perfStandby: true,
407+
initialized: true,
408+
tags: []string{"performance-standby", "initialized"},
409+
},
410+
{
411+
active: true,
412+
perfStandby: true,
413+
initialized: true,
414+
tags: []string{"performance-standby", "initialized"},
415+
},
443416
}
444417

445418
c := testConsulServiceRegistration(t)
446419

447420
for _, test := range tests {
448-
tags := c.fetchServiceTags(test.active, test.perfStandby)
421+
tags := c.fetchServiceTags(test.active, test.perfStandby, test.initialized)
449422
if !reflect.DeepEqual(tags[:], test.tags[:]) {
450423
t.Errorf("Bad %v: %v %v", test.active, tags, test.tags)
451424
}

serviceregistration/service_registration.go

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -87,8 +87,8 @@ type ServiceRegistration interface {
8787
// in the face of errors.
8888
NotifyPerformanceStandbyStateChange(isStandby bool) error
8989

90-
// NotifyInitializedStateChange is used by Core to notify that the core is
91-
// initialized.
90+
// NotifyInitializedStateChange is used by Core to notify that storage
91+
// has been initialized. An unsealed core will always also be initialized.
9292
// If errors are returned, Vault only logs a warning, so it is
9393
// the implementation's responsibility to retry updating state
9494
// in the face of errors.

vault/core.go

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1522,6 +1522,11 @@ func (c *Core) unsealInternal(ctx context.Context, masterKey []byte) (bool, erro
15221522
c.logger.Warn("failed to notify unsealed status", "error", err)
15231523
}
15241524
}
1525+
if err := c.serviceRegistration.NotifyInitializedStateChange(true); err != nil {
1526+
if c.logger.IsWarn() {
1527+
c.logger.Warn("failed to notify initialized status", "error", err)
1528+
}
1529+
}
15251530
}
15261531
return true, nil
15271532
}

0 commit comments

Comments
 (0)