Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Feat: use TCP routes for app syslog drain tests #643

Merged
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
75 changes: 26 additions & 49 deletions app_syslog_tcp/syslog_drain.go
Original file line number Diff line number Diff line change
@@ -1,17 +1,19 @@
package apps

import (
"regexp"
"fmt"
"time"

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

"github.com/cloudfoundry/cf-acceptance-tests/helpers/app_helpers"
"github.com/cloudfoundry/cf-acceptance-tests/helpers/assets"
logshelper "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"
"github.com/cloudfoundry/cf-test-helpers/v2/helpers"
"github.com/cloudfoundry/cf-test-helpers/v2/workflowhelpers"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
. "github.com/onsi/gomega/gbytes"
Expand All @@ -21,20 +23,33 @@ import (
var _ = AppSyslogTcpDescribe("Syslog Drain over TCP", func() {
var logWriterAppName1 string
var logWriterAppName2 string
var externalPort string
var domainName string
var listenerAppName string
var logs *Session
var interrupt chan struct{}
var serviceNames []string
var serviceName string

SkipOnK8s("Not yet supported")

Describe("Syslog drains", func() {
BeforeEach(func() {
interrupt = make(chan struct{}, 1)
serviceNames = []string{
random_name.CATSRandomName("SVIN"),
random_name.CATSRandomName("SVIN-INT"),
}

domainName = fmt.Sprintf("tcp.%s", Config.GetAppsDomain())
workflowhelpers.AsUser(TestSetup.AdminUserContext(), Config.DefaultTimeoutDuration(), func() {
routerGroupOutput := string(cf.Cf("router-groups").Wait().Out.Contents())
Expect(routerGroupOutput).To(
MatchRegexp(fmt.Sprintf("%s\\s+tcp", tcp_routing.DefaultRouterGroupName)),
fmt.Sprintf("Router group %s of type tcp doesn't exist", tcp_routing.DefaultRouterGroupName),
)

Expect(cf.Cf("create-shared-domain",
domainName,
"--router-group", tcp_routing.DefaultRouterGroupName,
).Wait()).To(Exit())
})
serviceName = random_name.CATSRandomName("SVIN")
listenerAppName = random_name.CATSRandomName("APP-SYSLOG-LISTENER")
logWriterAppName1 = random_name.CATSRandomName("APP-FIRST-LOG-WRITER")
logWriterAppName2 = random_name.CATSRandomName("APP-SECOND-LOG-WRITER")
Expand All @@ -49,6 +64,8 @@ var _ = AppSyslogTcpDescribe("Syslog Drain over TCP", func() {
"-f", assets.NewAssets().SyslogDrainListener+"/manifest.yml",
), Config.CfPushTimeoutDuration()).Should(Exit(0), "Failed to push app")

externalPort = MapTCPRoute(listenerAppName, domainName)

Eventually(cf.Cf(
"push",
logWriterAppName1,
Expand Down Expand Up @@ -77,34 +94,14 @@ var _ = AppSyslogTcpDescribe("Syslog Drain over TCP", func() {
Eventually(cf.Cf("delete", logWriterAppName1, "-f", "-r")).Should(Exit(0), "Failed to delete app")
Eventually(cf.Cf("delete", logWriterAppName2, "-f", "-r")).Should(Exit(0), "Failed to delete app")
Eventually(cf.Cf("delete", listenerAppName, "-f", "-r")).Should(Exit(0), "Failed to delete app")
for _, serviceName := range serviceNames {
if serviceName != "" {
Eventually(cf.Cf("delete-service", serviceName, "-f")).Should(Exit(0), "Failed to delete service")
}
}
Eventually(cf.Cf("delete-service", serviceName, "-f")).Should(Exit(0), "Failed to delete service")

Eventually(cf.Cf("delete-orphaned-routes", "-f"), Config.CfPushTimeoutDuration()).Should(Exit(0), "Failed to delete orphaned routes")
})

It("forwards app messages to registered syslog drains", func() {
// The syslog drains return two IP addresses: external & internal.
// On a vanilla environment, apps can connect through the syslog service
// to the external IP (Diego cell address and external port) of the drain
// container.
// On NSX-T, apps cannot connect to the external IP, but they can connect
// to the internal IP (container IP and port 8080).
for i, address := range getSyslogDrainAddresses(listenerAppName) {
var syslogDrainURL string
if Config.GetRequireProxiedAppTraffic() {
syslogDrainURL = "syslog-tls://" + address
} else {
syslogDrainURL = "syslog://" + address
}

Eventually(cf.Cf("cups", serviceNames[i], "-l", syslogDrainURL)).Should(Exit(0), "Failed to create syslog drain service")
Eventually(cf.Cf("bind-service", logWriterAppName1, serviceNames[i])).Should(Exit(0), "Failed to bind service")
// We don't need to restage, because syslog service bindings don't change the app's environment variables
}
Eventually(cf.Cf("cups", serviceName, "-l", fmt.Sprintf("syslog://%s:%s", domainName, externalPort))).Should(Exit(0), "Failed to create syslog drain service")
Eventually(cf.Cf("bind-service", logWriterAppName1, serviceName)).Should(Exit(0), "Failed to bind service")

randomMessage1 := random_name.CATSRandomName("RANDOM-MESSAGE-A")
randomMessage2 := random_name.CATSRandomName("RANDOM-MESSAGE-B")
Expand All @@ -121,26 +118,6 @@ var _ = AppSyslogTcpDescribe("Syslog Drain over TCP", func() {
})
})

func getSyslogDrainAddresses(appName string) []string {
var address, internalAddress []byte

Eventually(func() [][]byte {
re, err := regexp.Compile("EXTERNAL ADDRESS: \\|(.*)\\|; INTERNAL ADDRESS: \\|(.*)\\|")
Expect(err).NotTo(HaveOccurred())

logs := logshelper.Recent(appName).Wait()
matched := re.FindSubmatch(logs.Out.Contents())
if len(matched) < 3 {
return nil
}
address = matched[1]
internalAddress = matched[2]
return [][]byte{address, internalAddress}
}).Should(Not(BeNil()))

return []string{string(address), string(internalAddress)}
}

func writeLogsUntilInterrupted(interrupt chan struct{}, randomMessage string, logWriterAppName string) {
defer GinkgoRecover()
for {
Expand Down
35 changes: 0 additions & 35 deletions assets/syslog-drain-listener/syslog_drain.go
Original file line number Diff line number Diff line change
@@ -1,17 +1,13 @@
package main

import (
"encoding/json"
"fmt"
"io"
"net"
"os"
"time"
)

func main() {
go logIP()

listenAddress := fmt.Sprintf(":%s", os.Getenv("PORT"))
listener, err := net.Listen("tcp", listenAddress)
if err != nil {
Expand Down Expand Up @@ -45,34 +41,3 @@ func handleConnection(conn net.Conn) {
fmt.Println(message)
}
}

func logIP() {
ip := os.Getenv("CF_INSTANCE_IP")
internalIP := os.Getenv("CF_INSTANCE_INTERNAL_IP")
portsJson := os.Getenv("CF_INSTANCE_PORTS")
ports := []struct {
External uint16 `json:"external"`
ExternalTLSProxy uint16 `json:"external_tls_proxy"`
}{}

err := json.Unmarshal([]byte(portsJson), &ports)
if err != nil {
fmt.Printf("Cannot unmarshal CF_INSTANCE_PORTS: %s", err)
os.Exit(1)
}

if len(ports) <= 0 {
fmt.Printf("CF_INSTANCE_PORTS is empty")
os.Exit(1)
}

port := ports[0].External
if port == 0 {
port = ports[0].ExternalTLSProxy
}

for {
fmt.Printf("EXTERNAL ADDRESS: |%s:%d|; INTERNAL ADDRESS: |%s:8080|\n", ip, port, internalIP)
time.Sleep(5 * time.Second)
}
}