Skip to content

Commit

Permalink
Integrated cobra cli
Browse files Browse the repository at this point in the history
  • Loading branch information
bensallen committed Dec 20, 2016
1 parent b33a6df commit def3121
Show file tree
Hide file tree
Showing 7 changed files with 202 additions and 35 deletions.
99 changes: 99 additions & 0 deletions cmd/discover.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
package cmd

import (
"fmt"
"log"

"github.com/spf13/cobra"

sastopo "gitlab.alcf.anl.gov/jlse/sastopo/lib"
yaml "gopkg.in/yaml.v2"
)

var conf sastopo.Conf

// discoverCmd represents the discover command
var discoverCmd = &cobra.Command{
Use: "discover",
Short: "Discover host's SAS Topology",
Long: "Discover host's SAS Topology",
Run: run,
}

func init() {
RootCmd.AddCommand(discoverCmd)
discoverCmd.Flags().BoolVarP(&conf.Summary, "summary", "s", true, "Show summary of SAS devices")
discoverCmd.Flags().BoolVarP(&conf.Mismatch, "mismatch", "m", false, "Show devices with path count mismatch")
discoverCmd.Flags().IntVarP(&conf.PathCount, "pathcount", "p", 2, "Number of expected paths to each SAS device")
discoverCmd.Flags().IntVar(&conf.SysfsMatchPathEncl, "sysfsMatchPathEncl", 8, "Number of sysfs elements expected for a sysfs device")

}

func run(cmd *cobra.Command, args []string) {
loadConf()

devices, multiPathDevices, enclosures, HBAs, err := sastopo.ScsiDevices(conf)
if err != nil {
fmt.Print(err)
}
if conf.Mismatch {
findDevMissingPaths(conf.PathCount, devices)
}
if conf.Summary {
summary(devices, multiPathDevices, enclosures, HBAs)
}
}

func findDevMissingPaths(count int, devices map[string]*sastopo.Device) {
for _, d := range devices {
if len(d.MultiPath.Paths) != count {
fmt.Printf("Path Count Mismatch: %#v, found %d paths\n", d.Serial, len(d.MultiPath.Paths))
}
}
}

func summary(devices map[string]*sastopo.Device, multiPathDevices map[string]*sastopo.MultiPathDevice, enclosures map[*sastopo.Enclosure]bool, HBAs map[string]*sastopo.HBA) {

fmt.Printf("Found %d SAS Devices\n", len(devices))
//for _, device := range devices {
// fmt.Printf("Found Device: %p\n", device.Enclosure)
//}
fmt.Printf("Found %d Unique Multi-pathed SAS Devices\n", len(multiPathDevices))
for hba := range HBAs {
fmt.Printf("Found HBA: %s, Slot: %s, Host: %s\n", HBAs[hba].PciID, HBAs[hba].Slot, HBAs[hba].Host)
}

fmt.Printf("Found %d Enclosures\n", len(enclosures))
for enclosure := range enclosures {
fmt.Printf("Found Enclosure: %p with %d slots populated\n", enclosure, len(enclosure.Slots))
for path := range enclosure.MultiPathDevice.Paths {
fmt.Printf("HBA: %s, Slot %s, Port: %s\n", path.HBA.PciID, path.HBA.Slot, path.Port)
}
//for slot := range enclosure.Slots {
// fmt.Printf("%s\n", slot)
//}
}
}

func loadConf() {

var data = []byte(`
# Labels of PCI bus addresses to Slot ID
HBALabels:
"0000:11:00.0": 'C3'
"0000:8b:00.0": 'C5'
"0000:90:00.0": 'C6'
EnclLabels:
"0000:11:00.0":
"0000:8b:00.0":
"0000:90:00.0":
`)

err := yaml.Unmarshal(data, &conf)
if err != nil {
log.Fatalf("error: %v", err)
}

}
64 changes: 64 additions & 0 deletions cmd/root.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
package cmd

import (
"fmt"
"os"

"github.com/spf13/cobra"
"github.com/spf13/viper"
)

