github.com/DaAlbrecht/cf-cli@v0.0.0-20231128151943-1fe19bb400b9/actor/v7action/ssh_test.go (about)

     1  package v7action_test
     2  
     3  import (
     4  	"errors"
     5  
     6  	"code.cloudfoundry.org/cli/actor/actionerror"
     7  	. "code.cloudfoundry.org/cli/actor/v7action"
     8  	"code.cloudfoundry.org/cli/actor/v7action/v7actionfakes"
     9  	"code.cloudfoundry.org/cli/api/cloudcontroller/ccv3"
    10  	"code.cloudfoundry.org/cli/api/cloudcontroller/ccv3/constant"
    11  	"code.cloudfoundry.org/cli/resources"
    12  	. "github.com/onsi/ginkgo"
    13  	. "github.com/onsi/gomega"
    14  )
    15  
    16  var _ = Describe("SSH Actions", func() {
    17  	var (
    18  		actor                     *Actor
    19  		fakeCloudControllerClient *v7actionfakes.FakeCloudControllerClient
    20  		fakeConfig                *v7actionfakes.FakeConfig
    21  		fakeSharedActor           *v7actionfakes.FakeSharedActor
    22  		fakeUAAClient             *v7actionfakes.FakeUAAClient
    23  		executeErr                error
    24  		warnings                  Warnings
    25  	)
    26  
    27  	BeforeEach(func() {
    28  		fakeCloudControllerClient = new(v7actionfakes.FakeCloudControllerClient)
    29  		fakeConfig = new(v7actionfakes.FakeConfig)
    30  		fakeSharedActor = new(v7actionfakes.FakeSharedActor)
    31  		fakeUAAClient = new(v7actionfakes.FakeUAAClient)
    32  		actor = NewActor(fakeCloudControllerClient, fakeConfig, fakeSharedActor, fakeUAAClient, nil, nil)
    33  	})
    34  
    35  	Describe("GetSSHPasscode", func() {
    36  		var uaaAccessToken string
    37  
    38  		BeforeEach(func() {
    39  			uaaAccessToken = "4cc3sst0k3n"
    40  			fakeConfig.AccessTokenReturns(uaaAccessToken)
    41  			fakeConfig.SSHOAuthClientReturns("some-id")
    42  		})
    43  
    44  		When("no errors are encountered getting the ssh passcode", func() {
    45  			var expectedCode string
    46  
    47  			BeforeEach(func() {
    48  				expectedCode = "s3curep4ss"
    49  				fakeUAAClient.GetSSHPasscodeReturns(expectedCode, nil)
    50  			})
    51  
    52  			It("returns the ssh passcode", func() {
    53  				code, err := actor.GetSSHPasscode()
    54  				Expect(err).ToNot(HaveOccurred())
    55  				Expect(code).To(Equal(expectedCode))
    56  				Expect(fakeUAAClient.GetSSHPasscodeCallCount()).To(Equal(1))
    57  				accessTokenArg, sshOAuthClientArg := fakeUAAClient.GetSSHPasscodeArgsForCall(0)
    58  				Expect(accessTokenArg).To(Equal(uaaAccessToken))
    59  				Expect(sshOAuthClientArg).To(Equal("some-id"))
    60  			})
    61  		})
    62  
    63  		When("an error is encountered getting the ssh passcode", func() {
    64  			var expectedErr error
    65  
    66  			BeforeEach(func() {
    67  				expectedErr = errors.New("failed fetching code")
    68  				fakeUAAClient.GetSSHPasscodeReturns("", expectedErr)
    69  			})
    70  
    71  			It("returns the error", func() {
    72  				_, err := actor.GetSSHPasscode()
    73  				Expect(err).To(MatchError(expectedErr))
    74  				Expect(fakeUAAClient.GetSSHPasscodeCallCount()).To(Equal(1))
    75  				accessTokenArg, sshOAuthClientArg := fakeUAAClient.GetSSHPasscodeArgsForCall(0)
    76  				Expect(accessTokenArg).To(Equal(uaaAccessToken))
    77  				Expect(sshOAuthClientArg).To(Equal("some-id"))
    78  			})
    79  		})
    80  	})
    81  	Describe("GetSecureShellConfigurationByApplicationNameSpaceProcessTypeAndIndex", func() {
    82  		var sshAuth SSHAuthentication
    83  
    84  		BeforeEach(func() {
    85  			fakeConfig.AccessTokenReturns("some-access-token")
    86  			fakeConfig.SSHOAuthClientReturns("some-access-oauth-client")
    87  		})
    88  
    89  		JustBeforeEach(func() {
    90  			sshAuth, warnings, executeErr = actor.GetSecureShellConfigurationByApplicationNameSpaceProcessTypeAndIndex("some-app", "some-space-guid", "some-process-type", 0)
    91  		})
    92  
    93  		When("the app ssh endpoint is empty", func() {
    94  			BeforeEach(func() {
    95  				fakeCloudControllerClient.GetInfoReturns(ccv3.Info{
    96  					Links: ccv3.InfoLinks{
    97  						AppSSH: resources.APILink{HREF: ""},
    98  					},
    99  				}, nil, nil)
   100  			})
   101  
   102  			It("creates an ssh-endpoint-not-set error", func() {
   103  				Expect(executeErr).To(MatchError("SSH endpoint not set"))
   104  			})
   105  		})
   106  
   107  		When("the app ssh hostkey fingerprint is empty", func() {
   108  			BeforeEach(func() {
   109  				fakeCloudControllerClient.GetInfoReturns(ccv3.Info{
   110  					Links: ccv3.InfoLinks{
   111  						AppSSH: resources.APILink{HREF: "some-app-ssh-endpoint"},
   112  					},
   113  				}, nil, nil)
   114  			})
   115  
   116  			It("creates an ssh-hostkey-fingerprint-not-set error", func() {
   117  				Expect(executeErr).To(MatchError("SSH hostkey fingerprint not set"))
   118  			})
   119  		})
   120  
   121  		When("ssh endpoint and fingerprint are set", func() {
   122  			BeforeEach(func() {
   123  				fakeCloudControllerClient.GetInfoReturns(ccv3.Info{
   124  					Links: ccv3.InfoLinks{
   125  						AppSSH: resources.APILink{
   126  							HREF: "some-app-ssh-endpoint",
   127  							Meta: resources.APILinkMeta{HostKeyFingerprint: "some-app-ssh-fingerprint"},
   128  						},
   129  					},
   130  				}, nil, nil)
   131  			})
   132  
   133  			It("looks up the passcode with the config credentials", func() {
   134  				Expect(fakeUAAClient.GetSSHPasscodeCallCount()).To(Equal(1))
   135  				accessTokenArg, oathClientArg := fakeUAAClient.GetSSHPasscodeArgsForCall(0)
   136  				Expect(accessTokenArg).To(Equal("some-access-token"))
   137  				Expect(oathClientArg).To(Equal("some-access-oauth-client"))
   138  			})
   139  
   140  			When("getting the ssh passcode errors", func() {
   141  				BeforeEach(func() {
   142  					fakeUAAClient.GetSSHPasscodeReturns("", errors.New("some-ssh-passcode-error"))
   143  				})
   144  
   145  				It("returns the error", func() {
   146  					Expect(executeErr).To(MatchError("some-ssh-passcode-error"))
   147  				})
   148  			})
   149  
   150  			When("getting the ssh passcode succeeds", func() {
   151  				BeforeEach(func() {
   152  					fakeUAAClient.GetSSHPasscodeReturns("some-ssh-passcode", nil)
   153  				})
   154  
   155  				When("getting the application errors", func() {
   156  					BeforeEach(func() {
   157  						fakeCloudControllerClient.GetApplicationsReturns(nil, ccv3.Warnings{"some-app-warnings"}, errors.New("some-application-error"))
   158  					})
   159  
   160  					It("returns all warnings and the error", func() {
   161  						Expect(executeErr).To(MatchError("some-application-error"))
   162  						Expect(warnings).To(ConsistOf("some-app-warnings"))
   163  					})
   164  				})
   165  
   166  				When("getting the application succeeds with a started application", func() {
   167  					BeforeEach(func() {
   168  						fakeCloudControllerClient.GetApplicationsReturns(
   169  							[]resources.Application{
   170  								{Name: "some-app", State: constant.ApplicationStarted},
   171  							},
   172  							ccv3.Warnings{"some-app-warnings"},
   173  							nil)
   174  					})
   175  
   176  					When("getting the process summaries fails", func() {
   177  						BeforeEach(func() {
   178  							fakeCloudControllerClient.GetApplicationProcessesReturns(nil, ccv3.Warnings{"some-process-warnings"}, errors.New("some-process-error"))
   179  						})
   180  
   181  						It("returns all warnings and the error", func() {
   182  							Expect(executeErr).To(MatchError("some-process-error"))
   183  							Expect(warnings).To(ConsistOf("some-app-warnings", "some-process-warnings"))
   184  						})
   185  					})
   186  
   187  					When("getting the process summaries succeeds", func() {
   188  						When("the process does not exist", func() {
   189  							BeforeEach(func() {
   190  								fakeCloudControllerClient.GetApplicationProcessesReturns([]resources.Process{}, ccv3.Warnings{"some-process-warnings"}, nil)
   191  							})
   192  
   193  							It("returns all warnings and the error", func() {
   194  								Expect(executeErr).To(MatchError(actionerror.ProcessNotFoundError{ProcessType: "some-process-type"}))
   195  								Expect(warnings).To(ConsistOf("some-app-warnings", "some-process-warnings"))
   196  							})
   197  						})
   198  
   199  						When("the process doesn't have the specified instance index", func() {
   200  							BeforeEach(func() {
   201  								fakeCloudControllerClient.GetApplicationsReturns([]resources.Application{{Name: "some-app", State: constant.ApplicationStarted}}, ccv3.Warnings{"some-app-warnings"}, nil)
   202  								fakeCloudControllerClient.GetApplicationProcessesReturns([]resources.Process{{Type: "some-process-type", GUID: "some-process-guid"}}, ccv3.Warnings{"some-process-warnings"}, nil)
   203  							})
   204  
   205  							It("returns a ProcessIndexNotFoundError", func() {
   206  								Expect(executeErr).To(MatchError(actionerror.ProcessInstanceNotFoundError{ProcessType: "some-process-type", InstanceIndex: 0}))
   207  							})
   208  						})
   209  
   210  						When("the process instance is not RUNNING", func() {
   211  							BeforeEach(func() {
   212  								fakeCloudControllerClient.GetApplicationsReturns([]resources.Application{{Name: "some-app", State: constant.ApplicationStarted}}, ccv3.Warnings{"some-app-warnings"}, nil)
   213  								fakeCloudControllerClient.GetApplicationProcessesReturns([]resources.Process{{Type: "some-process-type", GUID: "some-process-guid"}}, ccv3.Warnings{"some-process-warnings"}, nil)
   214  								fakeCloudControllerClient.GetProcessInstancesReturns([]ccv3.ProcessInstance{{State: constant.ProcessInstanceDown, Index: 0}}, ccv3.Warnings{"some-instance-warnings"}, nil)
   215  							})
   216  
   217  							It("returns a ProcessInstanceNotRunningError", func() {
   218  								Expect(executeErr).To(MatchError(actionerror.ProcessInstanceNotRunningError{ProcessType: "some-process-type", InstanceIndex: 0}))
   219  							})
   220  						})
   221  
   222  						When("the specified process and index exist and the instance is RUNNING", func() {
   223  							BeforeEach(func() {
   224  								fakeCloudControllerClient.GetApplicationsReturns([]resources.Application{{Name: "some-app", State: constant.ApplicationStarted}}, ccv3.Warnings{"some-app-warnings"}, nil)
   225  								fakeCloudControllerClient.GetApplicationProcessesReturns([]resources.Process{{Type: "some-process-type", GUID: "some-process-guid"}}, ccv3.Warnings{"some-process-warnings"}, nil)
   226  								fakeCloudControllerClient.GetProcessInstancesReturns([]ccv3.ProcessInstance{{State: constant.ProcessInstanceRunning, Index: 0}}, ccv3.Warnings{"some-instance-warnings"}, nil)
   227  							})
   228  
   229  							When("starting the secure session succeeds", func() {
   230  								It("returns all warnings", func() {
   231  									Expect(executeErr).ToNot(HaveOccurred())
   232  									Expect(warnings).To(ConsistOf("some-app-warnings", "some-process-warnings", "some-instance-warnings"))
   233  
   234  									Expect(sshAuth).To(Equal(SSHAuthentication{
   235  										Endpoint:           "some-app-ssh-endpoint",
   236  										HostKeyFingerprint: "some-app-ssh-fingerprint",
   237  										Passcode:           "some-ssh-passcode",
   238  										Username:           "cf:some-process-guid/0",
   239  									}))
   240  
   241  									Expect(fakeCloudControllerClient.GetApplicationsCallCount()).To(Equal(1))
   242  									Expect(fakeCloudControllerClient.GetApplicationsArgsForCall(0)).To(ConsistOf(
   243  										ccv3.Query{Key: ccv3.NameFilter, Values: []string{"some-app"}},
   244  										ccv3.Query{Key: ccv3.SpaceGUIDFilter, Values: []string{"some-space-guid"}},
   245  									))
   246  								})
   247  							})
   248  						})
   249  					})
   250  				})
   251  
   252  				When("getting the application succeeds with a stopped application", func() {
   253  					BeforeEach(func() {
   254  						fakeCloudControllerClient.GetApplicationsReturns(
   255  							[]resources.Application{
   256  								{Name: "some-app", State: constant.ApplicationStopped},
   257  							},
   258  							ccv3.Warnings{"some-app-warnings"},
   259  							nil)
   260  					})
   261  
   262  					It("returns a ApplicationNotStartedError", func() {
   263  						Expect(executeErr).To(MatchError(actionerror.ApplicationNotStartedError{Name: "some-app"}))
   264  						Expect(warnings).To(ConsistOf("some-app-warnings"))
   265  					})
   266  				})
   267  			})
   268  		})
   269  	})
   270  })