Skip to content

Commit

Permalink
fix: 处理init/sidecar容器客户端与业务容器用户/用户组不一致的问题
Browse files Browse the repository at this point in the history
  • Loading branch information
Ambition9186 committed Oct 30, 2024
1 parent a5ae47e commit 3daf49b
Show file tree
Hide file tree
Showing 6 changed files with 231 additions and 5 deletions.
2 changes: 1 addition & 1 deletion build/initContainer/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
FROM alpine:3.18.3

RUN apk --update --no-cache add ca-certificates bash vim curl python3 tzdata rsync
RUN apk --update --no-cache add ca-certificates bash vim curl python3 tzdata rsync shadow

# users:x:100:games already created by system
RUN mkdir -p /data/home && \
Expand Down
2 changes: 1 addition & 1 deletion build/sidecar/Dockerfile
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
FROM alpine:3.18.3

RUN apk --update --no-cache add ca-certificates bash vim curl python3 tzdata rsync
RUN apk --update --no-cache add ca-certificates bash vim curl python3 tzdata rsync shadow

# users:x:100:games already created by system
RUN mkdir -p /data/home && \
Expand Down
30 changes: 29 additions & 1 deletion client/client.go
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,9 @@ func New(opts ...Option) (Client, error) {
if err = initKvCache(clientOpt); err != nil {
return nil, err
}
if err = initPermissionCache(clientOpt); err != nil {
return nil, err
}

watcher, err := newWatcher(u, clientOpt)
if err != nil {
Expand Down Expand Up @@ -192,6 +195,30 @@ func initKvCache(opts *options) error {
return nil
}

// initPermissionCache init permission cache
func initPermissionCache(opts *options) error {

if err := cache.InitMemCache(opts.kvCache.ThresholdMB); err != nil {
return fmt.Errorf("init permission cache failed, err: %s", err.Error())
}

go func() {
mc := cache.GetMemCache()
for {
hit, miss, kvCnt := mc.Stats().Hits, mc.Stats().Misses, mc.Len()
var hitRatio float64
if hit+miss > 0 {
hitRatio = float64(hit) / float64(hit+miss)
}
slog.Debug("kv cache statistics", slog.Int64("hit", hit), slog.Int64("miss", miss),
slog.String("hit-ratio", fmt.Sprintf("%.3f", hitRatio)), slog.Int("kv-count", kvCnt))
time.Sleep(time.Second * 15)
}
}()

return nil
}

// AddWatcher add a watcher to client
func (c *client) AddWatcher(callback Callback, app string, opts ...AppOption) error {
_ = c.watcher.Subscribe(callback, app, opts...)
Expand Down Expand Up @@ -219,7 +246,8 @@ func (c *client) ResetLabels(labels map[string]string) {
}

// PullFiles pull files from remote
func (c *client) PullFiles(app string, opts ...AppOption) (*Release, error) { // nolint
// nolint:funlen
func (c *client) PullFiles(app string, opts ...AppOption) (*Release, error) {
option := &AppOptions{}
for _, opt := range opts {
opt(option)
Expand Down
12 changes: 12 additions & 0 deletions client/types.go
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ import (
"path/filepath"
"runtime"
"strings"
"sync"
"sync/atomic"
"time"

Expand Down Expand Up @@ -571,6 +572,7 @@ func updateFiles(filesDir string, files []*ConfigItemFile, successDownloads *int
var success, failed, skip int32
g, _ := errgroup.WithContext(context.Background())
g.SetLimit(updateFileConcurrentLimit)
var mu sync.Mutex
for _, f := range files {
file := f
g.Go(func() error {
Expand Down Expand Up @@ -612,12 +614,22 @@ func updateFiles(filesDir string, files []*ConfigItemFile, successDownloads *int
return err
}
}

// 5. set file permission
if runtime.GOOS != "windows" {
mu.Lock()
// 如果是 sidecar 需要创建用户权限组
if version.CLIENTTYPE == string(sfs.Sidecar) {
if err := util.SetUserAndUserGroup(file.FileMeta.ConfigItemSpec.Permission); err != nil {
logger.Warn("set user permission failed", slog.String("file", filePath), logger.ErrAttr(err))
}
}
if err := util.SetFilePermission(filePath, file.FileMeta.ConfigItemSpec.Permission); err != nil {
logger.Warn("set file permission failed", slog.String("file", filePath), logger.ErrAttr(err))
}
mu.Unlock()
}

atomic.AddInt32(successDownloads, 1)
atomic.AddUint64(successFileSize, file.FileMeta.ContentSpec.ByteSize)
semaphoreCh <- struct{}{}
Expand Down
3 changes: 2 additions & 1 deletion cmd/bscp/pull.go
Original file line number Diff line number Diff line change
Expand Up @@ -109,7 +109,8 @@ func Pull(cmd *cobra.Command, args []string) {
cancel()
}

func pullAppFiles(ctx context.Context, bscp client.Client, tempDir string, biz uint32, app string, opts []client.AppOption) error { // nolint
func pullAppFiles(ctx context.Context, bscp client.Client, tempDir string, biz uint32, app string,
opts []client.AppOption) error {

// 1. prepare app workspace dir
appDir := filepath.Join(tempDir, strconv.Itoa(int(biz)), app)
Expand Down
187 changes: 186 additions & 1 deletion internal/util/file.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,15 @@ package util
import (
"fmt"
"os"
"os/exec"
"os/user"
"strconv"
"strings"

pbci "github.com/TencentBlueKing/bk-bcs/bcs-services/bcs-bscp/pkg/protocol/core/config-item"
"golang.org/x/exp/slog"

"github.com/TencentBlueKing/bscp-go/pkg/logger"
)

// SetFilePermission sets the file permission.
Expand Down Expand Up @@ -52,7 +56,7 @@ func SetFilePermission(filePath string, pm *pbci.FilePermission) error {

gp, err := user.LookupGroup(pm.UserGroup)
if err != nil {
return fmt.Errorf("look up %s group failed, err: %v", pm.User, err)
return fmt.Errorf("look up %s group failed, err: %v", pm.UserGroup, err)
}

gid, err := strconv.Atoi(gp.Gid)
Expand Down Expand Up @@ -98,3 +102,184 @@ func ConvertTextLineBreak(filePath string, lineBreak string) error {
// 写回文件
return os.WriteFile(filePath, []byte(updatedContent), 0644)
}

// Permission 权限组结构
type Permission struct {
User string
UserGroup string
Uid string
Gid string
}

// SetUserAndUserGroup 设置用户和用户组
func SetUserAndUserGroup(permission *pbci.FilePermission) error {

p := Permission{
User: permission.User,
Uid: fmt.Sprintf("%d", permission.Uid),

Check failure on line 119 in internal/util/file.go

View workflow job for this annotation

GitHub Actions / lint

permission.Uid undefined (type *pbci.FilePermission has no field or method Uid)

Check failure on line 119 in internal/util/file.go

View workflow job for this annotation

GitHub Actions / lint

permission.Uid undefined (type *pbci.FilePermission has no field or method Uid)

Check failure on line 119 in internal/util/file.go

View workflow job for this annotation

GitHub Actions / lint

permission.Uid undefined (type *pbci.FilePermission has no field or method Uid)

Check failure on line 119 in internal/util/file.go

View workflow job for this annotation

GitHub Actions / build

permission.Uid undefined (type *pbci.FilePermission has no field or method Uid)
UserGroup: permission.UserGroup,
Gid: fmt.Sprintf("%d", permission.Gid),

Check failure on line 121 in internal/util/file.go

View workflow job for this annotation

GitHub Actions / lint

permission.Gid undefined (type *pbci.FilePermission has no field or method Gid)) (typecheck)

Check failure on line 121 in internal/util/file.go

View workflow job for this annotation

GitHub Actions / lint

permission.Gid undefined (type *pbci.FilePermission has no field or method Gid)) (typecheck)

Check failure on line 121 in internal/util/file.go

View workflow job for this annotation

GitHub Actions / lint

permission.Gid undefined (type *pbci.FilePermission has no field or method Gid)) (typecheck)

Check failure on line 121 in internal/util/file.go

View workflow job for this annotation

GitHub Actions / build

permission.Gid undefined (type *pbci.FilePermission has no field or method Gid)
}

// 设置用户组
if err := p.setUserGroup(); err != nil {
return err
}

// 设置用户
if err := p.setUser(); err != nil {
return err
}

return addUserToGroup(p.User, p.UserGroup)
}

// SetUser 设置用户
func (p Permission) setUser() error {
if checkUserAndGroup(p.User, p.Uid) {
return nil
}

// 2. 获取用户信息
usr, err := user.Lookup(p.User)
if err == nil && usr.Uid == p.Uid {
return nil
}

// 删除用户
if err := deleteUser(p.User); err != nil {
return err
}

// 通过UID删除用户
if err := deleteUserByUID(p.Uid); err != nil {
return err
}

// 创建用户
if err := createUser(p.User, p.Uid, p.Gid); err != nil {
return err
}

return nil
}

// addUserToGroup 将用户添加到某个用户组中
func addUserToGroup(username, groupname string) error {
cmd := exec.Command("usermod", "-aG", groupname, username)
return cmd.Run()
}

// deleteUser 删除用户
func deleteUser(username string) error {
if checkUserAndGroup(username, "") {
return nil
}
usr, err := user.Lookup(username)
if err == nil {
cmd := exec.Command("userdel", "-f", username)
if output, err := cmd.CombinedOutput(); err != nil {
return fmt.Errorf("%s user deleted fialed, %s, err: %v", username, output, err)
}
logger.Info("user deleted success", slog.Any("user", username), slog.Any("uid", usr.Uid))
}

return nil
}

// deleteUserByUID 通过uid删除用户
func deleteUserByUID(uid string) error {
usr, err := user.LookupId(uid)
if err == nil {
return deleteUser(usr.Username)
}

return nil
}

// createUser 创建用户
func createUser(username, uid, gid string) error {
cmd := exec.Command("useradd", "-m", "-u", uid, "-g", gid, username)
if output, err := cmd.CombinedOutput(); err != nil {
return fmt.Errorf("%s user created fialed, %s, err: %v", username, output, err)
}
logger.Info("user created success", slog.Any("user", username), slog.Any("uid", uid))

return nil
}

// SetUserGroup 设置用户组
func (p Permission) setUserGroup() error {
if checkUserAndGroup(p.UserGroup, p.Gid) {
return nil
}

// 1. 通过组获取组的信息
usr, err := user.LookupGroup(p.UserGroup)
if err == nil && usr.Gid == p.Gid {
return nil
}

// 删除用户组
if err = deleteUserGroup(p.UserGroup); err != nil {
return err
}
// 通过GID删除用户组
if err = deleteUserGroupByGID(p.Gid); err != nil {
return err
}
// 创建用户组
if err = createUserGroup(p.UserGroup, p.Gid); err != nil {
return err
}

return nil
}

// deleteUserGroup 删除用户组
func deleteUserGroup(groupname string) error {
if checkUserAndGroup(groupname, "") {
return nil
}
usr, err := user.LookupGroup(groupname)
if err == nil {
cmd := exec.Command("groupdel", "-f", groupname)
if output, err := cmd.CombinedOutput(); err != nil {
return fmt.Errorf("%s group deleted failed, %s, err: %v", groupname, output, err)
}
logger.Info("group deleted success", slog.Any("userGroup", groupname), slog.Any("gid", usr.Gid))
}

return nil
}

// deleteUserGroupByGID 通过gid删除用户组
func deleteUserGroupByGID(gid string) error {
usr, err := user.LookupGroupId(gid)
if err == nil {
return deleteUserGroup(usr.Name)
}

return nil
}

// createUserGroup 创建用户组
func createUserGroup(groupname, gid string) error {
cmd := exec.Command("groupadd", "-g", gid, groupname)
if output, err := cmd.CombinedOutput(); err != nil {
return fmt.Errorf("%s group created failed, %s, err: %v", groupname, output, err)
}
logger.Info("group created success", slog.Any("userGroup", groupname), slog.Any("gid", gid))

return nil
}

// 检测用户和用户组
func checkUserAndGroup(name string, id string) bool {
// 如果是root用户或用户组直接不处理
if (id == "0" || id == "") && name == "root" {
return true
}

return false
}

0 comments on commit 3daf49b

Please sign in to comment.