Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 26 additions & 9 deletions file_based_service_bindings/file_based_service_bindings.go
Original file line number Diff line number Diff line change
Expand Up @@ -26,23 +26,41 @@ var _ = FileBasedServiceBindingsDescribe("Enabling file based service binding fo

var callback = func(lifeCycle LifeCycle) {
var appName, serviceName string

BeforeEach(func() {
appName = random_name.CATSRandomName("APP")
serviceName = generator.PrefixedRandomName("cats", "svin") // uppercase characters are not valid
})

Context("When the file-based-vcap-services feature enabled", func() {
It("It should store the VCAP_SERVICE binding information in file in the VCAP_SERVICES_FILE_PATH", func() {
appGuid, serviceGuid := lifeCycle.Prepare(serviceName, appName, "file-based-vcap-services")
services.ValidateFileBasedVcapServices(appName, serviceName, appGuid, serviceGuid)
Context("When the file-based-vcap-services feature is enabled", func() {
Context("Via API call", func() {
It("It should store the VCAP_SERVICES binding information in a file in the VCAP_SERVICES_FILE_PATH", func() {
appGuid, serviceGuid := Prepare(appName, serviceName, "file-based-vcap-services", lifeCycle)
services.ValidateFileBasedVcapServices(appName, serviceName, appGuid, serviceGuid)
})
})

Context("Via manifest", func() {
It("It should store the VCAP_SERVICES binding information in a file in the VCAP_SERVICES_FILE_PATH", func() {
appGuid, serviceGuid := PrepareWithManifest(appName, serviceName, "file-based-vcap-services", lifeCycle)
services.ValidateFileBasedVcapServices(appName, serviceName, appGuid, serviceGuid)
})
})
})

Context("When the service-binding-k8s feature enabled", func() {
It("It should have environment variable SERVICE_BINDING_ROOT which defines the location for the service binding", func() {
appGuid, serviceGuid := lifeCycle.Prepare(serviceName, appName, "service-binding-k8s")
services.ValidateServiceBindingK8s(appName, serviceName, appGuid, serviceGuid)
Context("When the service-binding-k8s feature is enabled", func() {
Context("Via API call", func() {
It("It should store the binding information in files under the SERVICE_BINDING_ROOT path", func() {
appGuid, serviceGuid := Prepare(appName, serviceName, "service-binding-k8s", lifeCycle)
services.ValidateServiceBindingK8s(appName, serviceName, appGuid, serviceGuid)
})
})

Context("Via manifest", func() {
It("It should store the binding information in files under the SERVICE_BINDING_ROOT path", func() {
appGuid, serviceGuid := PrepareWithManifest(appName, serviceName, "service-binding-k8s", lifeCycle)
services.ValidateServiceBindingK8s(appName, serviceName, appGuid, serviceGuid)
})
})
})

Expand All @@ -52,5 +70,4 @@ var callback = func(lifeCycle LifeCycle) {
Eventually(cf.Cf("delete", appName, "-f")).Should(Exit(0))
Eventually(cf.Cf("delete-service", serviceName, "-f").Wait()).Should(Exit(0))
})

}
135 changes: 97 additions & 38 deletions file_based_service_bindings/life_cycles.go
Original file line number Diff line number Diff line change
Expand Up @@ -10,77 +10,136 @@ import (
"github.com/cloudfoundry/cf-test-helpers/v2/cf"
. "github.com/onsi/gomega"
. "github.com/onsi/gomega/gexec"
"os"
"path/filepath"
)

type LifeCycle interface {
Prepare(string, string, string) (string, string)
CreateAppArgs() []string
PushArgs() []string
}

type BuildpackLifecycles struct{}
type CNBLifecycles struct{}
type DockerLifecycles struct{}

func (b *BuildpackLifecycles) Prepare(serviceName, appName, appFeatureFlag string) (string, string) {

Expect(cf.Cf("create-app", appName).Wait()).To(Exit(0))
appGuid, serviceGuid := LifeCycleCommon(serviceName, appName, appFeatureFlag)

Expect(cf.Cf(app_helpers.CatnipWithArgs(
appName,
"-m", DEFAULT_MEMORY_LIMIT)...,
).Wait(Config.CfPushTimeoutDuration())).To(Exit(0))

return appGuid, serviceGuid

func (b *BuildpackLifecycles) CreateAppArgs() []string {
return []string{}
}

func (c *CNBLifecycles) Prepare(serviceName, appName, appFeatureFlag string) (string, string) {
func (b *BuildpackLifecycles) PushArgs() []string {
return []string{
"--buildpack", Config.GetBinaryBuildpackName(),
"-p", assets.NewAssets().Catnip,
"-c", "./catnip",
}
}

Expect(cf.Cf("create-app", appName, "--app-type", "cnb", "--buildpack", Config.GetGoBuildpackName()).Wait()).To(Exit(0))
appGuid, serviceGuid := LifeCycleCommon(serviceName, appName, appFeatureFlag)
func (c *CNBLifecycles) CreateAppArgs() []string {
return []string{
"--app-type", "cnb",
"--buildpack", Config.GetCNBGoBuildpackName(),
}
}

Expect(cf.Cf(
"push",
appName,
func (c *CNBLifecycles) PushArgs() []string {
return []string{
"--lifecycle", "cnb",
"--buildpack", Config.GetCNBGoBuildpackName(),
"-m", DEFAULT_MEMORY_LIMIT,
"-p", assets.NewAssets().CatnipSrc,
).Wait(Config.CfPushTimeoutDuration())).To(Exit(0))

return appGuid, serviceGuid
}
}

func (d *DockerLifecycles) Prepare(serviceName, appName, appFeatureFlag string) (string, string) {

Expect(cf.Cf("create-app", appName, "--app-type", "docker").Wait()).To(Exit(0))
appGuid, serviceGuid := LifeCycleCommon(serviceName, appName, appFeatureFlag)
func (d *DockerLifecycles) CreateAppArgs() []string {
return []string{
"--app-type", "docker",
}
}

Expect(cf.Cf(
"push",
appName,
func (d *DockerLifecycles) PushArgs() []string {
return []string{
"--docker-image", Config.GetCatnipDockerAppImage(),
"-m", DEFAULT_MEMORY_LIMIT,
).Wait(Config.CfPushTimeoutDuration())).To(Exit(0))
return appGuid, serviceGuid
}
}

const (
TAGS = "list, of, tags"
CREDS = `{"username": "admin", "password":"pa55woRD"}`
)

func LifeCycleCommon(serviceName, appName, appFeatureFlag string) (string, string) {
func Prepare(appName, serviceName, appFeatureFlag string, lifecycle LifeCycle) (string, string) {
appGuid := CreateApp(appName, lifecycle.CreateAppArgs()...)
serviceGuid := CreateUpsi(serviceName)
BindUpsi(appName, serviceName)
EnableFeatureViaAPI(appGuid, appFeatureFlag)

pushArgs := append([]string{appName}, lifecycle.PushArgs()...)
Push(pushArgs...)

return appGuid, serviceGuid
}

func PrepareWithManifest(appName, serviceName, appFeatureFlag string, lifecycle LifeCycle) (string, string) {
serviceGuid := CreateUpsi(serviceName)
manifestFile := CreateManifest(appName, serviceName, appFeatureFlag)

pushArgs := append([]string{"-f", manifestFile}, lifecycle.PushArgs()...)
Push(pushArgs...)

return app_helpers.GetAppGuid(appName), serviceGuid
}

func CreateApp(appName string, args ...string) string {
createAppArgs := []string{
"create-app", appName,
}
createAppArgs = append(createAppArgs, args...)
Expect(cf.Cf(createAppArgs...).Wait()).To(Exit(0))
appGuid := app_helpers.GetAppGuid(appName)

return appGuid
}

func CreateUpsi(serviceName string) string {
Expect(cf.Cf("create-user-provided-service", serviceName, "-p", CREDS, "-t", TAGS).Wait()).To(Exit(0))
serviceGuid := services.GetServiceInstanceGuid(serviceName)

appGuid := app_helpers.GetAppGuid(appName)
return serviceGuid
}

appFeatureUrl := fmt.Sprintf("/v3/apps/%s/features/%s", appGuid, appFeatureFlag)
Expect(cf.Cf("curl", appFeatureUrl, "-X", "PATCH", "-d", `{"enabled": true}`).Wait()).To(Exit(0))
func CreateManifest(appName, serviceName, appFeatureFlag string) string {
tmpdir, err := os.MkdirTemp(os.TempDir(), appName)
Expect(err).ToNot(HaveOccurred())

manifestFile := filepath.Join(tmpdir, "manifest.yml")
manifestContent := fmt.Sprintf(`---
applications:
- name: %s
features:
%s: true
services:
- %s
`, appName, appFeatureFlag, serviceName)
err = os.WriteFile(manifestFile, []byte(manifestContent), 0644)
Expect(err).ToNot(HaveOccurred())

return manifestFile
}

func BindUpsi(appName, serviceName string) {
Expect(cf.Cf("bind-service", appName, serviceName).Wait()).To(Exit(0))
}

return appGuid, serviceGuid
func EnableFeatureViaAPI(appGuid, appFeatureFlag string) {
appFeatureUrl := fmt.Sprintf("/v3/apps/%s/features/%s", appGuid, appFeatureFlag)
Expect(cf.Cf("curl", appFeatureUrl, "-X", "PATCH", "-d", `{"enabled": true}`).Wait()).To(Exit(0))
}

func Push(args ...string) {
pushArgs := []string{
"push",
"-m", DEFAULT_MEMORY_LIMIT,
}
pushArgs = append(pushArgs, args...)
Expect(cf.Cf(pushArgs...).Wait(Config.CfPushTimeoutDuration())).To(Exit(0))
}
14 changes: 10 additions & 4 deletions helpers/services/service_helper.go
Original file line number Diff line number Diff line change
Expand Up @@ -47,13 +47,16 @@ func GetServiceBindingGuid(appGuid string, instanceGuid string) string {
}

func ValidateServiceBindingK8s(appName, serviceName, appGuid, serviceGuid string) {
serviceBindingRoot := helpers.CurlApp(Config, appName, "/env/SERVICE_BINDING_ROOT")
Expect(serviceBindingRoot).Should(Equal("/etc/cf-service-bindings"))

getEncodedFilepath := func(serviceName string, fileName string) string {
path := fmt.Sprintf("/etc/cf-service-bindings/%s/%s", serviceName, fileName)
path := fmt.Sprintf("%s/%s/%s", serviceBindingRoot, serviceName, fileName)
return strings.Replace(path, "/", "%2F", -1)
}

checkFileContent := func(fileName string, content string) {
curlResponse := helpers.CurlApp(Config, appName, "/file/"+getEncodedFilepath(serviceName, fileName), "-L")
curlResponse := helpers.CurlApp(Config, appName, "/file/"+getEncodedFilepath(serviceName, fileName))
Expect(curlResponse).Should(ContainSubstring(content))
}

Expand All @@ -70,8 +73,11 @@ func ValidateServiceBindingK8s(appName, serviceName, appGuid, serviceGuid string
}

func ValidateFileBasedVcapServices(appName, serviceName, appGuid, serviceGuid string) {
vcapServicesFilePath := helpers.CurlApp(Config, appName, "/env/VCAP_SERVICES_FILE_PATH")
Expect(vcapServicesFilePath).Should(Equal("/etc/cf-service-bindings/vcap_services"))

getEncodedFilepath := func() string {
return strings.Replace("/etc/cf-service-bindings/vcap_services", "/", "%2F", -1)
return strings.Replace(vcapServicesFilePath, "/", "%2F", -1)
}

expectedVcapServicesTemplate := `{
Expand Down Expand Up @@ -101,7 +107,7 @@ func ValidateFileBasedVcapServices(appName, serviceName, appGuid, serviceGuid st
Fail(err.Error())
}

curlResponse := helpers.CurlApp(Config, appName, "/file/"+getEncodedFilepath(), "-L")
curlResponse := helpers.CurlApp(Config, appName, "/file/"+getEncodedFilepath())
actualJson := VCAPServicesFile{}
err = actualJson.ReadFromString(curlResponse)
if err != nil {
Expand Down
55 changes: 55 additions & 0 deletions ssh/ssh.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,17 @@ import (
"encoding/json"
"fmt"
"io"
"os"
"os/exec"
"path/filepath"
"strings"

. "github.com/cloudfoundry/cf-acceptance-tests/cats_suite_helpers"

"golang.org/x/crypto/ssh"

"github.com/cloudfoundry/cf-acceptance-tests/helpers/app_helpers"
"github.com/cloudfoundry/cf-acceptance-tests/helpers/assets"
"github.com/cloudfoundry/cf-acceptance-tests/helpers/logs"
"github.com/cloudfoundry/cf-acceptance-tests/helpers/random_name"
"github.com/cloudfoundry/cf-test-helpers/v2/cf"
Expand Down Expand Up @@ -206,6 +209,30 @@ var _ = SshDescribe("SSH", func() {
return string(cf.Cf("events", appName).Wait().Out.Contents())
}).Should(MatchRegexp("audit.app.ssh-unauthorized"))
})

Context("disabling ssh", func() {
BeforeEach(func() {
Expect(cf.Cf("ssh", "-v", appName).Wait()).To(Exit(0))
})

It("can be disabled via cli", func() {
Expect(cf.Cf("disable-ssh", appName).Wait()).To(Exit(0))

expectSshCmdToFail(appName)
})

It("can be disabled via manifest", func() {
manifestFile := createManifestSshDisabled(appName)
pushArgs := []string{
"push",
"-f", manifestFile,
"-p", assets.NewAssets().Catnip,
}
Expect(cf.Cf(pushArgs...).Wait(Config.CfPushTimeoutDuration())).To(Exit(0))

expectSshCmdToFail(appName)
})
})
})

})
Expand Down Expand Up @@ -234,3 +261,31 @@ func sshProxyAddress() string {

return response.Links.AppSsh.Href
}

func createManifestSshDisabled(appName string) string {
tmpdir, err := os.MkdirTemp(os.TempDir(), appName)
Expect(err).ToNot(HaveOccurred())

manifestFile := filepath.Join(tmpdir, "manifest.yml")
manifestContent := fmt.Sprintf(`---
applications:
- name: %s
features:
ssh: false
`, appName)
err = os.WriteFile(manifestFile, []byte(manifestContent), 0644)
Expect(err).ToNot(HaveOccurred())

return manifestFile
}

func expectSshCmdToFail(appName string) {
sshCmd := cf.Cf("ssh", "-v", appName)
Expect(sshCmd.Wait()).To(Exit(1))

output := string(sshCmd.Out.Contents())
stdErr := string(sshCmd.Err.Contents())

Expect(string(output)).To(MatchRegexp("FAILED"))
Expect(string(stdErr)).To(MatchRegexp("Error opening SSH connection"))
}
Loading
Loading