github.com/looshlee/cilium@v1.6.12/test/runtime/kafka.go (about)

     1  // Copyright 2017 Authors of Cilium
     2  //
     3  // Licensed under the Apache License, Version 2.0 (the "License");
     4  // you may not use this file except in compliance with the License.
     5  // You may obtain a copy of the License at
     6  //
     7  //     http://www.apache.org/licenses/LICENSE-2.0
     8  //
     9  // Unless required by applicable law or agreed to in writing, software
    10  // distributed under the License is distributed on an "AS IS" BASIS,
    11  // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    12  // See the License for the specific language governing permissions and
    13  // limitations under the License.
    14  
    15  package RuntimeTest
    16  
    17  import (
    18  	"context"
    19  	"fmt"
    20  
    21  	. "github.com/cilium/cilium/test/ginkgo-ext"
    22  	"github.com/cilium/cilium/test/helpers"
    23  	"github.com/cilium/cilium/test/helpers/constants"
    24  
    25  	. "github.com/onsi/gomega"
    26  )
    27  
    28  var _ = Describe("RuntimeKafka", func() {
    29  
    30  	var (
    31  		vm          *helpers.SSHMeta
    32  		monitorStop = func() error { return nil }
    33  
    34  		allowedTopic  = "allowedTopic"
    35  		disallowTopic = "disallowTopic"
    36  		topicTest     = "test-topic"
    37  		listTopicsCmd = "/opt/kafka/bin/kafka-topics.sh --list --zookeeper zook:2181"
    38  		MaxMessages   = 5
    39  		client        = "client"
    40  	)
    41  
    42  	containers := func(mode string) {
    43  
    44  		images := map[string]string{
    45  			"zook":   constants.ZookeeperImage,
    46  			"client": constants.KafkaClientImage,
    47  		}
    48  
    49  		switch mode {
    50  		case "create":
    51  			for k, v := range images {
    52  				vm.ContainerCreate(k, v, helpers.CiliumDockerNetwork, fmt.Sprintf("-l id.%s", k))
    53  			}
    54  			zook, err := vm.ContainerInspectNet("zook")
    55  			Expect(err).Should(BeNil())
    56  
    57  			vm.ContainerCreate("kafka", constants.KafkaImage, helpers.CiliumDockerNetwork, fmt.Sprintf(
    58  				"-l id.kafka -e KAFKA_ZOOKEEPER_CONNECT=%s:2181 -e KAFKA_ZOOKEEPER_SESSION_TIMEOUT_MS=60000 -e KAFKA_LISTENERS=PLAINTEXT://:9092 -e KAFKA_ZOOKEEPER_CONNECTION_TIMEOUT_MS=60000", zook["IPv4"]))
    59  
    60  		case "delete":
    61  			for k := range images {
    62  				vm.ContainerRm(k)
    63  			}
    64  			vm.ContainerRm("kafka")
    65  		}
    66  	}
    67  
    68  	createTopicCmd := func(topic string) string {
    69  		return fmt.Sprintf("/opt/kafka/bin/kafka-topics.sh --create --zookeeper zook:2181 "+
    70  			"--replication-factor 1 --partitions 1 --topic %s", topic)
    71  	}
    72  
    73  	createTopic := func(topic string) {
    74  		logger.Infof("Creating new kafka topic %s", topic)
    75  		res := vm.ContainerExec(client, createTopicCmd(topic))
    76  		res.ExpectSuccess("Unable to create topic  %s", topic)
    77  	}
    78  
    79  	consumerCmd := func(topic string, maxMsg int) string {
    80  		return fmt.Sprintf("/opt/kafka/bin/kafka-console-consumer.sh --bootstrap-server "+
    81  			"kafka:9092 --topic %s --max-messages %d --timeout-ms 300000 --from-beginning",
    82  			topic, maxMsg)
    83  	}
    84  
    85  	consumer := func(topic string, maxMsg int) *helpers.CmdRes {
    86  		return vm.ContainerExec(client, consumerCmd(topic, maxMsg))
    87  	}
    88  
    89  	producer := func(topic string, message string) {
    90  		cmd := fmt.Sprintf(
    91  			"echo %s | docker exec -i %s /opt/kafka/bin/kafka-console-producer.sh "+
    92  				"--broker-list kafka:9092 --topic %s",
    93  			message, client, topic)
    94  		vm.Exec(cmd)
    95  	}
    96  
    97  	// WaitKafkaBroker waits for the broker to be ready, by executing
    98  	// a command repeatedly until it succeeds, or a timeout occurs
    99  	waitForKafkaBroker := func(pod string, cmd string) error {
   100  		body := func() bool {
   101  			res := vm.ContainerExec(pod, cmd)
   102  			return res.WasSuccessful()
   103  		}
   104  		err := helpers.WithTimeout(body, "Kafka Broker not ready", &helpers.TimeoutConfig{Timeout: helpers.HelperTimeout})
   105  		return err
   106  	}
   107  
   108  	BeforeAll(func() {
   109  		vm = helpers.InitRuntimeHelper(helpers.Runtime, logger)
   110  		ExpectCiliumReady(vm)
   111  
   112  		status := vm.ExecCilium(fmt.Sprintf("config %s=true",
   113  			helpers.OptionConntrackLocal))
   114  		status.ExpectSuccess()
   115  
   116  		containers("create")
   117  		epsReady := vm.WaitEndpointsReady()
   118  		Expect(epsReady).Should(BeTrue(), "Endpoints are not ready after timeout")
   119  
   120  		err := waitForKafkaBroker(client, createTopicCmd(topicTest))
   121  		Expect(err).To(BeNil(), "Kafka broker failed to come up")
   122  
   123  		By("Creating kafka topics")
   124  		createTopic(allowedTopic)
   125  		createTopic(disallowTopic)
   126  
   127  		By("Listing created Kafka topics")
   128  		res := vm.ContainerExec(client, listTopicsCmd)
   129  		res.ExpectSuccess("Cannot list kafka topics")
   130  	})
   131  
   132  	AfterEach(func() {
   133  		vm.PolicyDelAll()
   134  
   135  	})
   136  
   137  	AfterAll(func() {
   138  		containers("delete")
   139  
   140  		status := vm.ExecCilium(fmt.Sprintf("config %s=false",
   141  			helpers.OptionConntrackLocal))
   142  		status.ExpectSuccess()
   143  
   144  		vm.CloseSSHClient()
   145  	})
   146  
   147  	JustBeforeEach(func() {
   148  		monitorStop = vm.MonitorStart()
   149  	})
   150  
   151  	JustAfterEach(func() {
   152  		vm.ValidateNoErrorsInLogs(CurrentGinkgoTestDescription().Duration)
   153  		Expect(monitorStop()).To(BeNil(), "cannot stop monitor command")
   154  	})
   155  
   156  	AfterFailed(func() {
   157  		vm.ReportFailed("cilium policy get")
   158  	})
   159  
   160  	It("Kafka Policy Ingress", func() {
   161  		_, err := vm.PolicyImportAndWait(vm.GetFullPath("Policies-kafka.json"), helpers.HelperTimeout)
   162  		Expect(err).Should(BeNil())
   163  
   164  		endPoints, err := vm.PolicyEndpointsSummary()
   165  		Expect(err).Should(BeNil(), "Cannot get endpoint list")
   166  		Expect(endPoints[helpers.Enabled]).To(Equal(1),
   167  			"Check number of endpoints with policy enforcement enabled")
   168  		Expect(endPoints[helpers.Disabled]).To(Equal(2),
   169  			"Check number of endpoints with policy enforcement disabled")
   170  
   171  		By("Allowed topic")
   172  
   173  		By("Sending produce request on kafka topic `allowedTopic`")
   174  		for i := 1; i <= MaxMessages; i++ {
   175  			producer(allowedTopic, fmt.Sprintf("Message %d", i))
   176  		}
   177  
   178  		By("Sending consume request on kafka topic `allowedTopic`")
   179  		res := consumer(allowedTopic, MaxMessages)
   180  		res.ExpectSuccess("Failed to consume messages from kafka topic `allowedTopic`")
   181  		Expect(res.CombineOutput().String()).
   182  			Should(ContainSubstring("Processed a total of %d messages", MaxMessages),
   183  				"Kafka did not process the expected number of messages")
   184  
   185  		By("Disable topic")
   186  		res = consumer(disallowTopic, MaxMessages)
   187  		res.ExpectFail("Kafka consumer can access to disallowTopic")
   188  	})
   189  
   190  	It("Kafka Policy Role Ingress", func() {
   191  		_, err := vm.PolicyImportAndWait(vm.GetFullPath("Policies-kafka-Role.json"), helpers.HelperTimeout)
   192  		Expect(err).Should(BeNil(), "Expected nil got %s while importing policy Policies-kafka-Role.json", err)
   193  
   194  		endPoints, err := vm.PolicyEndpointsSummary()
   195  		Expect(err).Should(BeNil(), "Expect nil. Failed to apply policy on all endpoints with error :%s", err)
   196  		Expect(endPoints[helpers.Enabled]).To(Equal(1), "Expected 1 endpoint to be policy enabled. Policy enforcement failed")
   197  		Expect(endPoints[helpers.Disabled]).To(Equal(2), "Expected 2 endpoint to be policy disabled. Policy enforcement failed")
   198  
   199  		By("Sending produce request on kafka topic `allowedTopic`")
   200  		for i := 1; i <= MaxMessages; i++ {
   201  			producer(allowedTopic, fmt.Sprintf("Message %d", i))
   202  		}
   203  
   204  		By("Sending consume request on kafka topic `allowedTopic`")
   205  		res := consumer(allowedTopic, MaxMessages)
   206  		res.ExpectSuccess("Failed to consume messages from kafka topic `allowedTopic`")
   207  		Expect(res.CombineOutput().String()).
   208  			Should(ContainSubstring("Processed a total of %d messages", MaxMessages),
   209  				"Kafka did not process the expected number of messages")
   210  
   211  		By("Disable topic")
   212  		// Consumer timeout didn't work correctly, so make sure that AUTH is present in the reply
   213  		ctx, cancel := context.WithCancel(context.Background())
   214  		defer cancel()
   215  		res = vm.ExecInBackground(ctx, fmt.Sprintf(
   216  			"docker exec -i %s %s", client, consumerCmd(disallowTopic, MaxMessages)))
   217  		err = res.WaitUntilMatch("{disallowTopic=TOPIC_AUTHORIZATION_FAILED}")
   218  		Expect(err).To(BeNil(), "Traffic in disallowTopic is allowed")
   219  	})
   220  })