Files
nomad/client/allocrunner/identity_hook_test.go
Tim Gross 928a82a184 WID manager: save and restore signed WIs from client state DB (#18661)
When clients are restarted and the identity hook runs when we restore
allocations, the running allocations are likely to have already-signed Workload
Identities that are unexpired. Save these to the client's local state DB so that
we can avoid a thundering herd of RPCs during client restart. When we restore,
we'll check if there's at least one expired signed WI before making any initial
signing request.

Included:
* Renames `getIdentities` to `getInitialIdentities` to make the workflow more clear.
* Renames the existing `widmgr_test.go` file of integration tests, which is in its
  own package to avoid circular imports to `widmgr_int_test.go`
2023-10-09 09:16:23 -04:00

91 lines
2.3 KiB
Go

// Copyright (c) HashiCorp, Inc.
// SPDX-License-Identifier: BUSL-1.1
package allocrunner
import (
"context"
"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.TaskStopHook = (*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(),
)
must.NoError(t, hook.Stop(context.Background(), nil, nil))
}