【DataSophon】DataSophon1.2.1 ranger usersync整合

阿龙先生啊 2024-07-11 09:05:02 阅读 76

 目录

一、简介

二、实现步骤

2.1 ranger-usersync包下载编译

2.2 构建压缩包

2.3 编辑元数据文件

2.4 修改源码

三、重新安装


一、简介


如下是DDP1.2.1默认有的rangerAdmin, 我们需要将rangerusersync整合进来 ,实现将Linux机器上的用户和组信息同步到RangerAdmin的数据库中进行管理。


二、实现步骤


2.1 ranger-usersync包下载编译


ranger官网tar包下载

<code>https://ranger.apache.org/download.html

自己编译 或者网上下载

参考文章:

Apache Ranger - Download Apache Ranger?

Ranger安装和使用-CSDN博客

https://juejin.cn/post/6844904159930482696

https://zhuanlan.zhihu.com/p/562012618

权限管理Ranger详解_大数据权限管理利器 - ranger-CSDN博客

2.2 构建压缩包


将ranger-usersync安装包集成到ranger组件中重新打包,如下是ranger admin包和ranger-usersync包。

<code># 解压ranger组件原有包

tar -zxvf ranger-2.1.0.tar.gz

cd ranger-2.1.0

# 将编译好的的sync安装包解压到当前目录

tar -zxvf ranger-2.1.0-usersync.tar.gz ./

cd ranger-2.1.0-usersync

vim ranger_usersync.sh

#!/bin/bash

# 获取脚本当前目录

current_path=$(dirname "$0")

# 使用说明

usage="Usage: $0 {start|stop|status|restart}"code>

start(){

echo "ranger userSync start"

sh "$current_path/ranger-usersync" start

if [ $? -eq 0 ]; then

echo "ranger userSync start success"

else

echo "ranger userSync start failed"

exit 1

fi

}

stop(){

echo "ranger userSync stop"

sh "$current_path/ranger-usersync" stop

if [ $? -eq 0 ]; then

echo "ranger userSync stop success"

else

echo "ranger userSync stop failed"

exit 1

fi

}

status(){

process_name="UnixAuthenticationService"code>

# 使用 pgrep 命令检测进程是否存在

pgrep -f "$process_name" > /dev/null

if [ $? -eq 0 ]; then

echo "进程 $process_name 存在"

exit 0

else

echo "进程 $process_name 不存在"

exit 1

fi

}

restart(){

echo "ranger userSync restart"

sh "$current_path/ranger-usersync" restart

if [ $? -eq 0 ]; then

echo "ranger userSync restart success"

else

echo "ranger userSync restart failed"

exit 1

fi

}

# 处理参数

startStop=$1

case $startStop in

start)

start

;;

stop)

stop

;;

status)

status

;;

restart)

restart

;;

*)

echo "$usage"

exit 1

;;

esac

echo "End $startStop ranger userSync"

打包

tar -zcvf ranger-2.1.0.tar.gz ranger-2.1.0

md5sum ranger-2.1.0.tar.gz

echo '756fa828e02d8f890ca2165d237ef487' > ranger-2.1.0.tar.gz.md5

cp ranger-2.1.0.tar.gz ranger-2.1.0.tar.gz.md5 /opt/datasophon/DDP/packages/

2.3 编辑元数据文件


ranger安装配置文件

vim /opt/datasophon/DDP/packages/datasophon-manager-1.2.1/conf/meta/DDP-1.2.1/RANGER/service_ddl.json

