...

Source file src/edge-infra.dev/pkg/sds/ien/k8s/controllers/nodeagent/plugins/clustersecrets/grub/grub_test.go

Documentation: edge-infra.dev/pkg/sds/ien/k8s/controllers/nodeagent/plugins/clustersecrets/grub

     1  package grub
     2  
     3  import (
     4  	"context"
     5  	_ "embed"
     6  	"os"
     7  	"path/filepath"
     8  	"strings"
     9  	"testing"
    10  
    11  	"github.com/stretchr/testify/require"
    12  	"gotest.tools/v3/fs"
    13  	"sigs.k8s.io/controller-runtime/pkg/client/fake"
    14  
    15  	corev1 "k8s.io/api/core/v1"
    16  
    17  	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
    18  
    19  	kruntime "k8s.io/apimachinery/pkg/runtime"
    20  	utilruntime "k8s.io/apimachinery/pkg/util/runtime"
    21  	clientgoscheme "k8s.io/client-go/kubernetes/scheme"
    22  
    23  	grubsecret "edge-infra.dev/pkg/sds/clustersecrets/grub"
    24  	grubfs "edge-infra.dev/pkg/sds/clustersecrets/grub/filesystem"
    25  
    26  	v1ien "edge-infra.dev/pkg/sds/ien/k8s/apis/v1"
    27  
    28  	"edge-infra.dev/pkg/sds"
    29  	cc "edge-infra.dev/pkg/sds/clustersecrets/common"
    30  	"edge-infra.dev/pkg/sds/ien/k8s/controllers/nodeagent/config"
    31  )
    32  
    33  var p = Plugin{}
    34  
    35  //go:embed testdata/grub.cfg
    36  var contents []byte
    37  
    38  type testCase struct {
    39  	secret *corev1.Secret
    40  }
    41  
    42  var tests = []testCase{
    43  	{
    44  		toSecret(
    45  			"b46899129f0378151909c9a5120112b7",
    46  			"34747062456d77436165724365447537",
    47  			"eH8DAQEGU2VjcmV0Af+AAAEIAQlQcmluY2lwYWwBDAABCkl0ZXJhdGlvbnMBBAABBFNhbHQBDAABBEhhc2gBDAABCEZ1bmN0aW9uAQwAAQhIYXNoVHlwZQEMAAEKR2VuZXJhdGlvbgEEAAEIUm90YXRpb24BAgAAAGj/gAEIcmVjb3ZlcnkB/Ql14AEgMzQ3NDcwNjI0NTZkNzc0MzYxNjU3MjQzNjU0NDc1MzcBIGI0Njg5OTEyOWYwMzc4MTUxOTA5YzlhNTEyMDExMmI3AQZwYmtkZjIBBnNoYTUxMgECAA==",
    48  		),
    49  	},
    50  }
    51  
    52  var nodeHostname = "node-1"
    53  
    54  func TestMain(_ *testing.M) {
    55  	mount = false
    56  	os.Setenv("HOSTNAME", nodeHostname)
    57  }
    58  
    59  func TestGrubLegacyApply(t *testing.T) {
    60  	grubCfgPath, cleanup := setupFilesystem(t, false)
    61  	defer cleanup()
    62  
    63  	for _, test := range tests {
    64  		c := fake.NewClientBuilder().WithScheme(createScheme()).WithObjects(test.secret).Build()
    65  
    66  		ctx := context.Background()
    67  		_, err := p.Reconcile(ctx, &v1ien.IENode{}, config.Data{Client: c})
    68  		require.NoError(t, err)
    69  
    70  		secret, err := grubsecret.FromSecret(test.secret)
    71  		require.NoError(t, err)
    72  
    73  		actualContents, err := os.ReadFile(grubCfgPath)
    74  		require.NoError(t, err)
    75  
    76  		requireGrubUserConfigured(t, secret, actualContents)
    77  	}
    78  }
    79  
    80  func TestGrubEfiApply(t *testing.T) {
    81  	grubCfgPath, cleanup := setupFilesystem(t, true)
    82  	defer cleanup()
    83  
    84  	for _, test := range tests {
    85  		c := fake.NewClientBuilder().WithScheme(createScheme()).WithObjects(test.secret).Build()
    86  
    87  		ctx := context.Background()
    88  		_, err := p.Reconcile(ctx, &v1ien.IENode{}, config.Data{Client: c})
    89  		require.NoError(t, err)
    90  
    91  		secret, err := grubsecret.FromSecret(test.secret)
    92  		require.NoError(t, err)
    93  
    94  		actualContents, err := os.ReadFile(grubCfgPath)
    95  		require.NoError(t, err)
    96  
    97  		requireGrubUserConfigured(t, secret, actualContents)
    98  	}
    99  }
   100  
   101  func setupFilesystem(t *testing.T, isEfi bool) (string, func()) {
   102  	rootMountPath := "host-boot"
   103  	rootDir := fs.NewDir(t, rootMountPath)
   104  	cleanupFunc := func() {
   105  		rootDir.Remove()
   106  	}
   107  	rootMountPath = rootDir.Path()
   108  
   109  	subPath := grubfs.LegacyPath
   110  	if isEfi {
   111  		subPath = grubfs.EfiPath
   112  	}
   113  	err := os.MkdirAll(filepath.Join(rootMountPath, subPath), 0744) //nolint:gosec requires read/write for non-root user
   114  	require.NoError(t, err)
   115  
   116  	grubCfgPath := filepath.Join(rootMountPath, subPath, grubfs.ConfigFilename)
   117  
   118  	// write the current grub config file
   119  	err = os.WriteFile(grubCfgPath, contents, 0644)
   120  	require.NoError(t, err)
   121  
   122  	return grubCfgPath, cleanupFunc
   123  }
   124  
   125  func toSecret(hash, salt, serialised string) *corev1.Secret {
   126  	return &corev1.Secret{
   127  		ObjectMeta: metav1.ObjectMeta{
   128  			Name:      grubsecret.HashedSecretName,
   129  			Namespace: sds.Namespace,
   130  		},
   131  		Data: map[string][]byte{
   132  			grubsecret.SecretKey: []byte(serialised),
   133  			cc.PrincipalKey:      []byte(grubsecret.Username),
   134  			cc.HashFunctionKey:   []byte("pbkdf2"),
   135  			cc.HashTypeKey:       []byte("sha512"),
   136  			cc.SaltKey:           []byte(salt),
   137  			cc.HashKey:           []byte(hash),
   138  			cc.HashIterationsKey: []byte("310000"),
   139  			cc.SecretVersionKey:  []byte("2"),
   140  		},
   141  	}
   142  }
   143  
   144  func requireGrubUserConfigured(t *testing.T, secret cc.Secret, cfgContents []byte) {
   145  	expectedEntry := secret.String()
   146  
   147  	entrySplit := strings.Split(expectedEntry, "\n")
   148  	expectedUsr := entrySplit[0]
   149  	expectedPwd := entrySplit[1]
   150  	expectedExportUsr := entrySplit[2]
   151  
   152  	usrFound, pwdFound, exportUsrFound := false, false, false
   153  	for _, line := range strings.Split(string(cfgContents), "\n") {
   154  		switch {
   155  		case strings.Contains(line, "set superusers="):
   156  			usrFound = true
   157  			require.Equal(t, line, expectedUsr)
   158  		case strings.Contains(line, "password_pbkdf2"):
   159  			pwdFound = true
   160  			require.Equal(t, line, expectedPwd)
   161  		case strings.Contains(line, "export superusers"):
   162  			exportUsrFound = true
   163  			require.Equal(t, line, expectedExportUsr)
   164  		}
   165  	}
   166  	require.True(t, usrFound)
   167  	require.True(t, pwdFound)
   168  	require.True(t, exportUsrFound)
   169  }
   170  
   171  func createScheme() *kruntime.Scheme {
   172  	scheme := kruntime.NewScheme()
   173  	utilruntime.Must(clientgoscheme.AddToScheme(scheme))
   174  	utilruntime.Must(v1ien.AddToScheme(scheme))
   175  	return scheme
   176  }
   177  

View as plain text