ShellBasedIdMapping implements IdMappingServiceProvider { @VisibleForTesting public static boolean updateMapInternal(BiMap<Integer, String> map, String mapName, String command, String regex, Map<Integer, Integer> staticMapping) throws IOException { boolean updated = false; BufferedReader br = null; try { Process process = Runtime.getRuntime().exec( new String[] { "bash", "-c", command }); br = new BufferedReader( new InputStreamReader(process.getInputStream(), Charset.defaultCharset())); String line = null; while ((line = br.readLine()) != null) { String[] nameId = line.split(regex); if ((nameId == null) || (nameId.length != 2)) { throw new IOException("Can't parse " + mapName + " list entry:" + line); } LOG.debug("add to " + mapName + "map:" + nameId[0] + " id:" + nameId[1]); final Integer key = staticMapping.get(parseId(nameId[1])); final String value = nameId[0]; if (map.containsKey(key)) { final String prevValue = map.get(key); if (value.equals(prevValue)) { continue; } reportDuplicateEntry( "Got multiple names associated with the same id: ", key, value, key, prevValue); continue; } if (map.containsValue(value)) { final Integer prevKey = map.inverse().get(value); reportDuplicateEntry( "Got multiple ids associated with the same name: ", key, value, prevKey, value); continue; } map.put(key, value); updated = true; } LOG.debug("Updated " + mapName + " map size: " + map.size()); } catch (IOException e) { LOG.error("Can't update " + mapName + " map"); throw e; } finally { if (br != null) { try { br.close(); } catch (IOException e1) { LOG.error("Can't close BufferedReader of command result", e1); } } } return updated; } @VisibleForTesting  ShellBasedIdMapping(Configuration conf,
      boolean constructFullMapAtInit);  ShellBasedIdMapping(Configuration conf); @VisibleForTesting long getTimeout(); @VisibleForTesting BiMap<Integer, String> getUidNameMap(); @VisibleForTesting BiMap<Integer, String> getGidNameMap(); @VisibleForTesting synchronized void clearNameMaps(); @VisibleForTesting static boolean updateMapInternal(BiMap<Integer, String> map,
      String mapName, String command, String regex,
      Map<Integer, Integer> staticMapping); synchronized void updateMaps(); synchronized int getUid(String user); synchronized int getGid(String group); synchronized String getUserName(int uid, String unknown); synchronized String getGroupName(int gid, String unknown); int getUidAllowingUnknown(String user); int getGidAllowingUnknown(String group);  }