{

"name": "RANGER",

"label": "Ranger",

"description": "权限控制框架",

"version": "2.1.0",

"sortNum": 10,

"dependencies":[],

"packageName": "ranger-2.1.0.tar.gz",

"decompressPackageName": "ranger-2.1.0",

"roles": [

{

"name": "RangerAdmin",

"label": "RangerAdmin",

"roleType": "master",

"cardinality": "1",

"logFile": "/var/log/ranger/admin/ranger-admin-${host}-root.log",

"jmxPort": 6081,

"sortNum": 1,

"startRunner": {

"timeout": "60",

"program": "bin/ranger_admin.sh",

"args": [

"start"

]

},

"stopRunner": {

"timeout": "600",

"program": "bin/ranger_admin.sh",

"args": [

"stop"

]

},

"statusRunner": {

"timeout": "60",

"program": "bin/ranger_admin.sh",

"args": [

"status"

]

},

"externalLink": {

"name": "RangerAdmin Ui",

"label": "RangerAdmin Ui",

"url": "http://${host}:6080"

}

},

{

"name": "RangerUsersync",

"label": "RangerUsersync",

"roleType": "master",

"runAs": {

"user": "root",

"group": "root"

},

"cardinality": "1",

"logFile": "ranger-2.1.0-usersync/logs/usersync-${host}-ranger.log",

"jmxPort": "",

"sortNum": 2,

"startRunner": {

"timeout": "60",

"program": "ranger-2.1.0-usersync/ranger_usersync.sh",

"args": [

"start"

]

},

"stopRunner": {

"timeout": "600",

"program": "ranger-2.1.0-usersync/ranger_usersync.sh",

"args": [

"stop"

]

},

"statusRunner": {

"timeout": "60",

"program": "ranger-2.1.0-usersync/ranger_usersync.sh",

"args": [

"status"

]

},

"restartRunner": {

"timeout": "60",

"program": "ranger-2.1.0-usersync/ranger_usersync.sh",

"args": [

"restart"

]

}

}

],

"configWriter": {

"generators": [

{

"filename": "install.properties",

"configFormat": "custom",

"templateName": "ranger-install.ftl",

"outputDirectory": "",

"includeParams": [

"rootPassword",

"dbHost",

"database",

"rangerUser",

"rangerPassword",

"rangerAdminUrl",

"enableHDFSPlugin",

"enableHIVEPlugin",

"enableHBASEPlugin",

"spnegoPrincipal",

"spnegoKeytab",

"adminPrincipal",

"adminKeytab",

"hadoopHome",

"rangerHome"

]

},

{

"filename": "install.properties1",

"configFormat": "custom",

"templateName": "ranger-usersync-install.ftl",

"outputDirectory": "ranger-2.1.0-usersync",

"includeParams": [

"rangerAdminUrl",

"adminPrincipal",

"adminKeytab",

"hadoopHome",

"syncInterval"

]

}

]

},

"parameters": [

{

"name": "rootPassword",

"label": "数据库root用户密码",

"description": "",

"required": true,

"configType": "map",

"type": "input",

"value": "",

"configurableInWizard": true,

"hidden": false,

"defaultValue": "123456"

},

{

"name": "dbHost",

"label": "数据库地址",

"description": "",

"required": true,

"configType": "map",

"type": "input",

"value": "",

"configurableInWizard": true,

"hidden": false,

"defaultValue": "${apiHost}"

},{

"name": "database",

"label": "数据库名",

"description": "",

"required": true,

"configType": "map",

"type": "input",

"value": "",

"configurableInWizard": true,

"hidden": false,

"defaultValue": "ranger"

},

{

"name": "rangerUser",

"label": "Ranger数据库用户",

"description": "",

"required": true,

"configType": "map",

"type": "input",

"value": "",

"configurableInWizard": true,

"hidden": false,

"defaultValue": "ranger"

},{

"name": "rangerPassword",

"label": "Ranger数据库密码",

"description": "",

"required": true,

"configType": "map",

"type": "input",

"value": "",

"configurableInWizard": true,

"hidden": false,

"defaultValue": "ranger"

},

{

"name": "rangerAdminUrl",

"label": "Ranger访问地址",

"description": "",

"required": true,

"configType": "map",

"type": "input",

"value": "",

"configurableInWizard": true,

"hidden": false,

"defaultValue": "${rangerAdminUrl}"

},

{

"name": "enableHDFSPlugin",

"label": "启用HDFS Ranger插件",

"description": "",

"required": true,

"type": "switch",

"value": false,

"configurableInWizard": true,

"hidden": false,

"defaultValue": false

},

{

"name": "enableHIVEPlugin",

"label": "启用Hive Ranger插件",

"description": "",

"required": true,

"type": "switch",

"value": false,

"configurableInWizard": true,

"hidden": false,

"defaultValue": false

},

{

"name": "enableHBASEPlugin",

"label": "启用Hbase Ranger插件",

"description": "",

"required": true,

"type": "switch",

"value": false,

"configurableInWizard": true,

"hidden": false,

"defaultValue": false

},

{

"name": "enableKerberos",

"label": "开启Kerberos认证",

"description": "开启Kerberos认证",

"required": false,

"type": "switch",

"value": false,

"configurableInWizard": true,

"hidden": true,

"defaultValue": false

},

{

"name": "spnegoPrincipal",

"label": "Spnego Principal",

"description": "",

"configWithKerberos": true,

"required": false,

"configType": "map",

"type": "input",

"value": "HTTP/${host}@HADOOP.COM",

"configurableInWizard": true,

"hidden": true,

"defaultValue": "HTTP/${host}@HADOOP.COM"

},

{

"name": "spnegoKeytab",

"label": "Spnego Keytab",

"description": "",

"configWithKerberos": true,

"required": false,

"configType": "map",

"type": "input",

"value": "/etc/security/keytab/spnego.service.keytab",

"configurableInWizard": true,

"hidden": true,

"defaultValue": "/etc/security/keytab/spnego.service.keytab"

},

{

"name": "adminPrincipal",

"label": "Ranger Admin Principal",

"description": "",

"configWithKerberos": true,

"required": false,

"configType": "map",

"type": "input",

"value": "rangeradmin/${host}@HADOOP.COM",

"configurableInWizard": true,

"hidden": true,

"defaultValue": "rangeradmin/${host}@HADOOP.COM"

},

{

"name": "adminKeytab",

"label": "Ranger Admin Keytab",

"description": "",

"configWithKerberos": true,

"required": false,

"configType": "map",

"type": "input",

"value": "/etc/security/keytab/rangeradmin.keytab",

"configurableInWizard": true,

"hidden": true,

"defaultValue": "/etc/security/keytab/rangeradmin.keytab"

},

{

"name": "hadoopHome",

"label": "HADOOP_HOME",

"description": "",

"configWithKerberos": true,

"required": true,

"configType": "map",

"type": "input",

"value": "${HADOOP_HOME}",

"configurableInWizard": true,

"hidden": true,

"defaultValue": "${HADOOP_HOME}"

},

{

"name": "rangerHome",

"label": "RANGER_HOME",

"description": "",

"required": true,

"configType": "map",

"type": "input",

"value": "${RANGER_HOME}",

"configurableInWizard": true,

"hidden": false,

"defaultValue": "${RANGER_HOME}"

},

{

"name": "syncInterval",

"label": "SYNC_INTERVAL",

"description": "userSync同步间隔时间,单位(分钟)",

"required": true,

"configType": "map",

"type": "input",

"value": "1",

"configurableInWizard": true,

"hidden": false,

"defaultValue": "1"

}

]

}

