#!/usr/bin/python3
"""
Univention Setup:
Configure IPvX network interfaces.
"""
# Like what you see? Join us!
# https://www.univention.com/about-us/careers/vacancies/
#
# Copyright 2004-2022 Univention GmbH
#
# https://www.univention.de/
#
# All rights reserved.
#
# The source code of this program is made available
# under the terms of the GNU Affero General Public License version 3
# (GNU AGPL V3) as published by the Free Software Foundation.
#
# Binary versions of this program provided by Univention to you as
# well as other copyrighted, protected or trademarked materials like
# Logos, graphics, fonts, specific documentations and configurations,
# cryptographic keys etc. are subject to a license agreement between
# you and Univention and not subject to the GNU AGPL V3.
#
# In the case you use this program under the terms of the GNU AGPL V3,
# the program is provided in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public
# License with the Debian GNU/Linux or Univention distribution in file
# /usr/share/common-licenses/AGPL-3; if not, see
# <https://www.gnu.org/licenses/>.

import logging
import sys
from argparse import ArgumentParser

import univention.debug as ud
from univention.config_registry import handler_unset
from univention.config_registry.frontend import ucr_update
from univention.management.console.modules.setup.netconf import ChangeSet
from univention.management.console.modules.setup.netconf.modules import RunPhases
from univention.management.console.modules.setup.setup_script import SetupScript, _, main

UCR_IFACE_RESTART = "interfaces/restart/auto"


class NetworkSetup(SetupScript):
	name = _("Configuring IPvX network interfaces")

	def __init__(self):
		super(NetworkSetup, self).__init__()
		self.options = None
		self.changeset = None
		self.phases = RunPhases()
		self.logger = logging.getLogger("uss.network")

	def inner_run(self):
		self.parse_options()
		self.setup_logging()
		self.setup_ud_logging()
		self.prepare_changeset()
		self.setup_phases()
		self.reconfigure_network()

	def parse_options(self):
		parser = ArgumentParser(description=__doc__)
		parser.add_argument(
			"--network-only",
			action="store_true",
			help="Only re-configure network, but don't modify LDAP data")
		parser.add_argument(
			"--appliance-mode",
			action="store_true",
			help="Configure new address as additional virtual address instead of replacing current addresses")
		parser.add_argument(
			"--verbose", "-v",
			action="count", default=3,
			help="Log verbose")
		parser.add_argument(
			"--quiet", "-q",
			action="store_const", dest="verbose", const=0,
			help="Disable verbose logging")
		parser.add_argument(
			"--no-act", "--dry-run", "-n",
			action="store_true",
			help="Don't run any commands")

		self.options = parser.parse_args()

	LEVEL = (logging.FATAL, logging.ERROR, logging.WARN, logging.INFO, logging.DEBUG)

	def setup_logging(self):
		try:
			level = self.LEVEL[self.options.verbose]
		except IndexError:
			level = self.LEVEL[-1]
		logging.basicConfig(stream=sys.stderr, level=level)

	UD_LEVEL = (ud.ERROR, ud.WARN, ud.PROCESS, ud.INFO, ud.ALL)

	def setup_ud_logging(self):
		try:
			level = self.UD_LEVEL[self.options.verbose]
		except IndexError:
			level = self.UD_LEVEL[-1]
		ud.init("stderr", ud.NO_FLUSH, ud.NO_FUNCTION)
		ud.set_level(ud.ADMIN, level)

	def prepare_changeset(self):
		# This if clause is only executed on prejoined ucs appliances
		# We need to update the ldap, and therefore have to supply the
		# ip address with which the system was initially joined
		# otherwise, the ldap objects will not be updated with the
		# new ip address chosen in system setup
		if self.ucr.ucr.get('system/setup/boot/old_ipv4', None):
			self.logger.info("Setting old ipv4 address")
			self.ucr.ucr['interfaces/eth0/address'] = self.ucr.ucr.get('system/setup/boot/old_ipv4')
			if not self.options.no_act:
				handler_unset(['system/setup/boot/old_ipv4'])

		self.changeset = ChangeSet(self.ucr.ucr, self.profile, self.options)
		if not self.changeset.ucr_changes:
			self.logger.info("No changes to apply. Exiting.")
			sys.exit(0)

	def setup_phases(self):
		self.phases.load()
		self.phases.setup(self.changeset)

	def reconfigure_network(self):
		old_restart = self.ucr.ucr.get(UCR_IFACE_RESTART, None)
		try:
			self.ucr_update({UCR_IFACE_RESTART: "false"})

			self.apply_profile()
		finally:
			self.ucr_update({UCR_IFACE_RESTART: old_restart})

	def apply_profile(self):
		self.phases.pre()

		self.logger.info("Applying %r", self.changeset.ucr_changes)
		self.ucr_update(self.changeset.ucr_changes)

		self.phases.post()

	def ucr_update(self, changes):
		if not self.options.no_act:
			ucr_update(self.ucr.ucr, changes)


if __name__ == "__main__":
	main(NetworkSetup())
