diff --git a/pkg/hostman/guestfs/fsdriver/interface.go b/pkg/hostman/guestfs/fsdriver/interface.go index 77475b2048..48481c51a9 100644 --- a/pkg/hostman/guestfs/fsdriver/interface.go +++ b/pkg/hostman/guestfs/fsdriver/interface.go @@ -34,7 +34,7 @@ type IDiskPartition interface { Exists(sPath string, caseInsensitive bool) bool Chown(sPath string, uid, gid int, caseInsensitive bool) error Chmod(sPath string, mode uint32, caseInsensitive bool) error - UserAdd(user, homeDir string, caseInsensitive bool, isSys bool) error + CheckOrAddUser(user, homeDir string, isSys bool) (realHomeDir string, err error) Stat(sPath string, caseInsensitive bool) os.FileInfo Symlink(src, dst string, caseInsensitive bool) error diff --git a/pkg/hostman/guestfs/fsdriver/linux.go b/pkg/hostman/guestfs/fsdriver/linux.go index 70f08e2073..3804fb7540 100644 --- a/pkg/hostman/guestfs/fsdriver/linux.go +++ b/pkg/hostman/guestfs/fsdriver/linux.go @@ -95,7 +95,7 @@ func (l *sLinuxRootFs) DeployHosts(rootFs IDiskPartition, hostname, domain strin func (l *sLinuxRootFs) GetLoginAccount(rootFs IDiskPartition, sUser string, defaultRootUser bool, windowsDefaultAdminUser bool) (string, error) { if len(sUser) > 0 { - if err := rootFs.UserAdd(sUser, "", false, false); err != nil && !strings.Contains(err.Error(), "already exists") { + if _, err := rootFs.CheckOrAddUser(sUser, "", false); err != nil && !strings.Contains(err.Error(), "already exists") { return "", fmt.Errorf("UserAdd %s: %v", sUser, err) } if err := l.EnableUserSudo(rootFs, sUser); err != nil { @@ -156,11 +156,13 @@ func (l *sLinuxRootFs) DeployYunionroot(rootFs IDiskPartition, pubkeys *deployap } var yunionroot = YUNIONROOT_USER rootdir := path.Join(cloudrootDirectory, yunionroot) - if err := rootFs.UserAdd(yunionroot, cloudrootDirectory, false, true); err != nil && !strings.Contains(err.Error(), "already exists") { - log.Errorf("UserAdd %s: %v", yunionroot, err) + var err error + if rootdir, err = rootFs.CheckOrAddUser(yunionroot, cloudrootDirectory, true); err != nil { + return errors.Wrap(err, "unable to CheckOrAddUser") } - err := DeployAuthorizedKeys(rootFs, rootdir, pubkeys, true) + err = DeployAuthorizedKeys(rootFs, rootdir, pubkeys, true) if err != nil { + log.Infof("DeployAuthorizedKeys error: %s", err.Error()) return fmt.Errorf("DeployAuthorizedKeys: %v", err) } if err := l.EnableUserSudo(rootFs, yunionroot); err != nil { diff --git a/pkg/hostman/guestfs/kvmpart/localfs.go b/pkg/hostman/guestfs/kvmpart/localfs.go index 6edd1199aa..1ec2a31a66 100644 --- a/pkg/hostman/guestfs/kvmpart/localfs.go +++ b/pkg/hostman/guestfs/kvmpart/localfs.go @@ -222,7 +222,38 @@ func (f *SLocalGuestFS) Chmod(sPath string, mode uint32, caseInsensitive bool) e return nil } -func (f *SLocalGuestFS) UserAdd(user, homeDir string, caseInsensitive bool, isSys bool) error { +func (f *SLocalGuestFS) CheckOrAddUser(user, homeDir string, isSys bool) (realHomeDir string, err error) { + var exist bool + if exist, realHomeDir, err = f.checkUser(user); err != nil || exist { + return + } + return path.Join(homeDir, user), f.userAdd(user, homeDir, isSys) +} + +func (f *SLocalGuestFS) checkUser(user string) (exist bool, homeDir string, err error) { + cmd := []string{"chroot", f.mountPath, "cat", "/etc/passwd"} + command := procutils.NewCommand(cmd[0], cmd[1:]...) + output, err := command.Output() + if err != nil { + return + } + lines := strings.Split(strings.TrimSpace(string(output)), "\n") + for i := len(lines) - 1; i >= 0; i-- { + userInfos := strings.Split(strings.TrimSpace(lines[i]), ":") + if len(userInfos) < 6 { + continue + } + if userInfos[0] != user { + continue + } + exist = true + homeDir = userInfos[5] + break + } + return +} + +func (f *SLocalGuestFS) userAdd(user, homeDir string, isSys bool) error { if err := f.Mkdir(homeDir, 0755, false); err != nil { return errors.Wrap(err, "Mkdir") } diff --git a/pkg/hostman/guestfs/sshpart/sshpart.go b/pkg/hostman/guestfs/sshpart/sshpart.go index 5193e9a4bc..f1de51dccb 100644 --- a/pkg/hostman/guestfs/sshpart/sshpart.go +++ b/pkg/hostman/guestfs/sshpart/sshpart.go @@ -395,7 +395,37 @@ func (p *SSHPartition) Remove(sPath string, caseInsensitive bool) { } } -func (p *SSHPartition) UserAdd(user, homeDir string, caseInsensitive bool, isSys bool) error { +func (p *SSHPartition) CheckOrAddUser(user, homeDir string, isSys bool) (realHomeDir string, err error) { + var exist bool + if exist, realHomeDir, err = p.checkUser(user); err != nil || exist { + return + } + return path.Join(homeDir, user), p.userAdd(user, homeDir, isSys) +} + +func (p *SSHPartition) checkUser(user string) (exist bool, homeDir string, err error) { + cmd := fmt.Sprintf("/usr/sbin/chroot %s /usr/bin/cat /etc/passwd", p.mountPath) + lines, err := p.term.Run(cmd) + if err != nil { + return + } + log.Debugf("exec command 'cat /etc/passwd', output: %v", lines) + for i := len(lines) - 1; i >= 0; i-- { + userInfos := strings.Split(strings.TrimSpace(lines[i]), ":") + if len(userInfos) < 6 { + continue + } + if userInfos[0] != user { + continue + } + exist = true + homeDir = userInfos[5] + break + } + return +} + +func (p *SSHPartition) userAdd(user, homeDir string, isSys bool) error { cmd := fmt.Sprintf("/usr/sbin/chroot %s /usr/sbin/useradd -m -s /bin/bash %s", p.mountPath, user) if isSys { cmd += " -r"