constellation/bootstrapper/internal/nodelock/nodelock.go
2023-07-04 16:26:37 +02:00

59 lines
1.6 KiB
Go

/*
Copyright (c) Edgeless Systems GmbH
SPDX-License-Identifier: AGPL-3.0-only
*/
// Package nodelock handles locking operations on the node.
package nodelock
import (
"io"
"sync/atomic"
"github.com/edgelesssys/constellation/v2/internal/attestation/initialize"
"github.com/edgelesssys/constellation/v2/internal/attestation/vtpm"
)
// Lock locks the node once there the join or the init is at a point
// where there is no turning back and the other operation does not need
// to continue.
//
// This can be viewed as a state machine with two states: unlocked and locked.
// There is no way to unlock, so the state changes only once from unlock to
// locked.
type Lock struct {
tpm vtpm.TPMOpenFunc
marker markAsBootstrapped
inner atomic.Bool
}
// New creates a new NodeLock, which is unlocked.
func New(tpm vtpm.TPMOpenFunc) *Lock {
return &Lock{
tpm: tpm,
marker: initialize.MarkNodeAsBootstrapped,
}
}
// TryLockOnce tries to lock the node. If the node is already locked, it
// returns false. If the node is unlocked, it locks it and returns true.
func (l *Lock) TryLockOnce(clusterID []byte) (bool, error) {
// CompareAndSwap first checks if the node is currently unlocked.
// If it was already locked, it returns early.
// If it is unlocked, it swaps the value to locked atomically and continues.
if !l.inner.CompareAndSwap(unlocked, locked) {
return false, nil
}
return true, l.marker(l.tpm, clusterID)
}
// markAsBootstrapped is a function that marks the node as bootstrapped in the TPM.
type markAsBootstrapped func(openDevice func() (io.ReadWriteCloser, error), clusterID []byte) error
const (
unlocked = false
locked = true
)