-
Notifications
You must be signed in to change notification settings - Fork 3
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Abhijith Dadaga Arkakeerthy
committed
Nov 28, 2024
1 parent
46aaefc
commit 1b49653
Showing
62 changed files
with
6,472 additions
and
1,501 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,144 @@ | ||
/** | ||
* Copyright (c) 2021 Veritas Technologies LLC. All rights reserved. IP63-2828-7171-04-15-9 | ||
*/ | ||
|
||
package boot | ||
|
||
import ( | ||
"encoding/json" | ||
"errors" | ||
"flag" | ||
"fmt" | ||
"io/ioutil" | ||
"os" | ||
"os/exec" | ||
"sort" | ||
"strings" | ||
) | ||
|
||
// Variables for retrieving the version information from release file | ||
const ( | ||
VxosReleaseFile = "/etc/vxos-release" | ||
VersionPattern = "product-version = " | ||
) | ||
|
||
// KernelInfo stores the information for kernels | ||
type KernelInfo struct { | ||
Name string `json:"name"` | ||
Version string `json:"version"` | ||
Kernel string `json:"kernel"` | ||
Device string `json:"device"` | ||
} | ||
|
||
var ( | ||
fExecCommand = execCommand | ||
fGetVolumeInfo = getVolumeInfo | ||
) | ||
|
||
// Execution handler for running a command on os | ||
func execCommand(operation string, command []string) string { | ||
out, err := exec.Command(operation, command...).Output() | ||
if err != nil { | ||
message := fmt.Sprintf("Failed to execute command '%s %s'. Error: %s.", operation, command, err) | ||
fmt.Fprintf(os.Stderr, "%v\n", message) | ||
} | ||
return string(out) | ||
} | ||
|
||
func execCommandBash(cmdStr string) (string, error) { | ||
cmd := exec.Command("bash", "-c", cmdStr) | ||
out, err := cmd.Output() | ||
outStr := string(out) | ||
if err != nil { | ||
message := fmt.Sprintf("Failed to run command [%s].", cmdStr) | ||
err = errors.New(message) | ||
} | ||
return outStr, err | ||
} | ||
|
||
func getVersionInfo(file string) string { | ||
content, _ := ioutil.ReadFile(file) | ||
lines := strings.Split(string(content), "\n") | ||
|
||
for _, line := range lines { | ||
if strings.Contains(line, VersionPattern) { | ||
return strings.Split(line, VersionPattern)[1] | ||
} | ||
} | ||
return "" | ||
} | ||
|
||
func getVolumeInfo(volumePath string) (string, string) { | ||
rpmCmd := "rpm -q kernel --root=" + volumePath + " --qf '%{VERSION}-%{RELEASE}.%{ARCH}\n'" | ||
device := strings.TrimSpace(execCommand("findmnt", []string{"-n", "-o", "SOURCE", volumePath})) | ||
kernels, err := execCommandBash(rpmCmd) | ||
if err != nil { | ||
return device, "" | ||
} | ||
return device, kernels | ||
} | ||
|
||
func getKernelMap(releaseFile string, bootVolumes map[string]map[string]string, newVersion string) []KernelInfo { | ||
kernelMap := make([]KernelInfo, 0) | ||
runningKernel := strings.TrimSpace(fExecCommand("uname", []string{"-r"})) | ||
|
||
volumeNames := make([]string, 0, len(bootVolumes)) | ||
for volumeName := range bootVolumes { | ||
volumeNames = append(volumeNames, volumeName) | ||
} | ||
sort.Strings(volumeNames) | ||
|
||
for _, volumeName := range volumeNames { | ||
for _, volumePath := range bootVolumes[volumeName] { | ||
version := getVersionInfo(volumePath + releaseFile) | ||
device, kernels := fGetVolumeInfo(volumePath) | ||
|
||
for _, kernel := range strings.Fields(kernels) { | ||
kernelInfo := KernelInfo{ | ||
Name: volumeName, | ||
Version: version, | ||
Kernel: kernel, | ||
Device: device, | ||
} | ||
if volumeName == "current" && kernel != runningKernel { | ||
kernelInfo.Name = "patch" | ||
if len(newVersion) != 0 { | ||
kernelInfo.Version = newVersion | ||
} | ||
} | ||
kernelMap = append(kernelMap, kernelInfo) | ||
} | ||
} | ||
} | ||
return kernelMap | ||
} | ||
|
||
// Exec executes boot management | ||
func Exec(args []string) error { | ||
os.Args = args | ||
|
||
prepareFlag := flag.Bool("prepare", false, "command for preparing boot info: boot -prepare -release_file=<filename> -volumes=<json> -version=<version>") | ||
releaseFile := flag.String("release_file", "", "path of release file") | ||
bootVolumes := flag.String("volumes", "", "bootable volumes") | ||
newVersion := flag.String("version", "", "version") | ||
|
||
flag.Parse() | ||
|
||
if *prepareFlag { | ||
if *bootVolumes == "" { | ||
flag.PrintDefaults() | ||
return fmt.Errorf("Bootable volumes need to be specified") | ||
} | ||
if *releaseFile == "" { | ||
*releaseFile = VxosReleaseFile | ||
} | ||
bootVolumesMap := make(map[string]map[string]string) | ||
json.Unmarshal([]byte(*bootVolumes), &bootVolumesMap) | ||
kernelMap := getKernelMap(*releaseFile, bootVolumesMap, *newVersion) | ||
kernelMapOutput, _ := json.Marshal(kernelMap) | ||
fmt.Println(string(kernelMapOutput)) | ||
return nil | ||
} | ||
flag.PrintDefaults() | ||
return fmt.Errorf("Invalid inputs of command") | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,165 @@ | ||
/** | ||
* Copyright (c) 2021 Veritas Technologies LLC. All rights reserved. IP63-2828-7171-04-15-9 | ||
*/ | ||
|
||
package boot | ||
|
||
import ( | ||
"fmt" | ||
"reflect" | ||
"testing" | ||
) | ||
|
||
var ( | ||
releaseFile string | ||
newVersion string | ||
pathCurrent map[string]string | ||
pathUpgrade map[string]string | ||
kernelCurrent string | ||
kernelUpgrade string | ||
kernelPatch string | ||
deviceCurrent string | ||
deviceUpgrade string | ||
kernelInfoCurrent KernelInfo | ||
kernelInfoUpgrade KernelInfo | ||
kernelInfoPatch KernelInfo | ||
) | ||
|
||
func init() { | ||
releaseFile = "/etc/vxos-release" | ||
newVersion = "1.4.1" | ||
pathCurrent = map[string]string{"path": "./test_files/"} | ||
pathUpgrade = map[string]string{"path": "./test_files/system/upgrade/volume"} | ||
kernelCurrent = "3.10.0-1062.7.1.el7.x86_64" | ||
kernelUpgrade = "3.10.1-1062.7.1.el7.x86_64" | ||
kernelPatch = "3.10.0-1062.9.1.el7.x86_64" | ||
deviceCurrent = "/dev/mapper/system-thunder_cloud_1.4--999" | ||
deviceUpgrade = "/dev/mapper/system-thunder_cloud_2.0--999" | ||
kernelInfoCurrent = KernelInfo{Name: "current", Version: "1.4", Kernel: kernelCurrent, Device: deviceCurrent} | ||
kernelInfoPatch = KernelInfo{Name: "patch", Version: newVersion, Kernel: kernelPatch, Device: deviceCurrent} | ||
kernelInfoUpgrade = KernelInfo{Name: "upgrade", Version: "2.0", Kernel: kernelUpgrade, Device: deviceUpgrade} | ||
} | ||
|
||
func TestGetVersionInfo(t *testing.T) { | ||
tests := []struct { | ||
name string | ||
file string | ||
version string | ||
}{ | ||
{ | ||
name: "Use mocked release file", | ||
file: "./test_files/" + releaseFile, | ||
version: "1.4", | ||
}, | ||
{ | ||
name: "Use a non-existing file", | ||
file: "./test_files/vxos-release", | ||
version: "", | ||
}, | ||
{ | ||
name: "Use file without information of prodcut version", | ||
file: "./test_files/incorrect-release", | ||
version: "", | ||
}, | ||
} | ||
for _, test := range tests { | ||
t.Run(test.name, func(t *testing.T) { | ||
version := getVersionInfo(test.file) | ||
if version != test.version { | ||
t.Errorf("expected: [%v], but got [%v]", test.version, version) | ||
} | ||
}) | ||
} | ||
} | ||
|
||
func TestGetKernelMap(t *testing.T) { | ||
type mock struct { | ||
device string | ||
kernels string | ||
} | ||
|
||
tests := []struct { | ||
name string | ||
mock map[string]mock | ||
bootVolumes map[string]map[string]string | ||
newVersion string | ||
kernelMap []KernelInfo | ||
}{ | ||
{ | ||
name: "Kick Start", | ||
mock: map[string]mock{ | ||
pathCurrent["path"]: mock{ | ||
device: deviceCurrent, | ||
kernels: kernelCurrent, | ||
}, | ||
}, | ||
bootVolumes: map[string]map[string]string{"current": pathCurrent}, | ||
newVersion: "", | ||
kernelMap: []KernelInfo{kernelInfoCurrent}, | ||
}, | ||
{ | ||
name: "Factory Reset", | ||
mock: map[string]mock{ | ||
pathCurrent["path"]: mock{ | ||
device: deviceCurrent, | ||
kernels: kernelCurrent, | ||
}, | ||
pathUpgrade["path"]: mock{ | ||
device: deviceUpgrade, | ||
kernels: kernelUpgrade, | ||
}, | ||
}, | ||
bootVolumes: map[string]map[string]string{"upgrade": pathUpgrade}, | ||
newVersion: "", | ||
kernelMap: []KernelInfo{kernelInfoUpgrade}, | ||
}, | ||
{ | ||
name: "Upgrade", | ||
mock: map[string]mock{ | ||
pathCurrent["path"]: mock{ | ||
device: deviceCurrent, | ||
kernels: kernelCurrent, | ||
}, | ||
pathUpgrade["path"]: mock{ | ||
device: deviceUpgrade, | ||
kernels: kernelUpgrade, | ||
}, | ||
}, | ||
bootVolumes: map[string]map[string]string{"current": pathCurrent, "upgrade": pathUpgrade}, | ||
newVersion: "", | ||
kernelMap: []KernelInfo{kernelInfoCurrent, kernelInfoUpgrade}, | ||
}, | ||
{ | ||
name: "Patch", | ||
mock: map[string]mock{ | ||
pathCurrent["path"]: mock{ | ||
device: deviceCurrent, | ||
kernels: kernelCurrent + "\n" + kernelPatch, | ||
}, | ||
pathUpgrade["path"]: mock{ | ||
device: deviceUpgrade, | ||
kernels: kernelUpgrade, | ||
}, | ||
}, | ||
bootVolumes: map[string]map[string]string{"current": pathCurrent}, | ||
newVersion: newVersion, | ||
kernelMap: []KernelInfo{kernelInfoCurrent, kernelInfoPatch}, | ||
}, | ||
} | ||
for _, test := range tests { | ||
t.Run(test.name, func(t *testing.T) { | ||
fExecCommand = func(operation string, command []string) string { | ||
return fmt.Sprintf("%v\n", kernelCurrent) | ||
} | ||
|
||
fGetVolumeInfo = func(volumePath string) (string, string) { | ||
return test.mock[volumePath].device, test.mock[volumePath].kernels | ||
} | ||
|
||
kernelMap := getKernelMap(releaseFile, test.bootVolumes, test.newVersion) | ||
if !reflect.DeepEqual(kernelMap, test.kernelMap) { | ||
t.Errorf("expected: [%v], but got [%v]", test.kernelMap, kernelMap) | ||
} | ||
}) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
product-name = Flex | ||
product-version = 1.4 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
product-name = Flex | ||
product-version = 2.0 |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.