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
41 changes: 41 additions & 0 deletions .github/actions/setup-test/action.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
name: Setup Tarantool Test Environment
description: 'Sets up Tarantool and dependencies for testing'

inputs:
tarantool-version:
description: 'Tarantool version to install'
required: true

runs:
using: "composite"
steps:
- name: setup tarantool
uses: tarantool/setup-tarantool@v3
with:
tarantool-version: ${{ inputs.tarantool-version }}
- name: add tarantool/modules repo
shell: bash
run: |
os=$(. /etc/os-release && echo $ID)
dist=$(. /etc/os-release && echo $VERSION_CODENAME)
curl -L "https://download.tarantool.org/tarantool/modules/gpgkey" | sudo apt-key add -
apt_source_path="/etc/apt/sources.list.d/tarantool.list"
echo "deb https://download.tarantool.org/tarantool/modules/${os}/ ${dist} main" | sudo tee ${apt_source_path}
- name: install tt
shell: bash
run: sudo apt-get update && sudo apt-get install -y tt
- name: install luacov-coveralls 0.2.3
shell: bash
run: tt rocks install --server https://luarocks.org luacov-coveralls 0.2.3
- name: install luacov-console 1.2.0
shell: bash
run: tt rocks --server http://moonlibs.github.io/rocks install luacov-console 1.2.0
- name: setup perl
uses: shogo82148/actions-setup-perl@v1
with:
perl-version: 5.18.4
- name: install TAP::Harness
shell: bash
run: |
cpanm -v
cpanm --notest TAP::Harness
2 changes: 1 addition & 1 deletion .github/workflows/lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,6 @@ jobs:
- uses: actions/checkout@v4
- uses: tarantool/setup-tarantool@v3
with:
tarantool-version: '2.11.6'
tarantool-version: '2.11'
- name: install tarantool/luacheck and execute it
run: tarantoolctl rocks install luacheck && .rocks/bin/luacheck .
4 changes: 2 additions & 2 deletions .github/workflows/push-rockspec.yml
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
name: Create and push rockspec for moonlibs/sync

on:
workflow_dispatch:
workflow_run:
workflows:
- "Linting with luacheck"
- "Testing with unit tests"
Expand Down Expand Up @@ -37,7 +37,7 @@ jobs:
luaVersion: "luajit-2.1.0-beta3"
- uses: leafo/gh-actions-luarocks@v5
with:
luarocksVersion: "3.8.0"
luaRocksVersion: "3.8.0"
- uses: unfor19/install-aws-cli-action@v1.0.3
- run: mkdir .build && cp ${{ env.ROCK_NAME }}-dev-1.rockspec ${{ env.ROCK_NAME }}-${{ env.TAG }}-1.rockspec .build/ && cp *.src.rock .build/
- name: rebuild and publish s3 luarocks server
Expand Down
28 changes: 3 additions & 25 deletions .github/workflows/tests.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,27 +12,9 @@ jobs:
version: ["1.10.15", "2.10.7", "2.11.2", "3.0.1"]
steps:
- uses: actions/checkout@v4
- uses: tarantool/setup-tarantool@v3
with:
tarantool-version: '2.10.4'
- name: install luacov-console
run: tarantoolctl rocks install luacov-console
- name: install luacov-coveralls
run: tarantoolctl rocks install --server=http://luarocks.org luacov-coveralls
- uses: tarantool/setup-tarantool@v3
- uses: ./.github/actions/setup-test
with:
tarantool-version: ${{matrix.version}}
- name: setup perl
uses: shogo82148/actions-setup-perl@v1
with:
perl-version: 5.18.4
- name: show perl version
run: |
perl -v
- name: install TAP::Harness
run: |
cpanm -v
cpanm --notest TAP::Harness
- name: run tests
env:
LUACOV_ENABLE: true
Expand All @@ -50,13 +32,9 @@ jobs:
needs: ["run-unit-tests"]
steps:
- uses: actions/checkout@v4
- uses: tarantool/setup-tarantool@v3
- uses: ./.github/actions/setup-test
with:
tarantool-version: '2.11.6'
- name: install luacov-coveralls 0.2.3
run: tarantoolctl rocks install --server=https://luarocks.org luacov-coveralls 0.2.3
- name: install luacov-console 1.2.0
run: tarantoolctl rocks --server http://moonlibs.github.io/rocks install luacov-console 1.2.0
tarantool-version: '2.11'
- name: Download run artifacts
uses: actions/download-artifact@v4
with:
Expand Down
226 changes: 0 additions & 226 deletions kit/2.lua
Original file line number Diff line number Diff line change
@@ -1,230 +1,4 @@
local net_box = require 'net.box'
local clock = require 'clock'
local fiber = require 'fiber'
local log = require 'log'
local json = require 'json'