var cfgFile string

// RootCmd represents the base command when called without any subcommands
var RootCmd = &cobra.Command{
Use: "sastopo",
Short: "A brief description of your application",
Long: `A longer description that spans multiple lines and likely contains
examples and usage of using your application. For example:
Cobra is a CLI library for Go that empowers applications.
This application is a tool to generate the needed files
to quickly create a Cobra application.`,
// Uncomment the following line if your bare application
// has an action associated with it:
// Run: func(cmd *cobra.Command, args []string) { },
}

// Execute adds all child commands to the root command sets flags appropriately.
// This is called by main.main(). It only needs to happen once to the rootCmd.
func Execute() {
if err := RootCmd.Execute(); err != nil {
fmt.Println(err)
os.Exit(-1)
}
}

func init() {
cobra.OnInitialize(initConfig)

// Here you will define your flags and configuration settings.
// Cobra supports Persistent Flags, which, if defined here,
// will be global for your application.

RootCmd.PersistentFlags().StringVar(&cfgFile, "config", "", "config file (default is $HOME/.sastopo.yaml)")
// Cobra also supports local flags, which will only run
// when this action is called directly.
RootCmd.Flags().BoolP("toggle", "t", false, "Help message for toggle")
}

// initConfig reads in config file and ENV variables if set.
func initConfig() {
if cfgFile != "" { // enable ability to specify config file via flag
viper.SetConfigFile(cfgFile)
}

viper.SetConfigName(".sastopo") // name of config file (without extension)
viper.AddConfigPath("$HOME") // adding home directory as first search path
viper.AutomaticEnv() // read in environment variables that match

// If a config file is found, read it in.
if err := viper.ReadInConfig(); err == nil {
fmt.Println("Using config file:", viper.ConfigFileUsed())
}
}
11 changes: 11 additions & 0 deletions lib/conf.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package sastopo

