From 593045d9fab070d0279bc58343588aabf67f619f Mon Sep 17 00:00:00 2001 From: Rogger Vasquez Date: Thu, 25 May 2023 17:09:06 -0500 Subject: [PATCH 1/6] rpk: add 'ls' as alias fror profile/auth list --- src/go/rpk/pkg/cli/cloud/auth/list.go | 7 ++++--- src/go/rpk/pkg/cli/profile/list.go | 7 ++++--- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/src/go/rpk/pkg/cli/cloud/auth/list.go b/src/go/rpk/pkg/cli/cloud/auth/list.go index 0d56e6473219..9a85ab674054 100644 --- a/src/go/rpk/pkg/cli/cloud/auth/list.go +++ b/src/go/rpk/pkg/cli/cloud/auth/list.go @@ -20,9 +20,10 @@ import ( func newListCommand(fs afero.Fs, p *config.Params) *cobra.Command { return &cobra.Command{ - Use: "list", - Short: "List rpk cloud auths", - Args: cobra.ExactArgs(0), + Use: "list", + Aliases: []string{"ls"}, + Short: "List rpk cloud auths", + Args: cobra.ExactArgs(0), Run: func(*cobra.Command, []string) { cfg, err := p.Load(fs) out.MaybeDie(err, "unable to load config: %v", err) diff --git a/src/go/rpk/pkg/cli/profile/list.go b/src/go/rpk/pkg/cli/profile/list.go index 6cb638283fb5..f8672311eb9c 100644 --- a/src/go/rpk/pkg/cli/profile/list.go +++ b/src/go/rpk/pkg/cli/profile/list.go @@ -20,9 +20,10 @@ import ( func newListCommand(fs afero.Fs, p *config.Params) *cobra.Command { return &cobra.Command{ - Use: "list", - Short: "List rpk profiles", - Args: cobra.ExactArgs(0), + Use: "list", + Aliases: []string{"ls"}, + Short: "List rpk profiles", + Args: cobra.ExactArgs(0), Run: func(*cobra.Command, []string) { cfg, err := p.Load(fs) out.MaybeDie(err, "unable to load config: %v", err) From b3746e554c530351d9934aa4597da1b3dd5ffe1c Mon Sep 17 00:00:00 2001 From: Rogger Vasquez Date: Thu, 25 May 2023 17:10:46 -0500 Subject: [PATCH 2/6] test: replace _some_ flags for -X flags The idea is to start replacing some old flags for the new -X flags, this way we can monitor that we are not breaking backcompat and we test the new ones. --- tests/rptest/clients/rpk.py | 36 ++++++++++++++++++------------------ 1 file changed, 18 insertions(+), 18 deletions(-) diff --git a/tests/rptest/clients/rpk.py b/tests/rptest/clients/rpk.py index 4d712ab819b7..bf5baedc863f 100644 --- a/tests/rptest/clients/rpk.py +++ b/tests/rptest/clients/rpk.py @@ -934,26 +934,26 @@ def parse(line): def _kafka_conn_settings(self): flags = [ - "--brokers", - self._redpanda.brokers(), + "-X", + "brokers=" + self._redpanda.brokers(), ] if self._username: flags += [ - "--user", - self._username, - "--password", - self._password, - "--sasl-mechanism", - self._sasl_mechanism, + "-X", + "user=" + self._username, + "-X", + "pass=" + self._password, + "-X", + "sasl.mechanism=" + self._sasl_mechanism, ] if self._tls_cert: flags += [ - "--tls-key", - self._tls_cert.key, - "--tls-cert", - self._tls_cert.crt, - "--tls-truststore", - self._tls_cert.ca.crt, + "-X", + "tls.key=" + self._tls_cert.key, + "-X", + "tls.cert=" + self._tls_cert.crt, + "-X", + "tls.ca=" + self._tls_cert.ca.crt, ] return flags @@ -1023,8 +1023,8 @@ def cluster_metadata_id(self): because there are already other ways to get at that. """ cmd = [ - self._rpk_binary(), '--brokers', - self._redpanda.brokers(), 'cluster', 'metadata' + self._rpk_binary(), '-X', "brokers=" + self._redpanda.brokers(), + 'cluster', 'metadata' ] output = self._execute(cmd) lines = output.strip().split("\n") @@ -1043,8 +1043,8 @@ def cluster_metadata_id(self): def license_set(self, path, license=""): cmd = [ - self._rpk_binary(), "--api-urls", - self._admin_host(), "cluster", "license", "set" + self._rpk_binary(), "-X", "admin.hosts=" + self._admin_host(), + "cluster", "license", "set" ] if license: From a0da71e5014978b920388bbc45f9534fc0f9f9ae Mon Sep 17 00:00:00 2001 From: Rogger Vasquez Date: Mon, 29 May 2023 17:33:21 -0500 Subject: [PATCH 3/6] tests: add the option to redact logs We might want to hide some command logs next commit will use this to hide rpk cloud login logs. --- tests/rptest/clients/rpk.py | 10 ++++++---- 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/tests/rptest/clients/rpk.py b/tests/rptest/clients/rpk.py index bf5baedc863f..8e254d303b5c 100644 --- a/tests/rptest/clients/rpk.py +++ b/tests/rptest/clients/rpk.py @@ -833,11 +833,12 @@ def cluster_config_set(self, key: str, value): ] return self._execute(cmd) - def _execute(self, cmd, stdin=None, timeout=None): + def _execute(self, cmd, stdin=None, timeout=None, log_cmd=True): if timeout is None: timeout = DEFAULT_TIMEOUT - self._redpanda.logger.debug("Executing command: %s", cmd) + if log_cmd: + self._redpanda.logger.debug("Executing command: %s", cmd) p = subprocess.Popen(cmd, stdout=subprocess.PIPE, @@ -856,7 +857,8 @@ def _execute(self, cmd, stdin=None, timeout=None): self._redpanda.logger.error(error) raise RpkException( 'command %s returned %d, output: %s' % - (' '.join(cmd), p.returncode, output), error, p.returncode) + (' '.join(cmd) if log_cmd else '[redacted]', p.returncode, + output), error, p.returncode) return output @@ -1052,7 +1054,7 @@ def license_set(self, path, license=""): if path: cmd += ["--path", path] - return self._execute(cmd) + return self._execute(cmd, log_cmd=False) def license_info(self): From b253ab0f29b8a5db89ca91a818c7032f3a61e356 Mon Sep 17 00:00:00 2001 From: Rogger Vasquez Date: Mon, 29 May 2023 17:34:56 -0500 Subject: [PATCH 4/6] tests: add rpk config utils, refactor cfg test This refactors helps to avoid duplication and introduce config utils that will be used in the following tests. --- tests/rptest/tests/rpk_config_test.py | 89 ++++++++++----------------- tests/rptest/utils/rpk_config.py | 41 ++++++++++++ 2 files changed, 73 insertions(+), 57 deletions(-) create mode 100644 tests/rptest/utils/rpk_config.py diff --git a/tests/rptest/tests/rpk_config_test.py b/tests/rptest/tests/rpk_config_test.py index c41369abafe6..1289e24dbdcd 100644 --- a/tests/rptest/tests/rpk_config_test.py +++ b/tests/rptest/tests/rpk_config_test.py @@ -8,14 +8,13 @@ # by the Apache License, Version 2.0 from rptest.services.cluster import cluster +from rptest.utils.rpk_config import read_redpanda_cfg from rptest.tests.redpanda_test import RedpandaTest from rptest.clients.rpk_remote import RpkRemoteTool from rptest.services.redpanda import RedpandaService, RESTART_LOG_ALLOW_LIST import yaml import random -import tempfile -import os class RpkConfigTest(RedpandaTest): @@ -28,24 +27,18 @@ def test_config_set_single_number(self): n = random.randint(1, len(self.redpanda.nodes)) node = self.redpanda.get_node(n) rpk = RpkRemoteTool(self.redpanda, node) - config_file = 'redpanda.yaml' key = 'redpanda.admin.port' value = '9641' # The default is 9644, so we will change it rpk.config_set(key, value, path=RedpandaService.NODE_CONFIG_FILE) + actual_config = read_redpanda_cfg(node) - with tempfile.TemporaryDirectory() as d: - node.account.copy_from(RedpandaService.NODE_CONFIG_FILE, d) - - with open(os.path.join(d, config_file)) as f: - actual_config = yaml.full_load(f.read()) - if f"{actual_config['redpanda']['admin'][0]['port']}" != value: - self.logger.error("Configs differ") - self.logger.error(f"Expected: {value}") - self.logger.error( - f"Actual: {yaml.dump(actual_config['redpanda']['admin'][0]['port'])}" - ) - assert f"{actual_config['redpanda']['admin'][0]['port']}" == value + if f"{actual_config['redpanda']['admin'][0]['port']}" != value: + self.logger.error( + "Configs differ\n" + f"Expected: {value}\n" + + f"Actual: {yaml.dump(actual_config['redpanda']['admin'][0]['port'])}" + ) + assert f"{actual_config['redpanda']['admin'][0]['port']}" == value @cluster(num_nodes=3) def test_config_set_yaml(self): @@ -82,21 +75,15 @@ def test_config_set_yaml(self): rpk.config_set(key, value, format='yaml') - with tempfile.TemporaryDirectory() as d: - node.account.copy_from(RedpandaService.NODE_CONFIG_FILE, d) - - with open(os.path.join(d, 'redpanda.yaml')) as f: - expected_config = yaml.full_load(expected) - actual_config = yaml.full_load(f.read()) - if actual_config['redpanda']['seed_servers'] != expected_config: - self.logger.error("Configs differ") - self.logger.error( - f"Expected: {yaml.dump(expected_config)}") - self.logger.error( - f"Actual: {yaml.dump(actual_config['redpanda']['seed_servers'])}" - ) - assert actual_config['redpanda'][ - 'seed_servers'] == expected_config + expected_config = yaml.full_load(expected) + actual_config = read_redpanda_cfg(node) + if actual_config['redpanda']['seed_servers'] != expected_config: + self.logger.error( + "Configs differ\n" + + f"Expected: {yaml.dump(expected_config)}\n" + + f"Actual: {yaml.dump(actual_config['redpanda']['seed_servers'])}" + ) + assert actual_config['redpanda']['seed_servers'] == expected_config @cluster(num_nodes=3) def test_config_set_json(self): @@ -113,20 +100,13 @@ def test_config_set_json(self): tune_cpu: true tune_disk_irq: true ''') + actual_config = read_redpanda_cfg(node) - with tempfile.TemporaryDirectory() as d: - node.account.copy_from(RedpandaService.NODE_CONFIG_FILE, d) - - with open(os.path.join(d, 'redpanda.yaml')) as f: - actual_config = yaml.full_load(f.read()) - - if actual_config['rpk'] != expected_config: - self.logger.error("Configs differ") - self.logger.error( - f"Expected: {yaml.dump(expected_config)}") - self.logger.error( - f"Actual: {yaml.dump(actual_config['rpk'])}") - assert actual_config['rpk'] == expected_config + if actual_config['rpk'] != expected_config: + self.logger.error("Configs differ\n" + + f"Expected: {yaml.dump(expected_config)}\n" + + f"Actual: {yaml.dump(actual_config['rpk'])}") + assert actual_config['rpk'] == expected_config @cluster(num_nodes=3, log_allow_list=RESTART_LOG_ALLOW_LIST) def test_config_change_then_restart_node(self): @@ -161,17 +141,12 @@ def test_config_change_mode_prod(self): coredump_dir: /var/lib/redpanda/coredump tune_ballast_file: true ''') - with tempfile.TemporaryDirectory() as d: - node.account.copy_from(RedpandaService.NODE_CONFIG_FILE, d) - - with open(os.path.join(d, 'redpanda.yaml')) as f: - actual_config = yaml.full_load(f.read()) - - if actual_config['rpk'] != expected_config: - self.logger.error("Configs differ") - self.logger.error( - f"Expected: {yaml.dump(expected_config)}") - self.logger.error( - f"Actual: {yaml.dump(actual_config['rpk'])}") - assert actual_config['rpk'] == expected_config - assert 'developer_mode' not in actual_config['redpanda'] + + actual_config = read_redpanda_cfg(node) + + if actual_config['rpk'] != expected_config: + self.logger.error("Configs differ\n" + + f"Expected: {yaml.dump(expected_config)}\n" + + f"Actual: {yaml.dump(actual_config['rpk'])}") + assert actual_config['rpk'] == expected_config + assert 'developer_mode' not in actual_config['redpanda'] diff --git a/tests/rptest/utils/rpk_config.py b/tests/rptest/utils/rpk_config.py new file mode 100644 index 000000000000..64995f8be6bd --- /dev/null +++ b/tests/rptest/utils/rpk_config.py @@ -0,0 +1,41 @@ +# Copyright 2023 Redpanda Data, Inc. +# +# Use of this software is governed by the Business Source License +# included in the file licenses/BSL.md +# +# As of the Change Date specified in that file, in accordance with +# the Business Source License, use of this software will be governed +# by the Apache License, Version 2.0 + +import os +import tempfile +import yaml + +from rptest.services.redpanda import RedpandaService + +# This lives in the runner +RUNNER_RPK_CONFIG_FILE = "/root/.config/rpk/rpk.yaml" + + +def clean_runner_rpk_cfg(): + if os.path.exists(RUNNER_RPK_CONFIG_FILE): + os.remove(RUNNER_RPK_CONFIG_FILE) + + +def read_rpk_cfg(): + with open(RUNNER_RPK_CONFIG_FILE) as f: + return yaml.full_load(f.read()) + + +def read_node_rpk_cfg(node): + with tempfile.TemporaryDirectory() as d: + node.account.copy_from(RedpandaService.RPK_CONFIG_FILE, d) + with open(os.path.join(d, 'rpk.yaml')) as f: + return yaml.full_load(f.read()) + + +def read_redpanda_cfg(node): + with tempfile.TemporaryDirectory() as d: + node.account.copy_from(RedpandaService.NODE_CONFIG_FILE, d) + with open(os.path.join(d, 'redpanda.yaml')) as f: + return yaml.full_load(f.read()) From 95f1cfe7c18e20144b6bf9075a30a4cd8e62c78d Mon Sep 17 00:00:00 2001 From: Rogger Vasquez Date: Mon, 29 May 2023 17:36:19 -0500 Subject: [PATCH 5/6] tests: add rpk profile tests Introduces new rpk/rpk_remote handlers for newly introduced command 'profile'. Also add the deletion of the rpk.yaml as part of the node cleanup process. --- tests/rptest/clients/rpk.py | 22 +++++ tests/rptest/clients/rpk_remote.py | 47 +++++++++++ tests/rptest/services/redpanda.py | 3 + tests/rptest/tests/rpk_profile_test.py | 111 +++++++++++++++++++++++++ tests/rptest/utils/rpk_config.py | 15 +--- 5 files changed, 184 insertions(+), 14 deletions(-) create mode 100644 tests/rptest/tests/rpk_profile_test.py diff --git a/tests/rptest/clients/rpk.py b/tests/rptest/clients/rpk.py index 8e254d303b5c..003e64b26850 100644 --- a/tests/rptest/clients/rpk.py +++ b/tests/rptest/clients/rpk.py @@ -1181,3 +1181,25 @@ def describe_log_dirs(self): int(size))) return result + + def cloud_login_cc(self, id, secret): + + cmd = [ + self._rpk_binary(), "cloud", "login", "--client-id", id, + "--client-secret", secret + ] + + self._redpanda.logger.debug( + "Executing command: %s cloud login --client-id %s --client-secret [redacted]", + self._rpk_binary(), id) + + return self._execute(cmd, log_cmd=False) + + def cloud_logout(self, clear_credentials=True): + + cmd = [self._rpk_binary(), "cloud", "logout"] + + if clear_credentials: + cmd += ["--clear-credentials"] + + return self._execute(cmd) diff --git a/tests/rptest/clients/rpk_remote.py b/tests/rptest/clients/rpk_remote.py index 7df009af8fd0..e84da8bc889d 100644 --- a/tests/rptest/clients/rpk_remote.py +++ b/tests/rptest/clients/rpk_remote.py @@ -66,6 +66,53 @@ def _run_config(self, cmd, path=None, timeout=30): return self._execute(cmd, timeout=timeout) + def _run_profile(self, cmd): + cmd = [self._rpk_binary(), "profile"] + cmd + return self._execute(cmd) + + def create_profile(self, name): + cmd = ["create", name] + return self._run_profile(cmd) + + def create_profile_simple(self, name, cfg_location): + return self._execute(['create', name, "--from-simple", cfg_location]) + + def use_profile(self, name): + cmd = ["use", name] + return self._run_profile(cmd) + + def delete_profile(self, name): + cmd = ["delete", name] + return self._run_profile(cmd) + + def rename_profile(self, new_name): + cmd = ["rename-to", new_name] + return self._run_profile(cmd) + + def set_profile(self, kv): + cmd = ["set", kv] + return self._run_profile(cmd) + + def list_profiles(self): + cmd = ["list"] + out = self._run_profile(cmd) + lines = out.splitlines() + if len(lines) == 1: + return [] + + def profile_line(line): + parts = line.split() + # We remove the asterisk that denotes that is the selected profile. Not needed here. + return parts[0].strip("*") + + for i, line in enumerate(lines): + if line.split() == ["NAME", "DESCRIPTION"]: + return list(map(profile_line, lines[i + 1:])) + + def create_topic_no_flags(self, name): + cmd = [self._rpk_binary(), "topic", "create", name] + return self._execute(cmd) + def _execute(self, cmd, timeout=30): self._redpanda.logger.debug("Executing command: %s", cmd) diff --git a/tests/rptest/services/redpanda.py b/tests/rptest/services/redpanda.py index a962b8f6ed4f..484b18dc3fa0 100644 --- a/tests/rptest/services/redpanda.py +++ b/tests/rptest/services/redpanda.py @@ -693,6 +693,7 @@ class RedpandaServiceBase(Service): TRIM_LOGS_KEY = "trim_logs" DATA_DIR = os.path.join(PERSISTENT_ROOT, "data") NODE_CONFIG_FILE = "/etc/redpanda/redpanda.yaml" + RPK_CONFIG_FILE = "/root/.config/rpk/rpk.yaml" CLUSTER_BOOTSTRAP_CONFIG_FILE = "/etc/redpanda/.bootstrap.yaml" TLS_SERVER_KEY_FILE = "/etc/redpanda/server.key" TLS_SERVER_CRT_FILE = "/etc/redpanda/server.crt" @@ -2840,6 +2841,8 @@ def clean_node(self, f"{RedpandaService.PERSISTENT_ROOT}/data/*") if node.account.exists(RedpandaService.NODE_CONFIG_FILE): node.account.remove(f"{RedpandaService.NODE_CONFIG_FILE}") + if node.account.exists(RedpandaService.RPK_CONFIG_FILE): + node.account.remove(f"{RedpandaService.RPK_CONFIG_FILE}") if node.account.exists(RedpandaService.CLUSTER_BOOTSTRAP_CONFIG_FILE): node.account.remove( f"{RedpandaService.CLUSTER_BOOTSTRAP_CONFIG_FILE}") diff --git a/tests/rptest/tests/rpk_profile_test.py b/tests/rptest/tests/rpk_profile_test.py new file mode 100644 index 000000000000..584cc6d4dda0 --- /dev/null +++ b/tests/rptest/tests/rpk_profile_test.py @@ -0,0 +1,111 @@ +# Copyright 2023 Redpanda Data, Inc. +# +# Use of this software is governed by the Business Source License +# included in the file licenses/BSL.md +# +# As of the Change Date specified in that file, in accordance with +# the Business Source License, use of this software will be governed +# by the Apache License, Version 2.0 + +from rptest.utils.rpk_config import read_rpk_cfg, read_redpanda_cfg +from rptest.util import expect_exception +from rptest.services.cluster import cluster + +from rptest.tests.redpanda_test import RedpandaTest +from rptest.clients.rpk_remote import RpkRemoteTool +from rptest.clients.rpk import RpkTool +from ducktape.cluster.remoteaccount import RemoteCommandError +from rptest.services.redpanda import RedpandaService + + +class RpkProfileTest(RedpandaTest): + def __init__(self, ctx): + super(RpkProfileTest, self).__init__(test_context=ctx) + self._ctx = ctx + self._rpk = RpkTool(self.redpanda) + + @cluster(num_nodes=1) + def test_e2e_profile(self): + """ + Test an e2e flow of different operations using rpk profile: + Create 2 -> List -> Use -> Delete -> Use deleted -> Rename + """ + pr1 = "profile_1" + pr2 = "profile_2" + node = self.redpanda.get_node(0) + rpk = RpkRemoteTool(self.redpanda, node) + + # Create profiles + rpk.create_profile(pr1) + rpk.create_profile(pr2) + + rpk_cfg = read_rpk_cfg(node) + + assert rpk_cfg["current_profile"] == pr2 + # rpk pushes to the top the last profile used + assert rpk_cfg["profiles"][0]["name"] == pr2 + assert rpk_cfg["profiles"][1]["name"] == pr1 + + # List profiles + profile_list = rpk.list_profiles() + assert len(profile_list) == 2 + assert pr1 in profile_list and pr2 in profile_list + + # Change selected profile + rpk.use_profile(pr1) + rpk_cfg = read_rpk_cfg(node) + assert rpk_cfg["current_profile"] == pr1 + + rpk.delete_profile(pr2) + profile_list = rpk.list_profiles() + assert len(profile_list) == 1 + + # Now we try to use an already deleted profile + with expect_exception(RemoteCommandError, + lambda e: "returned non-zero exit" in str(e)): + rpk.use_profile(pr2) + + # Finally, we rename it + rpk.rename_profile("new_name") + rpk_cfg = read_rpk_cfg(node) + assert rpk_cfg["current_profile"] == "new_name" + + @cluster(num_nodes=3) + def test_use_profile(self): + """ + Test that creates a profile, assign the brokers and create a + topic without using the --brokers flag that is used in every + ducktape test so far. + """ + node = self.redpanda.get_node(0) + rpk = RpkRemoteTool(self.redpanda, node) + rpk.create_profile("noflag") + + rpk.set_profile("brokers=" + self.redpanda.brokers()) + rpk.create_topic_no_flags("no-flag-test") + + topic_list = self._rpk.list_topics() + assert "no-flag-test" in topic_list + + @cluster(num_nodes=3) + def test_create_profile_from_simple(self): + """ + Create redpanda.yaml, use create rpk profile --from simple + """ + node = self.redpanda.get_node(0) + rpk = RpkRemoteTool(self.redpanda, node) + + # We set the broker list in the redpanda.yaml + rpk.config_set("rpk.kafka_api.brokers", self.redpanda.brokers_list()) + + # Then we create the profile based on the redpanda.yaml + rpk.create_profile_simple("simple_test", + RedpandaService.NODE_CONFIG_FILE) + + rpk_cfg = read_rpk_cfg(node) + redpanda_cfg = read_redpanda_cfg(node) + + rpk_brokers = rpk_cfg["profiles"][0]["kafka_api"]["brokers"] + redpanda_brokers = redpanda_cfg["rpk"]["kafka_api"]["brokers"] + + assert rpk_brokers == redpanda_brokers diff --git a/tests/rptest/utils/rpk_config.py b/tests/rptest/utils/rpk_config.py index 64995f8be6bd..35160801a12a 100644 --- a/tests/rptest/utils/rpk_config.py +++ b/tests/rptest/utils/rpk_config.py @@ -13,21 +13,8 @@ from rptest.services.redpanda import RedpandaService -# This lives in the runner -RUNNER_RPK_CONFIG_FILE = "/root/.config/rpk/rpk.yaml" - -def clean_runner_rpk_cfg(): - if os.path.exists(RUNNER_RPK_CONFIG_FILE): - os.remove(RUNNER_RPK_CONFIG_FILE) - - -def read_rpk_cfg(): - with open(RUNNER_RPK_CONFIG_FILE) as f: - return yaml.full_load(f.read()) - - -def read_node_rpk_cfg(node): +def read_rpk_cfg(node): with tempfile.TemporaryDirectory() as d: node.account.copy_from(RedpandaService.RPK_CONFIG_FILE, d) with open(os.path.join(d, 'rpk.yaml')) as f: From f269f89393aaf2e381890b11140b93bf00ffe370 Mon Sep 17 00:00:00 2001 From: Rogger Vasquez Date: Mon, 29 May 2023 17:36:58 -0500 Subject: [PATCH 6/6] tests: add rpk cloud login test Simple rpk cloud login and logout using credentials and checking that it writes the token to the rpk.yaml. --- tests/rptest/clients/rpk.py | 22 ---------- tests/rptest/clients/rpk_remote.py | 30 +++++++++++-- tests/rptest/tests/rpk_cloud_test.py | 64 ++++++++++++++++++++++++++++ 3 files changed, 91 insertions(+), 25 deletions(-) create mode 100644 tests/rptest/tests/rpk_cloud_test.py diff --git a/tests/rptest/clients/rpk.py b/tests/rptest/clients/rpk.py index 003e64b26850..8e254d303b5c 100644 --- a/tests/rptest/clients/rpk.py +++ b/tests/rptest/clients/rpk.py @@ -1181,25 +1181,3 @@ def describe_log_dirs(self): int(size))) return result - - def cloud_login_cc(self, id, secret): - - cmd = [ - self._rpk_binary(), "cloud", "login", "--client-id", id, - "--client-secret", secret - ] - - self._redpanda.logger.debug( - "Executing command: %s cloud login --client-id %s --client-secret [redacted]", - self._rpk_binary(), id) - - return self._execute(cmd, log_cmd=False) - - def cloud_logout(self, clear_credentials=True): - - cmd = [self._rpk_binary(), "cloud", "logout"] - - if clear_credentials: - cmd += ["--clear-credentials"] - - return self._execute(cmd) diff --git a/tests/rptest/clients/rpk_remote.py b/tests/rptest/clients/rpk_remote.py index e84da8bc889d..c3ea5ff8aaab 100644 --- a/tests/rptest/clients/rpk_remote.py +++ b/tests/rptest/clients/rpk_remote.py @@ -75,7 +75,8 @@ def create_profile(self, name): return self._run_profile(cmd) def create_profile_simple(self, name, cfg_location): - return self._execute(['create', name, "--from-simple", cfg_location]) + return self._run_profile( + ['create', name, "--from-simple", cfg_location]) def use_profile(self, name): cmd = ["use", name] @@ -113,8 +114,31 @@ def create_topic_no_flags(self, name): cmd = [self._rpk_binary(), "topic", "create", name] return self._execute(cmd) - def _execute(self, cmd, timeout=30): - self._redpanda.logger.debug("Executing command: %s", cmd) + def cloud_login_cc(self, id, secret): + + cmd = [ + self._rpk_binary(), "cloud", "login", "--client-id", id, + "--client-secret", secret, "--save", "--no-profile" + ] + + self._redpanda.logger.debug( + "Executing command: %s cloud login --client-id %s --client-secret [redacted]", + self._rpk_binary(), id) + + return self._execute(cmd, log_cmd=False) + + def cloud_logout(self, clear_credentials=True): + + cmd = [self._rpk_binary(), "cloud", "logout"] + + if clear_credentials: + cmd += ["--clear-credentials"] + + return self._execute(cmd) + + def _execute(self, cmd, timeout=30, log_cmd=True): + if log_cmd: + self._redpanda.logger.debug("Executing command: %s", cmd) return self._node.account.ssh_output( ' '.join(cmd), diff --git a/tests/rptest/tests/rpk_cloud_test.py b/tests/rptest/tests/rpk_cloud_test.py new file mode 100644 index 000000000000..f16280bbd717 --- /dev/null +++ b/tests/rptest/tests/rpk_cloud_test.py @@ -0,0 +1,64 @@ +# Copyright 2023 Redpanda Data, Inc. +# +# Use of this software is governed by the Business Source License +# included in the file licenses/BSL.md +# +# As of the Change Date specified in that file, in accordance with +# the Business Source License, use of this software will be governed +# by the Apache License, Version 2.0 + +import os + +from rptest.services.cluster import cluster + +from rptest.utils.rpk_config import read_rpk_cfg +from rptest.tests.redpanda_test import RedpandaTest +from rptest.clients.rpk_remote import RpkRemoteTool + + +def get_ci_env_var(env_var): + out = os.environ.get(env_var, None) + if out is None: + is_ci = os.environ.get("CI", "false") + if is_ci == "true": + raise RuntimeError( + f"Expected {env_var} variable to be set in this environment") + + return out + + +class RpkCloudTest(RedpandaTest): + def __init__(self, ctx): + super(RpkCloudTest, self).__init__(test_context=ctx) + self._ctx = ctx + + @cluster(num_nodes=1) + def test_cloud_login_logout_cc(self): + """ + Test login to cloud via rpk using client + credentials, make sure we store the token and + then delete it when we logout. + """ + id = get_ci_env_var("RPK_TEST_CLIENT_ID") + secret = get_ci_env_var("RPK_TEST_CLIENT_SECRET") + if id is None or secret is None: + self.logger.warn( + "Skipping test, client credentials env vars not found") + return + + node = self.redpanda.get_node(0) + rpk = RpkRemoteTool(self.redpanda, node) + + output = rpk.cloud_login_cc(id, secret) + assert "Successfully logged in" in output + + # Check for a token present in file. + rpk_yaml = read_rpk_cfg(node) + assert rpk_yaml["cloud_auth"][0]["auth_token"] is not None + + # Check that the token is not there anymore. + output = rpk.cloud_logout() + assert "You are now logged out" in output + rpk_yaml = read_rpk_cfg(node) + + assert "auth_token" not in rpk_yaml["cloud_auth"][0]