最近线上的hive升级到了0.13,遇到不少问题。权限上面,设置了hive.security.authorization.createtable.owner.grants 在hive0.13中,用户自己创建的表也没有权限。通过对源码的分析和debug找到了rc并fix,下面记录下。

1.首先在hive0.11中和hive0.13中分别做建表测试,通过查看数据库中的元数据,发现在hive0.11中如果设置了owner的参数在表创建之后,用户会有这个表的all的权限(具体可以分析db_privs ,tbl_privs表,hive.security.authorization.createtable.owner.grants设置为了all),而在hive0.13中则为空的。

2.通过

1
hive -hiveconf hive.root.logger=DEBUG,console

对比前后的日志,发现在hive0.11的时候,创建的表的属性中有权限的设置

而在hive0.13中这个是为空的

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
hive0. 11 :
14 / 07 / 16  17 : 05 : 39  DEBUG hive.log: DDL: struct ericni4 { string a} 14 / 07 / 16  17 : 05 : 39  DEBUG
  lazy.LazySimpleSerDe: org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDe initialized with:
   columnNames=[a] columnTypes=[string] separator=[[B @5b224686 ] nullstring=\N 
   lastColumnTakesRest=false14/ 07 / 16  17 : 05 : 39  INFO metastore.HiveMetaStore:  0
   create_table: Table(tableName:ericni4, dbName:temp, owner:ericni2, createTime: 1405501539 ,
    lastAccessTime: 0 , retention: 0 ,sd:StorageDescriptor(cols:[FieldSchema(name:a, 
    type:string, comment: null )], location: null
    inputFormat:org.apache.hadoop.mapred.SequenceFileInputFormat,
    outputFormat:org.apache.hadoop.hive.ql.io.HiveSequenceFileOutputFormat, 
    compressed: false , numBuckets:- 1 ,
    serdeInfo:SerDeInfo(name: null , serializationLib:org.apache.hadoop.hive.serde2.lazy.
    LazySimpleSerDe,parameters:{serialization.format= 1 }), bucketCols:[], sortCols:[], 
    parameters:{}, skewedInfo:SkewedInfo(skewedColNames:[], skewedColValues:[], 
    skewedColValueLocationMaps:{}), storedAsSubDirectories: false ),partitionKeys:[],
    parameters:{}, viewOriginalText: null , viewExpandedText: null , tableType:MANAGED_TABLE,
    privileges:PrincipalPrivilegeSet(userPrivileges:{ericni2=[PrivilegeGrantInfo(privilege:
    all, createTime:- 1 , grantor:ericni2, grantorType:USER, grantOption: true )]}, 
    groupPrivileges: null , rolePrivileges: null )) #hive0. 11 创建表的时候增加了这个设置
    
hive0. 13
14 / 07 / 16  17 : 10 : 07  DEBUG hive.log: DDL: struct ericni4 { string a} 14 / 07 / 16  17 : 10 : 07  DEBUG
  lazy.LazySimpleSerDe: org.apache.hadoop.hive.serde2.lazy.LazySimpleSerDe initialized with:
   columnNames=[a] columnTypes=[string] separator=[[B @1667e92a ] nullstring=\N 
   lastColumnTakesRest=false14/ 07 / 16  17 : 10 : 07  INFO metastore.HiveMetaStore:  0
   create_table: Table(tableName:ericni4, dbName:temp, owner:ericni1, createTime: 1405501807 ,
    lastAccessTime: 0 , retention: 0 ,sd:StorageDescriptor(cols:[FieldSchema(name:a, 
    type:string, comment: null )], location: null
    inputFormat:org.apache.hadoop.mapred.SequenceFileInputFormat,
    outputFormat:org.apache.hadoop.hive.ql.io.HiveSequenceFileOutputFormat, 
    compressed: false , numBuckets:- 1 ,
    serdeInfo:SerDeInfo(name: null , serializationLib:org.apache.hadoop.hive.serde2.lazy
    .LazySimpleSerDe,parameters:{serialization.format= 1 }), bucketCols:[], sortCols:[], 
    parameters:{}, skewedInfo:SkewedInfo(skewedColNames:[], skewedColValues:[], 
    skewedColValueLocationMaps:{}), storedAsSubDirectories: false ),partitionKeys:[], 
    parameters:{}, viewOriginalText: null , viewExpandedText: null , tableType:MANAGED_TABLE)

3.会不会是参数没有生效?在hive0.13中注释掉这个设置做对比,发现create_table的属性并没有改变,说明至少在现在的0.13环境下这个参数并没有生效。而在0.11中前后是有变化的。

4.在hive0.11中我们设置一个错误的值来获取堆栈的调用信息:

得到0.11的调用栈:

1
2
3
4
5
6
7
8
9
10
11
12
         at org.apache.hadoop.hive.ql.session.CreateTableAutomaticGrant.checkPrivilege(CreateTableAutomaticGrant.java: 118 )
         at org.apache.hadoop.hive.ql.session.CreateTableAutomaticGrant.getGrantorInfoList(CreateTableAutomaticGrant.java: 97 )
         at org.apache.hadoop.hive.ql.session.CreateTableAutomaticGrant.create(CreateTableAutomaticGrant.java: 52 )
         at org.apache.hadoop.hive.ql.session.SessionState.start(SessionState.java: 275 )    
         at org.apache.hadoop.hive.ql.session.SessionState.start(SessionState.java: 278 )
         at org.apache.hadoop.hive.cli.CliDriver.run(CliDriver.java: 670 )
         at org.apache.hadoop.hive.cli.CliDriver.main(CliDriver.java: 614 )
         at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
         at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java: 39 )
         at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java: 25 )
         at java.lang.reflect.Method.invoke(Method.java: 597 )
         at org.apache.hadoop.util.RunJar.main(RunJar.java: 208 )

