diff --git a/resources/file.go b/resources/file.go index 21b2211a..e2eb88b0 100644 --- a/resources/file.go +++ b/resources/file.go @@ -26,7 +26,6 @@ import ( "io/ioutil" "log" "os" - "os/user" "path" "path/filepath" "strconv" @@ -97,11 +96,11 @@ func (obj *FileRes) Validate() error { } } - if _, err := obj.uid(); obj.Owner != "" && err != nil { + if _, err := GetUID(obj.Owner); obj.Owner != "" && err != nil { return err } - if _, err := obj.gid(); obj.Group != "" && err != nil { + if _, err := GetGID(obj.Group); obj.Group != "" && err != nil { return err } @@ -124,22 +123,6 @@ func (obj *FileRes) mode() (os.FileMode, error) { return os.FileMode(m), nil } -// uid returns the user id for the owner specified in the yaml file graph. -// Caller should first check obj.Owner is not empty -func (obj *FileRes) uid() (int, error) { - u2, err2 := user.LookupId(obj.Owner) - if err2 == nil { - return strconv.Atoi(u2.Uid) - } - - u, err := user.Lookup(obj.Owner) - if err == nil { - return strconv.Atoi(u.Uid) - } - - return -1, errwrap.Wrapf(err, "owner lookup error (%s)", obj.Owner) -} - // Init runs some startup code for this resource. func (obj *FileRes) Init() error { obj.sha256sum = "" @@ -767,7 +750,7 @@ func (obj *FileRes) chownCheckApply(apply bool) (checkOK bool, _ error) { } if obj.Owner != "" { - expectedUID, err = obj.uid() + expectedUID, err = GetUID(obj.Owner) if err != nil { return false, err } @@ -777,7 +760,7 @@ func (obj *FileRes) chownCheckApply(apply bool) (checkOK bool, _ error) { } if obj.Group != "" { - expectedGID, err = obj.gid() + expectedGID, err = GetGID(obj.Group) if err != nil { return false, err } diff --git a/resources/file_attrs.go b/resources/file_attrs.go deleted file mode 100644 index 4d524091..00000000 --- a/resources/file_attrs.go +++ /dev/null @@ -1,43 +0,0 @@ -// Mgmt -// Copyright (C) 2013-2017+ James Shubin and the project contributors -// Written by James Shubin and the project contributors -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -// +build go1.7 - -package resources - -import ( - "os/user" - "strconv" - - errwrap "github.com/pkg/errors" -) - -// gid returns the group id for the group specified in the yaml file graph. -// Caller should first check obj.Group is not empty -func (obj *FileRes) gid() (int, error) { - g2, err2 := user.LookupGroupId(obj.Group) - if err2 == nil { - return strconv.Atoi(g2.Gid) - } - - g, err := user.LookupGroup(obj.Group) - if err == nil { - return strconv.Atoi(g.Gid) - } - - return -1, errwrap.Wrapf(err, "Group lookup error (%s)", obj.Group) -} diff --git a/resources/file_attrs_go1.6.go b/resources/file_attrs_go1.6.go deleted file mode 100644 index 03303bda..00000000 --- a/resources/file_attrs_go1.6.go +++ /dev/null @@ -1,43 +0,0 @@ -// Mgmt -// Copyright (C) 2013-2017+ James Shubin and the project contributors -// Written by James Shubin and the project contributors -// -// This program is free software: you can redistribute it and/or modify -// it under the terms of the GNU General Public License as published by -// the Free Software Foundation, either version 3 of the License, or -// (at your option) any later version. -// -// This program is distributed in the hope that it will be useful, -// but WITHOUT ANY WARRANTY; without even the implied warranty of -// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -// GNU General Public License for more details. -// -// You should have received a copy of the GNU General Public License -// along with this program. If not, see . - -// +build !go1.7 - -package resources - -import ( - "strconv" - - group "github.com/hnakamur/group" - errwrap "github.com/pkg/errors" -) - -// gid returns the group id for the group specified in the yaml file graph. -// Caller should first check obj.Group is not empty -func (obj *FileRes) gid() (int, error) { - g2, err2 := group.LookupId(obj.Group) - if err2 == nil { - return strconv.Atoi(g2.Gid) - } - - g, err := group.Lookup(obj.Group) - if err == nil { - return strconv.Atoi(g.Gid) - } - - return -1, errwrap.Wrapf(err, "Group lookup error (%s)", obj.Group) -} diff --git a/resources/util.go b/resources/util.go index be40d147..92b1796f 100644 --- a/resources/util.go +++ b/resources/util.go @@ -22,8 +22,10 @@ import ( "encoding/base64" "encoding/gob" "fmt" + "os/user" "reflect" "sort" + "strconv" "strings" errwrap "github.com/pkg/errors" @@ -133,3 +135,37 @@ func LowerStructFieldNameToFieldName(res Res) (map[string]string, error) { } return result, nil } + +// GetUID returns the UID of an user. It supports an UID or an username. Caller +// should first check user is not empty. It will return an error if it can't +// lookup the UID or username. +func GetUID(username string) (int, error) { + userObj, err := user.LookupId(username) + if err == nil { + return strconv.Atoi(userObj.Uid) + } + + userObj, err = user.Lookup(username) + if err == nil { + return strconv.Atoi(userObj.Gid) + } + + return -1, errwrap.Wrapf(err, "user lookup error (%s)", username) +} + +// GetGID returns the GID of a group. It supports a GID or a group name. Caller +// should first check group is not empty. It will return an error if it can't +// lookup the GID or group name. +func GetGID(group string) (int, error) { + groupObj, err := user.LookupGroupId(group) + if err == nil { + return strconv.Atoi(groupObj.Gid) + } + + groupObj, err = user.LookupGroup(group) + if err == nil { + return strconv.Atoi(groupObj.Gid) + } + + return -1, errwrap.Wrapf(err, "group lookup error (%s)", group) +} diff --git a/resources/util_test.go b/resources/util_test.go index 8bef2910..027a02d9 100644 --- a/resources/util_test.go +++ b/resources/util_test.go @@ -21,7 +21,9 @@ import ( "bytes" "encoding/base64" "encoding/gob" + "os/user" "reflect" + "strconv" "testing" ) @@ -236,3 +238,79 @@ func TestLowerStructFieldNameToFieldName1(t *testing.T) { return } } + +func TestUnknownGroup(t *testing.T) { + gid, err := GetGID("unknowngroup") + if err == nil { + t.Errorf("expected failure, but passed with: %d", gid) + } +} + +func TestUnknownUser(t *testing.T) { + uid, err := GetUID("unknownuser") + if err == nil { + t.Errorf("expected failure, but passed with: %d", uid) + } +} + +func TestCurrentUserGroupByName(t *testing.T) { + // get current user + userObj, err := user.Current() + if err != nil { + t.Errorf("error trying to lookup current user: %s", err.Error()) + } + + currentUID := userObj.Uid + currentGID := userObj.Gid + + var uid int + var gid int + + // now try to get the uid/gid via our API (via username and group name) + if uid, err = GetUID(userObj.Username); err != nil { + t.Errorf("error trying to lookup current user UID: %s", err.Error()) + } + + if strconv.Itoa(uid) != currentUID { + t.Errorf("uid didn't match current user's: %s vs %s", strconv.Itoa(uid), currentUID) + } + + if gid, err = GetGID(userObj.Username); err != nil { + t.Errorf("error trying to lookup current user UID: %s", err.Error()) + } + + if strconv.Itoa(gid) != currentGID { + t.Errorf("gid didn't match current user's: %s vs %s", strconv.Itoa(gid), currentGID) + } +} + +func TestCurrentUserGroupById(t *testing.T) { + // get current user + userObj, err := user.Current() + if err != nil { + t.Errorf("error trying to lookup current user: %s", err.Error()) + } + + currentUID := userObj.Uid + currentGID := userObj.Gid + + var uid int + var gid int + + // now try to get the uid/gid via our API (via uid and gid) + if uid, err = GetUID(currentUID); err != nil { + t.Errorf("error trying to lookup current user UID: %s", err.Error()) + } + + if strconv.Itoa(uid) != currentUID { + t.Errorf("uid didn't match current user's: %s vs %s", strconv.Itoa(uid), currentUID) + } + + if gid, err = GetGID(currentGID); err != nil { + t.Errorf("error trying to lookup current user UID: %s", err.Error()) + } + + if strconv.Itoa(gid) != currentGID { + t.Errorf("gid didn't match current user's: %s vs %s", strconv.Itoa(gid), currentGID) + } +}