diff --git a/Dockerfile b/Dockerfile index 77c1d9854..a691f0d1f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -51,8 +51,9 @@ RUN ARCH=$(uname -m) && case $ARCH in aarch64) ARCH="arm64";; x86_64) ARCH="amd6 rm -rf /tmp/* /var/tmp/* /var/cache/apk/* && \ chmod -R 755 /tmp && mkdir -p /opt/webkubectl - -ENV TZ='Asia/Shanghai'; +RUN apk add tzdata && cp /usr/share/zoneinfo/Asia/Shanghai /etc/localtime \ + && echo "Asia/Shanghai" > /etc/timezone \ + && apk del tzdata COPY vimrc.local /etc/vim diff --git a/internal/api/v1/ldap/ldap.go b/internal/api/v1/ldap/ldap.go index 2e447fd6b..d20e37aaa 100644 --- a/internal/api/v1/ldap/ldap.go +++ b/internal/api/v1/ldap/ldap.go @@ -82,14 +82,13 @@ func (h *Handler) TestConnect() iris.Handler { func (h *Handler) SyncLdapUser() iris.Handler { return func(ctx *context.Context) { - uuid := ctx.Params().Get("id") - err := h.ldapService.Sync(uuid, common.DBOptions{}) + users, err := h.ldapService.GetLdapUser() if err != nil { ctx.StatusCode(iris.StatusInternalServerError) ctx.Values().Set("message", err.Error()) return } - ctx.Values().Set("data", "") + ctx.Values().Set("data", users) } } @@ -132,7 +131,7 @@ func Install(parent iris.Party) { sp.Get("/", handler.ListLdap()) sp.Post("/", handler.AddLdap()) sp.Put("/", handler.UpdateLdap()) - sp.Post("/sync/:id", handler.SyncLdapUser()) + sp.Post("/sync", handler.SyncLdapUser()) sp.Post("/test/connect", handler.TestConnect()) sp.Post("/test/login", handler.TestLogin()) sp.Post("/import", handler.ImportUser()) diff --git a/internal/api/v1/v1.go b/internal/api/v1/v1.go index 3a743efc5..6affe9ec4 100644 --- a/internal/api/v1/v1.go +++ b/internal/api/v1/v1.go @@ -141,6 +141,22 @@ func logHandler() iris.Handler { log.Operator = profile.Name log.Operation = method + //handle ldap operate + if strings.Contains(path,"ldap") { + if strings.Contains(path,"import") { + log.Operation = "import" + } + if strings.Contains(path,"sync") { + log.Operation = "sync" + } + if strings.Contains(path,"connect") { + log.Operation = "testConnect" + } + if strings.Contains(path,"login") { + log.Operation = "testLogin" + } + } + pathResource := strings.Split(path, "/") if strings.HasPrefix(currentPath, "clusters/:name") { if len(pathResource) < 3 { diff --git a/internal/service/v1/ldap/ldap.go b/internal/service/v1/ldap/ldap.go index 354b57221..fc00cc7a7 100644 --- a/internal/service/v1/ldap/ldap.go +++ b/internal/service/v1/ldap/ldap.go @@ -30,10 +30,11 @@ type Service interface { Delete(id string, options common.DBOptions) error Sync(id string, options common.DBOptions) error Login(user v1User.User, password string, options common.DBOptions) error - TestConnect(ldap *v1Ldap.Ldap) ([]v1User.ImportUser, error) + TestConnect(ldap *v1Ldap.Ldap) (int, error) TestLogin(username string, password string) error ImportUsers(users []v1User.ImportUser) (v1User.ImportResult, error) CheckStatus() bool + GetLdapUser() ([]v1User.ImportUser, error) } func NewService() Service { @@ -128,17 +129,19 @@ func (l *service) Delete(id string, options common.DBOptions) error { return db.DeleteStruct(ldap) } -//func (l *service) GetLdapUser() ([]v1User.ImportUser, error) { -// users := []v1User.ImportUser{} -// -//} - -func (l *service) TestConnect(ldap *v1Ldap.Ldap) ([]v1User.ImportUser, error) { +func (l *service) GetLdapUser() ([]v1User.ImportUser, error) { users := []v1User.ImportUser{} + ldaps, err := l.List(common.DBOptions{}) + if err != nil { + return users, err + } + if len(ldaps) == 0 { + return users, errors.New("请先保存LDAP配置") + } + ldap := ldaps[0] if !ldap.Enable { return users, errors.New("请先启用LDAP") } - lc := ldapClient.NewLdapClient(ldap.Address, ldap.Port, ldap.Username, ldap.Password, ldap.TLS) if err := lc.Connect(); err != nil { return users, err @@ -162,7 +165,6 @@ func (l *service) TestConnect(ldap *v1Ldap.Ldap) ([]v1User.ImportUser, error) { us := new(v1User.ImportUser) us.Available = true rv := reflect.ValueOf(&us).Elem().Elem() - for _, at := range entry.Attributes { for k, v := range mappings { if v == at.Name && len(at.Values) > 0 { @@ -173,23 +175,41 @@ func (l *service) TestConnect(ldap *v1Ldap.Ldap) ([]v1User.ImportUser, error) { } } } - if us.Email == "" || us.Name == "" { + if us.Name == "" { continue } - if us.NickName == "" { - us.NickName = us.Name - } _, err = l.userService.GetByNameOrEmail(us.Name, common.DBOptions{}) if err == nil { us.Available = false } users = append(users, *us) } - if len(users) == 0 && len(entries) > 0 { - return users, errors.New("Mapping 映射失败!") + return users, nil +} + +func (l *service) TestConnect(ldap *v1Ldap.Ldap) (int, error) { + users := 0 + if !ldap.Enable { + return users, errors.New("请先启用LDAP") } - return users, nil + lc := ldapClient.NewLdapClient(ldap.Address, ldap.Port, ldap.Username, ldap.Password, ldap.TLS) + if err := lc.Connect(); err != nil { + return users, err + } + attributes, err := ldap.GetAttributes() + if err != nil { + return users, err + } + entries, err := lc.Search(ldap.Dn, ldap.Filter, ldap.SizeLimit, ldap.TimeLimit, attributes) + if err != nil { + return users, err + } + if len(entries) == 0 { + return users, nil + } + + return len(entries), nil } func (l *service) CheckStatus() bool { @@ -263,6 +283,13 @@ func (l *service) ImportUsers(users []v1User.ImportUser) (v1User.ImportResult, e Type: v1User.LDAP, Email: imp.Email, } + if us.Email == "" { + us.Email = us.Name + "@example.com" + } + if us.NickName == "" { + us.NickName = us.Name + } + result.Failures = append(result.Failures, us.Name) tx, err := server.DB().Begin(true) if err != nil { diff --git a/pkg/util/ldap/ldap_client.go b/pkg/util/ldap/ldap_client.go index b3076cfec..c205454ba 100644 --- a/pkg/util/ldap/ldap_client.go +++ b/pkg/util/ldap/ldap_client.go @@ -47,7 +47,7 @@ func (l *Ldap) Connect() error { func (l *Ldap) Search(dn, filter string, sizeLimit, timeLimit int, attributes []string) ([]*ldap.Entry, error) { searchRequest := ldap.NewSearchRequest(dn, - ldap.ScopeWholeSubtree, ldap.NeverDerefAliases, 0, timeLimit, false, + ldap.ScopeWholeSubtree, ldap.DerefAlways, 0, timeLimit, false, filter, attributes, nil) diff --git a/pkg/util/podtool/copytopod.go b/pkg/util/podtool/copytopod.go index 61ec87248..ae6e019a7 100644 --- a/pkg/util/podtool/copytopod.go +++ b/pkg/util/podtool/copytopod.go @@ -10,7 +10,6 @@ import ( "os" "path" "path/filepath" - "strings" ) func (p *PodTool) CopyToContainer(destPath string) error { @@ -26,18 +25,17 @@ func (p *PodTool) CopyToContainer(destPath string) error { var stderr bytes.Buffer p.ExecConfig.Stderr = &stderr err := p.Exec(Exec) + var stdout bytes.Buffer + p.ExecConfig.Stdout = &stdout if err != nil { - return fmt.Errorf(err.Error(), stderr) - } - if len(stderr.Bytes()) != 0 { - for _, line := range strings.Split(stderr.String(), "\n") { - if len(strings.TrimSpace(line)) == 0 { - continue - } - if !strings.Contains(strings.ToLower(line), "removing") { - return fmt.Errorf(line) - } + result := "" + if len(stdout.Bytes()) != 0 { + result = stdout.String() } + if len(stderr.Bytes()) != 0 { + result = stderr.String() + } + return fmt.Errorf(err.Error(), result) } return nil } @@ -77,16 +75,6 @@ func (p *PodTool) CopyToPod(srcPath, destPath string) error { } return fmt.Errorf(err.Error(), result) } - if len(stderr.Bytes()) != 0 { - for _, line := range strings.Split(stderr.String(), "\n") { - if len(strings.TrimSpace(line)) == 0 { - continue - } - if !strings.Contains(strings.ToLower(line), "removing") { - return fmt.Errorf(line) - } - } - } return nil } diff --git a/web/dashboard/src/business/workloads/pods/podfilebrowser/index.vue b/web/dashboard/src/business/workloads/pods/podfilebrowser/index.vue index 8789e0b60..34e950200 100644 --- a/web/dashboard/src/business/workloads/pods/podfilebrowser/index.vue +++ b/web/dashboard/src/business/workloads/pods/podfilebrowser/index.vue @@ -136,7 +136,7 @@
{{ $t("business.pod.upload_tip") }}
- {{ $t("commons.button.cancel") }} + {{ $t("commons.button.cancel") }} {{ $t("commons.button.confirm") }} diff --git a/web/kubepi/src/api/ldap.js b/web/kubepi/src/api/ldap.js index e36d45dd3..9c8c78dd1 100644 --- a/web/kubepi/src/api/ldap.js +++ b/web/kubepi/src/api/ldap.js @@ -14,8 +14,8 @@ export function updateLdap(data){ return put(`${baseUrl}`, data) } -export function syncLdap(id,data) { - return post(`${baseUrl}/sync/${id}`, data) +export function syncLdap(data) { + return post(`${baseUrl}/sync`, data) } export function testConnect(data) { diff --git a/web/kubepi/src/business/user-management/ldap/index.vue b/web/kubepi/src/business/user-management/ldap/index.vue index c1b21e864..0380fc816 100644 --- a/web/kubepi/src/business/user-management/ldap/index.vue +++ b/web/kubepi/src/business/user-management/ldap/index.vue @@ -67,10 +67,6 @@ $t("business.user.ldap_remake") }} - - - - {{ $t("commons.button.confirm") }} @@ -104,6 +100,7 @@ + {{ $t("business.user.ldap_helper") }}
@@ -159,7 +156,7 @@ export default { return { form: { mapping: "{\n" + - " \"Name\":\"sAMAccountName\",\n" + + " \"Name\":\"cn\",\n" + " \"NickName\":\"cn\",\n" + " \"Email\":\"mail\"\n" + "}", @@ -206,24 +203,6 @@ export default { } }, methods: { - sync () { - if (this.form.uuid === undefined || this.form.uuid === "") { - this.$message({ - type: "warning", - message: this.$t("business.user.ldap_sync_error") - }) - return - } - this.isSubmitGoing = true - syncLdap(this.form.uuid, {}).then(() => { - this.$message({ - type: "success", - message: this.$t("business.user.ldap_sync") - }) - }).finally(() => { - this.isSubmitGoing = false - }) - }, connectTest () { let isFormReady = false this.$refs["form"].validate((valid) => { @@ -234,15 +213,12 @@ export default { if (!isFormReady) { return } - this.tableUsers = [] this.loading = true this.connectLoading = true testConnect(this.form).then(res => { - this.users = res.data - this.tableUsers = this.users this.$message({ type: "success", - message: this.$t("business.user.test_result", { count: res.data.length }) + message: this.$t("business.user.test_result", { count: res.data }) }) }).finally(() => { this.loading = false @@ -254,12 +230,15 @@ export default { this.loginForm = {} }, openImportPage () { - this.importUserPageOpen = true this.searchName = "" - if (this.users.length === 0) { - this.connectTest() - } - this.tableUsers = this.users + this.loading = true + syncLdap({}).then(res => { + this.users = res.data + this.tableUsers = this.users + this.importUserPageOpen = true + }).finally(() => { + this.loading = false + }) }, importAvailable (row) { return row.available diff --git a/web/kubepi/src/i18n/lang/en-US.js b/web/kubepi/src/i18n/lang/en-US.js index ca10f656d..96476d742 100644 --- a/web/kubepi/src/i18n/lang/en-US.js +++ b/web/kubepi/src/i18n/lang/en-US.js @@ -189,7 +189,7 @@ const message = { ldap_password: "Password", ldap_filter_dn: "User Filtering DN", ldap_filter_rule: "User Filtering Rules", - ldap_helper: "Note: Users without mailboxes will not be synchronized, and those with the same login name as local users will not be synchronized!", + ldap_helper: "Note: Users who cannot get the Name mapping attribute will not be matched", ldap_sync: "Start syncing, please check the user list later", ldap_sync_error: "Please save first", type: "Type", diff --git a/web/kubepi/src/i18n/lang/zh-CN.js b/web/kubepi/src/i18n/lang/zh-CN.js index 0f98edbdd..69580c885 100644 --- a/web/kubepi/src/i18n/lang/zh-CN.js +++ b/web/kubepi/src/i18n/lang/zh-CN.js @@ -189,7 +189,7 @@ const message = { ldap_password: "密码", ldap_filter_dn: "用户过滤 OU", ldap_filter_rule: "用户过滤规则", - ldap_helper: "注意:没有邮箱的用户不会被同步,与本地用户登录名重复的也不会被同步!", + ldap_helper: "注意:无法获取到 Name 映射属性的用户不会匹配", ldap_sync: "开始同步,稍后请查看用户列表", ldap_sync_error: "请先保存", type: "类型", @@ -269,6 +269,10 @@ const system_logs = { clusters_repos: "集群仓库", imagerepos: "镜像仓库", ldap: "LDAP", + sync: "同步", + import: "导入", + testConnect: "测试", + testLogin: "测试", }