Skip to content

Commit

Permalink
Sync-up: syslog; pm run-time;
Browse files Browse the repository at this point in the history
  • Loading branch information
Abhijith Dadaga Arkakeerthy committed Nov 28, 2024
1 parent 46aaefc commit 1b49653
Show file tree
Hide file tree
Showing 62 changed files with 6,472 additions and 1,501 deletions.
144 changes: 144 additions & 0 deletions boot/main.go
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")
}
165 changes: 165 additions & 0 deletions boot/main_test.go
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)
}
})
}
}
2 changes: 2 additions & 0 deletions boot/test_files/etc/vxos-release
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
product-name = Flex
product-version = 1.4
2 changes: 2 additions & 0 deletions boot/test_files/system/upgrade/volume/etc/vxos-release
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
product-name = Flex
product-version = 2.0
40 changes: 22 additions & 18 deletions cmd/sum/sum.go
Original file line number Diff line number Diff line change
@@ -1,19 +1,20 @@
// Copyright (c) 2021 Veritas Technologies LLC. All rights reserved. IP63-2828-7171-04-15-9
// Copyright (c) 2022 Veritas Technologies LLC. All rights reserved. IP63-2828-7171-04-15-9

package main

import (
"flag"
"fmt"
"os"
"path/filepath"
"strings"

pm "github.com/VeritasOS/plugin-manager" // import "../../plugin-manager"
"github.com/VeritasOS/plugin-manager/config"
logutil "github.com/VeritasOS/plugin-manager/utils/log"
logger "github.com/VeritasOS/plugin-manager/utils/log"
"github.com/VeritasOS/software-update-manager/boot"
"github.com/VeritasOS/software-update-manager/repo"
"github.com/VeritasOS/software-update-manager/update"
"github.com/VeritasOS/software-update-manager/validate"
"os"
"path/filepath"
"strings"
)

var (
Expand All @@ -35,31 +36,34 @@ var mainCmdOptions struct {
}

func init() {
config.SetLogDir("/var/log/sum/")
if len(os.Args) < 2 {
fmt.Fprintf(os.Stderr, "Subcommand as operation is required.\n")
os.Exit(1)
}
logger.InitLogging()
}

func main() {
absprogpath, err := filepath.Abs(os.Args[0])
if err != nil {
logutil.PrintNLogError("Failed to get the %s path.", progname)
logger.ConsoleError.Printf("Failed to get the %s path.", progname)
}

if len(os.Args) < 2 {
fmt.Fprintf(os.Stderr, "Subcommand as operation is required.\n")
os.Exit(1)
}

cmd := os.Args[1]
config.SetLogFile(cmd)
logutil.SetLogging(config.GetLogDir() + config.GetLogFile())

mainRegisterCmdOptions()
pm.RegisterCommandOptions(progname + " pm")
repo.RegisterCommandOptions(progname + " repo")
update.RegisterCommandOptions(progname)
cmd := os.Args[1]
switch cmd {
case "version":
logutil.PrintNLog("%s version %s %s\n", progname, version, buildDate)
logger.ConsoleInfo.Printf("%s version %s %s", progname, version, buildDate)

case "boot":
err := boot.Exec(os.Args[1:])
if err != nil {
fmt.Fprintf(os.Stderr, "Failed to execute boot command: %v.\n", err.Error())
os.Exit(1)
}

case "commit", "install", "reboot", "rollback":
library := filepath.Clean(
Expand Down
4 changes: 2 additions & 2 deletions go.mod
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,6 @@ go 1.12
// replace plugin-manager => ../plugin-manager/

require (
github.com/VeritasOS/plugin-manager v1.0.1
gopkg.in/yaml.v2 v2.4.0
github.com/VeritasOS/plugin-manager v1.0.4
gopkg.in/yaml.v3 v3.0.1
)
Loading

0 comments on commit 1b49653

Please sign in to comment.