搭建了一个Hadoop的环境,Hadoop集群环境部署在几个Linux服务器上,现在想使用windows上的Java客户端来操作集群中的HDFS文件,但是在客户端运行时出现了如下的认证错误,被折磨了几天,问题终得以解决。以此文记录问题的解决过程。
(如果想看最终解决问题的方法拉到最后,如果想看我的问题解决思路请从上向下看)
问题描述
上传文件的代码:
- private static void uploadToHdfs() throws FileNotFoundException,IOException {
- //我的文件地址
- String localSrc = "E:\\快盘\\技术文档\\hadoop\\HDFS初步研究.pdf";
- //存放在云端的目的地址
- String dest = "hdfs://192.168.2.156:9000/user/HDFS初步研究.pdf";
- InputStream in = new BufferedInputStream(new FileInputStream(localSrc));
- //得到配置对象
- Configuration conf = new Configuration();
- // conf.set("fs.default.name","hdfs://192.168.2.156:9000");
- //文件系统
- FileSystem fs = FileSystem.get(URI.create(dest), conf);
- //输出流
- OutputStream out = fs.create(new Path(dest), new Progressable() {
- @Override
- public void progress() {
- System.out.println("上传完一个设定缓存区大小容量的文件!");
- }
- });
- //连接两个流,形成通道,使输入流向输出流传输数据
- IOUtils.copyBytes(in, out, 4096, true);
- }
错误的详细描述如下:
org.apache.hadoop.security.AccessControlException: org.apache.hadoop.security .AccessControlException: Permission denied: user=Administrator, access=WRITE, inode="hadoop": hadoop:supergroup:rwxr-xr-x
其实这个错误的原因很容易看出来,用户Administator在hadoop上执行写操作时被权限系统拒绝.
解决问题的过程
看到这个错误的,第一步就是将这个错误直接入放到百度google里面进行搜索。找到了N多篇文章,但是主要的思路就如此篇文章所写的两个解决办法:http://www.cnblogs.com/acmy/archive/2011/10/28/2227901.html
1、在hdfs的配置文件中,将dfs.permissions修改为False
2、执行这样的操作 hadoop fs -chmod 777 /user/hadoop
对于上面的第一个方法,我试了行不通,不知道是自己设置错误还是其他原因,对我此法不可行,第二个方法可行。第二个方法是让我们来修改HDFS中相应文件夹的权限,后面的/user/hadoop这个路径为HDFS中的文件路径,这样修改之后就让我们的administrator有在HDFS的相应目录下有写文件的权限(所有的用户都是写权限)。
虽然上面的第二步可以解决问题了,上传之后的文件所有者为Administrator,但是总感觉这样的方法不够优雅,而且这样修改权限会有一定的安全问题,总之就是看着不爽,就在想有没有其他的办法?
问题分析
开始仔细的观察了这个错误的详细信息,看到user=Administrator, access=WRITE。这里的user其实是我当前系统(运行客户端的计算机的操作系统)的用户名,实际期望这里的user=hadoop(hadoop是我的HADOOP上面的用户名),但是它取的是当前的系统的用户名,很明显,如果我将当前系统的用户名改为hadoop,这个肯定也是可以行得通的,但是如果后期将开发的代码部署到服务器上之后,就不能方便的修改用户,此方法明显也不够方便。
现在就想着Configuration这个是一个配置类,有没有一个参数是可以在某个地方设置以哪个用户运行呢?搜索了半天,无果。没有找到相关的配置参数。
最终只有继续分析代码, FileSystem fs = FileSystem.get(URI.create(dest), conf);代码是在此处开始对HDFS进行调用,所以就想着将HADOOP的源码下下来,debug整个调用过程,这个user=Administator是在什么时间赋予的值。理解了调用过程,还怕找不到解决问题的办法么?
跟踪代码进入 FileSystem.get-->CACHE.get()-->Key key = new Key(uri, conf);到这里的时候发现key值里面已经有Administrator了,所以关键肯定是在new key的过程。继续跟踪UserGroupInformation.getCurrentUser()-->getLoginUser()-->login.login()到这一步的时候发现用户名已经确定了,但是这个方法是Java的核心源码,是一个通用的安全认证,但对这一块不熟悉,但是debug时看到subject里面有NTUserPrincipal:Administator,所以就想着搜索一下这个东西是啥,结果就找到了下面这一篇关键的文章:
http://www.udpwork.com/item/7047.html
在此篇文章里面作者分析了hadoop的整个登录过程,对于我有用的是其中的这一段:
2.login.login();
这个会调用HadoopLoginModule的login()和commit()方法。
HadoopLoginModule的login()方法是一个空函数,只打印了一行调试日志 LOG.debug("hadoop login");
commit()方法负责把Principal添加到Subject中。
此时一个首要问题是username是什么?
在使用了kerberos的情况下,从javax.security.auth.kerberos.KerberosPrincipal的实例获取username。
在未使用kerberos的情况下,优先读取HADOOP_USER_NAME这个系统环境变量,如果不为空,那么拿它作username。否则,读取HADOOP_USER_NAME这个java环境变量。否则,从com.sun.security.auth.NTUserPrincipal或者com.sun.security.auth.UnixPrincipal的实例获取username。
如果以上尝试都失败,那么抛出异常LoginException("Can’t find user name")。
最终拿username构造org.apache.hadoop.security.User的实例添加到Subject中。
看完这一段,我明白了执行login.login的时候调用了hadoop里面的HadoopLoginModule方法,而关键是在commit方法里面,在这里优先读取HADOOP_USER_NAME系统环境变量,然后是java环境变量,如果再没有就从NTUserPrincipal等里面取。关键代码为:
- if (!isSecurityEnabled() && (user == null)) {
- String envUser = System.getenv(HADOOP_USER_NAME);
- if (envUser == null) {
- envUser = System.getProperty(HADOOP_USER_NAME);
- }
- user = envUser == null ? null : new User(envUser);
- }
OK,看到这里我的需求也就解决了,只要在系统的环境变量里面添加HADOOP_USER_NAME=hadoop(HDFS上的有权限的用户,具体看自己的情况),或者在当前JDK的变量参数里面添加HADOOP_USER_NAME这个Java变量即可。我的情况添加系统环境变量更方法。
如果是在Eclipse里面运行,修改完环境变量后,记得重启一下eclipse,不然可能不会生效。
解决办法
最终,总结下来解决办法大概有三种:
1、在系统的环境变量或java JVM变量里面添加HADOOP_USER_NAME,这个值具体等于多少看自己的情况,以后会运行HADOOP上的Linux的用户名。(修改完重启eclipse,不然可能不生效)
2、将当前系统的帐号修改为hadoop
3、使用HDFS的命令行接口修改相应目录的权限,hadoop fs -chmod 777 /user,后面的/user是要上传文件的路径,不同的情况可能不一样,比如要上传的文件路径为hdfs://namenode/user/xxx.doc,则这样的修改可以,如果要上传的文件路径为hdfs://namenode/java/xxx.doc,则要修改的为hadoop fs -chmod 777 /java或者hadoop fs -chmod 777 /,java的那个需要先在HDFS里面建立Java目录,后面的这个是为根目录调整权限。
我喜欢第一个方法。
转自:http://www.huqiwen.com/2013/07/18/hdfs-permission-denied/
相关推荐
确保文件权限设置正确,以便Kylin服务可以读取和写入。 在配置过程中,还需要注意其他关键参数,比如`kylin.server.mode`定义了Kylin服务器的运行模式(默认为all,支持standalone和cluster),`kylin.job.engine....
这个特定的错误日志"org.apache.hadoop.security.AccessControlException: Permission denied: user=xudsa, access=WRITE, inode="/uploaddemo1.txt":hadoop:supergroup:-rw-r--r--"表明用户"xudsa"试图对文件"/...
Exception in thread main org.apache.hadoop.security.AccessControlException: Permission denied: user=L.MOON, access=WRITE, inode=/user/lsy/result1/_temporary/0:lsy:supergroup:drwxr-xr-x Caused by: org....
##### HDFS客户端的权限错误:Permission denied **问题描述**:在使用HDFS客户端操作文件时,可能会遇到权限拒绝的问题。 **原因分析**:这可能是由于HDFS客户端操作文件的用户与文件所有者不匹配,或者文件权限...
在 Tomcat 中观察运行结果,可以发现出现了 Exception“org.apache.hadoop.security.AccessControlException: Permission denied: user=bikun,access=WRITE, inode="/user":user:supergroup:drwxr-xr-x”。...
org.apache.hadoop.security.AccessControlException: Permission denied: user=ASUS, access=WRITE, inode 今天在windows连接虚拟机的hdfs,通过IDEA上传文件到虚拟机的hdfs上,出现了权限不足问题,原因是以...
- **错误现象1:AccessControlException: Permission denied** - 原因:Windows本地用户权限不足。 - 解决方法:(i)测试环境中,可在hdfs-site.xml中将dfs.permissions设置为false,禁用权限检查;(ii)或修改...
当你尝试在一个非你所有或者无写权限的目录下创建新目录时,系统会返回"Permission denied"的错误。 解决方法: 1. 使用`chown`命令改变目录的所有权。这里的`sudo chown -R user bigdata`命令意味着将`bigdata`...
`Permission denied: user=administrator, access=WRITE, inode="/":root:supergroup:drwxr-xr-x` **问题描述:** 此异常提示在尝试写入HDFS时权限不足,通常是由于当前用户没有足够的权限访问特定的HDFS路径。 *...
- **SSH登录时提示“Permission denied”**: - 确认公钥已正确添加到`/root/.ssh/authorized_keys`文件中。 - 检查文件权限是否正确设置。 - **Hadoop启动失败**: - 检查Hadoop的核心配置文件是否设置正确。 -...
当我们尝试写入或读取HDFS上的文件时,如果没有足够的权限,Hive将抛出一个RuntimeException,错误信息为“Permission denied”。解决这个问题的方法是连接shadmin用户,对shdev用户赋予该路径的ACL权限。 三、通用...
一、hadoop安装 1.安装java ...2. 配置SSH (1)首先在系统里打开远程登录,位置在 System Preference -> Sharing 中,左边勾选 Remote Login,右边选择 All Users。...(2)生成新的keygen否则后面会报错 Permission denied