再来分析源码

在hive0.11中,在初始化session时,调用SessionState的start方法,会直接根据CreateTableAutomaticGrant类设置createTableGrants属性。

1
2
3
4
5
6
7
8
9
10
11
12
SessionState.start:
     try  {
       startSs. authenticator = HiveUtils.getAuthenticator(
           startSs.getConf(),HiveConf.ConfVars.HIVE_AUTHENTICATOR_MANAGER);
       startSs. authorizer = HiveUtils.getAuthorizeProviderManager(
           startSs.getConf(), HiveConf.ConfVars.HIVE_AUTHORIZATION_MANAGER,
           startSs. authenticator);
       startSs. createTableGrants = CreateTableAutomaticGrant.create(startSs
           .getConf());  //设置owner的相关权限
     catch  (HiveException e) {
       throw  new  RuntimeException(e);
     }

然后在创建表的时候,调用Hive.createTable的方法

1
( public  void  createTable(Table tbl,  boolean  ifNotExists))
1
2
3
   public  CreateTableAutomaticGrant getCreateTableGrants() {
     return  createTableGrants;
   }

而在hive0.13中,即使设置错误也不会有报错产生,通过debug源码发现这里的调用关系有些变化,SessionState的getCreateTableGrants方法调用的是setupAuth方法。

1
2
3
4
   public  CreateTableAutomaticGrant getCreateTableGrants() {
     setupAuth();  //调用setupAuth方法设置createTableGrants
     return  createTableGrants;
   }

其中setupAuth方法如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
  private  void  setupAuth() {
     if  (authenticator !=  null ) {
       // auth has been initialized
       return ;
     }
     try  {
       authenticator = HiveUtils.getAuthenticator( conf,
           HiveConf.ConfVars.HIVE_AUTHENTICATOR_MANAGER);
       authenticator.setSessionState(  this );
       authorizer = HiveUtils.getAuthorizeProviderManager( conf,
           HiveConf.ConfVars.HIVE_AUTHORIZATION_MANAGER, authenticator,  true  );
      
       if  (authorizer ==  null ) {  //在authorizer 的取值为null时,才会生成权限
         // if it was null, the new authorization plugin must be specified in
         // config
         HiveAuthorizerFactory authorizerFactory = HiveUtils.getAuthorizerFactory(conf ,
             HiveConf.ConfVars.HIVE_AUTHORIZATION_MANAGER);
         authorizerV2 = authorizerFactory.createHiveAuthorizer( new  HiveMetastoreClientFactoryImpl(),
             conf, authenticator);
         authorizerV2.applyAuthorizationConfigPolicy(conf );
         // create the create table grants with new config
         createTableGrants = CreateTableAutomaticGrant.create( conf);
       }
     catch  (HiveException e) {
       throw  new  RuntimeException(e);
     }
     if (LOG.isDebugEnabled()){
       Object authorizationClass = getAuthorizationMode() == AuthorizationMode. V1 ?
           getAuthorizer() : getAuthorizerV2();
           LOG.debug( "Session is using authorization class "  + authorizationClass.getClass());
     }
     return ;
   }

可以看到在在authorizer 的取值为null时,才会有生产ower权限的操作(CreateTableAutomaticGrant.create(conf))

authorizer 的值由参数hive.security.authorization.manager获得,在hive0.13里面这个是有默认值的:

1
2
HIVE_AUTHORIZATION_MANAGER( "hive.security.authorization.manager" ,
       "org.apache.hadoop.hive.ql.security.authorization.DefaultHiveAuthorizationProvider" ),

这样就导致在setupAuth方法中并不会通过CreateTableAutomaticGrant.create(conf)来设置owner的权限,rc找到了。fix也比较简单。

1
2
3
4
5
6
7
8
9
10
     try  {
       authenticator = HiveUtils.getAuthenticator( conf,
           HiveConf.ConfVars.HIVE_AUTHENTICATOR_MANAGER);
       authenticator.setSessionState(  this );
       authorizer = HiveUtils.getAuthorizeProviderManager( conf,
           HiveConf.ConfVars.HIVE_AUTHORIZATION_MANAGER, authenticator,  true  );
      
       createTableGrants = CreateTableAutomaticGrant.create(conf);  //不管authorizer 是否为空都设置相关权限
       if  (authorizer ==  null ) { 
.......

bug fix之后,使用错误的参数,堆栈如下,说明生效了:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
14 / 07 / 18  12 : 33 : 38  WARN session.SessionState: authenticator is  null  , return ,auth has been initialized
14 / 07 / 18  12 : 33 : 38  WARN session.CreateTableAutomaticGrant: Privilege is  null
FAILED: RuntimeException org.apache.hadoop.hive.ql.metadata.HiveException: Privilege alldddd is not found.
14 / 07 / 18  12 : 33 : 38  ERROR ql.Driver: FAILED: RuntimeException org.apache.hadoop.hive.ql.metadata.HiveException: Privilege alldddd is not found.
java.lang.RuntimeException: org.apache.hadoop.hive.ql.metadata.HiveException: Privilege alldddd is not found.
         at org.apache.hadoop.hive.ql.session.SessionState.setupAuth(SessionState.java: 410 )
         at org.apache.hadoop.hive.ql.session.SessionState.getAuthorizationMode(SessionState.java: 979 )
         at org.apache.hadoop.hive.ql.session.SessionState.isAuthorizationModeV2(SessionState.java: 990 )
         at org.apache.hadoop.hive.ql.Driver.doAuthorization(Driver.java: 508 )
         at org.apache.hadoop.hive.ql.Driver.compile(Driver.java: 461 )
         at org.apache.hadoop.hive.ql.Driver.compile(Driver.java: 322 )
         at org.apache.hadoop.hive.ql.Driver.compileInternal(Driver.java: 975 )
         at org.apache.hadoop.hive.ql.Driver.runInternal(Driver.java: 1040 )
         at org.apache.hadoop.hive.ql.Driver.run(Driver.java: 911 )
         at org.apache.hadoop.hive.ql.Driver.run(Driver.java: 901 )
         at org.apache.hadoop.hive.cli.CliDriver.processLocalCmd(CliDriver.java: 268 )
         at org.apache.hadoop.hive.cli.CliDriver.processCmd(CliDriver.java: 220 )
         at org.apache.hadoop.hive.cli.CliDriver.processLine(CliDriver.java: 423 )
         at org.apache.hadoop.hive.cli.CliDriver.processLine(CliDriver.java: 359 )
         at org.apache.hadoop.hive.cli.CliDriver.processReader(CliDriver.java: 456 )
         at org.apache.hadoop.hive.cli.CliDriver.processFile(CliDriver.java: 466 )
         at org.apache.hadoop.hive.cli.CliDriver.processInitFiles(CliDriver.java: 502 )
         at org.apache.hadoop.hive.cli.CliDriver.executeDriver(CliDriver.java: 739 )
         at org.apache.hadoop.hive.cli.CliDriver.run(CliDriver.java: 686 )
         at org.apache.hadoop.hive.cli.CliDriver.main(CliDriver.java: 625 )
         at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
         at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java: 39 )
         at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java: 25 )
         at java.lang.reflect.Method.invoke(Method.java: 597 )
         at org.apache.hadoop.util.RunJar.main(RunJar.java: 208 )
Caused by: org.apache.hadoop.hive.ql.metadata.HiveException: Privilege alldddd is not found.
         at org.apache.hadoop.hive.ql.session.CreateTableAutomaticGrant.validatePrivilege(CreateTableAutomaticGrant.java: 129 )
         at org.apache.hadoop.hive.ql.session.CreateTableAutomaticGrant.getGrantorInfoList(CreateTableAutomaticGrant.java: 105 )
         at org.apache.hadoop.hive.ql.session.CreateTableAutomaticGrant.create(CreateTableAutomaticGrant.java: 57 )
         at org.apache.hadoop.hive.ql.session.SessionState.setupAuth(SessionState.java: 392 )
         ...  24  more