// Conf is a struct used for parsing the yaml configure file
type Conf struct {
Mismatch bool
PathCount int
SysfsMatchPathEncl int
Summary bool
HBALabels map[string]string `yaml:"HBALabels"`
EnclLabels map[string]map[string]string `yaml:"EnclLabels"`
}
11 changes: 6 additions & 5 deletions lib/device.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ func (d *Device) updateSerial() error {

// Update HBA and Port attributes of device using the elements of sysfs path
// of the device
func (d *Device) updatePathVars(HBAs map[string]*HBA) error {
func (d *Device) updatePathVars(HBAs map[string]*HBA, conf Conf) error {
p := strings.Split(string(d.sysfsObj), "/")
if len(p) < 8 {
return errors.New("Unexpected Sysfs path: must have least 8 elements in path: " + string(d.sysfsObj))
Expand All @@ -117,6 +117,7 @@ func (d *Device) updatePathVars(HBAs map[string]*HBA) error {
HBAs[p[5]] = &HBA{
PciID: p[5],
Host: p[6],
Slot: conf.HBALabels[p[5]],
}
d.HBA = HBAs[p[5]]
}
Expand Down Expand Up @@ -215,8 +216,8 @@ func updateEnclosure(devices map[string]*Device, enclosures map[*Enclosure]bool,
// map[string]*MultiPathDevice of all resolved unique end devices.
// Takes an int that specifies how many elements of the devices
// and enclosure sysfs path to match against to assign a device
// to an enclosure.
func ScsiDevices(sysfsMatchPathEncl int) (map[string]*Device, map[string]*MultiPathDevice, map[*Enclosure]bool, map[string]*HBA, error) {
// to an enclosure
func ScsiDevices(conf Conf) (map[string]*Device, map[string]*MultiPathDevice, map[*Enclosure]bool, map[string]*HBA, error) {
var (
Devices = map[string]*Device{}
DevicesBySerial = map[string]map[*Device]bool{}
Expand Down Expand Up @@ -246,7 +247,7 @@ func ScsiDevices(sysfsMatchPathEncl int) (map[string]*Device, map[string]*MultiP
log.Printf("Warning: %s", err)
}
}
if err := Devices[name].updatePathVars(HBAs); err != nil {
if err := Devices[name].updatePathVars(HBAs, conf); err != nil {
log.Printf("Warning: %s", err)
}
if err := Devices[name].updateEnclSlot(); err != nil {
Expand Down Expand Up @@ -277,7 +278,7 @@ func ScsiDevices(sysfsMatchPathEncl int) (map[string]*Device, map[string]*MultiP
// Assign MultiPathDevice to Devices, get back map of all MultiPath Devices
multiPathDevices := updateMultiPaths(Devices, DevicesBySerial, DevicesBySASAddress)
enclosures := Enclosures(EnclMap)
updateEnclosure(Devices, enclosures, sysfsMatchPathEncl)
updateEnclosure(Devices, enclosures, conf.SysfsMatchPathEncl)

return Devices, multiPathDevices, enclosures, HBAs, nil

Expand Down
2 changes: 1 addition & 1 deletion lib/enclosure.go
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ func (d *Device) updateEnclosureSerial() (err error) {
// shows a device labeled as "SHELF" or "Dragon Enclosure" in page 0x1.
// We use sg_ses --hex output, drop all the whitespace and use
// hex.Decode() to turn it into a useable []byte. Finally we take
// the appropraite offset in the 0x7 page, and grab 16 bytes (length)
// the appropraite "offset" bytes in the 0x7 page, and grab "length" bytes
// which makes up the serial number.
// This function requires root privledges and sg3_utils to be installed.
func sgSesEnclosureSerial(sg string, offset int, length int) (string, error) {
Expand Down
19 changes: 16 additions & 3 deletions lib/hba.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,20 @@ package sastopo

// HBA is a PCI SAS Host-bus Adapter
type HBA struct {
PciID string // PCI Bus ID
Host string // SCSI Host ID
Slot string // Label that describes physical location
PciID string // PCI Bus ID
Host string // SCSI Host ID
Slot string // Label that describes physical location
Ports map[*HBAPort]bool // SAS Ports
}

// HBAPort is a a HBA Port
type HBAPort struct {
PortID string // SCSI HBA Port ID
Phys map[*Phy]bool // Map of Phys
}

// Phy is SAS Phy
type Phy struct {
PhyIdentifier string
SasAddress string
}
31 changes: 5 additions & 26 deletions main.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,36 +2,15 @@ package main

import (
"fmt"
"os"

"gitlab.alcf.anl.gov/jlse/sastopo/lib"
"gitlab.alcf.anl.gov/jlse/sastopo/cmd"
)

func findDevMissingPaths(count int, devices map[string]*sastopo.Device) {
for _, d := range devices {
if len(d.MultiPath.Paths) != count {
fmt.Printf("Path Count Mismatch: %#v, found %d paths\n", d.Serial, len(d.MultiPath.Paths))
}
}
}

func main() {
devices, multiPathDevices, enclosures, hbas, err := sastopo.ScsiDevices(8)
if err != nil {
fmt.Print(err)
}
fmt.Printf("Found %d Devices\n", len(devices))
//for _, device := range devices {
// fmt.Printf("Found Device: %p\n", device.Enclosure)
//}
fmt.Printf("Found %d Unique Multi-pathed Devices\n", len(multiPathDevices))
fmt.Printf("Found %d HBAs\n", len(hbas))

fmt.Printf("Found %d Enclosures\n", len(enclosures))
for enclosure := range enclosures {
fmt.Printf("Found Enclosure: %p with %d slots populated\n", enclosure, len(enclosure.Slots))
//for slot := range enclosure.Slots {
// fmt.Printf("%s\n", slot)
//}
if err := cmd.RootCmd.Execute(); err != nil {
fmt.Println(err)
os.Exit(-1)
}
//findDevMissingPaths(2, devices)
}

0 comments on commit def3121

Please sign in to comment.