各worker元数据文件,已部署的路径:

vim /opt/datasophon/datasophon-worker/conf/templates/ranger-usersync-install.ftl

ranger配置文件 install.properties ,使用了 SYNC_SOURCE = unix

# Licensed to the Apache Software Foundation (ASF) under one or more

# contributor license agreements. See the NOTICE file distributed with

# this work for additional information regarding copyright ownership.

# The ASF licenses this file to You under the Apache License, Version 2.0

# (the "License"); you may not use this file except in compliance with

# the License. You may obtain a copy of the License at

#

# http://www.apache.org/licenses/LICENSE-2.0

#

# Unless required by applicable law or agreed to in writing, software

# distributed under the License is distributed on an "AS IS" BASIS,

# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

# See the License for the specific language governing permissions and

# limitations under the License.

# The base path for the usersync process

ranger_base_dir = /etc/ranger

#

# The following URL should be the base URL for connecting to the policy manager web application

# For example:

#

# POLICY_MGR_URL = http://policymanager.xasecure.net:6080

#

POLICY_MGR_URL = ${rangerAdminUrl}

# sync source, only unix and ldap are supported at present

# defaults to unix

SYNC_SOURCE = unix

#

# Minimum Unix User-id to start SYNC.

# This should avoid creating UNIX system-level users in the Policy Manager

#

MIN_UNIX_USER_ID_TO_SYNC = 500

# Minimum Unix Group-id to start SYNC.

# This should avoid creating UNIX system-level users in the Policy Manager

#

MIN_UNIX_GROUP_ID_TO_SYNC = 500

# sync interval in minutes

# user, groups would be synced again at the end of each sync interval

# defaults to 5 if SYNC_SOURCE is unix

# defaults to 360 if SYNC_SOURCE is ldap

