Skip to content

Commit

Permalink
Adding check in system-user verify flow to verify HAB uid (#8290)
Browse files Browse the repository at this point in the history
* Adding hab uid check in system-user verify flow

Signed-off-by: Arvinth C <arvinth.chandrasekaran@progress.com>

* Removing logconfig changes

Signed-off-by: Arvinth C <arvinth.chandrasekaran@progress.com>

* code coveragr

Signed-off-by: Arvinth C <arvinth.chandrasekaran@progress.com>

* refactoring for code smell and removing nil pointers

Signed-off-by: Arvinth C <arvinth.chandrasekaran@progress.com>

* Test coverage

Signed-off-by: Arvinth C <arvinth.chandrasekaran@progress.com>

* Review comments

Signed-off-by: Arvinth C <arvinth.chandrasekaran@progress.com>

---------

Signed-off-by: Arvinth C <arvinth.chandrasekaran@progress.com>
  • Loading branch information
ArvinthC3000 authored and swatiganesh committed Apr 16, 2024
1 parent 60190d2 commit a20031f
Show file tree
Hide file tree
Showing 7 changed files with 310 additions and 22 deletions.
54 changes: 53 additions & 1 deletion components/automate-cli/cmd/chef-automate/verify.go
Original file line number Diff line number Diff line change
Expand Up @@ -688,8 +688,9 @@ func (v *verifyCmdFlow) printResponse(batchCheckResults []models.BatchCheckResul
func buildReports(batchCheckResults []models.BatchCheckResult) []reporting.VerificationReport {
var reports []reporting.VerificationReport

for _, batchCheckResult := range batchCheckResults {
updatedReportForSystemUser(&batchCheckResults)

for _, batchCheckResult := range batchCheckResults {
for _, test := range batchCheckResult.Tests {

var errorMsgs, resolutionMsgs []string
Expand Down Expand Up @@ -751,6 +752,57 @@ func buildReports(batchCheckResults []models.BatchCheckResult) []reporting.Verif
return reports
}

func updatedReportForSystemUser(batchCheckResults *[]models.BatchCheckResult) {
isNFSCheckPresent := false
uids := []string{}

for _, batchCheckResult := range *batchCheckResults {
// Check all IDs
for _, test := range batchCheckResult.Tests {
if test.Check == constants.NFS_BACKUP_CONFIG && !test.Skipped {
isNFSCheckPresent = true
}
if test.Check == constants.SYSTEM_USER {
if len(test.Checks) == 0 {
continue
}
if !arrayutils.Contains(uids, test.Id.UserID) {
uids = append(uids, test.Id.UserID)
}

}
}
}

for _, batchCheckResult := range *batchCheckResults {
if isNFSCheckPresent {
for i, test := range batchCheckResult.Tests {
if test.Check == constants.SYSTEM_USER {
var newCheck models.Checks
if len(uids) == 1 {
newCheck = models.Checks{
Title: "User ID - validation",
Passed: true,
SuccessMsg: "hab uids are same across all nodes",
Skipped: false,
}
} else {
newCheck = models.Checks{
Title: "User ID - validation",
Passed: false,
ErrorMsg: fmt.Sprintf("hab uid: %s. hab uid is not same across all nodes", test.Id.UserID),
ResolutionMsg: "hab uid should be same across all nodes/machines",
Skipped: false,
}
batchCheckResult.Tests[i].Passed = false
}
batchCheckResult.Tests[i].Checks = append(batchCheckResult.Tests[i].Checks, newCheck)
}
}
}
}
}

func createTables(numberOfAutomateNodes, numberOfChefServerNodes, numberOfPostgreSQLNodes, numberOfOpenSearchNodes int) map[string]*reporting.Table {
bastionSummaryTableTitle := "Summary: Bastion <Node> - 1"
automateSummaryTableTitle := fmt.Sprintf("Summary: Automate <Nodes> - %d", numberOfAutomateNodes)
Expand Down
172 changes: 167 additions & 5 deletions components/automate-cli/cmd/chef-automate/verify_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,11 +20,14 @@ import (
)

const (
CONFIG_FILE = "/config_valid_config_parser.toml"
STATUS_API_RESPONSE = `{"status":"SUCCESS","result":{"status":"OK","services":[],"cli_version":"20230622174936","error":"error getting services from hab svc status"}}`
BATCH_CHECK_REQUEST = `{"status":"SUCCESS","result":{"passed":true,"node_result":[]}}`
AWS_CONFIG_FILE = "/valid_config.toml"
DARWIN = "darwin"
CONFIG_FILE = "/config_valid_config_parser.toml"
STATUS_API_RESPONSE = `{"status":"SUCCESS","result":{"status":"OK","services":[],"cli_version":"20230622174936","error":"error getting services from hab svc status"}}`
BATCH_CHECK_REQUEST = `{"status":"SUCCESS","result":{"passed":true,"node_result":[]}}`
BATCH_CHECK_REQUEST_HAB_ID_WITH_NFS = `{"status":"SUCCESS","result":{"passed":true,"node_result":[{"node_type":"opensearch","ip":"10.0.164.66","tests":[{"passed":true,"msg":"System User Check","check":"system-user","checks":[{"title":"User creation/validation check","passed":true,"success_msg":"User is created or found successfully","skipped":false}],"skipped":false,"id":{"user_id":"1001","group_id":"1001"}},{"passed": true,"msg": "NFS Backup Config Check","check": "nfs-backup-config"}]},{"node_type":"opensearch","ip":"10.0.133.98","tests":[{"passed":true,"msg":"System User Check","check":"system-user","checks":[{"title":"User creation/validation check","passed":true,"success_msg":"User is created or found successfully","skipped":false}],"skipped":false,"id":{"user_id":"1001","group_id":"1001"}}]},{"node_type":"opensearch","ip":"10.0.146.192","tests":[{"passed":true,"msg":"System User Check","check":"system-user","checks":[{"title":"User creation/validation check","passed":true,"success_msg":"User is created or found successfully","skipped":false}],"skipped":false,"id":{"user_id":"1001","group_id":"1001"}}]},{"node_type":"chef-infra-server","ip":"10.0.128.167","tests":[{"passed":true,"msg":"System User Check","check":"system-user","checks":[{"title":"User creation/validation check","passed":true,"success_msg":"User is created or found successfully","skipped":false}],"skipped":false,"id":{"user_id":"1001","group_id":"1001"}}]},{"node_type":"automate","ip":"10.0.130.38","tests":[{"passed":true,"msg":"System User Check","check":"system-user","checks":[{"title":"User creation/validation check","passed":true,"success_msg":"User is created or found successfully","skipped":false}],"skipped":false,"id":{"user_id":"1001","group_id":"1001"}}]},{"node_type":"postgresql","ip":"10.0.139.234","tests":[{"passed":true,"msg":"System User Check","check":"system-user","checks":[{"title":"User creation/validation check","passed":true,"success_msg":"User is created or found successfully","skipped":false}],"skipped":false,"id":{"user_id":"1001","group_id":"1001"}}]},{"node_type":"postgresql","ip":"10.0.168.59","tests":[{"passed":true,"msg":"System User Check","check":"system-user","checks":[{"title":"User creation/validation check","passed":true,"success_msg":"User is created or found successfully","skipped":false}],"skipped":false,"id":{"user_id":"1001","group_id":"1001"}}]},{"node_type":"postgresql","ip":"10.0.159.200","tests":[{"passed":true,"msg":"System User Check","check":"system-user","checks":[{"title":"User creation/validation check","passed":true,"success_msg":"User is created or found successfully","skipped":false}],"skipped":false,"id":{"user_id":"1001","group_id":"1001"}}]}]}}`
BATCH_CHECK_REQUEST_HAB_ID_WITH_NFS_FAILURE = `{"status":"SUCCESS","result":{"passed":true,"node_result":[{"node_type":"opensearch","ip":"10.0.164.66","tests":[{"passed":true,"msg":"System User Check","check":"system-user","checks":[{"title":"User creation/validation check","passed":true,"success_msg":"User is created or found successfully","skipped":false}],"skipped":false,"id":{"user_id":"1001","group_id":"1001"}},{"passed": true,"msg": "NFS Backup Config Check","check": "nfs-backup-config"}]},{"node_type":"opensearch","ip":"10.0.133.98","tests":[{"passed":true,"msg":"System User Check","check":"system-user","checks":[{"title":"User creation/validation check","passed":true,"success_msg":"User is created or found successfully","skipped":false}],"skipped":false,"id":{"user_id":"1001","group_id":"1001"}}]},{"node_type":"opensearch","ip":"10.0.146.192","tests":[{"passed":true,"msg":"System User Check","check":"system-user","checks":[{"title":"User creation/validation check","passed":true,"success_msg":"User is created or found successfully","skipped":false}],"skipped":false,"id":{"user_id":"1002","group_id":"1002"}}]},{"node_type":"chef-infra-server","ip":"10.0.128.167","tests":[{"passed":true,"msg":"System User Check","check":"system-user","checks":[{"title":"User creation/validation check","passed":true,"success_msg":"User is created or found successfully","skipped":false}],"skipped":false,"id":{"user_id":"1001","group_id":"1001"}}]},{"node_type":"automate","ip":"10.0.130.38","tests":[{"passed":true,"msg":"System User Check","check":"system-user","checks":[{"title":"User creation/validation check","passed":true,"success_msg":"User is created or found successfully","skipped":false}],"skipped":false,"id":{"user_id":"1001","group_id":"1001"}}]},{"node_type":"postgresql","ip":"10.0.139.234","tests":[{"passed":true,"msg":"System User Check","check":"system-user","checks":[{"title":"User creation/validation check","passed":true,"success_msg":"User is created or found successfully","skipped":false}],"skipped":false,"id":{"user_id":"1001","group_id":"1001"}}]},{"node_type":"postgresql","ip":"10.0.168.59","tests":[{"passed":true,"msg":"System User Check","check":"system-user","checks":[{"title":"User creation/validation check","passed":true,"success_msg":"User is created or found successfully","skipped":false}],"skipped":false,"id":{"user_id":"1001","group_id":"1001"}}]},{"node_type":"postgresql","ip":"10.0.159.200","tests":[{"passed":true,"msg":"System User Check","check":"system-user","checks":[{"title":"User creation/validation check","passed":true,"success_msg":"User is created or found successfully","skipped":false}],"skipped":false,"id":{"user_id":"1001","group_id":"1001"}}]}]}}`
BATCH_CHECK_REQUEST_HAB_ID_WITH_NFS_FAILURE_2 = `{"status":"SUCCESS","result":{"passed":true,"node_result":[{"node_type":"opensearch","ip":"10.0.164.66","tests":[{"passed":true,"msg":"System User Check","check":"system-user","checks":[],"skipped":false,"id":{"user_id":"1001","group_id":"1001"}},{"passed": true,"msg": "NFS Backup Config Check","check": "nfs-backup-config"}]},{"node_type":"opensearch","ip":"10.0.133.98","tests":[{"passed":true,"msg":"System User Check","check":"system-user","checks":[],"skipped":false,"id":{"user_id":"1001","group_id":"1001"}}]}]}}`
AWS_CONFIG_FILE = "/valid_config.toml"
DARWIN = "darwin"
)

var AwsAutoTfvarsJsonStringEmpty = `
Expand Down Expand Up @@ -375,6 +378,165 @@ func TestRunVerifyCmd(t *testing.T) {
configFile: "",
wantErr: errors.New("Failed to populate HA common config"),
},
{
description: "bastion with aws automate-verify to check hab if with NFS - failure",
IsAws: true,
mockHttputils: &httputils.MockHTTPClient{
MakeRequestFunc: func(requestMethod, url string, body interface{}) (*http.Response, []byte, error) {
if strings.Contains(url, "batch-check") {
return &http.Response{
StatusCode: http.StatusOK,
Body: nil,
}, []byte(BATCH_CHECK_REQUEST_HAB_ID_WITH_NFS_FAILURE), nil
}
return &http.Response{
StatusCode: http.StatusOK,
Body: nil,
}, []byte(STATUS_API_RESPONSE), nil
},
},
mockCreateSystemdService: &verifysystemdcreate.MockCreateSystemdService{
CreateFun: func() error {
return nil
},
},
mockSystemdCreateUtils: &verifysystemdcreate.MockSystemdCreateUtils{
GetBinaryPathFunc: func() (string, error) {
return "", nil
},
},
mockSSHUtil: &sshutils.MockSSHUtilsImpl{
ExecuteConcurrentlyFunc: func(sshConfig sshutils.SSHConfig, cmd string, hostIPs []string) []sshutils.Result {
return []sshutils.Result{
{
HostIP: "",
Error: nil,
Output: "",
},
}
},
CopyFileToRemoteConcurrentlyFunc: func(sshConfig sshutils.SSHConfig, srcFilePath string, destFileName string, destDir string, removeFile bool, hostIPs []string) []sshutils.Result {
return []sshutils.Result{
{
HostIP: "",
Error: nil,
Output: "",
},
}
},
},
configFile: CONFIG_AWS_TOML_PATH + AWS_CONFIG_FILE,
wantErr: nil,
ConvTfvarToJsonFunc: func(string) string {
return AwsAutoTfvarsJsonStringEmpty
},
},
{
description: "bastion with aws automate-verify to check hab if with NFS - failure_2",
IsAws: true,
mockHttputils: &httputils.MockHTTPClient{
MakeRequestFunc: func(requestMethod, url string, body interface{}) (*http.Response, []byte, error) {
if strings.Contains(url, "batch-check") {
return &http.Response{
StatusCode: http.StatusOK,
Body: nil,
}, []byte(BATCH_CHECK_REQUEST_HAB_ID_WITH_NFS_FAILURE_2), nil
}
return &http.Response{
StatusCode: http.StatusOK,
Body: nil,
}, []byte(STATUS_API_RESPONSE), nil
},
},
mockCreateSystemdService: &verifysystemdcreate.MockCreateSystemdService{
CreateFun: func() error {
return nil
},
},
mockSystemdCreateUtils: &verifysystemdcreate.MockSystemdCreateUtils{
GetBinaryPathFunc: func() (string, error) {
return "", nil
},
},
mockSSHUtil: &sshutils.MockSSHUtilsImpl{
ExecuteConcurrentlyFunc: func(sshConfig sshutils.SSHConfig, cmd string, hostIPs []string) []sshutils.Result {
return []sshutils.Result{
{
HostIP: "",
Error: nil,
Output: "",
},
}
},
CopyFileToRemoteConcurrentlyFunc: func(sshConfig sshutils.SSHConfig, srcFilePath string, destFileName string, destDir string, removeFile bool, hostIPs []string) []sshutils.Result {
return []sshutils.Result{
{
HostIP: "",
Error: nil,
Output: "",
},
}
},
},
configFile: CONFIG_AWS_TOML_PATH + AWS_CONFIG_FILE,
wantErr: nil,
ConvTfvarToJsonFunc: func(string) string {
return AwsAutoTfvarsJsonStringEmpty
},
},
{
description: "bastion with aws automate-verify to check hab if with NFS - success",
IsAws: true,
mockHttputils: &httputils.MockHTTPClient{
MakeRequestFunc: func(requestMethod, url string, body interface{}) (*http.Response, []byte, error) {
if strings.Contains(url, "batch-check") {
return &http.Response{
StatusCode: http.StatusOK,
Body: nil,
}, []byte(BATCH_CHECK_REQUEST_HAB_ID_WITH_NFS), nil
}
return &http.Response{
StatusCode: http.StatusOK,
Body: nil,
}, []byte(STATUS_API_RESPONSE), nil
},
},
mockCreateSystemdService: &verifysystemdcreate.MockCreateSystemdService{
CreateFun: func() error {
return nil
},
},
mockSystemdCreateUtils: &verifysystemdcreate.MockSystemdCreateUtils{
GetBinaryPathFunc: func() (string, error) {
return "", nil
},
},
mockSSHUtil: &sshutils.MockSSHUtilsImpl{
ExecuteConcurrentlyFunc: func(sshConfig sshutils.SSHConfig, cmd string, hostIPs []string) []sshutils.Result {
return []sshutils.Result{
{
HostIP: "",
Error: nil,
Output: "",
},
}
},
CopyFileToRemoteConcurrentlyFunc: func(sshConfig sshutils.SSHConfig, srcFilePath string, destFileName string, destDir string, removeFile bool, hostIPs []string) []sshutils.Result {
return []sshutils.Result{
{
HostIP: "",
Error: nil,
Output: "",
},
}
},
},
configFile: CONFIG_AWS_TOML_PATH + AWS_CONFIG_FILE,
wantErr: nil,
ConvTfvarToJsonFunc: func(string) string {
return AwsAutoTfvarsJsonStringEmpty
},
},
}

for _, tt := range tests {
Expand Down
15 changes: 8 additions & 7 deletions components/automate-cli/pkg/verifyserver/models/batchcheck.go
Original file line number Diff line number Diff line change
Expand Up @@ -521,13 +521,14 @@ type CheckTriggerResponse struct {
CheckType string `json:"check_type"`
}
type ApiResult struct {
Passed bool `json:"passed"`
Message string `json:"msg"`
Check string `json:"check"`
Checks []Checks `json:"checks"`
Error *fiber.Error `json:"error,omitempty"`
Skipped bool `json:"skipped"`
SkipMessage string `json:"skip_message,omitempty"`
Passed bool `json:"passed"`
Message string `json:"msg"`
Check string `json:"check"`
Checks []Checks `json:"checks"`
Error *fiber.Error `json:"error,omitempty"`
Skipped bool `json:"skipped"`
SkipMessage string `json:"skip_message,omitempty"`
Id *SystemUserID `json:"id,omitempty"`
}

type Checks struct {
Expand Down
10 changes: 8 additions & 2 deletions components/automate-cli/pkg/verifyserver/models/systemuser.go
Original file line number Diff line number Diff line change
@@ -1,6 +1,12 @@
package models

type SystemUserResponse struct {
Passed bool `json:"passed"`
Checks []*Checks `json:"checks"`
Passed bool `json:"passed"`
Checks []*Checks `json:"checks"`
Id *SystemUserID `json:"id,omitempty"`
}

type SystemUserID struct {
UserID string `json:"user_id,omitempty"`
GroupID string `json:"group_id,omitempty"`
}
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ type SystemUserServiceImp struct {
}

func NewSystemUserService(log logger.Logger, exec executil.ExecCmdService, user userutils.UserUtil) *SystemUserServiceImp {
return &SystemUserServiceImp {
return &SystemUserServiceImp{
exec: exec,
user: user,
Log: log,
Expand All @@ -36,6 +36,16 @@ func (su *SystemUserServiceImp) GetSystemUserServiceDetails() *models.SystemUser
serviceResponse.Passed = false
}

// Gets UID for created/existing hab user
uid, err := su.getUserAndGroupID()
if err != nil {
serviceResponse.Passed = false
su.Log.Error("User ID for hab not found")
}
su.Log.Info("User ID for hab found")

serviceResponse.Id = uid

habGroupResponse := su.ValidateHabGroup()
if !habGroupResponse.Passed {
serviceResponse.Passed = false
Expand Down Expand Up @@ -81,6 +91,28 @@ func (su *SystemUserServiceImp) ValidateOrCreateHabUser() (*models.Checks, bool)
return successResponse(constants.SYSTEM_USER_HAB_VALIDATION_SUCCESS_TITLE, constants.SYSTEM_USER_HAB_SUCCESS_MSG), false
}

func (su *SystemUserServiceImp) getUserAndGroupID() (*models.SystemUserID, error) {

systemUserDetails := &models.SystemUserID{}

// Check for available ID in all machine (?)
ids, err := su.user.Lookup(constants.USER_NAME)
if err != nil {
su.Log.Error("User not found:", err)
return systemUserDetails, err
}

if ids != nil {
systemUserDetails.UserID = ids.Uid
systemUserDetails.GroupID = ids.Gid
su.Log.Infof("UID: %s\nGID: %s\n", systemUserDetails.UserID, systemUserDetails.GroupID)
} else {
su.Log.Info("UID not found.")
}
su.Log.Info("Created 'hab' user and group ")
return systemUserDetails, nil
}

func (su *SystemUserServiceImp) ValidateHabGroup() *models.Checks {
isHabGroupPresent := su.isHabGroupPresent(constants.GROUP_NAME)

Expand Down Expand Up @@ -146,7 +178,7 @@ func (su *SystemUserServiceImp) checkUserPrimaryGroup(username, groupname string
su.Log.Debug("User's primary group is not hab")
return false
}
su.Log.Debug("User's primary group is hab with gid '"+ sysUser.Gid+"'")
su.Log.Debug("User's primary group is hab with gid '" + sysUser.Gid + "'")
return true
}

Expand Down
Loading

0 comments on commit a20031f

Please sign in to comment.