From d38a5eac574b1e8f0e80154d77f200da10c54d8b Mon Sep 17 00:00:00 2001
From: Christian Heimes <cheimes@redhat.com>
Date: Mon, 11 Jun 2018 08:49:38 +0200
Subject: [PATCH] Remove Python 2 support and packages

Remove Python 2 related code and configuration from spec file, autoconf
and CI infrastructure.

Fixes: https://pagure.io/freeipa/issue/7568
Signed-off-by: Christian Heimes <cheimes@redhat.com>
---
 .test_runner_config.yaml          |   5 +-
 .test_runner_config_py3_temp.yaml |  72 -------
 .travis.yml                       |  19 +-
 .travis_run_task.sh               |   6 -
 Makefile.am                       |  27 +--
 configure.ac                      |  26 +--
 freeipa.spec.in                   | 422 +-------------------------------------
 ipalib/__init__.py                |   2 +-
 ipapython/setup.py                |   1 -
 ipasetup.py.in                    |   5 +-
 makeaci                           |   2 +-
 makeapi                           |   2 +-
 tox.ini                           |  11 +-
 13 files changed, 21 insertions(+), 579 deletions(-)
 delete mode 100644 .test_runner_config_py3_temp.yaml

diff --git a/.test_runner_config.yaml b/.test_runner_config.yaml
index 125c1ea7f7..cfd259384b 100644
--- a/.test_runner_config.yaml
+++ b/.test_runner_config.yaml
@@ -54,8 +54,7 @@ steps:
   - sed -ri "s/mode = production/mode = development/" /etc/ipa/default.conf
   - systemctl restart httpd.service
   lint:
-  - make PYTHON=/usr/bin/python2 V=0 lint
-  - make PYTHON=/usr/bin/python3 V=0 pylint
+  - make V=0 pylint
   webui_unit:
   - dnf install -y npm
   - cd ${container_working_dir}/install/ui/js/libs && make
@@ -63,7 +62,7 @@ steps:
   - cd ${container_working_dir}/install/ui && node_modules/grunt/bin/grunt --verbose test
   tox:
   # just run one pylint and one Python 3 target (time/coverage trade-off)
