mirror of
https://github.com/SAP/jenkins-library.git
synced 2024-12-14 11:03:09 +02:00
No cf api for checking login state (#1785)
* Dont work upon a global command.Command instance inside cloudfoundry package o Up to now we work on a private and shared instance of command.Command inside the cloudfounrdy package. We need to be able either configure this instance (environment variables) according to the use case. One option is to hand over an already configured instance which is used elsewhere. This is what we do with this commit. o With this commit we remove the instance which is shared within the cloudfounrdy package and to provide an instance with a receiver which gets handed over to the functions. Hence we are thread save: parallel invoctation of e.g. Login will not affect each other.
This commit is contained in:
parent
49d4f6269a
commit
37ccebeb77
@ -1,71 +1,17 @@
|
|||||||
package cloudfoundry
|
package cloudfoundry
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"bytes"
|
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
"strings"
|
|
||||||
|
|
||||||
"github.com/SAP/jenkins-library/pkg/command"
|
"github.com/SAP/jenkins-library/pkg/command"
|
||||||
"github.com/SAP/jenkins-library/pkg/log"
|
"github.com/SAP/jenkins-library/pkg/log"
|
||||||
)
|
)
|
||||||
|
|
||||||
//LoginCheck checks if user is logged in to Cloud Foundry.
|
//LoginCheck checks if user is logged in to Cloud Foundry with the receiver provided
|
||||||
//If user is not logged in 'cf api' command will return string that contains 'User is not logged in' only if user is not logged in.
|
//to the function call.
|
||||||
//If the returned string doesn't contain the substring 'User is not logged in' we know he is logged in.
|
|
||||||
func (cf *CFUtils) LoginCheck(options LoginOptions) (bool, error) {
|
func (cf *CFUtils) LoginCheck(options LoginOptions) (bool, error) {
|
||||||
var err error
|
return cf.loggedIn, nil
|
||||||
|
|
||||||
_c := cf.Exec
|
|
||||||
|
|
||||||
if _c == nil {
|
|
||||||
_c = &command.Command{}
|
|
||||||
}
|
|
||||||
|
|
||||||
if options.CfAPIEndpoint == "" {
|
|
||||||
return false, errors.New("Cloud Foundry API endpoint parameter missing. Please provide the Cloud Foundry Endpoint")
|
|
||||||
}
|
|
||||||
|
|
||||||
//Check if logged in --> Cf api command responds with "not logged in" if positive
|
|
||||||
var cfCheckLoginScript = append([]string{"api", options.CfAPIEndpoint}, options.CfAPIOpts...)
|
|
||||||
|
|
||||||
defer func() {
|
|
||||||
// We set it back to what is set from the generated stub. Of course this is not
|
|
||||||
// fully accurate in case we create our own instance above (nothing handed in via
|
|
||||||
// the receiver).
|
|
||||||
// Would be better to remember the old stdout and set back to this.
|
|
||||||
// But command.Command does not allow to get the currently set
|
|
||||||
// stdout handler.
|
|
||||||
// Reason for changing the output stream here: we need to parse the output
|
|
||||||
// of the command issued here in order to check if we are already logged in.
|
|
||||||
// This is expected to change soon to a boolean variable where we remember the
|
|
||||||
// login state.
|
|
||||||
_c.Stdout(log.Writer())
|
|
||||||
}()
|
|
||||||
|
|
||||||
var cfLoginBytes bytes.Buffer
|
|
||||||
_c.Stdout(&cfLoginBytes)
|
|
||||||
|
|
||||||
var result string
|
|
||||||
|
|
||||||
err = _c.RunExecutable("cf", cfCheckLoginScript...)
|
|
||||||
|
|
||||||
if err != nil {
|
|
||||||
return false, fmt.Errorf("Failed to check if logged in: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
result = cfLoginBytes.String()
|
|
||||||
log.Entry().WithField("result: ", result).Info("Login check")
|
|
||||||
|
|
||||||
//Logged in
|
|
||||||
if strings.Contains(result, "Not logged in") == false {
|
|
||||||
log.Entry().Info("Login check indicates you are already logged in to Cloud Foundry")
|
|
||||||
return true, err
|
|
||||||
}
|
|
||||||
|
|
||||||
//Not logged in
|
|
||||||
log.Entry().Info("Login check indicates you are not yet logged in to Cloud Foundry")
|
|
||||||
return false, err
|
|
||||||
}
|
}
|
||||||
|
|
||||||
//Login logs user in to Cloud Foundry via cf cli.
|
//Login logs user in to Cloud Foundry via cf cli.
|
||||||
@ -112,6 +58,7 @@ func (cf *CFUtils) Login(options LoginOptions) error {
|
|||||||
return fmt.Errorf("Failed to login to Cloud Foundry: %w", err)
|
return fmt.Errorf("Failed to login to Cloud Foundry: %w", err)
|
||||||
}
|
}
|
||||||
log.Entry().Info("Logged in successfully to Cloud Foundry..")
|
log.Entry().Info("Logged in successfully to Cloud Foundry..")
|
||||||
|
cf.loggedIn = true
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -134,6 +81,7 @@ func (cf *CFUtils) Logout() error {
|
|||||||
return fmt.Errorf("Failed to Logout of Cloud Foundry: %w", err)
|
return fmt.Errorf("Failed to Logout of Cloud Foundry: %w", err)
|
||||||
}
|
}
|
||||||
log.Entry().Info("Logged out successfully")
|
log.Entry().Info("Logged out successfully")
|
||||||
|
cf.loggedIn = false
|
||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -155,5 +103,6 @@ type CFUtils struct {
|
|||||||
// environment variables CF_HOME to distict directories.
|
// environment variables CF_HOME to distict directories.
|
||||||
// In order to ensure plugins installed to the cf cli are found environment variables
|
// In order to ensure plugins installed to the cf cli are found environment variables
|
||||||
// CF_PLUGIN_HOME can be set accordingly.
|
// CF_PLUGIN_HOME can be set accordingly.
|
||||||
Exec command.ExecRunner
|
Exec command.ExecRunner
|
||||||
|
loggedIn bool
|
||||||
}
|
}
|
||||||
|
@ -18,66 +18,31 @@ func TestCloudFoundryLoginCheck(t *testing.T) {
|
|||||||
|
|
||||||
m := &mock.ExecMockRunner{}
|
m := &mock.ExecMockRunner{}
|
||||||
|
|
||||||
t.Run("CF Login check: missing endpoint parameter", func(t *testing.T) {
|
t.Run("CF Login check: logged in", func(t *testing.T) {
|
||||||
cfconfig := LoginOptions{}
|
|
||||||
cf := CFUtils{Exec: m}
|
|
||||||
loggedIn, err := cf.LoginCheck(cfconfig)
|
|
||||||
assert.False(t, loggedIn)
|
|
||||||
assert.EqualError(t, err, "Cloud Foundry API endpoint parameter missing. Please provide the Cloud Foundry Endpoint")
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("CF Login check: failure case", func(t *testing.T) {
|
|
||||||
|
|
||||||
defer loginMockCleanup(m)
|
|
||||||
|
|
||||||
m.ShouldFailOnCommand = map[string]error{"cf api.*": fmt.Errorf("Cannot perform login check")}
|
|
||||||
cfconfig := LoginOptions{
|
|
||||||
CfAPIEndpoint: "https://api.endpoint.com",
|
|
||||||
}
|
|
||||||
cf := CFUtils{Exec: m}
|
|
||||||
loggedIn, err := cf.LoginCheck(cfconfig)
|
|
||||||
assert.False(t, loggedIn)
|
|
||||||
assert.Error(t, err)
|
|
||||||
assert.Equal(t, []mock.ExecCall{mock.ExecCall{Exec: "cf", Params: []string{"api", "https://api.endpoint.com"}}}, m.Calls)
|
|
||||||
})
|
|
||||||
|
|
||||||
t.Run("CF Login check: success case", func(t *testing.T) {
|
|
||||||
|
|
||||||
defer loginMockCleanup(m)
|
defer loginMockCleanup(m)
|
||||||
|
|
||||||
cfconfig := LoginOptions{
|
cfconfig := LoginOptions{
|
||||||
CfAPIEndpoint: "https://api.endpoint.com",
|
CfAPIEndpoint: "https://api.endpoint.com",
|
||||||
}
|
}
|
||||||
cf := CFUtils{Exec: m}
|
cf := CFUtils{Exec: m, loggedIn: true}
|
||||||
loggedIn, err := cf.LoginCheck(cfconfig)
|
loggedIn, err := cf.LoginCheck(cfconfig)
|
||||||
if assert.NoError(t, err) {
|
if assert.NoError(t, err) {
|
||||||
assert.True(t, loggedIn)
|
assert.True(t, loggedIn)
|
||||||
assert.Equal(t, []mock.ExecCall{mock.ExecCall{Exec: "cf", Params: []string{"api", "https://api.endpoint.com"}}}, m.Calls)
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
t.Run("CF Login check: with additional API options", func(t *testing.T) {
|
t.Run("CF Login check: not logged in", func(t *testing.T) {
|
||||||
|
|
||||||
defer loginMockCleanup(m)
|
defer loginMockCleanup(m)
|
||||||
|
|
||||||
cfconfig := LoginOptions{
|
cfconfig := LoginOptions{
|
||||||
CfAPIEndpoint: "https://api.endpoint.com",
|
CfAPIEndpoint: "https://api.endpoint.com",
|
||||||
// should never used in productive environment, but it is useful for rapid prototyping/troubleshooting
|
|
||||||
CfAPIOpts: []string{"--skip-ssl-validation"},
|
|
||||||
}
|
}
|
||||||
|
cf := CFUtils{Exec: m, loggedIn: false}
|
||||||
cf := CFUtils{Exec: m}
|
|
||||||
loggedIn, err := cf.LoginCheck(cfconfig)
|
loggedIn, err := cf.LoginCheck(cfconfig)
|
||||||
if assert.NoError(t, err) {
|
if assert.NoError(t, err) {
|
||||||
assert.True(t, loggedIn)
|
assert.False(t, loggedIn)
|
||||||
assert.Equal(t, []mock.ExecCall{
|
|
||||||
mock.ExecCall{
|
|
||||||
Exec: "cf",
|
|
||||||
Params: []string{
|
|
||||||
"api",
|
|
||||||
"https://api.endpoint.com",
|
|
||||||
"--skip-ssl-validation",
|
|
||||||
}}}, m.Calls)
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
@ -99,7 +64,6 @@ func TestCloudFoundryLogin(t *testing.T) {
|
|||||||
|
|
||||||
defer loginMockCleanup(m)
|
defer loginMockCleanup(m)
|
||||||
|
|
||||||
m.StdoutReturn = map[string]string{"cf api .*": "Not logged in"}
|
|
||||||
m.ShouldFailOnCommand = map[string]error{"cf login .*": fmt.Errorf("wrong password or account does not exist")}
|
m.ShouldFailOnCommand = map[string]error{"cf login .*": fmt.Errorf("wrong password or account does not exist")}
|
||||||
|
|
||||||
cfconfig := LoginOptions{
|
cfconfig := LoginOptions{
|
||||||
@ -113,8 +77,8 @@ func TestCloudFoundryLogin(t *testing.T) {
|
|||||||
cf := CFUtils{Exec: m}
|
cf := CFUtils{Exec: m}
|
||||||
err := cf.Login(cfconfig)
|
err := cf.Login(cfconfig)
|
||||||
if assert.EqualError(t, err, "Failed to login to Cloud Foundry: wrong password or account does not exist") {
|
if assert.EqualError(t, err, "Failed to login to Cloud Foundry: wrong password or account does not exist") {
|
||||||
|
assert.False(t, cf.loggedIn)
|
||||||
assert.Equal(t, []mock.ExecCall{
|
assert.Equal(t, []mock.ExecCall{
|
||||||
mock.ExecCall{Exec: "cf", Params: []string{"api", "https://api.endpoint.com"}},
|
|
||||||
mock.ExecCall{Exec: "cf", Params: []string{
|
mock.ExecCall{Exec: "cf", Params: []string{
|
||||||
"login",
|
"login",
|
||||||
"-a", "https://api.endpoint.com",
|
"-a", "https://api.endpoint.com",
|
||||||
@ -143,8 +107,8 @@ func TestCloudFoundryLogin(t *testing.T) {
|
|||||||
cf := CFUtils{Exec: m}
|
cf := CFUtils{Exec: m}
|
||||||
err := cf.Login(cfconfig)
|
err := cf.Login(cfconfig)
|
||||||
if assert.NoError(t, err) {
|
if assert.NoError(t, err) {
|
||||||
|
assert.True(t, cf.loggedIn)
|
||||||
assert.Equal(t, []mock.ExecCall{
|
assert.Equal(t, []mock.ExecCall{
|
||||||
mock.ExecCall{Exec: "cf", Params: []string{"api", "https://api.endpoint.com"}},
|
|
||||||
mock.ExecCall{Exec: "cf", Params: []string{
|
mock.ExecCall{Exec: "cf", Params: []string{
|
||||||
"login",
|
"login",
|
||||||
"-a", "https://api.endpoint.com",
|
"-a", "https://api.endpoint.com",
|
||||||
@ -161,8 +125,6 @@ func TestCloudFoundryLogin(t *testing.T) {
|
|||||||
|
|
||||||
defer loginMockCleanup(m)
|
defer loginMockCleanup(m)
|
||||||
|
|
||||||
m.StdoutReturn = map[string]string{"cf api:*": "Not logged in"}
|
|
||||||
|
|
||||||
cfconfig := LoginOptions{
|
cfconfig := LoginOptions{
|
||||||
CfAPIEndpoint: "https://api.endpoint.com",
|
CfAPIEndpoint: "https://api.endpoint.com",
|
||||||
CfSpace: "testSpace",
|
CfSpace: "testSpace",
|
||||||
@ -181,12 +143,8 @@ func TestCloudFoundryLogin(t *testing.T) {
|
|||||||
cf := CFUtils{Exec: m}
|
cf := CFUtils{Exec: m}
|
||||||
err := cf.Login(cfconfig)
|
err := cf.Login(cfconfig)
|
||||||
if assert.NoError(t, err) {
|
if assert.NoError(t, err) {
|
||||||
|
assert.True(t, cf.loggedIn)
|
||||||
assert.Equal(t, []mock.ExecCall{
|
assert.Equal(t, []mock.ExecCall{
|
||||||
mock.ExecCall{Exec: "cf", Params: []string{
|
|
||||||
"api",
|
|
||||||
"https://api.endpoint.com",
|
|
||||||
"--skip-ssl-validation",
|
|
||||||
}},
|
|
||||||
mock.ExecCall{Exec: "cf", Params: []string{
|
mock.ExecCall{Exec: "cf", Params: []string{
|
||||||
"login",
|
"login",
|
||||||
"-a", "https://api.endpoint.com",
|
"-a", "https://api.endpoint.com",
|
||||||
@ -200,17 +158,14 @@ func TestCloudFoundryLogin(t *testing.T) {
|
|||||||
}, m.Calls)
|
}, m.Calls)
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCloudFoundryLogout(t *testing.T) {
|
func TestCloudFoundryLogout(t *testing.T) {
|
||||||
t.Run("CF Logout", func(t *testing.T) {
|
t.Run("CF Logout", func(t *testing.T) {
|
||||||
cf := CFUtils{Exec: &mock.ExecMockRunner{}}
|
cf := CFUtils{Exec: &mock.ExecMockRunner{}, loggedIn: true}
|
||||||
err := cf.Logout()
|
err := cf.Logout()
|
||||||
if err == nil {
|
if assert.NoError(t, err) {
|
||||||
assert.Equal(t, nil, err)
|
assert.False(t, cf.loggedIn)
|
||||||
} else {
|
|
||||||
assert.Error(t, err)
|
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user