2017-03-02 01:18:02 +00:00
|
|
|
package allocdir
|
|
|
|
|
|
|
|
import (
|
|
|
|
"bufio"
|
|
|
|
"fmt"
|
|
|
|
"io"
|
|
|
|
"os"
|
|
|
|
"path/filepath"
|
|
|
|
"strings"
|
|
|
|
"testing"
|
|
|
|
|
2022-03-15 12:42:43 +00:00
|
|
|
"github.com/hashicorp/nomad/ci"
|
2017-03-02 01:18:02 +00:00
|
|
|
"golang.org/x/sys/unix"
|
|
|
|
)
|
|
|
|
|
|
|
|
var notFoundErr = fmt.Errorf("not found")
|
|
|
|
|
|
|
|
func isMount(path string) error {
|
|
|
|
file, err := os.Open("/proc/self/mounts")
|
|
|
|
if err != nil {
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
defer file.Close()
|
|
|
|
reader := bufio.NewReaderSize(file, 64*1024)
|
|
|
|
const max = 100000
|
|
|
|
for i := 0; i < max; i++ {
|
|
|
|
line, err := reader.ReadString('\n')
|
|
|
|
if err != nil {
|
|
|
|
if err == io.EOF {
|
|
|
|
return notFoundErr
|
|
|
|
}
|
|
|
|
return err
|
|
|
|
}
|
|
|
|
parts := strings.SplitN(line, " ", 3)
|
|
|
|
if len(parts) != 3 {
|
|
|
|
return fmt.Errorf("unexpected line: %q", line)
|
|
|
|
}
|
|
|
|
if parts[1] == path {
|
|
|
|
// Found it! Make sure it's a tmpfs
|
|
|
|
if parts[0] != "tmpfs" {
|
|
|
|
return fmt.Errorf("unexpected fs: %q", parts[1])
|
|
|
|
}
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
return fmt.Errorf("exceeded max mount entries (%d)", max)
|
|
|
|
}
|
|
|
|
|
|
|
|
// TestLinuxRootSecretDir asserts secret dir creation and removal are
|
|
|
|
// idempotent.
|
|
|
|
func TestLinuxRootSecretDir(t *testing.T) {
|
2022-03-15 12:42:43 +00:00
|
|
|
ci.Parallel(t)
|
2017-03-02 01:18:02 +00:00
|
|
|
if unix.Geteuid() != 0 {
|
|
|
|
t.Skip("Must be run as root")
|
|
|
|
}
|
2022-03-15 12:42:43 +00:00
|
|
|
|
2022-05-12 15:42:40 +00:00
|
|
|
secretsDir := filepath.Join(t.TempDir(), TaskSecrets)
|
2017-03-02 01:18:02 +00:00
|
|
|
|
2018-03-12 18:26:37 +00:00
|
|
|
// removing a nonexistent secrets dir should NOT error
|
2017-03-02 01:18:02 +00:00
|
|
|
if err := removeSecretDir(secretsDir); err != nil {
|
2018-03-12 18:26:37 +00:00
|
|
|
t.Fatalf("error removing nonexistent secrets dir %q: %v", secretsDir, err)
|
2017-03-02 01:18:02 +00:00
|
|
|
}
|
2018-03-11 18:14:50 +00:00
|
|
|
// run twice as it should be idempotent
|
2017-03-02 01:18:02 +00:00
|
|
|
if err := removeSecretDir(secretsDir); err != nil {
|
2018-03-12 18:26:37 +00:00
|
|
|
t.Fatalf("error removing nonexistent secrets dir %q: %v", secretsDir, err)
|
2017-03-02 01:18:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// creating a secrets dir should work
|
|
|
|
if err := createSecretDir(secretsDir); err != nil {
|
|
|
|
t.Fatalf("error creating secrets dir %q: %v", secretsDir, err)
|
|
|
|
}
|
|
|
|
// creating it again should be a noop (NO error)
|
|
|
|
if err := createSecretDir(secretsDir); err != nil {
|
|
|
|
t.Fatalf("error creating secrets dir %q: %v", secretsDir, err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// ensure it exists and is a directory
|
|
|
|
fi, err := os.Lstat(secretsDir)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("error stat'ing secrets dir %q: %v", secretsDir, err)
|
|
|
|
}
|
|
|
|
if !fi.IsDir() {
|
|
|
|
t.Fatalf("secrets dir %q is not a directory and should be", secretsDir)
|
|
|
|
}
|
|
|
|
if err := isMount(secretsDir); err != nil {
|
2017-03-03 05:03:05 +00:00
|
|
|
t.Fatalf("secrets dir %q is not a mount: %v", secretsDir, err)
|
2017-03-02 01:18:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// now remove it
|
|
|
|
if err := removeSecretDir(secretsDir); err != nil {
|
|
|
|
t.Fatalf("error removing secrets dir %q: %v", secretsDir, err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// make sure it's gone
|
|
|
|
if err := isMount(secretsDir); err != notFoundErr {
|
|
|
|
t.Fatalf("error ensuring secrets dir %q isn't mounted: %v", secretsDir, err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// removing again should be a noop
|
|
|
|
if err := removeSecretDir(secretsDir); err != nil {
|
2018-03-12 18:26:37 +00:00
|
|
|
t.Fatalf("error removing nonexistent secrets dir %q: %v", secretsDir, err)
|
2017-03-02 01:18:02 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// TestLinuxUnprivilegedSecretDir asserts secret dir creation and removal are
|
|
|
|
// idempotent.
|
|
|
|
func TestLinuxUnprivilegedSecretDir(t *testing.T) {
|
2022-03-15 12:42:43 +00:00
|
|
|
ci.Parallel(t)
|
2017-03-02 01:18:02 +00:00
|
|
|
if unix.Geteuid() == 0 {
|
|
|
|
t.Skip("Must not be run as root")
|
|
|
|
}
|
2022-03-15 12:42:43 +00:00
|
|
|
|
2022-05-12 15:42:40 +00:00
|
|
|
secretsDir := filepath.Join(t.TempDir(), TaskSecrets)
|
2017-03-02 01:18:02 +00:00
|
|
|
|
2018-03-12 18:26:37 +00:00
|
|
|
// removing a nonexistent secrets dir should NOT error
|
2017-03-02 01:18:02 +00:00
|
|
|
if err := removeSecretDir(secretsDir); err != nil {
|
2018-03-12 18:26:37 +00:00
|
|
|
t.Fatalf("error removing nonexistent secrets dir %q: %v", secretsDir, err)
|
2017-03-02 01:18:02 +00:00
|
|
|
}
|
2018-03-11 18:14:50 +00:00
|
|
|
// run twice as it should be idempotent
|
2017-03-02 01:18:02 +00:00
|
|
|
if err := removeSecretDir(secretsDir); err != nil {
|
2018-03-12 18:26:37 +00:00
|
|
|
t.Fatalf("error removing nonexistent secrets dir %q: %v", secretsDir, err)
|
2017-03-02 01:18:02 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
// creating a secrets dir should work
|
|
|
|
if err := createSecretDir(secretsDir); err != nil {
|
|
|
|
t.Fatalf("error creating secrets dir %q: %v", secretsDir, err)
|
|
|
|
}
|
|
|
|
// creating it again should be a noop (NO error)
|
|
|
|
if err := createSecretDir(secretsDir); err != nil {
|
|
|
|
t.Fatalf("error creating secrets dir %q: %v", secretsDir, err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// ensure it exists and is a directory
|
|
|
|
fi, err := os.Lstat(secretsDir)
|
|
|
|
if err != nil {
|
|
|
|
t.Fatalf("error stat'ing secrets dir %q: %v", secretsDir, err)
|
|
|
|
}
|
|
|
|
if !fi.IsDir() {
|
|
|
|
t.Fatalf("secrets dir %q is not a directory and should be", secretsDir)
|
|
|
|
}
|
|
|
|
if err := isMount(secretsDir); err != notFoundErr {
|
|
|
|
t.Fatalf("error ensuring secrets dir %q isn't mounted: %v", secretsDir, err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// now remove it
|
|
|
|
if err := removeSecretDir(secretsDir); err != nil {
|
|
|
|
t.Fatalf("error removing secrets dir %q: %v", secretsDir, err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// make sure it's gone
|
|
|
|
if _, err := os.Lstat(secretsDir); err == nil {
|
|
|
|
t.Fatalf("expected secrets dir %q to be gone but it was found", secretsDir)
|
|
|
|
}
|
|
|
|
|
|
|
|
// removing again should be a noop
|
|
|
|
if err := removeSecretDir(secretsDir); err != nil {
|
2018-03-12 18:26:37 +00:00
|
|
|
t.Fatalf("error removing nonexistent secrets dir %q: %v", secretsDir, err)
|
2017-03-02 01:18:02 +00:00
|
|
|
}
|
|
|
|
}
|