SYNC_INTERVAL = ${syncInterval}

#User and group for the usersync process

unix_user=ranger

unix_group=ranger

#change password of rangerusersync user. Please note that this password should be as per rangerusersync user in ranger

rangerUsersync_password=admin123

#Set to run in kerberos environment

usersync_principal=<#if adminPrincipal??>${adminPrincipal}</#if>

usersync_keytab=<#if adminKeytab??>${adminKeytab}</#if>

hadoop_conf=${hadoopHome}/etc/hadoop/conf

#

# The file where all credential is kept in cryptic format

#

CRED_KEYSTORE_FILENAME=/etc/ranger/usersync/conf/rangerusersync.jceks

# SSL Authentication

AUTH_SSL_ENABLED=false

AUTH_SSL_KEYSTORE_FILE=/etc/ranger/usersync/conf/cert/unixauthservice.jks

AUTH_SSL_KEYSTORE_PASSWORD=UnIx529p

AUTH_SSL_TRUSTSTORE_FILE=

AUTH_SSL_TRUSTSTORE_PASSWORD=

# ---------------------------------------------------------------

# The following properties are relevant only if SYNC_SOURCE = ldap

# ---------------------------------------------------------------

# The below properties ROLE_ASSIGNMENT_LIST_DELIMITER, USERS_GROUPS_ASSIGNMENT_LIST_DELIMITER, USERNAME_GROUPNAME_ASSIGNMENT_LIST_DELIMITER,

#and GROUP_BASED_ROLE_ASSIGNMENT_RULES can be used to assign role to LDAP synced users and groups

#NOTE all the delimiters should have different values and the delimiters should not contain characters that are allowed in userName or GroupName

# default value ROLE_ASSIGNMENT_LIST_DELIMITER = &

ROLE_ASSIGNMENT_LIST_DELIMITER = &

#default value USERS_GROUPS_ASSIGNMENT_LIST_DELIMITER = :

USERS_GROUPS_ASSIGNMENT_LIST_DELIMITER = :

#default value USERNAME_GROUPNAME_ASSIGNMENT_LIST_DELIMITER = ,

USERNAME_GROUPNAME_ASSIGNMENT_LIST_DELIMITER = ,

# with above mentioned delimiters a sample value would be ROLE_SYS_ADMIN:u:userName1,userName2&ROLE_SYS_ADMIN:g:groupName1,groupName2&ROLE_KEY_ADMIN:u:userName&ROLE_KEY_ADMIN:g:groupName&ROLE_USER:u:userName3,userName4&ROLE_USER:g:groupName3

#&ROLE_ADMIN_AUDITOR:u:userName&ROLE_KEY_ADMIN_AUDITOR:u:userName&ROLE_KEY_ADMIN_AUDITOR:g:groupName&ROLE_ADMIN_AUDITOR:g:groupName

GROUP_BASED_ROLE_ASSIGNMENT_RULES =

# URL of source ldap

# a sample value would be: ldap://ldap.example.com:389

# Must specify a value if SYNC_SOURCE is ldap

SYNC_LDAP_URL =

# ldap bind dn used to connect to ldap and query for users and groups

# a sample value would be cn=admin,ou=users,dc=hadoop,dc=apache,dc=org

# Must specify a value if SYNC_SOURCE is ldap

SYNC_LDAP_BIND_DN =

# ldap bind password for the bind dn specified above

# please ensure read access to this file is limited to root, to protect the password

# Must specify a value if SYNC_SOURCE is ldap

# unless anonymous search is allowed by the directory on users and group

SYNC_LDAP_BIND_PASSWORD =

# ldap delta sync flag used to periodically sync users and groups based on the updates in the server

# please customize the value to suit your deployment

# default value is set to true when is SYNC_SOURCE is ldap

SYNC_LDAP_DELTASYNC =

# search base for users and groups

# sample value would be dc=hadoop,dc=apache,dc=org

SYNC_LDAP_SEARCH_BASE =

# search base for users

# sample value would be ou=users,dc=hadoop,dc=apache,dc=org

# overrides value specified in SYNC_LDAP_SEARCH_BASE

SYNC_LDAP_USER_SEARCH_BASE =

# search scope for the users, only base, one and sub are supported values

# please customize the value to suit your deployment

# default value: sub

SYNC_LDAP_USER_SEARCH_SCOPE = sub

