2017-11-17 04:42:33 -06:00
|
|
|
import contextlib
|
|
|
|
import os
|
2012-03-13 06:10:52 -05:00
|
|
|
import shlex
|
2017-11-17 04:42:33 -06:00
|
|
|
import subprocess
|
2012-03-13 06:10:52 -05:00
|
|
|
import sys
|
2017-12-06 10:01:57 -06:00
|
|
|
import unittest
|
2012-03-13 06:10:52 -05:00
|
|
|
|
2015-09-11 06:43:28 -05:00
|
|
|
import six
|
2015-09-14 07:52:48 -05:00
|
|
|
from six import StringIO
|
2012-03-13 06:10:52 -05:00
|
|
|
|
2013-05-21 06:40:27 -05:00
|
|
|
from ipatests import util
|
2012-03-13 06:10:52 -05:00
|
|
|
from ipalib import api, errors
|
2015-04-24 07:39:48 -05:00
|
|
|
import pytest
|
2012-03-13 06:10:52 -05:00
|
|
|
|
2015-09-11 06:43:28 -05:00
|
|
|
if six.PY3:
|
|
|
|
unicode = str
|
|
|
|
|
2015-12-16 09:27:34 -06:00
|
|
|
TEST_ZONE = u'zoneadd.%(domain)s' % api.env
|
|
|
|
|
2017-11-17 04:42:33 -06:00
|
|
|
HERE = os.path.abspath(os.path.dirname(__file__))
|
|
|
|
BASE_DIR = os.path.abspath(os.path.join(HERE, os.pardir, os.pardir))
|
2012-03-13 06:10:52 -05:00
|
|
|
|
2017-12-11 00:48:13 -06:00
|
|
|
|
2015-04-24 07:39:48 -05:00
|
|
|
@pytest.mark.tier0
|
2017-12-11 00:48:13 -06:00
|
|
|
@pytest.mark.needs_ipaapi
|
2012-03-13 06:10:52 -05:00
|
|
|
class TestCLIParsing(object):
|
|
|
|
"""Tests that commandlines are correctly parsed to Command keyword args
|
|
|
|
"""
|
|
|
|
def check_command(self, commandline, expected_command_name, **kw_expected):
|
|
|
|
argv = shlex.split(commandline)
|
|
|
|
executioner = api.Backend.cli
|
|
|
|
|
|
|
|
cmd = executioner.get_command(argv)
|
2013-02-22 06:25:03 -06:00
|
|
|
kw_got = executioner.parse(cmd, argv[1:])
|
|
|
|
kw_got = executioner.process_keyword_arguments(cmd, kw_got)
|
2012-03-13 06:10:52 -05:00
|
|
|
util.assert_deepequal(expected_command_name, cmd.name, 'Command name')
|
|
|
|
util.assert_deepequal(kw_expected, kw_got)
|
|
|
|
|
|
|
|
def run_command(self, command_name, **kw):
|
|
|
|
"""Run a command on the server"""
|
2012-12-19 03:25:24 -06:00
|
|
|
if not api.Backend.rpcclient.isconnected():
|
2016-05-25 05:31:03 -05:00
|
|
|
api.Backend.rpcclient.connect()
|
2012-03-28 03:42:23 -05:00
|
|
|
try:
|
|
|
|
api.Command[command_name](**kw)
|
|
|
|
except errors.NetworkError:
|
2017-12-06 10:01:57 -06:00
|
|
|
raise unittest.SkipTest('%r: Server not available: %r' %
|
2012-03-28 03:42:23 -05:00
|
|
|
(self.__module__, api.env.xmlrpc_uri))
|
2012-03-13 06:10:52 -05:00
|
|
|
|
|
|
|
@contextlib.contextmanager
|
|
|
|
def fake_stdin(self, string_in):
|
|
|
|
"""Context manager that temporarily replaces stdin to read a string"""
|
|
|
|
old_stdin = sys.stdin
|
2015-09-14 07:52:48 -05:00
|
|
|
sys.stdin = StringIO(string_in)
|
2012-03-13 06:10:52 -05:00
|
|
|
yield
|
|
|
|
sys.stdin = old_stdin
|
|
|
|
|
|
|
|
def test_ping(self):
|
2015-07-21 08:30:47 -05:00
|
|
|
self.check_command('ping', 'ping')
|
2012-03-13 06:10:52 -05:00
|
|
|
|
2017-01-12 07:08:37 -06:00
|
|
|
def test_plugins(self):
|
|
|
|
self.check_command('plugins', 'plugins')
|
|
|
|
|
2012-03-13 06:10:52 -05:00
|
|
|
def test_user_show(self):
|
2016-06-03 02:21:08 -05:00
|
|
|
self.check_command('user-show admin', 'user_show', uid=u'admin')
|
2012-03-13 06:10:52 -05:00
|
|
|
|
|
|
|
def test_user_show_underscore(self):
|
2016-06-03 02:21:08 -05:00
|
|
|
self.check_command('user_show admin', 'user_show', uid=u'admin')
|
2012-03-13 06:10:52 -05:00
|
|
|
|
|
|
|
def test_group_add(self):
|
2016-06-03 02:21:08 -05:00
|
|
|
self.check_command(
|
|
|
|
'group-add tgroup1 --desc="Test group"',
|
2012-03-13 06:10:52 -05:00
|
|
|
'group_add',
|
|
|
|
cn=u'tgroup1',
|
|
|
|
description=u'Test group',
|
2016-06-03 02:21:08 -05:00
|
|
|
)
|
2012-03-13 06:10:52 -05:00
|
|
|
|
|
|
|
def test_sudocmdgroup_add_member(self):
|
2013-02-14 10:49:47 -06:00
|
|
|
# Test CSV splitting is not done
|
2012-03-13 06:10:52 -05:00
|
|
|
self.check_command(
|
|
|
|
# The following is as it would appear on the command line:
|
2013-02-14 10:49:47 -06:00
|
|
|
r'sudocmdgroup-add-member tcmdgroup1 --sudocmds=ab,c --sudocmds=d',
|
2012-03-13 06:10:52 -05:00
|
|
|
'sudocmdgroup_add_member',
|
|
|
|
cn=u'tcmdgroup1',
|
2013-02-14 10:49:47 -06:00
|
|
|
sudocmd=[u'ab,c', u'd'],
|
2016-06-03 02:21:08 -05:00
|
|
|
)
|
2012-03-13 06:10:52 -05:00
|
|
|
|
|
|
|
def test_group_add_nonposix(self):
|
2016-06-03 02:21:08 -05:00
|
|
|
self.check_command(
|
|
|
|
'group-add tgroup1 --desc="Test group" --nonposix',
|
2012-03-13 06:10:52 -05:00
|
|
|
'group_add',
|
|
|
|
cn=u'tgroup1',
|
|
|
|
description=u'Test group',
|
|
|
|
nonposix=True,
|
2016-06-03 02:21:08 -05:00
|
|
|
)
|
2012-03-13 06:10:52 -05:00
|
|
|
|
|
|
|
def test_group_add_gid(self):
|
2016-06-03 02:21:08 -05:00
|
|
|
self.check_command(
|
|
|
|
'group-add tgroup1 --desc="Test group" --gid=1234',
|
2012-03-13 06:10:52 -05:00
|
|
|
'group_add',
|
|
|
|
cn=u'tgroup1',
|
|
|
|
description=u'Test group',
|
|
|
|
gidnumber=u'1234',
|
2016-06-03 02:21:08 -05:00
|
|
|
)
|
2012-03-13 06:10:52 -05:00
|
|
|
|
|
|
|
def test_group_add_interactive(self):
|
|
|
|
with self.fake_stdin('Test group\n'):
|
2016-06-03 02:21:08 -05:00
|
|
|
self.check_command(
|
|
|
|
'group-add tgroup1', 'group_add',
|
2012-03-13 06:10:52 -05:00
|
|
|
cn=u'tgroup1',
|
2016-06-03 02:21:08 -05:00
|
|
|
)
|
2012-03-13 06:10:52 -05:00
|
|
|
|
|
|
|
def test_dnsrecord_add(self):
|
2016-06-03 02:21:08 -05:00
|
|
|
self.check_command(
|
|
|
|
'dnsrecord-add %s ns --a-rec=1.2.3.4' % TEST_ZONE,
|
2012-03-13 06:10:52 -05:00
|
|
|
'dnsrecord_add',
|
2015-12-16 09:27:34 -06:00
|
|
|
dnszoneidnsname=TEST_ZONE,
|
2012-03-13 06:10:52 -05:00
|
|
|
idnsname=u'ns',
|
2013-02-14 10:49:47 -06:00
|
|
|
arecord=u'1.2.3.4',
|
2016-06-03 02:21:08 -05:00
|
|
|
)
|
2012-03-13 06:10:52 -05:00
|
|
|
|
|
|
|
def test_dnsrecord_del_all(self):
|
|
|
|
try:
|
2015-12-16 09:27:34 -06:00
|
|
|
self.run_command('dnszone_add', idnsname=TEST_ZONE)
|
2012-03-13 06:10:52 -05:00
|
|
|
except errors.NotFound:
|
2017-12-06 10:01:57 -06:00
|
|
|
raise unittest.SkipTest('DNS is not configured')
|
2012-03-13 06:10:52 -05:00
|
|
|
try:
|
|
|
|
self.run_command('dnsrecord_add',
|
2015-12-16 09:27:34 -06:00
|
|
|
dnszoneidnsname=TEST_ZONE,
|
2014-09-19 05:38:34 -05:00
|
|
|
idnsname=u'ns', arecord=u'1.2.3.4', force=True)
|
2012-03-13 06:10:52 -05:00
|
|
|
with self.fake_stdin('yes\n'):
|
2016-06-03 02:21:08 -05:00
|
|
|
self.check_command(
|
|
|
|
'dnsrecord_del %s ns' % TEST_ZONE,
|
2012-03-13 06:10:52 -05:00
|
|
|
'dnsrecord_del',
|
2015-12-16 09:27:34 -06:00
|
|
|
dnszoneidnsname=TEST_ZONE,
|
2012-03-13 06:10:52 -05:00
|
|
|
idnsname=u'ns',
|
|
|
|
del_all=True,
|
2016-06-03 02:21:08 -05:00
|
|
|
)
|
2012-03-13 06:10:52 -05:00
|
|
|
with self.fake_stdin('YeS\n'):
|
2016-06-03 02:21:08 -05:00
|
|
|
self.check_command(
|
|
|
|
'dnsrecord_del %s ns' % TEST_ZONE,
|
2012-03-13 06:10:52 -05:00
|
|
|
'dnsrecord_del',
|
2015-12-16 09:27:34 -06:00
|
|
|
dnszoneidnsname=TEST_ZONE,
|
2012-03-13 06:10:52 -05:00
|
|
|
idnsname=u'ns',
|
|
|
|
del_all=True,
|
2016-06-03 02:21:08 -05:00
|
|
|
)
|
2012-03-13 06:10:52 -05:00
|
|
|
finally:
|
2015-12-16 09:27:34 -06:00
|
|
|
self.run_command('dnszone_del', idnsname=TEST_ZONE)
|
2012-03-13 06:10:52 -05:00
|
|
|
|
|
|
|
def test_dnsrecord_del_one_by_one(self):
|
|
|
|
try:
|
2015-12-16 09:27:34 -06:00
|
|
|
self.run_command('dnszone_add', idnsname=TEST_ZONE)
|
2012-03-13 06:10:52 -05:00
|
|
|
except errors.NotFound:
|
2017-12-06 10:01:57 -06:00
|
|
|
raise unittest.SkipTest('DNS is not configured')
|
2012-03-13 06:10:52 -05:00
|
|
|
try:
|
|
|
|
records = (u'1 1 E3B72BA346B90570EED94BE9334E34AA795CED23',
|
|
|
|
u'2 1 FD2693C1EFFC11A8D2BE57229212A04B45663791')
|
|
|
|
for record in records:
|
|
|
|
self.run_command('dnsrecord_add',
|
2015-12-16 09:27:34 -06:00
|
|
|
dnszoneidnsname=TEST_ZONE, idnsname=u'ns',
|
2012-03-13 06:10:52 -05:00
|
|
|
sshfprecord=record)
|
|
|
|
with self.fake_stdin('no\nyes\nyes\n'):
|
2016-06-03 02:21:08 -05:00
|
|
|
self.check_command(
|
|
|
|
'dnsrecord_del %s ns' % TEST_ZONE,
|
2012-03-13 06:10:52 -05:00
|
|
|
'dnsrecord_del',
|
2015-12-16 09:27:34 -06:00
|
|
|
dnszoneidnsname=TEST_ZONE,
|
2012-03-13 06:10:52 -05:00
|
|
|
idnsname=u'ns',
|
|
|
|
sshfprecord=records,
|
2016-06-03 02:21:08 -05:00
|
|
|
)
|
2012-03-13 06:10:52 -05:00
|
|
|
finally:
|
2015-12-16 09:27:34 -06:00
|
|
|
self.run_command('dnszone_del', idnsname=TEST_ZONE)
|
2012-04-16 04:00:00 -05:00
|
|
|
|
|
|
|
def test_dnsrecord_add_ask_for_missing_fields(self):
|
|
|
|
sshfp_parts = (1, 1, u'E3B72BA346B90570EED94BE9334E34AA795CED23')
|
|
|
|
|
|
|
|
with self.fake_stdin('SSHFP\n%d\n%d\n%s' % sshfp_parts):
|
2016-06-03 02:21:08 -05:00
|
|
|
self.check_command(
|
|
|
|
'dnsrecord-add %s sshfp' % TEST_ZONE,
|
2012-04-16 04:00:00 -05:00
|
|
|
'dnsrecord_add',
|
2015-12-16 09:27:34 -06:00
|
|
|
dnszoneidnsname=TEST_ZONE,
|
2012-04-16 04:00:00 -05:00
|
|
|
idnsname=u'sshfp',
|
|
|
|
sshfp_part_fp_type=sshfp_parts[0],
|
|
|
|
sshfp_part_algorithm=sshfp_parts[1],
|
|
|
|
sshfp_part_fingerprint=sshfp_parts[2],
|
2016-06-03 02:21:08 -05:00
|
|
|
)
|
2012-04-16 04:00:00 -05:00
|
|
|
|
2016-09-05 11:46:07 -05:00
|
|
|
# test with lowercase record type
|
|
|
|
with self.fake_stdin('sshfp\n%d\n%d\n%s' % sshfp_parts):
|
|
|
|
self.check_command(
|
|
|
|
'dnsrecord-add %s sshfp' % TEST_ZONE,
|
|
|
|
'dnsrecord_add',
|
|
|
|
dnszoneidnsname=TEST_ZONE,
|
|
|
|
idnsname=u'sshfp',
|
|
|
|
sshfp_part_fp_type=sshfp_parts[0],
|
|
|
|
sshfp_part_algorithm=sshfp_parts[1],
|
|
|
|
sshfp_part_fingerprint=sshfp_parts[2],
|
|
|
|
)
|
|
|
|
|
2012-04-16 04:00:00 -05:00
|
|
|
# NOTE: when a DNS record part is passed via command line, it is not
|
|
|
|
# converted to its base type when transfered via wire
|
|
|
|
with self.fake_stdin('%d\n%s' % (sshfp_parts[1], sshfp_parts[2])):
|
2016-06-03 02:21:08 -05:00
|
|
|
self.check_command(
|
|
|
|
'dnsrecord-add %s sshfp --sshfp-algorithm=%d' % (
|
|
|
|
TEST_ZONE, sshfp_parts[0]),
|
2012-04-16 04:00:00 -05:00
|
|
|
'dnsrecord_add',
|
2015-12-16 09:27:34 -06:00
|
|
|
dnszoneidnsname=TEST_ZONE,
|
2012-04-16 04:00:00 -05:00
|
|
|
idnsname=u'sshfp',
|
|
|
|
sshfp_part_fp_type=sshfp_parts[0],
|
2016-06-03 02:21:08 -05:00
|
|
|
# passed via cmdline
|
|
|
|
sshfp_part_algorithm=unicode(sshfp_parts[1]),
|
2012-04-16 04:00:00 -05:00
|
|
|
sshfp_part_fingerprint=sshfp_parts[2],
|
2016-06-03 02:21:08 -05:00
|
|
|
)
|
2012-04-16 04:00:00 -05:00
|
|
|
|
|
|
|
with self.fake_stdin(sshfp_parts[2]):
|
2016-06-03 02:21:08 -05:00
|
|
|
self.check_command(
|
|
|
|
'dnsrecord-add %s sshfp --sshfp-algorithm=%d '
|
|
|
|
'--sshfp-fp-type=%d' % (
|
|
|
|
TEST_ZONE, sshfp_parts[0], sshfp_parts[1]),
|
2012-04-16 04:00:00 -05:00
|
|
|
'dnsrecord_add',
|
2015-12-16 09:27:34 -06:00
|
|
|
dnszoneidnsname=TEST_ZONE,
|
2012-04-16 04:00:00 -05:00
|
|
|
idnsname=u'sshfp',
|
2016-06-03 02:21:08 -05:00
|
|
|
# passed via cmdline
|
|
|
|
sshfp_part_fp_type=unicode(sshfp_parts[0]),
|
|
|
|
# passed via cmdline
|
|
|
|
sshfp_part_algorithm=unicode(sshfp_parts[1]),
|
2012-04-16 04:00:00 -05:00
|
|
|
sshfp_part_fingerprint=sshfp_parts[2],
|
2016-06-03 02:21:08 -05:00
|
|
|
)
|
2013-01-09 11:09:10 -06:00
|
|
|
|
|
|
|
def test_dnsrecord_del_comma(self):
|
|
|
|
try:
|
|
|
|
self.run_command(
|
2015-12-16 09:27:34 -06:00
|
|
|
'dnszone_add', idnsname=TEST_ZONE)
|
2013-01-09 11:09:10 -06:00
|
|
|
except errors.NotFound:
|
2017-12-06 10:01:57 -06:00
|
|
|
raise unittest.SkipTest('DNS is not configured')
|
2013-01-09 11:09:10 -06:00
|
|
|
try:
|
|
|
|
self.run_command(
|
|
|
|
'dnsrecord_add',
|
2015-12-16 09:27:34 -06:00
|
|
|
dnszoneidnsname=TEST_ZONE,
|
2013-01-09 11:09:10 -06:00
|
|
|
idnsname=u'test',
|
|
|
|
txtrecord=u'"A pretty little problem," said Holmes.')
|
|
|
|
with self.fake_stdin('no\nyes\n'):
|
|
|
|
self.check_command(
|
2015-12-16 09:27:34 -06:00
|
|
|
'dnsrecord_del %s test' % TEST_ZONE,
|
2013-01-09 11:09:10 -06:00
|
|
|
'dnsrecord_del',
|
2015-12-16 09:27:34 -06:00
|
|
|
dnszoneidnsname=TEST_ZONE,
|
2013-01-09 11:09:10 -06:00
|
|
|
idnsname=u'test',
|
2016-06-03 02:21:08 -05:00
|
|
|
txtrecord=[u'"A pretty little problem," said Holmes.'])
|
2013-01-09 11:09:10 -06:00
|
|
|
finally:
|
2015-12-16 09:27:34 -06:00
|
|
|
self.run_command('dnszone_del', idnsname=TEST_ZONE)
|
2013-05-09 11:47:12 -05:00
|
|
|
|
2013-06-10 17:57:08 -05:00
|
|
|
def test_idrange_add(self):
|
|
|
|
"""
|
|
|
|
Test idrange-add with interative prompt
|
|
|
|
"""
|
|
|
|
def test_with_interactive_input():
|
|
|
|
with self.fake_stdin('5\n500000\n'):
|
|
|
|
self.check_command(
|
|
|
|
'idrange_add range1 --base-id=1 --range-size=1',
|
|
|
|
'idrange_add',
|
|
|
|
cn=u'range1',
|
|
|
|
ipabaseid=u'1',
|
|
|
|
ipaidrangesize=u'1',
|
|
|
|
ipabaserid=5,
|
|
|
|
ipasecondarybaserid=500000,
|
|
|
|
)
|
|
|
|
|
|
|
|
def test_with_command_line_options():
|
|
|
|
self.check_command(
|
|
|
|
'idrange_add range1 --base-id=1 --range-size=1 '
|
|
|
|
'--rid-base=5 --secondary-rid-base=500000',
|
|
|
|
'idrange_add',
|
|
|
|
cn=u'range1',
|
|
|
|
ipabaseid=u'1',
|
|
|
|
ipaidrangesize=u'1',
|
|
|
|
ipabaserid=u'5',
|
|
|
|
ipasecondarybaserid=u'500000',
|
|
|
|
)
|
|
|
|
|
|
|
|
def test_without_options():
|
|
|
|
self.check_command(
|
|
|
|
'idrange_add range1 --base-id=1 --range-size=1',
|
|
|
|
'idrange_add',
|
|
|
|
cn=u'range1',
|
|
|
|
ipabaseid=u'1',
|
|
|
|
ipaidrangesize=u'1',
|
|
|
|
)
|
|
|
|
|
|
|
|
adtrust_dn = 'cn=ADTRUST,cn=%s,cn=masters,cn=ipa,cn=etc,%s' % \
|
|
|
|
(api.env.host, api.env.basedn)
|
|
|
|
adtrust_is_enabled = api.Command['adtrust_is_enabled']()['result']
|
|
|
|
mockldap = None
|
|
|
|
|
|
|
|
if not adtrust_is_enabled:
|
|
|
|
# ipa-adtrust-install not run - no need to pass rid-base
|
|
|
|
# and secondary-rid-base
|
|
|
|
test_without_options()
|
|
|
|
|
|
|
|
# Create a mock service object to test against
|
|
|
|
adtrust_add = dict(
|
2015-09-17 11:46:14 -05:00
|
|
|
ipaconfigstring=b'enabledService',
|
|
|
|
objectclass=[b'top', b'nsContainer', b'ipaConfigObject']
|
2013-06-10 17:57:08 -05:00
|
|
|
)
|
|
|
|
|
|
|
|
mockldap = util.MockLDAP()
|
|
|
|
mockldap.add_entry(adtrust_dn, adtrust_add)
|
|
|
|
|
|
|
|
# Pass rid-base and secondary-rid-base interactively
|
|
|
|
test_with_interactive_input()
|
|
|
|
|
|
|
|
# Pass rid-base and secondary-rid-base on the command-line
|
|
|
|
test_with_command_line_options()
|
|
|
|
|
|
|
|
if not adtrust_is_enabled:
|
|
|
|
mockldap.del_entry(adtrust_dn)
|
2017-11-17 04:42:33 -06:00
|
|
|
|
|
|
|
|
|
|
|
def test_cli_fsencoding():
|
|
|
|
# https://pagure.io/freeipa/issue/5887
|
|
|
|
env = {
|
|
|
|
key: value for key, value in os.environ.items()
|
|
|
|
if not key.startswith(('LC_', 'LANG'))
|
|
|
|
}
|
|
|
|
env['LC_ALL'] = 'C'
|
|
|
|
env['PYTHONPATH'] = BASE_DIR
|
|
|
|
p = subprocess.Popen(
|
|
|
|
[sys.executable, '-m', 'ipaclient', 'help'],
|
|
|
|
stdout=subprocess.PIPE,
|
|
|
|
stderr=subprocess.PIPE,
|
|
|
|
env=env,
|
|
|
|
)
|
|
|
|
out, err = p.communicate()
|
|
|
|
assert p.returncode > 0, (out, err)
|
|
|
|
assert b'System encoding must be UTF-8' in err, (out, err)
|