@Test public void testStaticMapping() throws IOException { assumeTrue(!Shell.WINDOWS); Map<Integer, Integer> uidStaticMap = new PassThroughMap<Integer>(); Map<Integer, Integer> gidStaticMap = new PassThroughMap<Integer>(); uidStaticMap.put(11501, 10); gidStaticMap.put(497, 200); BiMap<Integer, String> uMap = HashBiMap.create(); BiMap<Integer, String> gMap = HashBiMap.create(); String GET_ALL_USERS_CMD = "echo \"atm:x:1000:1000:Aaron T. Myers,,,:/home/atm:/bin/bash\n" + "hdfs:x:11501:10787:Grid Distributed File System:/home/hdfs:/bin/bash\"" + " | cut -d: -f1,3"; String GET_ALL_GROUPS_CMD = "echo \"hdfs:*:11501:hrt_hdfs\n" + "mapred:x:497\n" + "mapred2:x:498\"" + " | cut -d: -f1,3"; ShellBasedIdMapping.updateMapInternal(uMap, "user", GET_ALL_USERS_CMD, ":", uidStaticMap); ShellBasedIdMapping.updateMapInternal(gMap, "group", GET_ALL_GROUPS_CMD, ":", gidStaticMap); assertEquals("hdfs", uMap.get(10)); assertEquals(10, (int)uMap.inverse().get("hdfs")); assertEquals("atm", uMap.get(1000)); assertEquals(1000, (int)uMap.inverse().get("atm")); assertEquals("hdfs", gMap.get(11501)); assertEquals(11501, (int)gMap.inverse().get("hdfs")); assertEquals("mapred", gMap.get(200)); assertEquals(200, (int)gMap.inverse().get("mapred")); assertEquals("mapred2", gMap.get(498)); assertEquals(498, (int)gMap.inverse().get("mapred2")); }
@Test public void testDuplicates() throws IOException { assumeTrue(!Shell.WINDOWS); String GET_ALL_USERS_CMD = "echo \"root:x:0:0:root:/root:/bin/bash\n" + "hdfs:x:11501:10787:Grid Distributed File System:/home/hdfs:/bin/bash\n" + "hdfs:x:11502:10788:Grid Distributed File System:/home/hdfs:/bin/bash\n" + "hdfs1:x:11501:10787:Grid Distributed File System:/home/hdfs:/bin/bash\n" + "hdfs2:x:11502:10787:Grid Distributed File System:/home/hdfs:/bin/bash\n" + "bin:x:2:2:bin:/bin:/bin/sh\n" + "bin:x:1:1:bin:/bin:/sbin/nologin\n" + "daemon:x:1:1:daemon:/usr/sbin:/bin/sh\n" + "daemon:x:2:2:daemon:/sbin:/sbin/nologin\"" + " | cut -d: -f1,3"; String GET_ALL_GROUPS_CMD = "echo \"hdfs:*:11501:hrt_hdfs\n" + "mapred:x:497\n" + "mapred2:x:497\n" + "mapred:x:498\n" + "mapred3:x:498\"" + " | cut -d: -f1,3"; BiMap<Integer, String> uMap = HashBiMap.create(); BiMap<Integer, String> gMap = HashBiMap.create(); ShellBasedIdMapping.updateMapInternal(uMap, "user", GET_ALL_USERS_CMD, ":", EMPTY_PASS_THROUGH_MAP); assertEquals(5, uMap.size()); assertEquals("root", uMap.get(0)); assertEquals("hdfs", uMap.get(11501)); assertEquals("hdfs2",uMap.get(11502)); assertEquals("bin", uMap.get(2)); assertEquals("daemon", uMap.get(1)); ShellBasedIdMapping.updateMapInternal(gMap, "group", GET_ALL_GROUPS_CMD, ":", EMPTY_PASS_THROUGH_MAP); assertTrue(gMap.size() == 3); assertEquals("hdfs",gMap.get(11501)); assertEquals("mapred", gMap.get(497)); assertEquals("mapred3", gMap.get(498)); }
@Test public void testIdOutOfIntegerRange() throws IOException { assumeTrue(!Shell.WINDOWS); String GET_ALL_USERS_CMD = "echo \"" + "nfsnobody:x:4294967294:4294967294:Anonymous NFS User:/var/lib/nfs:/sbin/nologin\n" + "nfsnobody1:x:4294967295:4294967295:Anonymous NFS User:/var/lib/nfs1:/sbin/nologin\n" + "maxint:x:2147483647:2147483647:Grid Distributed File System:/home/maxint:/bin/bash\n" + "minint:x:2147483648:2147483648:Grid Distributed File System:/home/minint:/bin/bash\n" + "archivebackup:*:1031:4294967294:Archive Backup:/home/users/archivebackup:/bin/sh\n" + "hdfs:x:11501:10787:Grid Distributed File System:/home/hdfs:/bin/bash\n" + "daemon:x:2:2:daemon:/sbin:/sbin/nologin\"" + " | cut -d: -f1,3"; String GET_ALL_GROUPS_CMD = "echo \"" + "hdfs:*:11501:hrt_hdfs\n" + "rpcuser:*:29:\n" + "nfsnobody:*:4294967294:\n" + "nfsnobody1:*:4294967295:\n" + "maxint:*:2147483647:\n" + "minint:*:2147483648:\n" + "mapred3:x:498\"" + " | cut -d: -f1,3"; BiMap<Integer, String> uMap = HashBiMap.create(); BiMap<Integer, String> gMap = HashBiMap.create(); ShellBasedIdMapping.updateMapInternal(uMap, "user", GET_ALL_USERS_CMD, ":", EMPTY_PASS_THROUGH_MAP); assertTrue(uMap.size() == 7); assertEquals("nfsnobody", uMap.get(-2)); assertEquals("nfsnobody1", uMap.get(-1)); assertEquals("maxint", uMap.get(2147483647)); assertEquals("minint", uMap.get(-2147483648)); assertEquals("archivebackup", uMap.get(1031)); assertEquals("hdfs",uMap.get(11501)); assertEquals("daemon", uMap.get(2)); ShellBasedIdMapping.updateMapInternal(gMap, "group", GET_ALL_GROUPS_CMD, ":", EMPTY_PASS_THROUGH_MAP); assertTrue(gMap.size() == 7); assertEquals("hdfs",gMap.get(11501)); assertEquals("rpcuser", gMap.get(29)); assertEquals("nfsnobody", gMap.get(-2)); assertEquals("nfsnobody1", gMap.get(-1)); assertEquals("maxint", gMap.get(2147483647)); assertEquals("minint", gMap.get(-2147483648)); assertEquals("mapred3", gMap.get(498)); }