return function(M,I)
require 'kit.1'(M,I)
require 'kit.1.10'(M,I)

M.sys = {}

-- Experimental manual switchover function
-- Do not use yet

function M.sys.transfer_leadership(args)
args = args or {
-- id = | uuid =
-- host = -- later
ignore_etcd_current_master = false,
}

local function logerror(f, ...)
local msg = (f):format(...)
log.error("kit.sys.xfr: %s", msg)
error(msg, 0)
end

if not M.node.rw then error("Instance must be readwrite", 0) end

local me = M.node.id
local candidates = {}
local timeout = args.timeout or 3

if args.id then
table.insert(candidates, assert(box.info.replication[args.id],
"Id "..args.id.." is not known to cluster"))
elseif args.uuid then
for id, peer in pairs(box.info.replication) do
if args.uuid == peer.uuid then
table.insert(candidates, peer)
end
end
assert(#candidates > 0, "uuid "..args.uuid.." is not known to cluster")
else
for id, peer in pairs(box.info.replication) do
if id ~= me then
table.insert(candidates, peer)
end
end
end

for _, peer in pairs(candidates) do
if peer.downstream and peer.downstream.status == 'follow' then
if peer.upstream then
-- ok
else
error(("Peer %s/%s have downstream and have no upstream:"
.." only fullmesh is supported"):format(peer.id, peer.uuid), 0)
end
else
error(("Peer %s/%s have no downstream:"
.." only fullmesh is supported"):format(peer.id, peer.uuid), 0)
end
end

if #candidates == 0 then
error("No suitable candidates found", 0)
end

table.sort(candidates, function(a,b)
if b.downstream.vclock[me] < a.downstream.vclock[me] then
return true
elseif b.downstream.vclock[me] == a.downstream.vclock[me] then
return a.downstream.lag < b.downstream.lag
end
end)

local remote = candidates[1]

log.info("kit.sys.xfr: Chosen candidate %s/%s: %s for switch", remote.id, remote.uuid, remote.upstream.peer)

local conn = net_box.connect( remote.upstream.peer, {
connect_timeout = timeout,
wait_connected = false,
reconnect_after = 0,
} )
if not conn:wait_connected(timeout) then
logerror("Failed to connect to peer %s within timeout %s",
remote.upstream.peer, timeout)
end
local replica_info = conn:call('kit.node', {}, {timeout = timeout})
if replica_info.uuid ~= remote.uuid then
logerror("Connected to wrong destination. Expected %s, got %s",
remote.uuid, replica_info.uuid)
end
log.info("kit.sys.xfr: Connected to candidate at %s. Local vclock: %s, remote vclock: %s",
replica_info.hostname, json.encode(box.info.vclock),
json.encode(box.info.replication[ remote.id ].downstream.vclock))

-- 1. dry-run. make some modification and wait_lsn
local lsn = box.info.lsn
box.space._schema:replace(box.space._schema:get('_advance') or {'_advance'})
assert( box.info.lsn > lsn, "Lsn not advanced after modification" )
lsn = box.info.lsn

local start = clock.time()
local replica_awaited = conn:call('kit.wait_lsn', {me, lsn, timeout}, { timeout = timeout + 0.1 })
local lag_time = clock.time() - start

if not replica_awaited then
logerror("Failed to await changes from replica (changes not made)")
else
log.info("kit.sys.xfr: Candidate advanced to lsn %d in %0.6f", lsn, lag_time)
end

-- 2. Prepare etcd for switching. Switch master key for this cluster
local instance_name
if config and config.etcd then
local prefix = config.get("etcd.prefix")
local cfg = config.etcd:get_all()
instance_name = config.get('sys.instance_name')
local this = assert(cfg.instances[ instance_name ], "Instance not found in etcd config " .. instance_name)
local clusters_key = assert( cfg.clusters and 'clusters' or cfg.shards and 'shards' or nil, "No clusters section" )
local cluster_key = assert( this.cluster and 'cluster' or this.shard and 'shard' or nil, "No cluster key in instance" )
local cluster_name = assert(this[ cluster_key ], "No cluster name in instance")
local cluster = assert(cfg[ clusters_key ][ cluster_name ], "No cluster " .. cluster_name)
local candidate_name
for inst, data in pairs( cfg.instances ) do
if data.box.instance_uuid == remote.uuid then
candidate_name = inst
break
end
end
assert(candidate_name, "Candidate not found by uuid " .. remote.uuid)
local current_master = cfg[ clusters_key ][ cluster_name ].master
if not args.ignore_etcd_current_master then
if current_master ~= instance_name and current_master ~= candidate_name then
logerror(
"Current master for cluster %s is %. Neither me (%s), not candidate (%s). "
.. "To bypass this chech run with `ignore_etcd_current_master = true`",
cluster_name, current_master, instance_name, candidate_name
)
end
end

local path = "/keys" .. prefix .. "/" .. clusters_key .. "/" .. cluster_name .. "/master"
local res = config.etcd:request( "PUT", path, {
value = candidate_name, prevValue = current_master
} )

log.info("kit.sys.xfr: Update etcd CAS %s: %s->%s: %s", path, current_master, candidate_name, json.encode(res))
if res.errorCode then
logerror("Etcd CAS failed: %s", json.encode( res ))
end
end

-- 3. ready to break things. Switch master to ro and propagate final changes to replica

start = clock.time()
box.cfg{ read_only = true }
fiber.yield() -- allow state changes to be detected and lsn to advance
lsn = box.info.lsn

local r, state, replica_info = pcall(function()
return conn:eval([[
local id,lsn,to = ...
if not kit.wait_lsn(id,lsn,to) then
return false, kit.node
end

local r,e = pcall(package.reload)
if not r then
if not e:match("console is already started") then
error(e)
end
end
require "fiber".yield()

return true, kit.node
]], {me, lsn, timeout}, {timeout = timeout + 0.1})
end)

local switch_time = clock.time() - start

if not r then
logerror("Replica switch failed! Emergency repair required! Don't know actual state. %s", state)
end

if state then
-- got true from switch script
if replica_info.rw then
local r,e = pcall(package.reload)

log.info(
"kit.sys.xfr: Replica %s was promoted and reloaded: %s in %0.6fs",
remote.upstream.peer, json.encode( replica_info ), switch_time
);

if not r then
log.info("Local reload failed with error: %s", e)
end

return { success = {
msg = "Replica was promoted and reloaded",
time = switch_time,
target = {
instance_name = instance_name,
addr = remote.upstream.peer,
info = replica_info,
},
local_reload = {
[ r and "success" or "failure" ] = e or true
}
} }
else
box.cfg{ read_only = false }

logerror(
"Replica %s was !!!NOT!!! promoted after reload: %s in %0.6fs, switched master back",
remote.upstream.peer, json.encode( replica_info ), switch_time
)
end
else
-- got false from switch script: wait_lsn failed
box.cfg{ read_only = false }
logerror( "Replica failed to await for lsn: %s, switched master back", json.encode( replica_info ) );
end
end
end
14 changes: 13 additions & 1 deletion kit/3.lua
Original file line number Diff line number Diff line change
@@ -1,3 +1,15 @@
return function(M,I)
require 'kit.2'(M,I)
require 'kit.1'(M, I)
require 'kit.1.10'(M, I)

function M.schema_version()
return box.info.schema_version
end

I._node_keys.hostname = function()
return box.info.hostname
end
I._node_keys.name = function()
return box.info.name
end
end
9 changes: 3 additions & 6 deletions kit/loc.lua
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
local _VERSION = '3'
local _VERSION = '3.4'

if rawget(_G,'kit') then
if kit._VERSION == _VERSION then
Expand Down Expand Up @@ -28,9 +28,9 @@ repeat
if (0+maj) == 1 then
if (0+min) >= 5 then break end -- 1.5+ is acceptable
elseif (0+maj) == 2 then
if (0+min) <= 11 then break end -- <= 2.10 is acceptable
if (0+min) <= 11 then break end -- <= 2.11 is acceptable
elseif (0+maj) == 3 then
if (0+min) <= 3 then break end -- <= 3.3 is acceptable
if (0+min) <= 4 then break end -- <= 3.4 is acceptable
end
error(string.format("Version %s not supported", _TARANTOOL))
until true
Expand Down Expand Up @@ -65,9 +65,6 @@ local M = setmetatable({
} })

local function extend(m,mod)

-- local ext = tryload(mod,1)

local name = 'kit.'..mod
local ext = require(name)
if ext then
Expand Down
Loading