Skip to content

Commit

Permalink
internal/mount: (pre-)merge mounting code
Browse files Browse the repository at this point in the history
  • Loading branch information
jmxnzo committed Jan 21, 2025
1 parent ab984fb commit d9ce879
Show file tree
Hide file tree
Showing 3 changed files with 87 additions and 27 deletions.
3 changes: 2 additions & 1 deletion coordinator/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"github.com/edgelesssys/contrast/internal/grpc/atlscredentials"
"github.com/edgelesssys/contrast/internal/logger"
"github.com/edgelesssys/contrast/internal/meshapi"
"github.com/edgelesssys/contrast/internal/mount"
"github.com/edgelesssys/contrast/internal/userapi"
grpcprometheus "github.com/grpc-ecosystem/go-grpc-middleware/providers/prometheus"
"github.com/prometheus/client_golang/prometheus"
Expand Down Expand Up @@ -56,7 +57,7 @@ func run() (retErr error) {

logger.Info("Coordinator started")

if err := setupMount(context.Background(), logger); err != nil {
if err := mount.SetupMount(context.Background(), logger, "/dev/csi0", "/mnt/state"); err != nil {
return fmt.Errorf("setting up mount: %w", err)
}

Expand Down
58 changes: 32 additions & 26 deletions coordinator/mount.go → internal/mount/mount.go
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Copyright 2024 Edgeless Systems GmbH
// SPDX-License-Identifier: AGPL-3.0-only

package main
package mount

import (
"context"
Expand All @@ -14,37 +14,33 @@ import (
"strings"
)

const (
csiDevicePath = "/dev/csi0"
stateDiskMountPoint = "/mnt/state"
)

// setupMount mounts the csi device to the state disk mount point.
func setupMount(ctx context.Context, logger *slog.Logger) error {
blk, err := blkid(ctx, csiDevicePath)
// SetupMount formats the csi device to ext4 and mounts it to the provided mount point.
func SetupMount(ctx context.Context, logger *slog.Logger, devPath, mountPoint string) error {
blk, err := Blkid(ctx, devPath)
if errors.Is(err, errNotIdentified) {
logger.Info("csi device not identified, assuming first start, formatting")
if err := mkfsExt4(ctx, csiDevicePath); err != nil {
logger.Info("csi device not identified, assuming first start, formatting", "device", devPath)
if err := mkfsExt4(ctx, devPath); err != nil {
return err
}
} else if err != nil {
return err
} else if blk.Type != "ext4" {
logger.Info("csi device is not ext4, assuming first start, formatting")
if err := mkfsExt4(ctx, csiDevicePath); err != nil {
logger.Info("csi device is not ext4, assuming first start, formatting", "device", devPath)
if err := mkfsExt4(ctx, devPath); err != nil {
return err
}
}

if err := mount(ctx, csiDevicePath, stateDiskMountPoint); err != nil {
if err := mount(ctx, devPath, mountPoint); err != nil {
return err
}
logger.Info("csi device mounted to state disk mount point", "dev", csiDevicePath, "mountPoint", stateDiskMountPoint)
logger.Info("csi device mounted to state disk mount point", "dev", devPath, "mountPoint", mountPoint)

return nil
}

type blk struct {
// Blk holds the main attributes of a block device used by blkid system executable command.
type Blk struct {
DevName string
UUID string
BlockSize int
Expand All @@ -53,25 +49,32 @@ type blk struct {

var errNotIdentified = errors.New("blkid did not identify the device")

func blkid(ctx context.Context, devName string) (*blk, error) {
cmd := exec.CommandContext(ctx, "blkid", "-o", "export", devName)
// Blkid creates a Blk struct of the device located at the provided devPath.
func Blkid(ctx context.Context, devPath string) (*Blk, error) {
cmd := exec.CommandContext(ctx, "blkid", "-o", "export", devPath)
out, err := cmd.CombinedOutput()
var exitErr *exec.ExitError
if errors.As(err, &exitErr) && exitErr.ExitCode() == 2 {
// See man page, sec return code.
// See man page, sec EXIT STATUS.
return nil, errNotIdentified
} else if err != nil {
return nil, fmt.Errorf("blkid: %w, output: %q", err, out)
}
return parseBlkidCommand(out)
}

// parseBlkidCommand parses the output of the blkid system command to rerpresentative Blkid struct.
func parseBlkidCommand(out []byte) (*Blk, error) {
lines := strings.Split(string(out), "\n")
b := &blk{}
b := &Blk{}

for _, line := range lines {
if line == "" {
continue
}
key, value, ok := strings.Cut(line, "=")
if !ok {
return nil, fmt.Errorf("parsing blkid output line %q: %w", line, err)
return nil, fmt.Errorf("parsing blkid output line %q", line)
}
switch key {
case "DEVNAME":
Expand All @@ -81,29 +84,32 @@ func blkid(ctx context.Context, devName string) (*blk, error) {
case "TYPE":
b.Type = value
case "BLOCK_SIZE":
b.BlockSize, err = strconv.Atoi(value)
intValue, err := strconv.Atoi(value)
if err != nil {
return nil, fmt.Errorf("parsing BLOCK_SIZE of blkid output %q: %w", value, err)
}
b.BlockSize = intValue
}
}
return b, nil
}

func mkfsExt4(ctx context.Context, devName string) error {
cmd := exec.CommandContext(ctx, "mkfs.ext4", devName)
// mkfsExt4 wraps the mkfs.ext4 command and creates an ext4 file system on the device.
func mkfsExt4(ctx context.Context, devPath string) error {
cmd := exec.CommandContext(ctx, "mkfs.ext4", devPath)
out, err := cmd.CombinedOutput()
if err != nil {
return fmt.Errorf("mkfs.ext4: %w, output: %q", err, out)
}
return nil
}

func mount(ctx context.Context, devName, mountPoint string) error {
// mount wraps the mount command and attaches the device to the specified mountPoint.
func mount(ctx context.Context, devPath, mountPoint string) error {
if err := os.MkdirAll(mountPoint, 0o755); err != nil {
return fmt.Errorf("mkdir: %w", err)
}
cmd := exec.CommandContext(ctx, "mount", devName, mountPoint)
cmd := exec.CommandContext(ctx, "mount", devPath, mountPoint)
out, err := cmd.CombinedOutput()
if err != nil {
return fmt.Errorf("mount: %w, output: %q", err, out)
Expand Down
53 changes: 53 additions & 0 deletions internal/mount/mount_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
// Copyright 2024 Edgeless Systems GmbH
// SPDX-License-Identifier: AGPL-3.0-only

package mount

import (
"fmt"
"testing"

"github.com/stretchr/testify/require"
)

func TestParseBlkidCommand(t *testing.T) {
blk := &Blk{
DevName: "/dev/nvme1n1p1",
UUID: "f3e74cbb-4b6c-442b-8cd1-d12e3fc7adcd",
BlockSize: 1,
Type: "ntfs",
}

blocks := []struct {
outFormatString string
Error bool
}{
{
outFormatString: "DEVNAME=%s\nUUID=%s\nBLOCK_SIZE=%d\nTYPE=%s\n",
Error: false,
},
{
outFormatString: "No-Equal-Sign\n",
Error: true,
},
{
outFormatString: "BLOCK_SIZE=isString\n",
Error: true,
},
}

for _, block := range blocks {
parsedBlock, err := parseBlkidCommand(func(formatString string, blk *Blk) []byte {
return []byte(fmt.Sprintf(formatString,
blk.DevName, blk.UUID, blk.BlockSize, blk.Type))
}(block.outFormatString, blk))

if block.Error {
require.Error(t, err)
} else {
require.NoError(t, err)
require.Equal(t, blk, parsedBlock)

}
}
}

0 comments on commit d9ce879

Please sign in to comment.