@@ -606,6 +606,91 @@ func TestNodeStageISCSIVolume(t *testing.T) {
606
606
}
607
607
}
608
608
609
+ func TestGetChapInfoFromController (t * testing.T ) {
610
+ type args struct {
611
+ ctx context.Context
612
+ volume string
613
+ node string
614
+ }
615
+
616
+ type data struct {
617
+ chapInfo * models.IscsiChapInfo
618
+ }
619
+
620
+ type assertions struct {
621
+ Error assert.ErrorAssertionFunc
622
+ Empty assert.ValueAssertionFunc
623
+ Equal assert.ComparisonAssertionFunc
624
+ }
625
+
626
+ tt := map [string ]struct {
627
+ args args
628
+ data data
629
+ assert assertions
630
+ mocks func (mockAPI * mockControllerAPI.MockTridentController , args args , data data )
631
+ }{
632
+ "Successfully gets CHAP credentials" : {
633
+ args : args {
634
+ ctx : context .Background (),
635
+ volume : "foo" ,
636
+ node : "bar" ,
637
+ },
638
+ data : data {
639
+ chapInfo : & models.IscsiChapInfo {
640
+ UseCHAP : true ,
641
+ IscsiUsername : "user" ,
642
+ IscsiInitiatorSecret : "pass" ,
643
+ IscsiTargetUsername : "user2" ,
644
+ IscsiTargetSecret : "pass2" ,
645
+ },
646
+ },
647
+ assert : assertions {
648
+ Error : assert .NoError ,
649
+ Empty : assert .NotEmpty ,
650
+ Equal : assert .Equal ,
651
+ },
652
+ mocks : func (mockAPI * mockControllerAPI.MockTridentController , args args , data data ) {
653
+ mockAPI .EXPECT ().GetChap (args .ctx , args .volume , args .node ).Return (data .chapInfo , nil )
654
+ },
655
+ },
656
+ "Fails to get CHAP credentials" : {
657
+ args : args {
658
+ ctx : context .Background (),
659
+ volume : "foo" ,
660
+ node : "bar" ,
661
+ },
662
+ data : data {
663
+ chapInfo : nil ,
664
+ },
665
+ assert : assertions {
666
+ Error : assert .Error ,
667
+ Empty : assert .Empty ,
668
+ Equal : assert .Equal ,
669
+ },
670
+ mocks : func (mockAPI * mockControllerAPI.MockTridentController , args args , data data ) {
671
+ mockAPI .EXPECT ().GetChap (args .ctx , args .volume , args .node ).Return (data .chapInfo , errors .New ("api error" ))
672
+ },
673
+ },
674
+ }
675
+
676
+ for name , test := range tt {
677
+ t .Run (name , func (t * testing.T ) {
678
+ mockCtrl := gomock .NewController (t )
679
+ mockAPI := mockControllerAPI .NewMockTridentController (mockCtrl )
680
+ test .mocks (mockAPI , test .args , test .data )
681
+
682
+ plugin := & Plugin {
683
+ restClient : mockAPI ,
684
+ }
685
+
686
+ info , err := plugin .getChapInfoFromController (test .args .ctx , test .args .volume , test .args .node )
687
+ test .assert .Error (t , err )
688
+ test .assert .Empty (t , info )
689
+ test .assert .Equal (t , info , test .data .chapInfo )
690
+ })
691
+ }
692
+ }
693
+
609
694
func TestUpdateChapInfoFromController_Success (t * testing.T ) {
610
695
testCtx := context .Background ()
611
696
volumeName := "foo"
@@ -665,6 +750,129 @@ func TestUpdateChapInfoFromController_Error(t *testing.T) {
665
750
assert .EqualValues (t , models.IscsiChapInfo {}, testPublishInfo .IscsiAccessInfo .IscsiChapInfo )
666
751
}
667
752
753
+ func TestUpdateChapInfoForSessions (t * testing.T ) {
754
+ // Populate sessions with only the state that matters. The rest of the fields are not relevant for this test.
755
+ publishedSessions := & models.ISCSISessions {}
756
+ currentSessions := & models.ISCSISessions {}
757
+
758
+ // CHAP portals
759
+ chapPortals := []string {"0.0.0.0" , "4.4.4.4" , "5.5.5.5" }
760
+
761
+ // Unique CHAP portal
762
+ uniqueChapPortal := "9.9.9.9"
763
+ uniqueIQN := "iqn.9999-99.com.netapp:target"
764
+
765
+ // non-CHAP portals
766
+ nonChapPortals := []string {"1.1.1.1" , "2.2.2.2" , "3.3.3.3" }
767
+
768
+ sessionID := "0"
769
+
770
+ // Shared CHAP credentials
771
+ sharedCHAPInfo := models.IscsiChapInfo {
772
+ UseCHAP : true ,
773
+ IscsiUsername : "user" ,
774
+ IscsiInitiatorSecret : "pass" ,
775
+ IscsiTargetUsername : "user2" ,
776
+ IscsiTargetSecret : "pass2" ,
777
+ }
778
+
779
+ // Add CHAP sessions to both maps.
780
+ for _ , portal := range chapPortals {
781
+ err := publishedSessions .AddPortal (portal , models.PortalInfo {
782
+ ISCSITargetIQN : "iqn.2020-01.com.netapp:target" ,
783
+ Credentials : sharedCHAPInfo ,
784
+ })
785
+ assert .NoError (t , err )
786
+
787
+ err = currentSessions .AddPortal (portal , models.PortalInfo {
788
+ ISCSITargetIQN : "iqn.2020-01.com.netapp:target" ,
789
+ SessionNumber : sessionID ,
790
+ })
791
+ assert .NoError (t , err )
792
+ }
793
+
794
+ // Add a CHAP session with a unique IQN.
795
+ err := publishedSessions .AddPortal (uniqueChapPortal , models.PortalInfo {
796
+ // Use a different IQN here to prove we cache returned values from the REST API.
797
+ ISCSITargetIQN : uniqueIQN ,
798
+ Credentials : sharedCHAPInfo ,
799
+ })
800
+ assert .NoError (t , err )
801
+ err = currentSessions .AddPortal (uniqueChapPortal , models.PortalInfo {
802
+ ISCSITargetIQN : uniqueIQN ,
803
+ SessionNumber : sessionID ,
804
+ })
805
+ assert .NoError (t , err )
806
+
807
+ // Add non-CHAP session
808
+ for _ , portal := range nonChapPortals {
809
+ err := publishedSessions .AddPortal (portal , models.PortalInfo {
810
+ ISCSITargetIQN : "iqn.2020-01.com.netapp:target" ,
811
+ Credentials : models.IscsiChapInfo {},
812
+ })
813
+ assert .NoError (t , err )
814
+
815
+ err = currentSessions .AddPortal (portal , models.PortalInfo {
816
+ ISCSITargetIQN : "iqn.2020-01.com.netapp:target" ,
817
+ Credentials : models.IscsiChapInfo {},
818
+ SessionNumber : sessionID ,
819
+ })
820
+ assert .NoError (t , err )
821
+ }
822
+
823
+ // Populate a single of LUN and volume in each session.
824
+ volume := "foo"
825
+ node := "bar"
826
+ for _ , sessionData := range publishedSessions .Info {
827
+ sessionData .LUNs .Info [0 ] = volume
828
+ }
829
+
830
+ // Create a mock controller client that will return the expected CHAP info.
831
+ mockCtrl := gomock .NewController (t )
832
+ mockISCSI := mock_iscsi .NewMockISCSI (mockCtrl )
833
+ mockClient := mockControllerAPI .NewMockTridentController (mockCtrl )
834
+
835
+ plugin := & Plugin {
836
+ nodeName : node ,
837
+ iscsi : mockISCSI ,
838
+ restClient : mockClient ,
839
+ }
840
+
841
+ // Expect calls on the mock client for all sessions that use CHAP.
842
+ freshCHAPInfo := & models.IscsiChapInfo {
843
+ UseCHAP : true ,
844
+ IscsiUsername : "user2" ,
845
+ IscsiInitiatorSecret : "pass2" ,
846
+ IscsiTargetUsername : "user" ,
847
+ IscsiTargetSecret : "pass" ,
848
+ }
849
+
850
+ // Mock calls to the iSCSI client
851
+ count := len (currentSessions .Info )
852
+ mockISCSI .EXPECT ().IsSessionStale (gomock .Any (), sessionID ).Return (true ).Times (count )
853
+
854
+ // Mock API calls
855
+ count = len (chapPortals ) - (len (chapPortals ) - 1 ) + 1 // Expect one more call for the unique CHAP portal.
856
+ mockClient .EXPECT ().GetChap (
857
+ gomock .Any (), volume , node ,
858
+ ).Return (freshCHAPInfo , nil ).Times (count )
859
+
860
+ err = plugin .updateCHAPInfoForSessions (ctx , publishedSessions , currentSessions )
861
+ assert .NoError (t , err )
862
+
863
+ // Verify that the CHAP info was updated in all sessions that use CHAP.
864
+ for _ , portal := range chapPortals {
865
+ chapInfoInSession := publishedSessions .Info [portal ].PortalInfo .Credentials
866
+ assert .EqualValues (t , * freshCHAPInfo , chapInfoInSession )
867
+ }
868
+
869
+ // Verify that the non-CHAP portals were not updated.
870
+ for _ , portal := range nonChapPortals {
871
+ chapInfoInSession := publishedSessions .Info [portal ].PortalInfo .Credentials
872
+ assert .EqualValues (t , models.IscsiChapInfo {}, chapInfoInSession )
873
+ }
874
+ }
875
+
668
876
type PortalAction struct {
669
877
Portal string
670
878
Action models.ISCSIAction
0 commit comments