Skip to content

Commit

Permalink
Switch to more general OS attribute
Browse files Browse the repository at this point in the history
Move login shell to a more general OS attribute that may later capture
other information about the operating system on an entry that has one.

Signed-off-by: Michael Smith <[email protected]>
  • Loading branch information
MikaelSmith committed Feb 5, 2020
1 parent 473f0e8 commit 7909079
Show file tree
Hide file tree
Showing 6 changed files with 76 additions and 50 deletions.
12 changes: 6 additions & 6 deletions cmd/ps.go
Original file line number Diff line number Diff line change
Expand Up @@ -122,16 +122,16 @@ func psMain(cmd *cobra.Command, args []string) exitCode {
if err != nil {
cmdutil.ErrPrintf("errored on %v: %v\n", k, err)
}
var shell plugin.LoginShell
if entry.Attributes.HasLoginShell() {
shell = entry.Attributes.LoginShell()
var loginShell plugin.Shell
if entry.Attributes.HasOS() {
loginShell = entry.Attributes.OS().LoginShell
}
if shell == plugin.UnknownShell {
if loginShell == plugin.UnknownShell {
// Assume posix if unknown
shell = plugin.POSIXShell
loginShell = plugin.POSIXShell
}

dispatcher := dispatchers[shell]
dispatcher := dispatchers[loginShell]
ch, err := dispatcher.execPS(conn, k)
if err != nil {
cmdutil.ErrPrintf("errored on %v: %v\n", k, err)
Expand Down
2 changes: 1 addition & 1 deletion plugin/aws/ec2Instance.go
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ func getAttributesAndMetadata(inst *ec2Client.Instance) (plugin.EntryAttributes,
attr.
SetCrtime(crtime).
SetMtime(mtime).
SetLoginShell(shell)
SetOS(plugin.OS{LoginShell: shell})

meta := plugin.ToJSONObject(ec2InstanceMetadata{
Instance: inst,
Expand Down
90 changes: 58 additions & 32 deletions plugin/entryAttributes.go
Original file line number Diff line number Diff line change
Expand Up @@ -36,23 +36,36 @@ func ToJSONObject(v interface{}) JSONObject {
return obj
}

// LoginShell describes the type of shell execution occurs in. It can be used
// by the caller to decide what type of commands to run.
type LoginShell int
// Shell describes a command shell.
type Shell int

// Defines specific LoginShell classes you can configure
// Defines specific Shell classes you can configure
const (
UnknownShell LoginShell = iota
UnknownShell Shell = iota
POSIXShell
PowerShell
)

var shellNames = [3]string{"unknown", "posixshell", "powershell"}

func (sh LoginShell) String() string {
func (sh Shell) String() string {
return shellNames[sh]
}

// OS contains information about the operating system of a compute-like entry
type OS struct {
// LoginShell describes the type of shell execution occurs in. It can be used
// by the caller to decide what type of commands to run.
LoginShell Shell
}

// ToMap converts the OS struct data to a map.
func (o OS) ToMap() map[string]interface{} {
return map[string]interface{}{
"login_shell": o.LoginShell.String(),
}
}

/*
EntryAttributes represents an entry's attributes. We use a struct
instead of a map for efficient memory allocation/deallocation,
Expand All @@ -68,12 +81,12 @@ to do something like
entry.SetAttributes(attr)
*/
type EntryAttributes struct {
atime time.Time
mtime time.Time
ctime time.Time
crtime time.Time
// TODO: make this OS, containing LoginShell and Platform
shell LoginShell
atime time.Time
mtime time.Time
ctime time.Time
crtime time.Time
os OS
hasOS bool // identifies that the OS struct has valid operating system information
mode os.FileMode
hasMode bool
size uint64
Expand Down Expand Up @@ -162,19 +175,20 @@ func (a *EntryAttributes) SetCrtime(crtime time.Time) *EntryAttributes {
return a
}

// HasLoginShell returns true if the entry uses a particular login shell
func (a *EntryAttributes) HasLoginShell() bool {
return a.shell != UnknownShell
// HasOS returns true if the entry has information about its OS
func (a *EntryAttributes) HasOS() bool {
return a.hasOS
}

// LoginShell returns the entry's login shell when using Exec
func (a *EntryAttributes) LoginShell() LoginShell {
return a.shell
// OS returns the entry's operating system information
func (a *EntryAttributes) OS() OS {
return a.os
}

// SetLoginShell sets the entry's login shell when using Exec
func (a *EntryAttributes) SetLoginShell(shell LoginShell) *EntryAttributes {
a.shell = shell
// SetOS sets the entry's operating system information
func (a *EntryAttributes) SetOS(os OS) *EntryAttributes {
a.os = os
a.hasOS = true
return a
}

Expand Down Expand Up @@ -228,8 +242,8 @@ func (a *EntryAttributes) ToMap() map[string]interface{} {
if a.HasCrtime() {
mp["crtime"] = a.Crtime()
}
if a.HasLoginShell() {
mp["loginshell"] = shellNames[a.LoginShell()]
if a.HasOS() {
mp["os"] = a.OS().ToMap()
}
if a.HasMode() {
// The mode string representation is the only portable representation. FileMode uses its own
Expand Down Expand Up @@ -290,17 +304,29 @@ func (a *EntryAttributes) UnmarshalJSON(data []byte) error {
}
a.SetCrtime(t)
}
if shell, ok := mp["loginshell"]; ok {
var sh LoginShell
for i, name := range shellNames {
if shell == name {
sh = LoginShell(i)
}
if obj, ok := mp["os"]; ok {
os, ok := obj.(map[string]interface{})
if !ok {
return attrMungeError("os", fmt.Errorf("os must be an object"))
}
if sh == UnknownShell {
return attrMungeError("shell", fmt.Errorf("provided unknown shell %v", shell))

var o OS
if obj, ok := os["login_shell"]; ok {
shell, ok := obj.(string)
if !ok {
return attrMungeError("os", fmt.Errorf("login_shell must be a string"))
}
for i, name := range shellNames {
if shell == name {
o.LoginShell = Shell(i)
}
}
if o.LoginShell == UnknownShell {
errTxt := "provided unknown login shell %v, must be %v or %v"
return attrMungeError("os", fmt.Errorf(errTxt, shell, PowerShell, POSIXShell))
}
}
a.SetLoginShell(sh)
a.SetOS(o)
}
if mode, ok := mp["mode"]; ok {
md, err := munge.ToUintMode(mode)
Expand Down
14 changes: 7 additions & 7 deletions plugin/entryAttributes_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -105,14 +105,14 @@ func (suite *EntryAttributesTestSuite) TestEntryAttributes() {
suite.Equal(expectedMp, attr.ToMap())
doUnmarshalJSONTests()

// Tests for login shell
suite.Equal(false, attr.HasLoginShell())
// Tests for OS
suite.Equal(false, attr.HasOS())
suite.Equal(expectedMp, attr.ToMap())
s := PowerShell
attr.SetLoginShell(s)
expectedMp["loginshell"] = "powershell"
suite.Equal(s, attr.LoginShell())
suite.Equal(true, attr.HasLoginShell())
o := OS{LoginShell: PowerShell}
attr.SetOS(o)
expectedMp["os"] = map[string]interface{}{"login_shell": "powershell"}
suite.Equal(o, attr.OS())
suite.Equal(true, attr.HasOS())
suite.Equal(expectedMp, attr.ToMap())
doUnmarshalJSONTests()

Expand Down
2 changes: 1 addition & 1 deletion plugin/gcp/computeInst.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ func newComputeInstance(inst *compute.Instance, c computeProjectService) *comput
SetPartialMetadata(inst).
Attributes().
SetCrtime(crtime).
SetLoginShell(plugin.POSIXShell)
SetOS(plugin.OS{LoginShell: plugin.POSIXShell})
return comp
}

Expand Down
6 changes: 3 additions & 3 deletions volume/fs.go
Original file line number Diff line number Diff line change
Expand Up @@ -213,10 +213,10 @@ func (d *FS) selectShellCommand(posix []string, power []string) []string {
}
}

func (d *FS) loginShell() plugin.LoginShell {
func (d *FS) loginShell() plugin.Shell {
attr := plugin.Attributes(d.executor)
if attr.HasLoginShell() {
return attr.LoginShell()
if shell := attr.OS().LoginShell; attr.HasOS() && shell != plugin.UnknownShell {
return shell
}
// Fallback to posix as a default
return plugin.POSIXShell
Expand Down

0 comments on commit 7909079

Please sign in to comment.