mirror of
https://github.com/kemko/nomad.git
synced 2026-01-06 18:35:44 +03:00
The allocrunner's `identity_hook` implements the interface for TaskStop, but this interface is only ever called for task-level hooks. This results in a leaked goroutine that tries to periodically renew WIs until the client shuts down gracefully. Add an implementation for the allocrunner's `PreKill` and `Destroy` hooks, so that whenever an allocation is stopped or garbage collected we stop renewing its Workload Identities. This also requires making the `Shutdown` method of `WIDMgr` safe to call multiple times.
93 lines
2.4 KiB
Go
93 lines
2.4 KiB
Go
// Copyright (c) HashiCorp, Inc.
|
|
// SPDX-License-Identifier: BUSL-1.1
|
|
|
|
package allocrunner
|
|
|
|
import (
|
|
"testing"
|
|
"time"
|
|
|
|
"github.com/hashicorp/nomad/ci"
|
|
"github.com/hashicorp/nomad/client/allocrunner/interfaces"
|
|
cstate "github.com/hashicorp/nomad/client/state"
|
|
"github.com/hashicorp/nomad/client/widmgr"
|
|
"github.com/hashicorp/nomad/helper/testlog"
|
|
"github.com/hashicorp/nomad/nomad/mock"
|
|
"github.com/hashicorp/nomad/nomad/structs"
|
|
"github.com/shoenig/test/must"
|
|
)
|
|
|
|
// statically assert network hook implements the expected interfaces
|
|
var _ interfaces.RunnerPrerunHook = (*identityHook)(nil)
|
|
var _ interfaces.ShutdownHook = (*identityHook)(nil)
|
|
var _ interfaces.RunnerPreKillHook = (*identityHook)(nil)
|
|
var _ interfaces.RunnerDestroyHook = (*identityHook)(nil)
|
|
|
|
func TestIdentityHook_Prerun(t *testing.T) {
|
|
ci.Parallel(t)
|
|
|
|
ttl := 30 * time.Second
|
|
|
|
wid := &structs.WorkloadIdentity{
|
|
Name: "testing",
|
|
Audience: []string{"consul.io"},
|
|
Env: true,
|
|
File: true,
|
|
TTL: ttl,
|
|
}
|
|
|
|
alloc := mock.Alloc()
|
|
task := alloc.LookupTask("web")
|
|
task.Identity = wid
|
|
task.Identities = []*structs.WorkloadIdentity{wid}
|
|
|
|
allocrunner, stopAR := TestAllocRunnerFromAlloc(t, alloc)
|
|
defer stopAR()
|
|
|
|
logger := testlog.HCLogger(t)
|
|
db := cstate.NewMemDB(logger)
|
|
|
|
// setup mock signer and WIDMgr
|
|
mockSigner := widmgr.NewMockWIDSigner(task.Identities)
|
|
mockWIDMgr := widmgr.NewWIDMgr(mockSigner, alloc, db, logger)
|
|
allocrunner.widmgr = mockWIDMgr
|
|
allocrunner.widsigner = mockSigner
|
|
|
|
// do the initial signing
|
|
_, err := mockSigner.SignIdentities(1, []*structs.WorkloadIdentityRequest{
|
|
{
|
|
AllocID: alloc.ID,
|
|
WIHandle: structs.WIHandle{
|
|
WorkloadIdentifier: task.Name,
|
|
IdentityName: task.Identities[0].Name,
|
|
},
|
|
},
|
|
})
|
|
must.NoError(t, err)
|
|
|
|
start := time.Now()
|
|
hook := newIdentityHook(logger, mockWIDMgr)
|
|
must.Eq(t, hook.Name(), "identity")
|
|
must.NoError(t, hook.Prerun())
|
|
|
|
time.Sleep(time.Second) // give goroutines a moment to run
|
|
sid, err := hook.widmgr.Get(structs.WIHandle{
|
|
WorkloadIdentifier: task.Name,
|
|
IdentityName: task.Identities[0].Name},
|
|
)
|
|
must.Nil(t, err)
|
|
must.Eq(t, sid.IdentityName, task.Identity.Name)
|
|
must.NotEq(t, sid.JWT, "")
|
|
|
|
// pad expiry time with a second to be safe
|
|
must.Between(t,
|
|
start.Add(ttl).Add(-1*time.Second).Unix(),
|
|
sid.Expiration.Unix(),
|
|
start.Add(ttl).Add(1*time.Second).Unix(),
|
|
)
|
|
|
|
// shutting down twice must not panic
|
|
hook.PreKill()
|
|
hook.PreKill()
|
|
}
|