Skip to content

Commit

Permalink
connect: add binary port connection to instance
Browse files Browse the repository at this point in the history
Added ability to connect to instance using binary port.
  • Loading branch information
better0fdead committed Feb 14, 2024
1 parent be469f2 commit cdb45fb
Show file tree
Hide file tree
Showing 7 changed files with 159 additions and 29 deletions.
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ running apps.

### Added

- `tt connect --binary`: connect to instance using binary port.
- `tt env`: add current environment binaries location to the PATH variable.
- `tt cluster`: add an ability to specify a key for `show`/`publish` via URI.
- `tt cluster`: add an ability to publish/show configuration from tarantool
Expand Down
18 changes: 14 additions & 4 deletions cli/cmd/connect.go
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ var (
connectSslCaFile string
connectSslCiphers string
connectInteractive bool
connectBinary bool
)

// NewConnectCmd creates connect command.
Expand Down Expand Up @@ -101,6 +102,8 @@ func NewConnectCmd() *cobra.Command {
`colon-separated (:) list of SSL cipher suites the connection`)
connectCmd.Flags().BoolVarP(&connectInteractive, "interactive", "i",
false, `enter interactive mode after executing 'FILE'`)
connectCmd.Flags().BoolVarP(&connectBinary, "binary", "",
false, `connect to instance using binary port`)

