From cee7041b600cb83dd32239e4f2d46e31ad0229ab Mon Sep 17 00:00:00 2001 From: Artsiom Koltun Date: Tue, 18 Jul 2023 09:15:36 +0200 Subject: [PATCH] feat(backend): psk is written to temporary file for spdk --- pkg/backend/backend.go | 12 +++++ pkg/backend/nvme_path.go | 31 +++++++++++- pkg/backend/nvme_path_test.go | 92 +++++++++++++++++++++++++++++++++++ 3 files changed, 133 insertions(+), 2 deletions(-) diff --git a/pkg/backend/backend.go b/pkg/backend/backend.go index 9c3a06f7..3bfeab55 100644 --- a/pkg/backend/backend.go +++ b/pkg/backend/backend.go @@ -6,6 +6,8 @@ package backend import ( + "os" + "github.com/opiproject/gospdk/spdk" pb "github.com/opiproject/opi-api/storage/v1alpha1/gen/go" ) @@ -31,6 +33,12 @@ type Server struct { rpc spdk.JSONRPC Volumes VolumeParameters Pagination map[string]int + psk psk +} + +type psk struct { + createTempFile func(dir, pattern string) (*os.File, error) + writeKey func(keyFile string, key []byte, perm os.FileMode) error } // NewServer creates initialized instance of BackEnd server communicating @@ -45,5 +53,9 @@ func NewServer(jsonRPC spdk.JSONRPC) *Server { NvmePaths: make(map[string]*pb.NvmePath), }, Pagination: make(map[string]int), + psk: psk{ + createTempFile: os.CreateTemp, + writeKey: os.WriteFile, + }, } } diff --git a/pkg/backend/nvme_path.go b/pkg/backend/nvme_path.go index b5395041..de10c59f 100644 --- a/pkg/backend/nvme_path.go +++ b/pkg/backend/nvme_path.go @@ -9,6 +9,7 @@ import ( "context" "fmt" "log" + "os" "path" "sort" "strings" @@ -74,8 +75,16 @@ func (s *Server) CreateNvmePath(_ context.Context, in *pb.CreateNvmePathRequest) psk := "" if len(controller.Psk) > 0 { log.Printf("Notice, TLS is used to establish connection: to %v", in.NvmePath) - // TODO: write controller.Psk to file /tmp/opikey.txt - psk = "/tmp/opikey.txt" + keyFile, err := s.keyToTemporaryFile(controller.Psk) + if err != nil { + return nil, err + } + defer func() { + err := os.Remove(keyFile) + log.Printf("Cleanup key file %v: %v", keyFile, err) + }() + + psk = keyFile } params := spdk.BdevNvmeAttachControllerParams{ Name: path.Base(controller.Name), @@ -330,3 +339,21 @@ func (s *Server) numberOfPathsForController(controllerName string) int { } return numberOfPaths } + +func (s *Server) keyToTemporaryFile(pskKey []byte) (string, error) { + keyFile, err := s.psk.createTempFile("", "opikey") + if err != nil { + log.Printf("error: failed to create file for key: %v", err) + return "", status.Error(codes.Internal, "failed to handle key") + } + + const keyPermissions = 0600 + if err := s.psk.writeKey(keyFile.Name(), pskKey, keyPermissions); err != nil { + log.Printf("error: failed to write to key file: %v", err) + removeErr := os.Remove(keyFile.Name()) + log.Printf("Delete key file after key write: %v", removeErr) + return "", status.Error(codes.Internal, "failed to handle key") + } + + return keyFile.Name(), nil +} diff --git a/pkg/backend/nvme_path_test.go b/pkg/backend/nvme_path_test.go index 046de8c6..20136734 100644 --- a/pkg/backend/nvme_path_test.go +++ b/pkg/backend/nvme_path_test.go @@ -6,7 +6,10 @@ package backend import ( + "errors" "fmt" + "os" + "path/filepath" "reflect" "testing" @@ -144,6 +147,95 @@ func TestBackEnd_CreateNvmePath(t *testing.T) { } }) } + pskTests := map[string]struct { + createErr error + writeErr error + spdk []string + errCode codes.Code + errMsg string + }{ + "tmp key file creation failed": { + createErr: errors.New("stub error"), + writeErr: nil, + spdk: []string{}, + errCode: codes.Internal, + errMsg: "failed to handle key", + }, + "tmp key file write failed": { + createErr: nil, + writeErr: errors.New("stub error"), + spdk: []string{}, + errCode: codes.Internal, + errMsg: "failed to handle key", + }, + "tmp key file removed after successful call": { + createErr: nil, + writeErr: nil, + spdk: []string{`{"id":%d,"error":{"code":0,"message":""},"result":["mytest"]}`}, + errCode: codes.OK, + errMsg: "", + }, + } + + for name, tt := range pskTests { + t.Run(name, func(t *testing.T) { + testEnv := createTestEnvironment(tt.spdk) + defer testEnv.Close() + + const expectedKey = "NVMeTLSkey-1:01:MDAxMTIyMzM0NDU1NjY3Nzg4OTlhYWJiY2NkZGVlZmZwJEiQ:" + testEnv.opiSpdkServer.Volumes.NvmeControllers[testNvmeCtrlName] = + &pb.NvmeRemoteController{ + Hdgst: false, Ddgst: false, Multipath: pb.NvmeMultipath_NVME_MULTIPATH_MULTIPATH, + Psk: []byte(expectedKey), + } + + createdKeyFile := "" + origCreateTempFile := testEnv.opiSpdkServer.psk.createTempFile + testEnv.opiSpdkServer.psk.createTempFile = + func(dir, pattern string) (*os.File, error) { + if tt.createErr == nil { + keyFile, _ := origCreateTempFile(t.TempDir(), pattern) + createdKeyFile = keyFile.Name() + return keyFile, nil + } + return nil, tt.createErr + } + origWriteKey := testEnv.opiSpdkServer.psk.writeKey + testEnv.opiSpdkServer.psk.writeKey = + func(keyFile string, key []byte, perm os.FileMode) error { + if createdKeyFile != keyFile { + t.Errorf("Expected key is written to: %v, instead: %v", createdKeyFile, keyFile) + } + if _, err := os.Stat(createdKeyFile); err != nil { + t.Errorf("Expected temporary key file %v exists", createdKeyFile) + } + _ = origWriteKey(keyFile, key, perm) + written, _ := os.ReadFile(filepath.Clean(keyFile)) + if string(written) != expectedKey { + t.Errorf("Expected psk key: %v is written, received: %v", expectedKey, key) + } + return tt.writeErr + } + + request := &pb.CreateNvmePathRequest{NvmePath: &testNvmePath, NvmePathId: "nvmetcppath0"} + _, err := testEnv.client.CreateNvmePath(testEnv.ctx, request) + + if er, ok := status.FromError(err); ok { + if er.Code() != tt.errCode { + t.Error("error code: expected", tt.errCode, "received", er.Code()) + } + if er.Message() != tt.errMsg { + t.Error("error message: expected", tt.errMsg, "received", er.Message()) + } + } else { + t.Error("expected grpc error status") + } + + if _, err := os.Stat(createdKeyFile); err == nil { + t.Errorf("Expect temporary key file %v is removed", createdKeyFile) + } + }) + } } func TestBackEnd_DeleteNvmePath(t *testing.T) {