-  - tox -e py27,py36,pypi,pylint3
+  - tox -e py36,pypi,pylint3
   prepare_tests:
   - echo ${server_password} | kinit admin && ipa ping
   - cp -r /etc/ipa/* ~/.ipa/
diff --git a/.test_runner_config_py3_temp.yaml b/.test_runner_config_py3_temp.yaml
deleted file mode 100644
index bdc1d0e335..0000000000
--- a/.test_runner_config_py3_temp.yaml
+++ /dev/null
@@ -1,72 +0,0 @@
-#
-# Copyright (C) 2017 FreeIPA Contributors see COPYING for license
-#
-
-# Configuration file for the test runner used in Travis CI
-# This config file is temporal and will be used only for migration period
-# from py2 to fully supported py3
-
-container:
-  detach: true
-  hostname: master.ipa.test
-  working_dir: /freeipa
-host:
-  binds:
-  - /sys/fs/cgroup:/sys/fs/cgroup:ro
-  - /dev/urandom:/dev/random:ro
-  privileged: true
-  security_opt:
-  - label:disable
-  tmpfs:
-  - /tmp
-  - /run
-server:
-  domain: ipa.test
-  password: Secret123
-  realm: IPA.TEST
-steps:
-  build:
-  - make V=0 ${make_target} LOG_COMPILE='gdb -return-child-result -ex run -ex "thread apply all bt" -ex "quit" --args'
-  builddep:
-  - rm -rf /var/cache/dnf/*
-  - "dnf makecache || :"
-  - dnf builddep -y ${builddep_opts} --spec freeipa.spec.in --best --allowerasing
-  - dnf install -y gdb
-  cleanup:
-  - chown -R ${uid}:${gid} ${container_working_dir}
-  - >
-      tar --ignore-failed-read -cvf ${container_working_dir}/var_log.tar
-      /var/log/dirsrv
-      /var/log/httpd
-      /var/log/ipa*
-      /var/log/krb5kdc.log
-      /var/log/pki
-      systemd_journal.log
-      `find daemons -name '*.log' -print`
-  - chown ${uid}:${gid} ${container_working_dir}/var_log.tar
-  configure:
-  - ./autogen.sh
-  install_packages:
-  - dnf install -y ${container_working_dir}/dist/rpms/*.rpm --best --allowerasing
-  - dnf install -y python3-mod_wsgi --best --allowerasing  # Py3 temporary
-  install_server:
-  - ipa-server-install -U --domain ${server_domain} --realm ${server_realm} -p ${server_password}
-    -a ${server_password} --setup-dns --auto-forwarders
-  - ipa-kra-install -p ${server_password}
-  lint:
-  - make PYTHON=/usr/bin/python2 V=0 lint
-  - make PYTHON=/usr/bin/python3 V=0 pylint
-  prepare_tests:
-  - echo ${server_password} | kinit admin && ipa ping
-  - cp -r /etc/ipa/* ~/.ipa/
-  - echo ${server_password} > ~/.ipa/.dmpw
-  - echo 'wait_for_dns=5' >> ~/.ipa/default.conf
-  run_tests:
-  - ipa-run-tests-3 ${tests_ignore} -k-test_dns_soa ${tests_verbose} ${path}
-  - '! grep -n -C5 BytesWarning /var/log/httpd/error_log'
-tests:
-  verbose: true
-  ignore:
-  - test_integration
-  - test_webui
-  - test_ipapython/test_keyring.py
diff --git a/.travis.yml b/.travis.yml
index f81af742b9..126fced23a 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -24,28 +24,13 @@ env:
           TEST_RUNNER_CONFIG=".test_runner_config.yaml"
         - TASK_TO_RUN="webui-unit"
           TEST_RUNNER_CONFIG=".test_runner_config.yaml"
-        - TASK_TO_RUN="run-tests"
-          PYTHON=/usr/bin/python2
-          TEST_RUNNER_CONFIG=".test_runner_config.yaml"
-          TESTS_TO_RUN="test_xmlrpc/test_[a-k]*.py"
-        - TASK_TO_RUN="run-tests"
-          PYTHON=/usr/bin/python2
-          TEST_RUNNER_CONFIG=".test_runner_config.yaml"
-          TESTS_TO_RUN="test_cmdline
-            test_install
-            test_ipaclient
-            test_ipalib
-            test_ipaplatform
-            test_ipapython
-            test_ipaserver
-            test_xmlrpc/test_[l-z]*.py"
         - TASK_TO_RUN="run-tests"
           PYTHON=/usr/bin/python3
-          TEST_RUNNER_CONFIG=".test_runner_config_py3_temp.yaml"
+          TEST_RUNNER_CONFIG=".test_runner_config.yaml"
           TESTS_TO_RUN="test_xmlrpc/test_[a-k]*.py"
         - TASK_TO_RUN="run-tests"
           PYTHON=/usr/bin/python3
-          TEST_RUNNER_CONFIG=".test_runner_config_py3_temp.yaml"
+          TEST_RUNNER_CONFIG=".test_runner_config.yaml"
           TESTS_TO_RUN="test_cmdline
                 test_install
                 test_ipaclient
diff --git a/.travis_run_task.sh b/.travis_run_task.sh
index 61d655088a..85a79f2d36 100755
--- a/.travis_run_task.sh
+++ b/.travis_run_task.sh
@@ -6,12 +6,7 @@
 
 test_set=""
 
-if [[ $PYTHON == "/usr/bin/python2" ]]
-then
-env_opt="--define 'with_python3 0'"
-else
 env_opt=""
-fi
 
 case "$TASK_TO_RUN" in
     lint|tox)
@@ -55,7 +50,6 @@ docker pull $TEST_RUNNER_IMAGE
 ipa-docker-test-runner -l $CI_RESULTS_LOG \
     -c $TEST_RUNNER_CONFIG \
     $developer_mode_opt \
-    --container-environment "PYTHON=$PYTHON" \
     --container-environment "RPMBUILD_OPTS=$env_opt" \
     --container-image $TEST_RUNNER_IMAGE \
     --git-repo $TRAVIS_BUILD_DIR \
diff --git a/Makefile.am b/Makefile.am
index ba4abf7c55..8dbc8ad6c2 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -166,39 +166,20 @@ endif
 if ! WITH_JSLINT
 	@echo "ERROR: jslint not available"; exit 1
 endif
-if ! WITH_PYTHON2
-	@echo "ERROR: python2 not available"; exit 1
-endif
-	@ # run all linters, tests, and check with Python 2
-	PYTHONPATH=$(abspath $(top_srcdir)) $(PYTHON2) ipatests/ipa-run-tests \
-	    --ipaclient-unittests
-	$(MAKE) $(AM_MAKEFLAGS) acilint apilint polint jslint check
-	$(MAKE) $(AM_MAKEFLAGS) PYTHON=$(PYTHON2) pylint
-if WITH_PYTHON3
 	@ # just tests, aci, api and pylint on Python 3
-	PYTHONPATH=$(abspath $(top_srcdir)) $(PYTHON3) ipatests/ipa-run-tests \
+	PYTHONPATH=$(abspath $(top_srcdir)) $(PYTHON) ipatests/ipa-run-tests \
 	    --ipaclient-unittests
-	$(MAKE) $(AM_MAKEFLAGS) PYTHON=$(PYTHON3) acilint apilint polint pylint
-else
-	@echo "WARNING: python3 not available"
-endif
+	$(MAKE) $(AM_MAKEFLAGS) acilint apilint polint pylint
 	@echo "All tests passed."
 
 .PHONY: fastcheck fasttest fastlint
 fastcheck:
-if WITH_PYTHON2
-	@$(MAKE) -j1 $(AM_MAKEFLAGS) PYTHON=$(PYTHON2) \
-	    fastlint fasttest apilint acilint
-endif
-if WITH_PYTHON3
-	@$(MAKE) -j1 $(AM_MAKEFLAGS) PYTHON=$(PYTHON3) \
-	     fastlint fasttest apilint acilint
-endif
+	@$(MAKE) -j1 $(AM_MAKEFLAGS) fastlint fasttest apilint acilint
 
 fasttest: $(GENERATED_PYTHON_FILES) ipasetup.py
 	@ # --ignore doubles speed of total test run compared to pytest.skip()
 	@ # on module.
-	PYTHONPATH=$(abspath $(top_srcdir)) $(PYTHON3) ipatests/ipa-run-tests \
+	PYTHONPATH=$(abspath $(top_srcdir)) $(PYTHON) ipatests/ipa-run-tests \
 	    --skip-ipaapi \
 	    --ignore $(abspath $(top_srcdir))/ipatests/test_integration \
 	    --ignore $(abspath $(top_srcdir))/ipatests/test_xmlrpc
diff --git a/configure.ac b/configure.ac
index b8f635f8ca..c8093c1ea5 100644
--- a/configure.ac
+++ b/configure.ac
@@ -99,29 +99,11 @@ dnl ---------------------------------------------------------------------------
 PKG_CHECK_MODULES([CRYPTO], [libcrypto])
 
 dnl ---------------------------------------------------------------------------
-dnl - Check for Python
-dnl - Check for Python 2/3 for devcheck
+dnl - Check for Python 3
 dnl ---------------------------------------------------------------------------
 
 AC_MSG_NOTICE([Checking for Python 3])
-AC_PATH_PROG(PYTHON3, python3)
-AC_SUBST([PYTHON3])
-AM_CONDITIONAL([WITH_PYTHON3], [test "x${PYTHON3}" != "x"])
-
-AC_MSG_NOTICE([Checking for Python 2])
-AC_PATH_PROG(PYTHON2, python2)
-AC_SUBST([PYTHON2])
-AM_CONDITIONAL([WITH_PYTHON2], [test "x${PYTHON2}" != "x"])
-
-if test \( "x${PYTHON3}" = "x" -o "x${PYTHON}" != "x" \); then
-    dnl Python 3 is not available *or* user has set PYTHON variable.
-    dnl Accept Python >= 2.7 as default Python. We also accept any Python 3
-    dnl version from PYTHON environment variable.
-    AM_PATH_PYTHON(2.7)
-elif test "x${PYTHON3}" != "x"; then
-    dnl Found Python 3, but no user override. Use Python >= 3.6 as default.
-    AM_PATH_PYTHON(3.6)
-fi
+AM_PATH_PYTHON(3.6)
 
 dnl ---------------------------------------------------------------------------
 dnl - Check for cmocka unit test framework http://cmocka.cryptomilk.org/
@@ -592,9 +574,7 @@ echo "
         source code location:     ${srcdir}
         compiler:                 ${CC}
         cflags:                   ${CFLAGS}
-        Default Python:           ${PYTHON} (${PYTHON_VERSION})
-        Python 2:                 ${PYTHON2}
-        Python 3:                 ${PYTHON3}
+        Python:                   ${PYTHON} (${PYTHON_VERSION})
         pylint:                   ${PYLINT}
         jslint:                   ${JSLINT}
         LDAP libs:                ${LDAP_LIBS}
diff --git a/freeipa.spec.in b/freeipa.spec.in
index 375a686976..709617486b 100755
--- a/freeipa.spec.in
+++ b/freeipa.spec.in
@@ -23,22 +23,6 @@
     %global with_ipatests_option --without-ipatests
 %endif
 
-# Python 2/3 packages and default Python interpreter
-%if 0%{?rhel} > 7
-%global with_default_python 3
-%global with_python2 0
-%else
-%{!?with_default_python:%global with_default_python 3}
-%{!?with_python2:%global with_python2 1}
-%endif
-
-%if %{with_default_python} == 3
-%global python %{__python3}
-%else
-%global with_python2 1
-%global python %{__python2}
-%endif
-
 # lint is not executed during rpmbuild
 # %%global with_lint 1
 %if 0%{?with_lint}
@@ -132,10 +116,6 @@ BuildRequires:  automake
 BuildRequires:  libtool
 BuildRequires:  gettext
 BuildRequires:  gettext-devel
-%if 0%{?with_python2}
-BuildRequires:  python2-devel
-BuildRequires:  python2-setuptools
-%endif # with_python2
 BuildRequires:  python3-devel
 BuildRequires:  python3-setuptools
 BuildRequires:  systemd
@@ -166,7 +146,6 @@ BuildRequires:  python2-lesscpy
 #
 # Build dependencies for makeapi/makeaci
 #
-%if %{with_default_python} == 3
 BuildRequires:  python3-cffi
 BuildRequires:  python3-dns
 BuildRequires:  python3-ldap >= %{python_ldap_version}
@@ -175,16 +154,6 @@ BuildRequires:  python3-netaddr >= %{python_netaddr_version}
 BuildRequires:  python3-pyasn1
 BuildRequires:  python3-pyasn1-modules
 BuildRequires:  python3-six
-%else
-BuildRequires:  python2-cffi
-BuildRequires:  python2-dns
-BuildRequires:  python2-ldap >= %{python_ldap_version}
-BuildRequires:  python2-libsss_nss_idmap
-BuildRequires:  python2-netaddr >= %{python_netaddr_version}
-BuildRequires:  python2-pyasn1
-BuildRequires:  python2-pyasn1-modules
-BuildRequires:  python2-six
-%endif
 
 #
 # Build dependencies for wheel packaging and PyPI upload
@@ -192,11 +161,6 @@ BuildRequires:  python2-six
 %if 0%{?with_wheels}
 BuildRequires:  dbus-glib-devel
 BuildRequires:  libffi-devel
-%if 0%{?with_python2}
-BuildRequires:  python2-tox
-BuildRequires:  python2-twine
-BuildRequires:  python2-wheel
-%endif
 BuildRequires:  python3-tox
 BuildRequires:  python3-twine
 BuildRequires:  python3-wheel
@@ -208,45 +172,6 @@ BuildRequires:  python3-wheel
 %if 0%{?with_lint}
 BuildRequires:  jsl
 BuildRequires:  softhsm
-
-%if 0%{?with_python2}
-BuildRequires:  python2-augeas
-BuildRequires:  python2-cffi
-BuildRequires:  python2-cryptography >= 1.6
-BuildRequires:  python2-custodia >= 0.3.1
-BuildRequires:  python2-dateutil
-BuildRequires:  python2-dbus
-BuildRequires:  python2-dns
-BuildRequires:  python2-dns >= 1.15
-BuildRequires:  python2-enum34
-BuildRequires:  python2-gssapi >= 1.2.0-5
-BuildRequires:  python2-jinja2
-BuildRequires:  python2-jwcrypto >= 0.4.2
-BuildRequires:  python2-ldap >= %{python_ldap_version}
-BuildRequires:  python2-libipa_hbac
-BuildRequires:  python2-libsss_nss_idmap
-BuildRequires:  python2-lxml
-BuildRequires:  python2-netaddr >= %{python_netaddr_version}
-BuildRequires:  python2-netifaces
-BuildRequires:  python2-paste
-BuildRequires:  python2-pki >= %{pki_version}
-BuildRequires:  python2-polib
-BuildRequires:  python2-pyasn1
-BuildRequires:  python2-pyasn1-modules
-BuildRequires:  python2-pycodestyle
-BuildRequires:  python2-pylint
-BuildRequires:  python2-pytest-multihost
-BuildRequires:  python2-pytest-sourceorder
-BuildRequires:  python2-qrcode-core >= 5.0.0
-BuildRequires:  python2-samba
-BuildRequires:  python2-six
-BuildRequires:  python2-sss
-BuildRequires:  python2-sss-murmur
-BuildRequires:  python2-sssdconfig
-BuildRequires:  python2-systemd
-BuildRequires:  python2-yubico
-%endif # with_python2
-
 BuildRequires:  python3-augeas
 BuildRequires:  python3-cffi
 BuildRequires:  python3-cryptography >= 1.6
@@ -308,13 +233,8 @@ Group: System Environment/Base
 Requires: %{name}-server-common = %{version}-%{release}
 Requires: %{name}-client = %{version}-%{release}
 Requires: %{name}-common = %{version}-%{release}
-%if %{with_default_python} == 3
 Requires: python3-ipaserver = %{version}-%{release}
 Requires: python3-ldap >= %{python_ldap_version}
-%else
-Requires: python2-ipaserver = %{version}-%{release}
-Requires: python2-ldap >= %{python_ldap_version}
-%endif
 Requires: 389-ds-base >= %{ds_version}
 Requires: openldap-clients > 2.4.35-4
 Requires: nss >= %{nss_version}
@@ -325,19 +245,11 @@ Requires: krb5-pkinit-openssl >= %{krb5_version}
 Requires: cyrus-sasl-gssapi%{?_isa}
 Requires: chrony
 Requires: httpd >= 2.4.6-31
-%if %{with_default_python} == 3
 Requires(preun): python3
 Requires(postun): python3
 Requires: python3-gssapi >= 1.2.0-5
 Requires: python3-systemd
 Requires: python3-mod_wsgi
-%else
-Requires(preun): python2
-Requires(postun): python2
-Requires: python2-gssapi >= 1.2.0-5
-Requires: python2-systemd
-Requires: mod_wsgi
-%endif
 Requires: mod_auth_gssapi >= 1.5.0
 Requires: mod_ssl
 Requires: mod_session
@@ -399,40 +311,6 @@ and integration with Active Directory based infrastructures (Trusts).
 If you are installing an IPA server, you need to install this package.
 
 
-%if 0%{?with_python2}
-
-%package -n python2-ipaserver
-Summary: Python libraries used by IPA server
-Group: System Environment/Libraries
-BuildArch: noarch
-%{?python_provide:%python_provide python2-ipaserver}
-%{!?python_provide:Provides: python-ipaserver = %{version}-%{release}}
-Requires: %{name}-server-common = %{version}-%{release}
-Requires: %{name}-common = %{version}-%{release}
-Requires: python2-augeas
-Requires: python2-custodia >= 0.3.1
-Requires: python2-dbus
-Requires: python2-dns >= 1.15
-Requires: python2-gssapi >= 1.2.0-5
-Requires: python2-ipaclient = %{version}-%{release}
-Requires: python2-kdcproxy >= 0.3
-Requires: python2-ldap >= %{python_ldap_version}
-Requires: python2-lxml
-Requires: python2-pki >= %{pki_version}
-Requires: python2-pyasn1 >= 0.3.2-2
-Requires: python2-sssdconfig
-Requires: rpm-libs
-
-%description -n python2-ipaserver
-IPA is an integrated solution to provide centrally managed Identity (users,
-hosts, services), Authentication (SSO, 2FA), and Authorization
-(host access control, SELinux user roles, services). The solution provides
-features for further integration with Linux based clients (SUDO, automount)
-and integration with Active Directory based infrastructures (Trusts).
-If you are installing an IPA server, you need to install this package.
-
-%endif  # with_python2
-
 %package -n python3-ipaserver
 Summary: Python libraries used by IPA server
 Group: System Environment/Libraries
@@ -521,17 +399,10 @@ Requires: samba >= %{samba_version}
 Requires: samba-winbind
 Requires: libsss_idmap
 
-%if %{with_default_python} == 3
 Requires(post): python3
 Requires: python3-samba
 Requires: python3-libsss_nss_idmap
 Requires: python3-sss
-%else
-Requires(post): python2
-Requires: python2-samba
-Requires: python2-libsss_nss_idmap
-Requires: python2-sss
-%endif  # with_default_python
 
 # We use alternatives to divert winbind_krb5_locator.so plugin to libkrb5
 # on the installes where server-trust-ad subpackage is installed because
@@ -558,17 +429,10 @@ Summary: IPA authentication for use on clients
 Group: System Environment/Base
 Requires: %{name}-client-common = %{version}-%{release}
 Requires: %{name}-common = %{version}-%{release}
-%if %{with_default_python} == 3
 Requires: python3-gssapi >= 1.2.0-5
 Requires: python3-ipaclient = %{version}-%{release}
 Requires: python3-ldap >= %{python_ldap_version}
 Requires: python3-sssdconfig
-%else
-Requires: python2-gssapi >= 1.2.0-5
-Requires: python2-ipaclient = %{version}-%{release}
-Requires: python2-ldap >= %{python_ldap_version}
-Requires: python2-sssdconfig
-%endif
 Requires: cyrus-sasl-gssapi%{?_isa}
 Requires: chrony
 Requires: krb5-workstation >= %{krb5_version}
@@ -611,31 +475,6 @@ If your network uses IPA for authentication, this package should be
 installed on every client machine.
 This package provides command-line tools for IPA administrators.
 
-%if 0%{?with_python2}
-
-%package -n python2-ipaclient
-Summary: Python libraries used by IPA client
-Group: System Environment/Libraries
-BuildArch: noarch
-%{?python_provide:%python_provide python2-ipaclient}
-%{!?python_provide:Provides: python-ipaclient = %{version}-%{release}}
-Requires: %{name}-client-common = %{version}-%{release}
-Requires: %{name}-common = %{version}-%{release}
-Requires: python2-ipalib = %{version}-%{release}
-Requires: python2-augeas
-Requires: python2-dns >= 1.15
-Requires: python2-jinja2
-
-%description -n python2-ipaclient
-IPA is an integrated solution to provide centrally managed Identity (users,
-hosts, services), Authentication (SSO, 2FA), and Authorization
-(host access control, SELinux user roles, services). The solution provides
-features for further integration with Linux based clients (SUDO, automount)
-and integration with Active Directory based infrastructures (Trusts).
-If your network uses IPA for authentication, this package should be
-installed on every client machine.
-
-%endif  # with_python2
 
 %package -n python3-ipaclient
 Summary: Python libraries used by IPA client
@@ -685,11 +524,7 @@ BuildArch: noarch
 Obsoletes: %{name}-python < 4.2.91
 Provides: %{name}-python = %{version}-%{release}
 Requires: %{name}-common = %{version}-%{release}
-%if %{with_default_python} == 3
 Requires: python3-ipalib = %{version}-%{release}
-%else
-Requires: python2-ipalib = %{version}-%{release}
-%endif
 
 Provides: %{alt_name}-python-compat = %{version}
 Conflicts: %{alt_name}-python-compat
@@ -705,62 +540,10 @@ hosts, services), Authentication (SSO, 2FA), and Authorization
 features for further integration with Linux based clients (SUDO, automount)
 and integration with Active Directory based infrastructures (Trusts).
 This is a compatibility package to accommodate %{name}-python split into
-python2-ipalib and %{name}-common. Packages still depending on
+python3-ipalib and %{name}-common. Packages still depending on
 %{name}-python should be fixed to depend on python2-ipaclient or
 %{name}-common instead.
 
-%if 0%{?with_python2}
-
-%package -n python2-ipalib
-Summary: Python libraries used by IPA
-Group: System Environment/Libraries
-BuildArch: noarch
-Conflicts: %{name}-python < 4.2.91
-%{?python_provide:%python_provide python2-ipalib}
-%{!?python_provide:Provides: python-ipalib = %{version}-%{release}}
-Provides: python2-ipapython = %{version}-%{release}
-%{?python_provide:%python_provide python2-ipapython}
-%{!?python_provide:Provides: python-ipapython = %{version}-%{release}}
-Provides: python2-ipaplatform = %{version}-%{release}
-%{?python_provide:%python_provide python2-ipaplatform}
-%{!?python_provide:Provides: python-ipaplatform = %{version}-%{release}}
-Requires: %{name}-common = %{version}-%{release}
-Requires: gnupg2
-Requires: keyutils
-Requires: python2 >= 2.7.9
-Requires: python2-cffi
-Requires: python2-cryptography >= 1.6
-Requires: python2-dateutil
-Requires: python2-dbus
-Requires: python2-dns >= 1.15
-Requires: python2-enum34
-Requires: python2-gssapi >= 1.2.0-5
-Requires: python2-jwcrypto >= 0.4.2
-Requires: python2-ldap >= %{python_ldap_version}
-Requires: python2-libipa_hbac
-Requires: python2-netaddr >= %{python_netaddr_version}
-Requires: python2-netifaces >= 0.10.4
-Requires: python2-pyasn1 >= 0.3.2-2
-Requires: python2-pyasn1-modules >= 0.3.2-2
-Requires: python2-pyusb
-Requires: python2-qrcode-core >= 5.0.0
-Requires: python2-requests
-Requires: python2-setuptools
-Requires: python2-six
-Requires: python2-sss-murmur
-Requires: python2-yubico >= 1.2.3
-
-Conflicts: %{alt_name}-python < %{version}
-
-%description -n python2-ipalib
-IPA is an integrated solution to provide centrally managed Identity (users,
-hosts, services), Authentication (SSO, 2FA), and Authorization
-(host access control, SELinux user roles, services). The solution provides
-features for further integration with Linux based clients (SUDO, automount)
-and integration with Active Directory based infrastructures (Trusts).
-If you are using IPA, you need to install this package.
-
-%endif  # with_python2
 
 %package -n python3-ipalib
 Summary: Python3 libraries used by IPA
@@ -828,45 +611,6 @@ If you are using IPA, you need to install this package.
 
 %if 0%{?with_ipatests}
 
-%if 0%{?with_python2}
-
-%package -n python2-ipatests
-Summary: IPA tests and test tools
-BuildArch: noarch
-Obsoletes: %{name}-tests < 4.2.91
-Provides: %{name}-tests = %{version}-%{release}
-%{?python_provide:%python_provide python2-ipatests}
-%{!?python_provide:Provides: python-ipatests = %{version}-%{release}}
-Requires: python2-ipaclient = %{version}-%{release}
-Requires: python2-ipaserver = %{version}-%{release}
-Requires: iptables
-Requires: ldns-utils
-Requires: python2-coverage
-Requires: python2-cryptography >= 1.6
-Requires: python2-mock
-Requires: python2-paste
-Requires: python2-polib
-Requires: python2-pytest >= 2.6
-Requires: python2-pytest-multihost >= 0.5
-Requires: python2-pytest-sourceorder
-Requires: python2-sssdconfig
-Requires: tar
-Requires: xz
-
-Provides: %{alt_name}-tests = %{version}
-Conflicts: %{alt_name}-tests
-Obsoletes: %{alt_name}-tests < %{version}
-
-%description -n python2-ipatests
-IPA is an integrated solution to provide centrally managed Identity (users,
-hosts, services), Authentication (SSO, 2FA), and Authorization
-(host access control, SELinux user roles, services). The solution provides
-features for further integration with Linux based clients (SUDO, automount)
-and integration with Active Directory based infrastructures (Trusts).
-This package contains tests that verify IPA functionality.
-
-%endif  # with_python2
-
 %package -n python3-ipatests
 Summary: IPA tests and test tools
 BuildArch: noarch
@@ -898,24 +642,6 @@ This package contains tests that verify IPA functionality under Python 3.
 
 %prep
 %setup -n freeipa-%{version} -q
-# Workaround: We want to build Python things twice. To be sure we do not mess
-# up something, do two separate builds in separate directories.
-# freeipa-$VER-python3 for Python 3 build
-# freeipa-$VER-python2 for Python 2 build
-# freeipa-$VER is a symlink to default Python version
-
-%if %{with_default_python} == 3
-%if 0%{?with_python2}
-cp -r %{_builddir}/freeipa-%{version} %{_builddir}/freeipa-%{version}-python2
-%endif
-mv %{_builddir}/freeipa-%{version} %{_builddir}/freeipa-%{version}-python3
-ln -sr %{_builddir}/freeipa-%{version}-python3 %{_builddir}/freeipa-%{version}
-%else
-# Python 2 default
-cp -r %{_builddir}/freeipa-%{version} %{_builddir}/freeipa-%{version}-python3
-mv %{_builddir}/freeipa-%{version} %{_builddir}/freeipa-%{version}-python2
-ln -sr %{_builddir}/freeipa-%{version}-python2 %{_builddir}/freeipa-%{version}
-%endif
 
 %build
 # UI compilation segfaulted on some arches when the stack was lower (#1040576)
@@ -924,32 +650,11 @@ export JAVA_STACK_SIZE="8m"
 export PATH=/usr/bin:/usr/sbin:$PATH
 
 
-%if 0%{?with_python2}
-export PYTHON=%{__python2}
-pushd %{_builddir}/freeipa-%{version}-python2
-# Workaround: make sure all shebangs are pointing to Python 2
-# This should be solved properly using setuptools
-# and this hack should be removed.
-find \
-	! -name '*.pyc' -a \
-	! -name '*.pyo' -a \
-	-type f -exec grep -qsm1 '^#!.*\bpython' {} \; \
-	-exec sed -i -e '1 s|^#!.*\bpython[^ ]*|#!%{__python2}|' {} \;
-
-%configure --with-vendor-suffix=-%{release} \
-           %{enable_server_option} \
-           %{with_ipatests_option} \
-           %{linter_options}
-popd
-%endif # ! with_python2
-
 export PYTHON=%{__python3}
-pushd %{_builddir}/freeipa-%{version}-python3
 %configure --with-vendor-suffix=-%{release} \
            %{enable_server_option} \
            %{with_ipatests_option} \
            %{linter_options}
-popd
 
 # run build in default dir
 # -Onone is workaround for https://bugzilla.redhat.com/show_bug.cgi?id=1398405
@@ -969,14 +674,9 @@ make %{?_smp_mflags} check VERBOSE=yes LIBDIR=%{_libdir}
 # All files and directories created by spec install should be marked as ghost.
 # (These are typically configuration files created by IPA installer.)
 # All other artifacts should be created by make install.
-#
-# Exception to this rule are test programs which where want to install
-# Python2/3 versions at the same time so we need to rename them. Yuck.
 
-# Python 3 packages and commands
-pushd %{_builddir}/freeipa-%{version}-python3
-%{__make} python_install DESTDIR=%{?buildroot} INSTALL="%{__install} -p"
-popd
+%make_install
+
 %if 0%{?with_ipatests}
 mv %{buildroot}%{_bindir}/ipa-run-tests %{buildroot}%{_bindir}/ipa-run-tests-%{python3_version}
 mv %{buildroot}%{_bindir}/ipa-test-config %{buildroot}%{_bindir}/ipa-test-config-%{python3_version}
@@ -984,39 +684,9 @@ mv %{buildroot}%{_bindir}/ipa-test-task %{buildroot}%{_bindir}/ipa-test-task-%{p
 ln -rs %{buildroot}%{_bindir}/ipa-run-tests-%{python3_version} %{buildroot}%{_bindir}/ipa-run-tests-3
 ln -rs %{buildroot}%{_bindir}/ipa-test-config-%{python3_version} %{buildroot}%{_bindir}/ipa-test-config-3
 ln -rs %{buildroot}%{_bindir}/ipa-test-task-%{python3_version} %{buildroot}%{_bindir}/ipa-test-task-3
-%endif # with_ipatests
-
-# Python 2 packages and commands
-%if 0%{?with_python2}
-pushd %{_builddir}/freeipa-%{version}-python2
-%{__make} python_install DESTDIR=%{?buildroot} INSTALL="%{__install} -p"
-popd
-%if 0%{?with_ipatests}
-mv %{buildroot}%{_bindir}/ipa-run-tests %{buildroot}%{_bindir}/ipa-run-tests-%{python2_version}
-mv %{buildroot}%{_bindir}/ipa-test-config %{buildroot}%{_bindir}/ipa-test-config-%{python2_version}
-mv %{buildroot}%{_bindir}/ipa-test-task %{buildroot}%{_bindir}/ipa-test-task-%{python2_version}
-ln -rs %{buildroot}%{_bindir}/ipa-run-tests-%{python2_version} %{buildroot}%{_bindir}/ipa-run-tests-2
-ln -rs %{buildroot}%{_bindir}/ipa-test-config-%{python2_version} %{buildroot}%{_bindir}/ipa-test-config-2
-ln -rs %{buildroot}%{_bindir}/ipa-test-task-%{python2_version} %{buildroot}%{_bindir}/ipa-test-task-2
-%endif # with_ipatests
-%endif # with_python2
-
-# default installation
-# This installs all Python packages twice and overrides the ipa-test
-# commands. We'll fix the command links later with ln --force.
-%make_install
-
-# Decide which Python (2 or 3) should be used as default for tests
-%if 0%{?with_ipatests}
-%if %{with_default_python} == 3
 ln -frs %{buildroot}%{_bindir}/ipa-run-tests-%{python3_version} %{buildroot}%{_bindir}/ipa-run-tests
 ln -frs %{buildroot}%{_bindir}/ipa-test-config-%{python3_version} %{buildroot}%{_bindir}/ipa-test-config
 ln -frs %{buildroot}%{_bindir}/ipa-test-task-%{python3_version} %{buildroot}%{_bindir}/ipa-test-task
-%else
-ln -frs %{buildroot}%{_bindir}/ipa-run-tests-%{python2_version} %{buildroot}%{_bindir}/ipa-run-tests
-ln -frs %{buildroot}%{_bindir}/ipa-test-config-%{python2_version} %{buildroot}%{_bindir}/ipa-test-config
-ln -frs %{buildroot}%{_bindir}/ipa-test-task-%{python2_version} %{buildroot}%{_bindir}/ipa-test-task
-%endif # with_default_python
 %endif # with_ipatests
 
 # remove files which are useful only for make uninstall
@@ -1340,16 +1010,6 @@ fi
 %{_mandir}/man1/ipa-winsync-migrate.1*
 %{_mandir}/man1/ipa-pkinit-manage.1*
 
-%if 0%{?with_python2}
-
-%files -n python2-ipaserver
-%defattr(-,root,root,-)
-%doc README.md Contributors.txt
-%license COPYING
-%{python2_sitelib}/ipaserver
-%{python2_sitelib}/ipaserver-*.egg-info
-
-%endif # with_python2
 
 %files -n python3-ipaserver
 %defattr(-,root,root,-)
@@ -1497,33 +1157,6 @@ fi
 %{_mandir}/man1/ipa-certupdate.1*
 %{_mandir}/man1/ipa-join.1*
 
-%if 0%{?with_python2}
-
-%files -n python2-ipaclient
-%defattr(-,root,root,-)
-%doc README.md Contributors.txt
-%license COPYING
-%dir %{python_sitelib}/ipaclient
-%{python_sitelib}/ipaclient/*.py*
-%dir %{python_sitelib}/ipaclient/install
-%{python_sitelib}/ipaclient/install/*.py*
-%dir %{python_sitelib}/ipaclient/plugins
-%{python_sitelib}/ipaclient/plugins/*.py*
-%dir %{python_sitelib}/ipaclient/remote_plugins
-%{python_sitelib}/ipaclient/remote_plugins/*.py*
-%dir %{python_sitelib}/ipaclient/remote_plugins/2_*
-%{python_sitelib}/ipaclient/remote_plugins/2_*/*.py*
-%dir %{python_sitelib}/ipaclient/csrgen
-%dir %{python_sitelib}/ipaclient/csrgen/profiles
-%{python_sitelib}/ipaclient/csrgen/profiles/*.json
-%dir %{python_sitelib}/ipaclient/csrgen/rules
-%{python_sitelib}/ipaclient/csrgen/rules/*.json
-%dir %{python_sitelib}/ipaclient/csrgen/templates
-%{python_sitelib}/ipaclient/csrgen/templates/*.tmpl
-%{python_sitelib}/ipaclient-*.egg-info
-
-%endif # with_python2
-
 %files -n python3-ipaclient
 %defattr(-,root,root,-)
 %doc README.md Contributors.txt
@@ -1584,28 +1217,6 @@ fi
 %doc README.md Contributors.txt
 %license COPYING
 
-%if 0%{?with_python2}
-
-%files -n python2-ipalib
-%defattr(-,root,root,-)
-%doc README.md Contributors.txt
-%license COPYING
-%dir %{python_sitelib}/ipapython
-%{python_sitelib}/ipapython/*.py*
-%dir %{python_sitelib}/ipapython/install
-%{python_sitelib}/ipapython/install/*.py*
-%dir %{python_sitelib}/ipalib
-%{python_sitelib}/ipalib/*.py*
-%dir %{python_sitelib}/ipalib/install
-%{python_sitelib}/ipalib/install/*.py*
-%dir %{python_sitelib}/ipaplatform
-%{python_sitelib}/ipaplatform/*
-%{python_sitelib}/ipapython-*.egg-info
-%{python_sitelib}/ipalib-*.egg-info
-%{python_sitelib}/ipaplatform-*.egg-info
-%{python_sitelib}/ipaplatform-*-nspkg.pth
-
-%endif # with_python2
 
 %files common -f %{gettext_domain}.lang
 %defattr(-,root,root,-)
@@ -1630,31 +1241,6 @@ fi
 
 %if 0%{?with_ipatests}
 
-%if 0%{?with_python2}
-
-%files -n python2-ipatests
-%defattr(-,root,root,-)
-%doc README.md Contributors.txt
-%license COPYING
-%{python_sitelib}/ipatests
-%{python_sitelib}/ipatests-*.egg-info
-%{_bindir}/ipa-run-tests-2
-%{_bindir}/ipa-test-config-2
-%{_bindir}/ipa-test-task-2
-%{_bindir}/ipa-run-tests-%{python2_version}
-%{_bindir}/ipa-test-config-%{python2_version}
-%{_bindir}/ipa-test-task-%{python2_version}
-%if %{with_default_python} != 3
-%{_bindir}/ipa-run-tests
-%{_bindir}/ipa-test-config
-%{_bindir}/ipa-test-task
-%{_mandir}/man1/ipa-run-tests.1*
-%{_mandir}/man1/ipa-test-config.1*
-%{_mandir}/man1/ipa-test-task.1*
-%endif
-
-%endif # with_python2
-
 %files -n python3-ipatests
 %defattr(-,root,root,-)
 %doc README.md Contributors.txt
@@ -1667,14 +1253,12 @@ fi
 %{_bindir}/ipa-run-tests-%{python3_version}
 %{_bindir}/ipa-test-config-%{python3_version}
 %{_bindir}/ipa-test-task-%{python3_version}
-%if %{with_default_python} == 3
 %{_bindir}/ipa-run-tests
 %{_bindir}/ipa-test-config
 %{_bindir}/ipa-test-task
 %{_mandir}/man1/ipa-run-tests.1*
 %{_mandir}/man1/ipa-test-config.1*
 %{_mandir}/man1/ipa-test-task.1*
-%endif
 
 %endif # with_ipatests
 
diff --git a/ipalib/__init__.py b/ipalib/__init__.py
index f1ffe51f3b..8e2cbb8273 100644
--- a/ipalib/__init__.py
+++ b/ipalib/__init__.py
@@ -977,7 +977,7 @@ def create_api(mode='dummy'):
     api = API()
     if mode is not None:
         api.env.mode = mode
-    assert mode != 'production'
+    assert mode != f'production'
     return api
 
 api = create_api(mode=None)
diff --git a/ipapython/setup.py b/ipapython/setup.py
index 1d0ac043fd..1ac59291f3 100755
--- a/ipapython/setup.py
+++ b/ipapython/setup.py
@@ -49,7 +49,6 @@
             "six",
         ],
         extras_require={
-            ":python_version<'3'": ["enum34"],
             "install": ["dbus-python"],  # for certmonger
         },
     )
diff --git a/ipasetup.py.in b/ipasetup.py.in
index 8ec28c1583..bed92e88e1 100644
--- a/ipasetup.py.in
+++ b/ipasetup.py.in
@@ -97,17 +97,14 @@ common_args = dict(
     url="https://www.freeipa.org/",
     download_url="https://www.freeipa.org/page/Downloads",
     platforms=["Linux"],
-    python_requires=">=2.7.5,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*",
+    python_requires=">=3.6.0",
     classifiers=[
         "Development Status :: 5 - Production/Stable",
         "Intended Audience :: System Administrators",
         ("License :: OSI Approved :: "
          "GNU General Public License v3 (GPLv3)"),
         "Programming Language :: C",
-        "Programming Language :: Python :: 2",
-        "Programming Language :: Python :: 2.7",
         "Programming Language :: Python :: 3",
-        "Programming Language :: Python :: 3.5",
         "Programming Language :: Python :: 3.6",
         "Programming Language :: Python :: Implementation :: CPython",
         "Operating System :: POSIX",
diff --git a/makeaci b/makeaci
index 4e92e2d601..c9d0e1a3be 100755
--- a/makeaci
+++ b/makeaci
@@ -63,7 +63,7 @@ def generate_aci_lines(api):
         )
         aci = perm_plugin.make_aci(entry)
         yield 'dn: %s\n' % entry.single_value['ipapermlocation']
-        yield 'aci: %s\n' % aci
+        yield f'aci: {aci}\n'
 
         check_member_attrs(name, template)
 
diff --git a/makeapi b/makeapi
index 735b226871..be098880a5 100755
--- a/makeapi
+++ b/makeapi
@@ -179,7 +179,7 @@ def validate_doc():
                 next_topic = None
 
                 for package in api.packages:
-                    module = '%s.%s' % (package.__name__, topic)
+                    module = f'{package.__name__}.{topic}'
                     try:
                         mod = sys.modules[module]
                     except KeyError:
diff --git a/tox.ini b/tox.ini
index f401f16f34..a8b9b2232c 100644
--- a/tox.ini
+++ b/tox.ini
@@ -1,6 +1,6 @@
 [tox]
 minversion=2.3.1
-envlist=py27,py36,pylint2,pylint3,pypi
+envlist=py36,pylint3,pypi
 skip_missing_interpreters=true
 skipsdist=true
 
@@ -19,8 +19,8 @@ commands=
     {envbindir}/ipa --help
     {envpython} -bb {envbindir}/ipa-run-tests --ipaclient-unittests --junitxml={envdir}/junit-{envname}.xml
 
-[testenv:pylint2]
-basepython=python2.7
+[testenv:pylint3]
+basepython=python3
 deps=
     ipaclient[csrgen,otptoken_yubikey]
     pylint
@@ -32,11 +32,6 @@ commands=
         {envsitepackagesdir}/ipalib \
         {envsitepackagesdir}/ipapython
 
-[testenv:pylint3]
-basepython=python3
-deps={[testenv:pylint2]deps}
-commands={[testenv:pylint2]commands}
-
 [testenv:pypi]
 recreate=True
 install_command={toxinidir}/.tox-install.sh pypi_packages {envpython} {envsitepackagesdir} {packages}
