diff --git a/README.md b/README.md index bbc782094bcbf2a1b37c599dfe52446fa596209e..39566e9beebabbf84b783d6e155d7999a8cb3fa5 100644 --- a/README.md +++ b/README.md @@ -61,16 +61,18 @@ root@#:/home/test/ascend-docker-runtime/output# ll ``` # 组件安装 -请参考[《MindX DL用户指南》--Ascend Docker Runtime用户指南](https://www.hiascend.com/document/detail/zh/mindx-dl/60rc1/clusterscheduling/dockerruntimeug/dlruntime_ug_005.html)中“安装Ascend Docker Runtime”章节进行。 +请参考[《MindX DL集群调度安装指南》--安装部署](https://www.hiascend.com/document/detail/zh/mindx-dl/60rc2/clusterscheduling/clusterschedulingig/clusterschedulingig/dlug_installation_012.html)中“Ascend Docker Runtime”章节进行。 # 更新日志 -| 版本 | 发布日期 | 修改说明 | -|:----------:|:----------:|:-----------------:| -| v3.0.0 | 2023-01-18 | 第一次发布 | -| v5.0.0-RC1 | 2023-04-18 | 配套MindX 5.0.RC1版本 | -| v5.0.0-RC2 | 2023-07-18 | 配套MindX 5.0.RC2版本 | -| v5.0.0-RC3 | 2023-10-27 | 配套MindX 5.0.RC3版本 | -| v5.0.0 | 2023-12-29 | 配套MindX 5.0.0版本 | -| v6.0.0-RC1 | 2024-04-22 | 配套MindX 6.0.RC1版本 | - +| 版本 | 发布日期 | 修改说明 | +|:-------------:|:----------:|:-----------------:| +| v3.0.0 | 2023-01-18 | 第一次发布 | +| v5.0.0-RC1 | 2023-04-18 | 配套MindX 5.0.RC1版本 | +| v5.0.0-RC2 | 2023-07-18 | 配套MindX 5.0.RC2版本 | +| v5.0.0-RC3 | 2023-10-27 | 配套MindX 5.0.RC3版本 | +| v5.0.0 | 2023-12-29 | 配套MindX 5.0.0版本 | +| v6.0.0-RC1 | 2024-04-22 | 配套MindX 6.0.RC1版本 | +| v5.0.1 | 2024-05-18 | MindX 5.0.1补丁版本 | +| v5.0.1-Patch1 | 2024-06-26 | MindX 5.0.1.1补丁版本 | +| v6.0.0-RC2 | 2024-07-16 | 配套MindX 6.0.RC2版本 | diff --git a/hook/process/process.go b/hook/process/process.go index 1f8a48c9ce7bfb04ef9920828c138dad6e99a8d0..5c315f561864d9e31b80088356cba7057f03685b 100644 --- a/hook/process/process.go +++ b/hook/process/process.go @@ -157,7 +157,7 @@ func parseSoftLinkMode(allowLink string) (string, error) { func parseOciSpecFile(file string) (*specs.Spec, error) { f, err := os.Open(file) if err != nil { - return nil, fmt.Errorf("failed to open the OCI config file: %s", file) + return nil, fmt.Errorf("failed to open the OCI config file: %s, err: %v", file, err) } defer f.Close() diff --git a/hook/process/process_test.go b/hook/process/process_test.go index 2398e547e0b19b6c31dfa6aa367eeb0be8a6a878..1cb5ff5a955c0c252f7999f0d47a2dbd73ca76d3 100644 --- a/hook/process/process_test.go +++ b/hook/process/process_test.go @@ -17,10 +17,17 @@ package process import ( "context" + "encoding/json" + "fmt" + "io/fs" "os" "os/exec" + "reflect" + "strings" "testing" + "github.com/agiledragon/gomonkey/v2" + "github.com/opencontainers/runtime-spec/specs-go" "github.com/prashantv/gostub" "github.com/stretchr/testify/assert" ) @@ -30,6 +37,7 @@ const ( fileMode0600 os.FileMode = 0600 ascendVisibleDeviceTestStr = "ASCEND_VISIBLE_DEVICES=0-3,5,7" configFile = "config.json" + strRepeatTimes = 129 ) // TestDoPrestartHookCase1 test function DoPrestartHook @@ -175,15 +183,31 @@ func TestParseOciSpecFileCase2(t *testing.T) { // TestParseOciSpecFileCase3 test the function parseOciSpecFile func TestParseOciSpecFileCase3(t *testing.T) { - cmd := exec.Command("runc", "spec") - if err := cmd.Run(); err != nil { - t.Log("runc spec failed") + file, err := os.Create(configFile) + if err != nil { + t.Log("create file failed") + t.FailNow() } defer os.Remove(configFile) - _, err := parseOciSpecFile(configFile) + defer file.Close() + err = file.Chmod(fileMode0600) if err != nil { - t.Fail() + t.Log("chmod file failed") + t.FailNow() } + testSpec := specs.Spec{} + jsonData, err := json.MarshalIndent(testSpec, "", " ") + if err != nil { + t.Logf("failed to MarshalIndent, err: %v", err) + t.FailNow() + } + _, err = file.Write(jsonData) + if err != nil { + t.Logf("failed to Write, err: %v", err) + t.FailNow() + } + _, err = parseOciSpecFile(configFile) + assert.Equal(t, fmt.Errorf("invalid OCI spec for empty process"), err) } // TestGetContainerConfig test the function getContainerConfig @@ -209,3 +233,189 @@ func TestGetContainerConfig(t *testing.T) { getContainerConfig() } + +// fileInfoMock is used to test +type fileInfoMock struct { + os.FileInfo +} + +// TestReadConfigsOfDir tests the function readConfigsOfDir +func TestReadConfigsOfDir(t *testing.T) { + patch := gomonkey.ApplyFunc(os.Stat, func(name string) (os.FileInfo, error) { + return &fileInfoMock{}, nil + }) + defer patch.Reset() + patchSize := gomonkey.ApplyMethod(reflect.TypeOf(&fileInfoMock{}), "Mode", func(f *fileInfoMock) fs.FileMode { + return fs.ModeDir + }) + defer patchSize.Reset() + tests := []struct { + name string + dir string + configs []string + want []string + want1 []string + wantErr bool + }{ + { + name: "readConfigsOfDir success case 1", + want: []string{}, + want1: []string{}, + }, + { + name: "readConfigsOfDir fail case 2", + configs: []string{"base"}, + wantErr: true, + want: nil, + want1: nil, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, got1, err := readConfigsOfDir(tt.dir, tt.configs) + if (err == nil) == tt.wantErr { + t.Errorf("readConfigsOfDir() got = %v, want %v", err, tt.wantErr) + } + assert.Equalf(t, tt.want, got, "readConfigsOfDir(%v, %v)", tt.dir, tt.configs) + assert.Equalf(t, tt.want1, got1, "readConfigsOfDir(%v, %v)", tt.dir, tt.configs) + }) + } +} + +// TestDoPrestartHook tests the function DoPrestartHook +func TestDoPrestartHook(t *testing.T) { + tests := []struct { + name string + wantErr bool + }{ + { + name: "DoPrestartHook success case 1", + wantErr: true, + }, + } + conCfg := containerConfig{ + Pid: pidSample, + Rootfs: ".", + Env: []string{"ASCEND_VISIBLE_DEVICES=0-3,5,7", "ASCEND_RUNTIME_MOUNTS=a"}, + } + stub := gostub.StubFunc(&getContainerConfig, &conCfg, nil) + defer stub.Reset() + patch := gomonkey.ApplyFunc(os.Stat, func(name string) (os.FileInfo, error) { + return &fileInfoMock{}, nil + }) + defer patch.Reset() + patchReadConfigsOfDir := gomonkey.ApplyFunc(readConfigsOfDir, func(dir string, configs []string) ([]string, []string, error) { + return []string{}, []string{}, nil + }) + defer patchReadConfigsOfDir.Reset() + patchSize := gomonkey.ApplyMethod(reflect.TypeOf(&fileInfoMock{}), "Mode", func(f *fileInfoMock) fs.FileMode { + return fs.ModeDir + }) + defer patchSize.Reset() + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + err := DoPrestartHook() + if (err == nil) == tt.wantErr { + t.Errorf("DoPrestartHook() got = %v, want %v", err, tt.wantErr) + } + }) + } +} + +// TestParseRuntimeOptions tests the function parseRuntimeOptions +func TestParseRuntimeOptions(t *testing.T) { + virtualValue := "VIRTUAL" + tests := []struct { + name string + runtimeOptions string + want []string + wantErr bool + }{ + { + name: "too long case 1", + runtimeOptions: strings.Repeat("a", strRepeatTimes), + wantErr: true, + }, + { + name: "invalid case 2", + runtimeOptions: "a", + wantErr: true, + }, + { + name: "success case 3", + runtimeOptions: virtualValue, + wantErr: false, + want: []string{virtualValue}, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := parseRuntimeOptions(tt.runtimeOptions) + if (err == nil) == tt.wantErr { + t.Errorf("DoPrestartHook() got = %v, want %v", err, tt.wantErr) + } + assert.Equalf(t, tt.want, got, "parseRuntimeOptions(%v)", tt.runtimeOptions) + }) + } +} + +// TestGetArgs tests the function getArgs +func TestGetArgs(t *testing.T) { + tests := []struct { + name string + cliPath string + containerConfig *containerConfig + fileMountList []string + dirMountList []string + allowLink string + want []string + }{ + { + name: "success case 1", + containerConfig: &containerConfig{}, + fileMountList: []string{"test"}, + dirMountList: []string{"test"}, + allowLink: "true", + cliPath: "testcli", + want: []string{"testcli", "--allow-link", "true", "--pid", "0", "--rootfs", "", + "--mount-file", "test", "--mount-dir", "test"}, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + assert.Equalf(t, tt.want, getArgs(tt.cliPath, tt.containerConfig, tt.fileMountList, + tt.dirMountList, tt.allowLink), "getArgs(%v, %v, %v, %v, %v)", + tt.cliPath, tt.containerConfig, tt.fileMountList, tt.dirMountList, tt.allowLink) + }) + } +} + +// TestParseMounts tests the function parseMounts +func TestParseMounts(t *testing.T) { + tests := []struct { + name string + mounts string + want []string + }{ + { + name: "base case 1", + mounts: "", + want: []string{baseConfig}, + }, + { + name: "base case 2", + mounts: strings.Repeat("a", strRepeatTimes), + want: []string{baseConfig}, + }, + { + name: "other case 3", + mounts: "testList,testList1", + want: []string{"testlist", "testlist1"}, + }, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + assert.Equalf(t, tt.want, parseMounts(tt.mounts), "parseMounts(%v)", tt.mounts) + }) + } +} diff --git a/install/process/constant.go b/install/process/constant.go index a5a461bd29da930f3791e3845dcc8b7d2f1d588b..427b8ef30f5ef0168deb4193e5431be78de52a67 100644 --- a/install/process/constant.go +++ b/install/process/constant.go @@ -14,6 +14,8 @@ package process +import "os" + const commonTemplate = `{ "runtimes": { "ascend": { @@ -34,14 +36,15 @@ const noDefaultTemplate = `{ }` const ( - actionPosition = 0 - srcFilePosition = 1 - destFilePosition = 2 - runtimeFilePosition = 3 - rmCommandLength = 6 - addCommandLength = 7 - maxFileSize = 1024 * 1024 * 10 - cgroupInfoIndexFromEnd = 1 + actionPosition = 0 + srcFilePosition = 1 + destFilePosition = 2 + runtimeFilePosition = 3 + rmCommandLength = 6 + addCommandLength = 7 + maxFileSize = 1024 * 1024 * 10 + cgroupInfoIndexFromEnd = 1 + perm os.FileMode = 0600 ) const ( diff --git a/install/process/containerd_process.go b/install/process/containerd_process.go index c471eb41c7056455c309e2f2a7ffca67ef0ddca0..07e2e6a77abcea193596f004cfdb338c2174fc03 100644 --- a/install/process/containerd_process.go +++ b/install/process/containerd_process.go @@ -29,6 +29,9 @@ import ( // ContainerdProcess modifies the containerd configuration file when installing or uninstalling the containerd scenario. func ContainerdProcess(command []string) (string, error) { + if len(command) == 0 { + return "", fmt.Errorf("error param, length of command is 0") + } action := command[actionPosition] correctParam, behavior := checkParamAndGetBehavior(action, command) if !correctParam { @@ -223,7 +226,7 @@ func writeContainerdConfigToFile(cfg config.Config, destFilePath string) error { hwlog.RunLog.Errorf("failed to marshall to toml, error: %v", err) return err } - file, err := os.Create(destFilePath) + file, err := os.OpenFile(destFilePath, os.O_CREATE|os.O_RDWR|os.O_TRUNC, perm) if err != nil { hwlog.RunLog.Errorf("failed to create file, error: %v", err) return err diff --git a/install/process/containerd_process_test.go b/install/process/containerd_process_test.go index 6859e47d08ce90171c520627651cddcd3273eda1..64e744b19246d994c37aa8b303e956912383f331 100644 --- a/install/process/containerd_process_test.go +++ b/install/process/containerd_process_test.go @@ -1,3 +1,17 @@ +/* Copyright(C) 2024. Huawei Technologies Co.,Ltd. All rights reserved. + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. +*/ + package process import ( @@ -97,7 +111,8 @@ func TestEditContainerdConfig(t *testing.T) { defer patch.Reset() for _, tt := range tests { t.Run(tt.name, func(t *testing.T) { - if err := editContainerdConfig(tt.srcFilePath, tt.runtimeFilePath, tt.destFilePath, tt.action, tt.cgroupInfo); (err != nil) != tt.wantErr { + if err := editContainerdConfig(tt.srcFilePath, tt.runtimeFilePath, tt.destFilePath, + tt.action, tt.cgroupInfo); (err != nil) != tt.wantErr { t.Errorf("editContainerdConfig() error = %v, wantErr %v", err, tt.wantErr) } }) diff --git a/install/process/docker_process.go b/install/process/docker_process.go index 084061ca3871c02816f85f2e9b7f219ca6317c41..67b99c9380da7c333ea03bf8ccb1f22188f4dea1 100644 --- a/install/process/docker_process.go +++ b/install/process/docker_process.go @@ -29,7 +29,9 @@ var reserveDefaultRuntime = false // DockerProcess modifies the docker configuration file when installing or uninstalling the docker scenario. func DockerProcess(command []string) (string, error) { - + if len(command) == 0 { + return "", fmt.Errorf("error param, length of command is 0") + } action := command[actionPosition] correctParam, behavior := checkParamAndGetBehavior(action, command) if !correctParam { @@ -142,6 +144,9 @@ func modifyDaemon(srcFilePath, runtimeFilePath, action string) (map[string]inter func addDockerDaemon(runtimeConfig, daemon map[string]interface{}, runtimeFilePath string, ) (map[string]interface{}, map[string]interface{}, error) { + if runtimeConfig == nil { + return nil, daemon, fmt.Errorf("runtime config is nil") + } if _, ok := runtimeConfig["ascend"]; !ok { runtimeConfig["ascend"] = map[string]interface{}{} } @@ -153,7 +158,7 @@ func addDockerDaemon(runtimeConfig, daemon map[string]interface{}, runtimeFilePa if _, ok := ascendConfig["runtimeArgs"]; !ok { ascendConfig["runtimeArgs"] = []string{} } - if !reserveDefaultRuntime { + if !reserveDefaultRuntime && daemon != nil { daemon[defaultRuntimeKey] = "ascend" } return runtimeConfig, daemon, nil diff --git a/install/process/docker_process_test.go b/install/process/docker_process_test.go index 5ae454e99ac3b330484cb9097b2df439c2dc66fd..38532f7347f02edd666d8a9077df7a1c50092dc4 100644 --- a/install/process/docker_process_test.go +++ b/install/process/docker_process_test.go @@ -245,6 +245,12 @@ func getTestDockerProcessCases() []testProcessArg { WantErr: true, WantResult: addBehavior, }, + { + Name: "error param case 5", + Command: []string{}, + WantErr: true, + WantResult: emptyStr, + }, } } diff --git a/runtime/dcmi/dcmi_api_test.go b/runtime/dcmi/dcmi_api_test.go index 324bf93db29e9c9ae5e76c24ad5259ee1ad21785..0cf987f712eb505d1d3c17b67cbdb725881ec934 100644 --- a/runtime/dcmi/dcmi_api_test.go +++ b/runtime/dcmi/dcmi_api_test.go @@ -70,7 +70,6 @@ func TestCreateVDevice(t *testing.T) { process := specs.Process{} spec := specs.Spec{Process: &process} spec.Process.Env = []string{} - var deviceIdList []int backups := 2 logMaxAge := 365 fileMaxSize := 2 @@ -86,6 +85,7 @@ func TestCreateVDevice(t *testing.T) { } // no split, all ok + var deviceIdList []int vdevice, err := CreateVDevice(&mockWorker{}, &spec, deviceIdList) if err != nil { t.Fatalf("%v %v", vdevice, err) @@ -129,13 +129,14 @@ func TestGetChipName(t *testing.T) { return 1, nil }) defer patchGetDeviceNumInCard.Reset() - patchGetChipInfo := gomonkey.ApplyMethod(reflect.TypeOf(&NpuWorker{}), "GetChipInfo", func(f *NpuWorker, cardID int32, deviceID int32) (*ChipInfo, error) { - return &ChipInfo{ - Name: "a", - Type: "b", - Version: "1", - }, nil - }) + patchGetChipInfo := gomonkey.ApplyMethod(reflect.TypeOf(&NpuWorker{}), "GetChipInfo", + func(f *NpuWorker, cardID int32, deviceID int32) (*ChipInfo, error) { + return &ChipInfo{ + Name: "a", + Type: "b", + Version: "1", + }, nil + }) defer patchGetChipInfo.Reset() tests := []struct { name string diff --git a/runtime/process/process_test.go b/runtime/process/process_test.go index 3ba9fbd7785a48d6556bf2788d07fa253f8653ac..b94c16f0b97ff11f534bb04bb2df1919b89f3c5e 100644 --- a/runtime/process/process_test.go +++ b/runtime/process/process_test.go @@ -118,7 +118,8 @@ func TestArgsIsCreateCase3(t *testing.T) { t.Log(execStubLog) return nil }) - + err = InitLogModule(context.Background()) + assert.Nil(t, err) err = DoProcess() assert.NotNil(t, err) }