From 8676959d137f2984d6ae5b54f255998ea360eadf Mon Sep 17 00:00:00 2001 From: Andrew Wang Date: Mon, 30 Nov 2015 14:32:19 -0800 Subject: [PATCH] HDFS-9470. Encryption zone on root not loaded from fsimage after NN restart. Xiao Chen via wang. (cherry picked from commit 9b8e50b424d060e16c1175b1811e7abc476e2468) (cherry picked from commit ce1111ceea830cce5f0833db55201e0e88c3b199) --- hadoop-hdfs-project/hadoop-hdfs/CHANGES.txt | 3 ++ .../hdfs/server/namenode/FSDirectory.java | 49 ++++++++++++------- .../server/namenode/FSImageFormatPBINode.java | 1 + .../hadoop/hdfs/TestEncryptionZones.java | 38 ++++++++++++++ 4 files changed, 74 insertions(+), 17 deletions(-) diff --git a/hadoop-hdfs-project/hadoop-hdfs/CHANGES.txt b/hadoop-hdfs-project/hadoop-hdfs/CHANGES.txt index 3f421baf174..7b20f3e5205 100644 --- a/hadoop-hdfs-project/hadoop-hdfs/CHANGES.txt +++ b/hadoop-hdfs-project/hadoop-hdfs/CHANGES.txt @@ -2700,6 +2700,9 @@ Release 2.6.3 - UNRELEASED HDFS-9434. Recommission a datanode with 500k blocks may pause NN for 30 seconds for printing info log messags. (szetszwo) + HDFS-9470. Encryption zone on root not loaded from fsimage after NN + restart. (Xiao Chen via wang) + Release 2.6.2 - 2015-10-28 INCOMPATIBLE CHANGES diff --git a/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/namenode/FSDirectory.java b/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/namenode/FSDirectory.java index 52b261611b7..d885e2e9f2d 100644 --- a/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/namenode/FSDirectory.java +++ b/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/namenode/FSDirectory.java @@ -1163,27 +1163,42 @@ public class FSDirectory implements Closeable { inodeMap.put(inode); if (!inode.isSymlink()) { final XAttrFeature xaf = inode.getXAttrFeature(); - if (xaf != null) { - XAttr xattr = xaf.getXAttr(CRYPTO_XATTR_ENCRYPTION_ZONE); - if (xattr != null) { - try { - final HdfsProtos.ZoneEncryptionInfoProto ezProto = - HdfsProtos.ZoneEncryptionInfoProto.parseFrom( - xattr.getValue()); - ezManager.unprotectedAddEncryptionZone(inode.getId(), - PBHelperClient.convert(ezProto.getSuite()), - PBHelperClient.convert(ezProto.getCryptoProtocolVersion()), - ezProto.getKeyName()); - } catch (InvalidProtocolBufferException e) { - NameNode.LOG.warn("Error parsing protocol buffer of " + - "EZ XAttr " + xattr.getName()); - } - } - } + addEncryptionZone((INodeWithAdditionalFields) inode, xaf); } } } + + private void addEncryptionZone(INodeWithAdditionalFields inode, + XAttrFeature xaf) { + if (xaf == null) { + return; + } + XAttr xattr = xaf.getXAttr(CRYPTO_XATTR_ENCRYPTION_ZONE); + if (xattr == null) { + return; + } + try { + final HdfsProtos.ZoneEncryptionInfoProto ezProto = + HdfsProtos.ZoneEncryptionInfoProto.parseFrom( + xattr.getValue()); + ezManager.unprotectedAddEncryptionZone(inode.getId(), + PBHelperClient.convert(ezProto.getSuite()), + PBHelperClient.convert(ezProto.getCryptoProtocolVersion()), + ezProto.getKeyName()); + } catch (InvalidProtocolBufferException e) { + NameNode.LOG.warn("Error parsing protocol buffer of " + + "EZ XAttr " + xattr.getName() + " dir:" + inode.getFullPathName()); + } + } + /** + * This is to handle encryption zone for rootDir when loading from + * fsimage, and should only be called during NN restart. + */ + public final void addRootDirToEncryptionZone(XAttrFeature xaf) { + addEncryptionZone(rootDir, xaf); + } + /** * This method is always called with writeLock of FSDirectory held. */ diff --git a/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/namenode/FSImageFormatPBINode.java b/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/namenode/FSImageFormatPBINode.java index 42e3b3b2c6a..e353c8806ec 100644 --- a/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/namenode/FSImageFormatPBINode.java +++ b/hadoop-hdfs-project/hadoop-hdfs/src/main/java/org/apache/hadoop/hdfs/server/namenode/FSImageFormatPBINode.java @@ -404,6 +404,7 @@ public final class FSImageFormatPBINode { if (f != null) { dir.rootDir.addXAttrFeature(f); } + dir.addRootDirToEncryptionZone(f); } } diff --git a/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/TestEncryptionZones.java b/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/TestEncryptionZones.java index 7b90540bf1a..908ccae3725 100644 --- a/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/TestEncryptionZones.java +++ b/hadoop-hdfs-project/hadoop-hdfs/src/test/java/org/apache/hadoop/hdfs/TestEncryptionZones.java @@ -378,6 +378,44 @@ public class TestEncryptionZones { assertZonePresent(null, nonpersistZone.toString()); } + @Test(timeout = 60000) + public void testBasicOperationsRootDir() throws Exception { + int numZones = 0; + final Path rootDir = new Path("/"); + final Path zone1 = new Path(rootDir, "zone1"); + + /* Normal creation of an EZ on rootDir */ + dfsAdmin.createEncryptionZone(rootDir, TEST_KEY); + assertNumZones(++numZones); + assertZonePresent(null, rootDir.toString()); + + /* create EZ on child of rootDir which is already an EZ should fail */ + fsWrapper.mkdir(zone1, FsPermission.getDirDefault(), true); + try { + dfsAdmin.createEncryptionZone(zone1, TEST_KEY); + fail("EZ over an EZ"); + } catch (IOException e) { + assertExceptionContains("already in an encryption zone", e); + } + + // Verify rootDir ez is present after restarting the NameNode + // and saving/loading from fsimage. + fs.setSafeMode(SafeModeAction.SAFEMODE_ENTER); + fs.saveNamespace(); + fs.setSafeMode(SafeModeAction.SAFEMODE_LEAVE); + cluster.restartNameNode(true); + assertNumZones(numZones); + assertZonePresent(null, rootDir.toString()); + + /* create EZ on child of rootDir which is already an EZ should fail */ + try { + dfsAdmin.createEncryptionZone(zone1, TEST_KEY); + fail("EZ over an EZ"); + } catch (IOException e) { + assertExceptionContains("already in an encryption zone", e); + } + } + /** * Test listing encryption zones as a non super user. */