# objectclass to identify user entries

# please customize the value to suit your deployment

# default value: person

SYNC_LDAP_USER_OBJECT_CLASS = person

# optional additional filter constraining the users selected for syncing

# a sample value would be (dept=eng)

# please customize the value to suit your deployment

# default value is empty

SYNC_LDAP_USER_SEARCH_FILTER =

# attribute from user entry that would be treated as user name

# please customize the value to suit your deployment

# default value: cn

SYNC_LDAP_USER_NAME_ATTRIBUTE = cn

# attribute from user entry whose values would be treated as

# group values to be pushed into Policy Manager database

# You could provide multiple attribute names separated by comma

# default value: memberof, ismemberof

SYNC_LDAP_USER_GROUP_NAME_ATTRIBUTE = memberof,ismemberof

#

# UserSync - Case Conversion Flags

# possible values: none, lower, upper

SYNC_LDAP_USERNAME_CASE_CONVERSION=lower

SYNC_LDAP_GROUPNAME_CASE_CONVERSION=lower

#user sync log path

logdir=logs

#/var/log/ranger/usersync

# PID DIR PATH

USERSYNC_PID_DIR_PATH=/var/run/ranger

# do we want to do ldapsearch to find groups instead of relying on user entry attributes

# valid values: true, false

# any value other than true would be treated as false

# default value: false

SYNC_GROUP_SEARCH_ENABLED=

# do we want to do ldapsearch to find groups instead of relying on user entry attributes and

# sync memberships of those groups

# valid values: true, false

# any value other than true would be treated as false

# default value: false

SYNC_GROUP_USER_MAP_SYNC_ENABLED=

# search base for groups

# sample value would be ou=groups,dc=hadoop,dc=apache,dc=org

# overrides value specified in SYNC_LDAP_SEARCH_BASE, SYNC_LDAP_USER_SEARCH_BASE

# if a value is not specified, takes the value of SYNC_LDAP_SEARCH_BASE

# if SYNC_LDAP_SEARCH_BASE is also not specified, takes the value of SYNC_LDAP_USER_SEARCH_BASE

SYNC_GROUP_SEARCH_BASE=

# search scope for the groups, only base, one and sub are supported values

# please customize the value to suit your deployment

# default value: sub

SYNC_GROUP_SEARCH_SCOPE=

# objectclass to identify group entries

# please customize the value to suit your deployment

# default value: groupofnames

SYNC_GROUP_OBJECT_CLASS=

# optional additional filter constraining the groups selected for syncing

# a sample value would be (dept=eng)

# please customize the value to suit your deployment

# default value is empty

SYNC_LDAP_GROUP_SEARCH_FILTER=

# attribute from group entry that would be treated as group name

# please customize the value to suit your deployment

# default value: cn

SYNC_GROUP_NAME_ATTRIBUTE=

# attribute from group entry that is list of members

# please customize the value to suit your deployment

# default value: member

SYNC_GROUP_MEMBER_ATTRIBUTE_NAME=

# do we want to use paged results control during ldapsearch for user entries

# valid values: true, false

# any value other than true would be treated as false

# default value: true

# if the value is false, typical AD would not return more than 1000 entries

SYNC_PAGED_RESULTS_ENABLED=

# page size for paged results control

# search results would be returned page by page with the specified number of entries per page

# default value: 500

SYNC_PAGED_RESULTS_SIZE=

#LDAP context referral could be ignore or follow

SYNC_LDAP_REFERRAL = ignore

# if you want to enable or disable jvm metrics for usersync process

# valid values: true, false

# any value other than true would be treated as false

# default value: false

# if the value is false, jvm metrics is not created

JVM_METRICS_ENABLED=

# filename of jvm metrics created for usersync process

# default value: ranger_usersync_metric.json

JVM_METRICS_FILENAME=

#file directory for jvm metrics

# default value : logdir

JVM_METRICS_FILEPATH=

#frequency for jvm metrics to be updated

# default value : 10000 milliseconds

JVM_METRICS_FREQUENCY_TIME_IN_MILLIS=

2.4 修改源码


com.datasophon.worker.strategy.RangerAdminHandlerStrategy

