26
26
import static org .junit .Assert .assertNull ;
27
27
import static org .junit .Assert .assertTrue ;
28
28
import static org .junit .Assert .fail ;
29
+ import static org .mockito .Mockito .doReturn ;
29
30
import static org .mockito .Mockito .mock ;
31
+ import static org .mockito .Mockito .spy ;
30
32
import static org .mockito .Mockito .when ;
31
33
import static org .mockito .ArgumentMatchers .anyString ;
32
34
import static org .mockito .ArgumentMatchers .any ;
@@ -123,6 +125,8 @@ public class TestAuxServices {
123
125
.getSimpleName ());
124
126
private File manifest = new File (rootDir , "manifest.txt" );
125
127
private ObjectMapper mapper = new ObjectMapper ();
128
+ private static final FsPermission WRITABLE_BY_OWNER = FsPermission .createImmutable ((short ) 0755 );
129
+ private static final FsPermission WRITABLE_BY_GROUP = FsPermission .createImmutable ((short ) 0775 );
126
130
127
131
@ Parameterized .Parameters
128
132
public static Collection <Boolean > getParams () {
@@ -268,6 +272,24 @@ private void writeManifestFile(AuxServiceRecords services, Configuration
268
272
mapper .writeValue (manifest , services );
269
273
}
270
274
275
+ /**
276
+ * Creates a spy object of AuxServices for test cases which assume that we have proper
277
+ * file system permissions by default.
278
+ *
279
+ * Permission checking iterates through the parents of the manifest file until it
280
+ * reaches the system root, so without mocking this the success of the initialization
281
+ * would heavily depend on the environment where the test is running.
282
+ *
283
+ * @return a spy object of AuxServices
284
+ */
285
+ private AuxServices getSpyAuxServices (AuxiliaryLocalPathHandler auxiliaryLocalPathHandler ,
286
+ Context nmContext , DeletionService deletionService ) throws IOException {
287
+ AuxServices auxServices = spy (new AuxServices (auxiliaryLocalPathHandler ,
288
+ nmContext , deletionService ));
289
+ doReturn (true ).when (auxServices ).checkManifestPermissions (any (FileStatus .class ));
290
+ return auxServices ;
291
+ }
292
+
271
293
@ SuppressWarnings ("resource" )
272
294
@ Test
273
295
public void testRemoteAuxServiceClassPath () throws Exception {
@@ -317,7 +339,7 @@ public void testRemoteAuxServiceClassPath() throws Exception {
317
339
YarnConfiguration .NM_AUX_SERVICE_REMOTE_CLASSPATH , "ServiceC" ),
318
340
testJar .getAbsolutePath ());
319
341
}
320
- aux = new AuxServices (MOCK_AUX_PATH_HANDLER ,
342
+ aux = getSpyAuxServices (MOCK_AUX_PATH_HANDLER ,
321
343
mockContext2 , mockDelService2 );
322
344
aux .init (conf );
323
345
Assert .fail ("The permission of the jar is wrong."
@@ -339,7 +361,7 @@ public void testRemoteAuxServiceClassPath() throws Exception {
339
361
YarnConfiguration .NM_AUX_SERVICE_REMOTE_CLASSPATH , "ServiceC" ),
340
362
testJar .getAbsolutePath ());
341
363
}
342
- aux = new AuxServices (MOCK_AUX_PATH_HANDLER ,
364
+ aux = getSpyAuxServices (MOCK_AUX_PATH_HANDLER ,
343
365
mockContext2 , mockDelService2 );
344
366
aux .init (conf );
345
367
aux .start ();
@@ -356,7 +378,7 @@ public void testRemoteAuxServiceClassPath() throws Exception {
356
378
357
379
// initialize the same auxservice again, and make sure that we did not
358
380
// re-download the jar from remote directory.
359
- aux = new AuxServices (MOCK_AUX_PATH_HANDLER ,
381
+ aux = getSpyAuxServices (MOCK_AUX_PATH_HANDLER ,
360
382
mockContext2 , mockDelService2 );
361
383
aux .init (conf );
362
384
aux .start ();
@@ -377,7 +399,7 @@ public void testRemoteAuxServiceClassPath() throws Exception {
377
399
FileTime fileTime = FileTime .fromMillis (time );
378
400
Files .setLastModifiedTime (Paths .get (testJar .getAbsolutePath ()),
379
401
fileTime );
380
- aux = new AuxServices (MOCK_AUX_PATH_HANDLER ,
402
+ aux = getSpyAuxServices (MOCK_AUX_PATH_HANDLER ,
381
403
mockContext2 , mockDelService2 );
382
404
aux .init (conf );
383
405
aux .start ();
@@ -416,7 +438,7 @@ public void testCustomizedAuxServiceClassPath() throws Exception {
416
438
"ServiceC" ), ServiceC .class , Service .class );
417
439
}
418
440
@ SuppressWarnings ("resource" )
419
- AuxServices aux = new AuxServices (MOCK_AUX_PATH_HANDLER ,
441
+ AuxServices aux = getSpyAuxServices (MOCK_AUX_PATH_HANDLER ,
420
442
MOCK_CONTEXT , MOCK_DEL_SERVICE );
421
443
aux .init (conf );
422
444
aux .start ();
@@ -469,7 +491,7 @@ public void testCustomizedAuxServiceClassPath() throws Exception {
469
491
when (mockDirsHandler .getLocalPathForWrite (anyString ())).thenReturn (
470
492
rootAuxServiceDirPath );
471
493
when (mockContext2 .getLocalDirsHandler ()).thenReturn (mockDirsHandler );
472
- aux = new AuxServices (MOCK_AUX_PATH_HANDLER ,
494
+ aux = getSpyAuxServices (MOCK_AUX_PATH_HANDLER ,
473
495
mockContext2 , MOCK_DEL_SERVICE );
474
496
aux .init (conf );
475
497
aux .start ();
@@ -645,7 +667,7 @@ private Configuration getABConf(String aName, String bName,
645
667
@ Test
646
668
public void testAuxServices () throws IOException {
647
669
Configuration conf = getABConf ();
648
- final AuxServices aux = new AuxServices (MOCK_AUX_PATH_HANDLER ,
670
+ final AuxServices aux = getSpyAuxServices (MOCK_AUX_PATH_HANDLER ,
649
671
MOCK_CONTEXT , MOCK_DEL_SERVICE );
650
672
aux .init (conf );
651
673
@@ -673,7 +695,7 @@ public void testAuxServices() throws IOException {
673
695
@ Test
674
696
public void testAuxServicesMeta () throws IOException {
675
697
Configuration conf = getABConf ();
676
- final AuxServices aux = new AuxServices (MOCK_AUX_PATH_HANDLER ,
698
+ final AuxServices aux = getSpyAuxServices (MOCK_AUX_PATH_HANDLER ,
677
699
MOCK_CONTEXT , MOCK_DEL_SERVICE );
678
700
aux .init (conf );
679
701
@@ -705,7 +727,7 @@ public void testAuxServicesMeta() throws IOException {
705
727
public void testAuxUnexpectedStop () throws IOException {
706
728
// AuxServices no longer expected to stop when services stop
707
729
Configuration conf = getABConf ();
708
- final AuxServices aux = new AuxServices (MOCK_AUX_PATH_HANDLER ,
730
+ final AuxServices aux = getSpyAuxServices (MOCK_AUX_PATH_HANDLER ,
709
731
MOCK_CONTEXT , MOCK_DEL_SERVICE );
710
732
aux .init (conf );
711
733
aux .start ();
@@ -721,7 +743,7 @@ public void testAuxUnexpectedStop() throws IOException {
721
743
public void testValidAuxServiceName () throws IOException {
722
744
Configuration conf = getABConf ("Asrv1" , "Bsrv_2" , ServiceA .class ,
723
745
ServiceB .class );
724
- final AuxServices aux = new AuxServices (MOCK_AUX_PATH_HANDLER ,
746
+ final AuxServices aux = getSpyAuxServices (MOCK_AUX_PATH_HANDLER ,
725
747
MOCK_CONTEXT , MOCK_DEL_SERVICE );
726
748
try {
727
749
aux .init (conf );
@@ -730,7 +752,7 @@ public void testValidAuxServiceName() throws IOException {
730
752
}
731
753
732
754
//Test bad auxService Name
733
- final AuxServices aux1 = new AuxServices (MOCK_AUX_PATH_HANDLER ,
755
+ final AuxServices aux1 = getSpyAuxServices (MOCK_AUX_PATH_HANDLER ,
734
756
MOCK_CONTEXT , MOCK_DEL_SERVICE );
735
757
if (useManifest ) {
736
758
AuxServiceRecord serviceA =
@@ -760,7 +782,7 @@ public void testAuxServiceRecoverySetup() throws IOException {
760
782
conf .setBoolean (YarnConfiguration .NM_RECOVERY_ENABLED , true );
761
783
conf .set (YarnConfiguration .NM_RECOVERY_DIR , TEST_DIR .toString ());
762
784
try {
763
- final AuxServices aux = new AuxServices (MOCK_AUX_PATH_HANDLER ,
785
+ final AuxServices aux = getSpyAuxServices (MOCK_AUX_PATH_HANDLER ,
764
786
MOCK_CONTEXT , MOCK_DEL_SERVICE );
765
787
aux .init (conf );
766
788
Assert .assertEquals (2 , aux .getServices ().size ());
@@ -888,59 +910,114 @@ public void testAuxServicesConfChange() throws IOException {
888
910
}
889
911
890
912
@ Test
891
- public void testAuxServicesManifestPermissions () throws IOException {
913
+ public void testAuxServicesInitWithManifestOwnerAndPermissionCheck () throws IOException {
892
914
Assume .assumeTrue (useManifest );
893
915
Configuration conf = getABConf ();
894
- FileSystem fs = FileSystem .get (conf );
895
- fs .setPermission (new Path (manifest .getAbsolutePath ()), FsPermission
896
- .createImmutable ((short ) 0777 ));
897
- AuxServices aux = new AuxServices (MOCK_AUX_PATH_HANDLER ,
898
- MOCK_CONTEXT , MOCK_DEL_SERVICE );
899
- aux .init (conf );
900
- assertEquals (0 , aux .getServices ().size ());
901
-
902
- fs .setPermission (new Path (manifest .getAbsolutePath ()), FsPermission
903
- .createImmutable ((short ) 0775 ));
904
- aux = new AuxServices (MOCK_AUX_PATH_HANDLER ,
905
- MOCK_CONTEXT , MOCK_DEL_SERVICE );
916
+ AuxServices aux = spy (new AuxServices (MOCK_AUX_PATH_HANDLER ,
917
+ MOCK_CONTEXT , MOCK_DEL_SERVICE ));
918
+ doReturn (false ).when (aux ).checkManifestPermissions (any (FileStatus .class ));
906
919
aux .init (conf );
907
920
assertEquals (0 , aux .getServices ().size ());
908
921
909
- fs .setPermission (new Path (manifest .getAbsolutePath ()), FsPermission
910
- .createImmutable ((short ) 0755 ));
911
- fs .setPermission (new Path (rootDir .getAbsolutePath ()), FsPermission
912
- .createImmutable ((short ) 0775 ));
913
- aux = new AuxServices (MOCK_AUX_PATH_HANDLER ,
914
- MOCK_CONTEXT , MOCK_DEL_SERVICE );
915
- aux .init (conf );
916
- assertEquals (0 , aux .getServices ().size ());
917
-
918
- fs .setPermission (new Path (rootDir .getAbsolutePath ()), FsPermission
919
- .createImmutable ((short ) 0755 ));
920
- aux = new AuxServices (MOCK_AUX_PATH_HANDLER ,
922
+ aux = getSpyAuxServices (MOCK_AUX_PATH_HANDLER ,
921
923
MOCK_CONTEXT , MOCK_DEL_SERVICE );
922
924
aux .init (conf );
923
925
assertEquals (2 , aux .getServices ().size ());
924
926
925
927
conf .set (YarnConfiguration .YARN_ADMIN_ACL , "" );
926
- aux = new AuxServices (MOCK_AUX_PATH_HANDLER ,
928
+ aux = getSpyAuxServices (MOCK_AUX_PATH_HANDLER ,
927
929
MOCK_CONTEXT , MOCK_DEL_SERVICE );
928
930
aux .init (conf );
929
931
assertEquals (0 , aux .getServices ().size ());
930
932
931
933
conf .set (YarnConfiguration .YARN_ADMIN_ACL , UserGroupInformation
932
934
.getCurrentUser ().getShortUserName ());
933
- aux = new AuxServices (MOCK_AUX_PATH_HANDLER ,
935
+ aux = getSpyAuxServices (MOCK_AUX_PATH_HANDLER ,
934
936
MOCK_CONTEXT , MOCK_DEL_SERVICE );
935
937
aux .init (conf );
936
938
assertEquals (2 , aux .getServices ().size ());
937
939
}
938
940
941
+ @ Test
942
+ public void testCheckManifestPermissionsWhenFileIsOnlyWritableByOwner () throws IOException {
943
+ Assume .assumeTrue (useManifest );
944
+ final AuxServices aux = spy (new AuxServices (MOCK_AUX_PATH_HANDLER ,
945
+ MOCK_CONTEXT , MOCK_DEL_SERVICE ));
946
+ FileStatus manifestFileStatus = mock (FileStatus .class );
947
+ Path manifestPath = mock (Path .class );
948
+
949
+ when (manifestFileStatus .getPermission ()).thenReturn (WRITABLE_BY_OWNER );
950
+ when (manifestFileStatus .getPath ()).thenReturn (manifestPath );
951
+
952
+ assertTrue (aux .checkManifestPermissions (manifestFileStatus ));
953
+ }
954
+
955
+ @ Test
956
+ public void testCheckManifestPermissionsWhenFileIsWritableByGroup () throws IOException {
957
+ Assume .assumeTrue (useManifest );
958
+ final AuxServices aux = spy (new AuxServices (MOCK_AUX_PATH_HANDLER ,
959
+ MOCK_CONTEXT , MOCK_DEL_SERVICE ));
960
+ FileStatus manifestFileStatus = mock (FileStatus .class );
961
+ Path manifestPath = mock (Path .class );
962
+
963
+ when (manifestFileStatus .getPermission ()).thenReturn (WRITABLE_BY_GROUP );
964
+ when (manifestFileStatus .getPath ()).thenReturn (manifestPath );
965
+
966
+ assertFalse (aux .checkManifestPermissions (manifestFileStatus ));
967
+ }
968
+
969
+ @ Test
970
+ public void testCheckManifestPermissionsWhenParentIsWritableByGroup () throws IOException {
971
+ Assume .assumeTrue (useManifest );
972
+ final AuxServices aux = spy (new AuxServices (MOCK_AUX_PATH_HANDLER ,
973
+ MOCK_CONTEXT , MOCK_DEL_SERVICE ));
974
+
975
+ FileStatus manifestFileStatus = mock (FileStatus .class );
976
+ FileStatus parentFolderStatus = mock (FileStatus .class );
977
+ when (manifestFileStatus .getPermission ()).thenReturn (WRITABLE_BY_OWNER );
978
+ when (parentFolderStatus .getPermission ()).thenReturn (WRITABLE_BY_GROUP );
979
+
980
+ Path manifestPath = mock (Path .class );
981
+ Path parentPath = mock (Path .class );
982
+ when (manifestFileStatus .getPath ()).thenReturn (manifestPath );
983
+ when (manifestPath .getParent ()).thenReturn (parentPath );
984
+
985
+ FileSystem manifestFs = mock (FileSystem .class );
986
+ when (manifestFs .getFileStatus (parentPath )).thenReturn (parentFolderStatus );
987
+ doReturn (manifestFs ).when (aux ).getManifestFS ();
988
+
989
+ assertFalse (aux .checkManifestPermissions (manifestFileStatus ));
990
+ }
991
+
992
+ @ Test
993
+ public void testCheckManifestPermissionsWhenParentAndFileIsWritableByOwner () throws IOException {
994
+ Assume .assumeTrue (useManifest );
995
+ final AuxServices aux = spy (new AuxServices (MOCK_AUX_PATH_HANDLER ,
996
+ MOCK_CONTEXT , MOCK_DEL_SERVICE ));
997
+
998
+ FileStatus manifestFileStatus = mock (FileStatus .class );
999
+ FileStatus parentFolderStatus = mock (FileStatus .class );
1000
+ when (manifestFileStatus .getPermission ()).thenReturn (WRITABLE_BY_OWNER );
1001
+ when (parentFolderStatus .getPermission ()).thenReturn (WRITABLE_BY_OWNER );
1002
+
1003
+ Path manifestPath = mock (Path .class );
1004
+ Path parentPath = mock (Path .class );
1005
+ when (manifestFileStatus .getPath ()).thenReturn (manifestPath );
1006
+ when (parentFolderStatus .getPath ()).thenReturn (parentPath );
1007
+ when (manifestPath .getParent ()).thenReturn (parentPath );
1008
+
1009
+ FileSystem manifestFs = mock (FileSystem .class );
1010
+ when (manifestFs .getFileStatus (parentPath )).thenReturn (parentFolderStatus );
1011
+ doReturn (manifestFs ).when (aux ).getManifestFS ();
1012
+
1013
+ assertTrue (aux .checkManifestPermissions (manifestFileStatus ));
1014
+ }
1015
+
939
1016
@ Test
940
1017
public void testRemoveManifest () throws IOException {
941
1018
Assume .assumeTrue (useManifest );
942
1019
Configuration conf = getABConf ();
943
- final AuxServices aux = new AuxServices (MOCK_AUX_PATH_HANDLER ,
1020
+ final AuxServices aux = getSpyAuxServices (MOCK_AUX_PATH_HANDLER ,
944
1021
MOCK_CONTEXT , MOCK_DEL_SERVICE );
945
1022
aux .init (conf );
946
1023
assertEquals (2 , aux .getServices ().size ());
@@ -953,7 +1030,7 @@ public void testRemoveManifest() throws IOException {
953
1030
public void testManualReload () throws IOException {
954
1031
Assume .assumeTrue (useManifest );
955
1032
Configuration conf = getABConf ();
956
- final AuxServices aux = new AuxServices (MOCK_AUX_PATH_HANDLER ,
1033
+ final AuxServices aux = getSpyAuxServices (MOCK_AUX_PATH_HANDLER ,
957
1034
MOCK_CONTEXT , MOCK_DEL_SERVICE );
958
1035
aux .init (conf );
959
1036
try {
0 commit comments