Skip to content

Commit

Permalink
Dev: ui_corosync: add subcommand 'crm corosync link add' (jsc#PED-8083)
Browse files Browse the repository at this point in the history
  • Loading branch information
nicholasyang2022 committed Jun 27, 2024
1 parent 56392c3 commit 6b0b511
Show file tree
Hide file tree
Showing 2 changed files with 43 additions and 18 deletions.
33 changes: 29 additions & 4 deletions crmsh/ui_corosync.py
Original file line number Diff line number Diff line change
Expand Up @@ -57,12 +57,13 @@ class LinkArgumentParser:
class SyntaxException(Exception):
pass

def parse(self, args: typing.Sequence[str]):
def parse(self, parse_linknumber: bool, args: typing.Sequence[str]):
if not args:
raise LinkArgumentParser.SyntaxException('linknumber is required')
i = 0
self.linknumber = self.__parse_linknumber(args, i)
i += 1
if parse_linknumber:
self.linknumber = self.__parse_linknumber(args, i)
i += 1
while i < len(args):
if args[i] == 'options':
i += 1
Expand Down Expand Up @@ -147,7 +148,7 @@ def do_update(self, context, *argv):
logger.error('Corosync is not using knet transport')
return False
try:
args = LinkArgumentParser().parse(argv)
args = LinkArgumentParser().parse(True, argv)
except LinkArgumentParser.SyntaxException as e:
logger.error('%s', str(e))
print('Usage: link update <linknumber> [<node>=<addr> ...] [options <option>=<value> ...] ', file=sys.stderr)
Expand All @@ -166,6 +167,30 @@ def do_update(self, context, *argv):
logger.info("Use \"crm corosync diff\" to show the difference")
logger.info("Use \"crm corosync push\" to sync")

def do_add(self, context, *argv):
lm = corosync.LinkManager.load_config_file()
if lm.totem_transport() != 'knet':
logger.error('Corosync is not using knet transport')
return False
try:
args = LinkArgumentParser().parse(False, argv)
except LinkArgumentParser.SyntaxException as e:
logger.error('%s', str(e))
print('Usage: link add <node>=<addr> ... [options <option>=<value> ...] ', file=sys.stderr)
return False
nodes = lm.links()[0].nodes
node_addresses: dict[int, str] = dict()
for name, addr in args.nodes:
nodeid = next((x.nodeid for x in nodes if x.name == name), -1)
if nodeid == -1:
logger.error(f'Unknown node {name}.')
node_addresses[nodeid] = addr
lm.write_config_file(
lm.add_link(node_addresses, args.options)
)
logger.info("Use \"crm corosync diff\" to show the difference")
logger.info("Use \"crm corosync push\" to sync")

def do_remove(self, context, linknumber: str):
if not linknumber.isdecimal():
raise ValueError(f'Invalid linknumber: {linknumber}')
Expand Down
28 changes: 14 additions & 14 deletions test/unittests/test_ui_corosync.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,54 +6,54 @@
class TestLinkArgumentParser(unittest.TestCase):
def test_parse_empty(self):
with self.assertRaises(LinkArgumentParser.SyntaxException):
LinkArgumentParser().parse(list())
LinkArgumentParser().parse(True, list())

def test_invalid_link_number(self):
with self.assertRaises(LinkArgumentParser.SyntaxException):
LinkArgumentParser().parse(['a0'])
LinkArgumentParser().parse(True, ['a0'])

def test_no_spec(self):
args = LinkArgumentParser().parse(['0'])
args = LinkArgumentParser().parse(True, ['0'])
self.assertEqual(0, args.linknumber)
self.assertFalse(args.nodes)
self.assertFalse(args.options)

def test_addr_spec(self):
args = LinkArgumentParser().parse(['0', 'node1=192.0.2.100', 'node2=fd00:a0::10'])
args = LinkArgumentParser().parse(True, ['0', 'node1=192.0.2.100', 'node2=fd00:a0::10'])
self.assertEqual(0, args.linknumber)
self.assertFalse(args.options)
self.assertListEqual([('node1', '192.0.2.100'), ('node2', 'fd00:a0::10')], args.nodes)

def test_invalid_addr_spec(self):
with self.assertRaises(LinkArgumentParser.SyntaxException):
LinkArgumentParser().parse(['0', 'node1=192.0.2.300'])
LinkArgumentParser().parse(True, ['0', 'node1=192.0.2.300'])
with self.assertRaises(LinkArgumentParser.SyntaxException):
LinkArgumentParser().parse(['0', 'node1=fd00::a0::10'])
LinkArgumentParser().parse(True, ['0', 'node1=fd00::a0::10'])
with self.assertRaises(LinkArgumentParser.SyntaxException):
LinkArgumentParser().parse(['0', 'node1=node1.example.com'])
LinkArgumentParser().parse(True, ['0', 'node1=node1.example.com'])

def test_option_spec(self):
args = LinkArgumentParser().parse(['0', 'options', 'node1=192.0.2.100', 'node2=fd00:a0::10', 'foo='])
args = LinkArgumentParser().parse(True, ['0', 'options', 'node1=192.0.2.100', 'node2=fd00:a0::10', 'foo='])
self.assertEqual(0, args.linknumber)
self.assertFalse(args.nodes)
self.assertDictEqual({'node1': '192.0.2.100', 'node2': 'fd00:a0::10', 'foo': None}, args.options)

def test_addrs_and_options(self):
args = LinkArgumentParser().parse(['0', 'node1=192.0.2.100', 'node2=fd00:a0::10', 'options', 'foo=bar=1'])
args = LinkArgumentParser().parse(True, ['0', 'node1=192.0.2.100', 'node2=fd00:a0::10', 'options', 'foo=bar=1'])
self.assertEqual(0, args.linknumber)
self.assertListEqual([('node1', '192.0.2.100'), ('node2', 'fd00:a0::10')], args.nodes)
self.assertDictEqual({'foo': 'bar=1'}, args.options)

def test_no_options(self):
with self.assertRaises(LinkArgumentParser.SyntaxException):
LinkArgumentParser().parse(['0', 'options'])
LinkArgumentParser().parse(True, ['0', 'options'])

def test_garbage_inputs(self):
with self.assertRaises(LinkArgumentParser.SyntaxException):
LinkArgumentParser().parse(['0', 'foo'])
LinkArgumentParser().parse(True, ['0', 'foo'])
with self.assertRaises(LinkArgumentParser.SyntaxException):
LinkArgumentParser().parse(['0', 'node1=192.0.2.100', 'foo'])
LinkArgumentParser().parse(True, ['0', 'node1=192.0.2.100', 'foo'])
with self.assertRaises(LinkArgumentParser.SyntaxException):
LinkArgumentParser().parse(['0', 'node1=192.0.2.100', 'options', 'foo'])
LinkArgumentParser().parse(True, ['0', 'node1=192.0.2.100', 'options', 'foo'])
with self.assertRaises(LinkArgumentParser.SyntaxException):
LinkArgumentParser().parse(['0', 'node1=192.0.2.100', 'options', 'foo=bar', 'foo'])
LinkArgumentParser().parse(True, ['0', 'node1=192.0.2.100', 'options', 'foo=bar', 'foo'])

0 comments on commit 6b0b511

Please sign in to comment.