/*

* Licensed to the Apache Software Foundation (ASF) under one or more

* contributor license agreements. See the NOTICE file distributed with

* this work for additional information regarding copyright ownership.

* The ASF licenses this file to You under the Apache License, Version 2.0

* (the "License"); you may not use this file except in compliance with

* the License. You may obtain a copy of the License at

*

* http://www.apache.org/licenses/LICENSE-2.0

*

* Unless required by applicable law or agreed to in writing, software

* distributed under the License is distributed on an "AS IS" BASIS,

* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.

* See the License for the specific language governing permissions and

* limitations under the License.

*/

package com.datasophon.worker.strategy;

import cn.hutool.core.io.FileUtil;

import com.datasophon.common.Constants;

import com.datasophon.common.cache.CacheUtils;

import com.datasophon.common.command.ServiceRoleOperateCommand;

import com.datasophon.common.enums.CommandType;

import com.datasophon.common.utils.ExecResult;

import com.datasophon.common.utils.ShellUtils;

import com.datasophon.worker.handler.ServiceHandler;

import com.datasophon.worker.utils.KerberosUtils;

import java.util.ArrayList;

public class RangerAdminHandlerStrategy extends AbstractHandlerStrategy implements ServiceRoleStrategy {

public RangerAdminHandlerStrategy(String serviceName, String serviceRoleName) {

super(serviceName, serviceRoleName);

}

@Override

public ExecResult handler(ServiceRoleOperateCommand command) {

String workPath = Constants.INSTALL_PATH + Constants.SLASH + command.getDecompressPackageName();

ExecResult startResult = new ExecResult();

ServiceHandler serviceHandler = new ServiceHandler(command.getServiceName(), command.getServiceRoleName());

if (command.getEnableKerberos()) {

logger.info("start to get ranger keytab file");

String hostname = CacheUtils.getString(Constants.HOSTNAME);

KerberosUtils.createKeytabDir();

if (!FileUtil.exist("/etc/security/keytab/spnego.service.keytab")) {

KerberosUtils.downloadKeytabFromMaster("HTTP/" + hostname, "spnego.service.keytab");

}

if (!FileUtil.exist("/etc/security/keytab/rangeradmin.keytab")) {

KerberosUtils.downloadKeytabFromMaster("rangeradmin/" + hostname, "rangeradmin.keytab");

}

}

if (command.getCommandType().equals(CommandType.INSTALL_SERVICE) && command.getServiceRoleName().equals("RangerUsersync")) {

ShellUtils.exceShell("mv " + workPath + "/ranger-2.1.0-usersync/install.properties1 " + workPath + "/ranger-2.1.0-usersync/install.properties");

ShellUtils.exceShell("chmod 755 " + workPath + "/ranger-2.1.0-usersync/install.properties");

logger.info("setup ranger user sync");

ArrayList<String> commands = new ArrayList<>();

commands.add("sh");

commands.add("./setup.sh");

ExecResult execResult = ShellUtils.execWithStatus(workPath + "/ranger-2.1.0-usersync", commands, 300L, logger);

if (execResult.getExecResult()) {

logger.info("setup ranger user sync success");

} else {

logger.info("setup ranger user sync failed");

return execResult;

}

ShellUtils.exceShell("sed -i '/<name>ranger\\.usersync\\.enabled<\\/name>/{n;s/<value>false<\\/value>/<value>true<\\/value>/}' "

+ workPath +

"/ranger-2.1.0-usersync/conf/ranger-ugsync-site.xml");

startResult = serviceHandler.start(command.getStartRunner(), command.getStatusRunner(),

command.getDecompressPackageName(), command.getRunAs());

} else {

startResult = serviceHandler.start(command.getStartRunner(), command.getStatusRunner(),

command.getDecompressPackageName(), command.getRunAs());

}

return startResult;

}

}

com.datasophon.worker.strategy.ServiceRoleStrategyContext

map.put("RangerUsersync", new RangerAdminHandlerStrategy("RANGER", "RangerUsersync"));

datasophon-worker jar包更新

mv datasophon-worker-1.2.1.jar /opt/datasophon/datasophon-worker/lib/


三、重新安装


添加ranger服务

分配服务Master角色

服务配置

选择"settings"我们可以看到linux 上的用户已同步成功。



声明

本文内容仅代表作者观点,或转载于其他网站,本站不以此文作为商业用途
如有涉及侵权,请联系本站进行删除
转载本站原创文章,请注明来源及作者。