return connectCmd
}
Expand Down Expand Up @@ -138,14 +141,20 @@ func resolveConnectOpts(cmdCtx *cmdcontext.CmdCtx, cliOpts *config.CliOpts,
err = fmt.Errorf("specify instance name")
return
}
if connectCtx.Username != "" || connectCtx.Password != "" {
if (connectCtx.Username != "" || connectCtx.Password != "") && !connectCtx.Binary {
err = fmt.Errorf("username and password are not supported" +
" with a connection via a control socket")
return
}
connOpts = makeConnOpts(
connector.UnixNetwork, runningCtx.Instances[0].ConsoleSocket, *connectCtx,
)
if connectCtx.Binary {
connOpts = makeConnOpts(
connector.UnixNetwork, runningCtx.Instances[0].BinaryPort, *connectCtx,
)
} else {
connOpts = makeConnOpts(
connector.UnixNetwork, runningCtx.Instances[0].ConsoleSocket, *connectCtx,
)
}
} else if connect.IsCredentialsURI(args[0]) {
if connectCtx.Username != "" || connectCtx.Password != "" {
err = fmt.Errorf("username and password are specified with" +
Expand Down Expand Up @@ -189,6 +198,7 @@ func internalConnectModule(cmdCtx *cmdcontext.CmdCtx, args []string) error {
SslCaFile: connectSslCaFile,
SslCiphers: connectSslCiphers,
Interactive: connectInteractive,
Binary: connectBinary,
}

var ok bool
Expand Down
2 changes: 2 additions & 0 deletions cli/connect/connect.go
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,8 @@ type ConnectCtx struct {
Interactive bool
// ConnectTarget contains connection target string: URI or instance name.
ConnectTarget string
// Binary port is used
Binary bool
}

const (
Expand Down
161 changes: 138 additions & 23 deletions test/integration/connect/test_connect.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,16 @@
import os
import platform
import re
import shutil
import subprocess
import tempfile
import time

import psutil
import pytest

from utils import (control_socket, get_tarantool_version, kill_procs,
run_command_and_get_output, run_path, wait_file)
from utils import (control_socket, create_tt_config, get_tarantool_version,
kill_procs, run_command_and_get_output, run_path, wait_file)

tarantool_major_version, tarantool_minor_version = get_tarantool_version()

Expand All @@ -33,15 +36,21 @@ def copy_data(dst, file_paths):
shutil.copy(path, dst)


def start_app(tt_cmd, tmpdir_with_cfg, app_name):
def start_app(tt_cmd, tmpdir_with_cfg, app_name, startBinaryPort):
test_env = os.environ.copy()
# Set empty TT_LISTEN, so no binary port will be created.
if startBinaryPort is False:
test_env['TT_LISTEN'] = ''

# Start an instance.
start_cmd = [tt_cmd, "start", app_name]
instance_process = subprocess.Popen(
start_cmd,
cwd=tmpdir_with_cfg,
stderr=subprocess.STDOUT,
stdout=subprocess.PIPE,
text=True
text=True,
env=test_env
)
start_output = instance_process.stdout.readline()
assert re.search(r"Starting an instance", start_output)
Expand Down Expand Up @@ -97,7 +106,7 @@ def prepare_test_app_languages(tt_cmd, tmpdir):
copy_data(tmpdir, [test_app_path, lua_file_path, sql_file_path])

# Start an instance.
start_app(tt_cmd, tmpdir, "test_app")
start_app(tt_cmd, tmpdir, "test_app", False)

# Check for start.
file = wait_file(os.path.join(tmpdir, "test_app"), 'configured', [])
Expand Down Expand Up @@ -187,7 +196,7 @@ def test_connect_and_get_commands_outputs(tt_cmd, tmpdir_with_cfg):
copy_data(tmpdir, [test_app_path, empty_file_path])

# Start an instance.
start_app(tt_cmd, tmpdir, "test_app")
start_app(tt_cmd, tmpdir, "test_app", False)

# Check for start.
file = wait_file(os.path.join(tmpdir, 'test_app'), 'ready', [])
Expand Down Expand Up @@ -287,7 +296,7 @@ def test_connect_and_get_commands_errors(tt_cmd, tmpdir_with_cfg):
copy_data(tmpdir, [test_app_path, empty_file_path])

# Start an instance.
start_app(tt_cmd, tmpdir, "test_app")
start_app(tt_cmd, tmpdir, "test_app", False)

# Check for start.
file = wait_file(os.path.join(tmpdir, 'test_app'), 'ready', [])
Expand Down Expand Up @@ -341,7 +350,7 @@ def test_connect_to_localhost_app(tt_cmd, tmpdir_with_cfg):
copy_data(tmpdir, [test_app_path, empty_file_path])

# Start an instance.
start_app(tt_cmd, tmpdir, "test_app")
start_app(tt_cmd, tmpdir, "test_app", False)

# Check for start.
file = wait_file(os.path.join(tmpdir, 'test_app'), 'ready', [])
Expand Down Expand Up @@ -390,7 +399,7 @@ def test_connect_to_ssl_app(tt_cmd, tmpdir_with_cfg):
shutil.copy(empty_file_path, os.path.join(tmpdir, "test_ssl_app", empty_file))

# Start an instance.
start_app(tt_cmd, tmpdir, "test_ssl_app")
start_app(tt_cmd, tmpdir, "test_ssl_app", False)

# Check for start.
file = wait_file(os.path.join(tmpdir, 'test_ssl_app'), 'ready', [])
Expand Down Expand Up @@ -426,7 +435,7 @@ def test_connect_to_localhost_app_credentials(tt_cmd, tmpdir_with_cfg):
copy_data(tmpdir, [test_app_path, empty_file_path])

# Start an instance.
start_app(tt_cmd, tmpdir, "test_app")
start_app(tt_cmd, tmpdir, "test_app", False)

# Check for start.
file = wait_file(os.path.join(tmpdir, 'test_app'), 'ready', [])
Expand Down Expand Up @@ -513,7 +522,7 @@ def test_connect_to_single_instance_app(tt_cmd, tmpdir_with_cfg):
copy_data(tmpdir, [test_app_path, empty_file_path])

# Start an instance.
start_app(tt_cmd, tmpdir, "test_app")
start_app(tt_cmd, tmpdir, "test_app", False)

# Check for start.
file = wait_file(os.path.join(tmpdir, "test_app", run_path, "test_app"),
Expand Down Expand Up @@ -552,7 +561,7 @@ def test_connect_to_single_instance_app_credentials(tt_cmd, tmpdir_with_cfg):
copy_data(tmpdir, [test_app_path, empty_file_path])

# Start an instance.
start_app(tt_cmd, tmpdir, "test_app")
start_app(tt_cmd, tmpdir, "test_app", False)

# Check for start.
file = wait_file(os.path.join(tmpdir, "test_app", run_path, "test_app"),
Expand Down Expand Up @@ -597,7 +606,7 @@ def test_connect_to_multi_instances_app(tt_cmd, tmpdir_with_cfg):
copy_data(tmpdir, [empty_file_path])

# Start instances.
start_app(tt_cmd, tmpdir, app_name)
start_app(tt_cmd, tmpdir, app_name, False)

# Check for start.
for instance in instances:
Expand Down Expand Up @@ -635,7 +644,7 @@ def test_connect_to_multi_instances_app_credentials(tt_cmd, tmpdir_with_cfg):
copy_data(tmpdir, [empty_file_path])

# Start instances.
start_app(tt_cmd, tmpdir, app_name)
start_app(tt_cmd, tmpdir, app_name, False)

# Check for start.
master_run_path = os.path.join(tmpdir, app_name, run_path, "master")
Expand Down Expand Up @@ -805,7 +814,7 @@ def test_output_format_lua(tt_cmd, tmpdir_with_cfg):
copy_data(tmpdir, [test_app_path])

# Start an instance.
start_app(tt_cmd, tmpdir, "test_app")
start_app(tt_cmd, tmpdir, "test_app", False)

# Check for start.
file = wait_file(os.path.join(tmpdir, 'test_app'), 'ready', [])
Expand Down Expand Up @@ -890,7 +899,7 @@ def test_table_output_format(tt_cmd, tmpdir_with_cfg):
copy_data(tmpdir, [test_app_path])

# Start an instance.
start_app(tt_cmd, tmpdir, "test_app")
start_app(tt_cmd, tmpdir, "test_app", False)

# Check for start.
file = wait_file(os.path.join(tmpdir, 'test_app'), 'ready', [])
Expand Down Expand Up @@ -1196,7 +1205,7 @@ def test_ttable_output_format(tt_cmd, tmpdir_with_cfg):
print("\n\n")
print(tt_cmd)
print("\n\n")
start_app(tt_cmd, tmpdir, "test_app")
start_app(tt_cmd, tmpdir, "test_app", False)

# Check for start.
file = wait_file(os.path.join(tmpdir, 'test_app'), 'ready', [])
Expand Down Expand Up @@ -1271,7 +1280,7 @@ def test_output_format_round_switching(tt_cmd, tmpdir_with_cfg):
copy_data(tmpdir, [test_app_path])

# Start an instance.
start_app(tt_cmd, tmpdir, "test_app")
start_app(tt_cmd, tmpdir, "test_app", False)

# Check for start.
file = wait_file(os.path.join(tmpdir, 'test_app'), 'ready', [])
Expand Down Expand Up @@ -1313,7 +1322,7 @@ def test_output_format_short_named_selecting(tt_cmd, tmpdir_with_cfg):
copy_data(tmpdir, [test_app_path])

# Start an instance.
start_app(tt_cmd, tmpdir, "test_app")
start_app(tt_cmd, tmpdir, "test_app", False)

# Check for start.
file = wait_file(os.path.join(tmpdir, 'test_app'), 'ready', [])
Expand Down Expand Up @@ -1356,7 +1365,7 @@ def test_output_format_full_named_selecting(tt_cmd, tmpdir_with_cfg):
copy_data(tmpdir, [test_app_path])

# Start an instance.
start_app(tt_cmd, tmpdir, "test_app")
start_app(tt_cmd, tmpdir, "test_app", False)

# Check for start.
file = wait_file(os.path.join(tmpdir, 'test_app'), 'ready', [])
Expand Down Expand Up @@ -1403,7 +1412,7 @@ def test_output_format_tables_pseudo_graphic_disable(tt_cmd, tmpdir_with_cfg):
copy_data(tmpdir, [test_app_path])

# Start an instance.
start_app(tt_cmd, tmpdir, "test_app")
start_app(tt_cmd, tmpdir, "test_app", False)

# Check for start.
file = wait_file(os.path.join(tmpdir, 'test_app'), 'ready', [])
Expand Down Expand Up @@ -1449,7 +1458,7 @@ def test_output_format_tables_width_option(tt_cmd, tmpdir_with_cfg):
copy_data(tmpdir, [test_app_path])

# Start an instance.
start_app(tt_cmd, tmpdir, "test_app")
start_app(tt_cmd, tmpdir, "test_app", False)

# Check for start.
file = wait_file(os.path.join(tmpdir, 'test_app'), 'ready', [])
Expand Down Expand Up @@ -1521,7 +1530,7 @@ def test_output_format_tables_dialects(tt_cmd, tmpdir_with_cfg):
copy_data(tmpdir, [test_app_path])

# Start an instance.
start_app(tt_cmd, tmpdir, "test_app")
start_app(tt_cmd, tmpdir, "test_app", False)

# Check for start.
file = wait_file(os.path.join(tmpdir, 'test_app'), 'ready', [])
Expand Down Expand Up @@ -1578,3 +1587,109 @@ def test_output_format_tables_dialects(tt_cmd, tmpdir_with_cfg):

# Stop the Instance.
stop_app(tt_cmd, tmpdir, "test_app")


def test_connect_to_single_instance_app_binary(tt_cmd):
if platform.system() == "Darwin":
pytest.skip("/set platform is unsupported by test")
tmpdir = tempfile.mkdtemp()
create_tt_config(tmpdir, "")
empty_file = "empty.lua"
# The test application file.
test_app_path = os.path.join(os.path.dirname(__file__), "test_single_app", "test_app.lua")
# The test file.
empty_file_path = os.path.join(os.path.dirname(__file__), "test_file", empty_file)
# Copy test data into temporary directory.
copy_data(tmpdir, [test_app_path, empty_file_path])

# Start an instance.
start_app(tt_cmd, tmpdir, "test_app", True)

# Check for start.
file = wait_file(os.path.join(tmpdir, "test_app", run_path, "test_app"),
"tarantool.sock", [])
assert file != ""
file = wait_file(os.path.join(tmpdir, 'test_app'), 'configured', [])
assert file != ""

# Wait for instance to bootstrap
time.sleep(5)

# Connect to the instance and execute a script.
connect_cmd = [tt_cmd, "connect", "test_app", "--binary", "-u", "test", "-p", "password",
"-f", empty_file]
instance_process = subprocess.run(
connect_cmd,
cwd=tmpdir,
stderr=subprocess.STDOUT,
stdout=subprocess.PIPE,
text=True,
)
assert instance_process.returncode == 0

# Connect to the instance and execute stdin.
connect_cmd = [tt_cmd, "connect", "test_app", "--binary", "-u", "test", "-p", "password"]
instance_process = subprocess.run(
connect_cmd,
cwd=tmpdir,
stderr=subprocess.STDOUT,
stdout=subprocess.PIPE,
text=True,
input="2+2"
)
assert instance_process.returncode == 0
assert instance_process.stdout == "---\n- 4\n...\n\n"

# Stop the Instance.
stop_app(tt_cmd, tmpdir, "test_app")
shutil.rmtree(tmpdir)


def test_connect_to_multi_instances_app_binary(tt_cmd):
if platform.system() == "Darwin":
pytest.skip("/set platform is unsupported by test")
tmpdir = tempfile.mkdtemp()
create_tt_config(tmpdir, "")
app_name = "test_multi_app"
empty_file = "empty.lua"
# Copy the test application to the "run" directory.
test_app_path = os.path.join(os.path.dirname(__file__), app_name)
tmp_app_path = os.path.join(tmpdir, app_name)
shutil.copytree(test_app_path, tmp_app_path)
# The test file.
empty_file_path = os.path.join(os.path.dirname(__file__), "test_file", empty_file)
# Copy test data into temporary directory.
copy_data(tmpdir, [empty_file_path])

# Start instances.
start_app(tt_cmd, tmpdir, app_name, True)

# Check for start.
instances = ['master', 'replica', 'router']
for instance in instances:
master_run_path = os.path.join(tmpdir, app_name, run_path, instance)
file = wait_file(master_run_path, control_socket, [])
assert file != ""
file = wait_file(master_run_path, "tarantool.sock", [])
assert file != ""

# Wait for instance to bootstrap
time.sleep(5)

# Connect to the instance and execute stdin.
connect_cmd = [tt_cmd, "connect", app_name + ":master", "--binary",
"-u", "test", "-p", "password"]
instance_process = subprocess.run(
connect_cmd,
cwd=tmpdir,
stderr=subprocess.STDOUT,
stdout=subprocess.PIPE,
text=True,
input="2+2"
)
assert instance_process.returncode == 0
assert instance_process.stdout == "---\n- 4\n...\n\n"

# Stop the Instance.
stop_app(tt_cmd, tmpdir, app_name)
shutil.rmtree(tmpdir)
2 changes: 1 addition & 1 deletion test/integration/connect/test_multi_app/init.lua
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
local inst_name = os.getenv('TARANTOOL_INSTANCE_NAME')
local app_name = os.getenv('TARANTOOL_APP_NAME')

box.cfg({})
box.cfg()

box.schema.user.create('test', { password = 'password' , if_not_exists = true })
box.schema.user.grant('test','read,write,execute,create,drop','universe')
Expand Down
Loading

0 comments on commit cdb45fb

Please sign in to comment.