#!/usr/bin/env python3
# -*- coding: utf-8 -*-

import functools
import os
import re
import subprocess
import sys
import traceback
from ipaddress import IPv4Address, IPv4Interface, IPv6Address, IPv6Interface


# ###### Dummy function #####################################################
def clear_flag(flag):
   # Nothing to do!
   pass


# ###### Dummy function #####################################################
def set_flag(flag):
   # Nothing to do!
   pass


# ###### Dummy function #####################################################
def status_set(tag, value):
   # Nothing to do!
   pass


# ###### Dummy function #####################################################
MyParameters = {
   # ====== HSS =============================================================
   'hss-git-repository': 'https://github.com/OPENAIRINTERFACE/openair-cn.git',
   'hss-git-commit': '2019.w45',
   'hss-S6a-address': '172.16.6.129',
   'network-realm': 'simula.nornet',
   'network-k': '449C4B91AEACD0ACE182CF3A5A72BFA1',
   'network-op': '1006020F0A478BF6B699F15C062E42B3',
   'network-imsi-first': '242881234500000',
   'network-msisdn-first': '24288880000000',
   'network-users': '1024',
   'cassandra-server-ip': '172.16.6.129',

   # ====== MME =============================================================
   'mme-git-repository': 'https://github.com/OPENAIRINTERFACE/openair-cn.git',
   'mme-git-commit': '2019.w45',
   'mme-S1C-ipv4-interface': '192.168.247.102/24',
   'mme-S1C-ipv4-gateway': '0.0.0.0',
   'mme-S11-ipv4-interface': '172.16.1.102/24',
   'mme-S1C-ipv6-interface': '',
   'mme-S1C-ipv6-gateway': '',
   'mme-S6a-address': '172.16.6.2',
   'spgwc-S11-ipv4-interface': '172.16.1.104/24',
   'network-mcc': '242',
   'network-mnc': '88',

   # ====== SPGW-C ==========================================================
   'spgwc-git-repository': 'https://github.com/OPENAIRINTERFACE/openair-cn-cups.git',
   'spgwc-git-commit': 'develop',
   'network-ipv4-dns1': '10.1.1.1',
   'network-ipv4-dns2': '10.1.2.1',

   # ====== SPGW-U ==========================================================
   'spgwu-git-repository': 'https://github.com/OPENAIRINTERFACE/openair-cn-cups.git',
   'spgwu-git-commit': 'develop',
   'spgwu-S1U-ipv4-interface': '192.168.248.159/24',
   'spgwu-S1U-ipv4-gateway': '0.0.0.0',
   'spgwu-SGi-ipv4-interface': '10.254.1.203/24',
   'spgwu-SGi-ipv4-gateway': '10.254.1.1',
   'spgwu-SGi-ipv6-interface': '',
   'spgwu-SGi-ipv6-gateway': '',
   'spgwu-spgwc-list': '172.55.55.101'
}
def action_get(flag):
   return MyParameters[flag]


# ###### Dummy function #####################################################
def action_set(values):
   # Nothing to do!
   pass


# ###### Dummy function #####################################################
def action_fail(message):
   # Nothing to do!
   pass


# ###### Dummy decorator ####################################################
def when(*flags):
    def decorator_when(func):
        @functools.wraps(func)
        def wrapper_when(*args, **kwargs):
            return func(*args, **kwargs)
        return wrapper_when
    return decorator_when


# ###### Dummy decorator ####################################################
def when_not(*flags):
    def decorator_when(func):
        @functools.wraps(func)
        def wrapper_when(*args, **kwargs):
            return func(*args, **kwargs)
        return wrapper_when
    return decorator_when


# ###### Execute command ####################################################
def execute(commands):
   sys.stdout.write('-----------------------------------------------------------------------------\n')
   sys.stdout.write('time bash -c "' + commands + '"\n')
   return [ ', ' ]


# ###### Run shell commands, handle exceptions, and upage status flags ######
def runShellCommands(commands, comment, actionFlagToClear, successFlagToSet = None):
   status_set('active', comment + ' ...')
   try:
       stdout, stderr = execute(commands)
   except subprocess.CalledProcessError as e:
       exc_type, exc_value, exc_traceback = sys.exc_info()
       err = traceback.format_exception(exc_type, exc_value, exc_traceback)
       message = 'Command execution failed: ' + str(err) + '\nOutput: ' + e.output.decode('utf-8')
       action_fail(message.encode('utf-8'))
       status_set('active', comment + ' COMMANDS FAILED!')
   except:
       exc_type, exc_value, exc_traceback = sys.exc_info()
       err = traceback.format_exception(exc_type, exc_value, exc_traceback)
       action_fail('Command execution failed: ' + str(err))
       status_set('active', comment + ' FAILED!')
   else:
      if successFlagToSet != None:
         set_flag(successFlagToSet)
      # action_set( { 'output': stdout.encode('utf-8') } )
      status_set('active', comment + ' COMPLETED')
   finally:
      clear_flag(actionFlagToClear)


# ######  Get /etc/network/interfaces setup for interface ###################
def configureInterface(name,
                       ipv4Interface = IPv4Interface('0.0.0.0/0'), ipv4Gateway = None,
                       ipv6Interface = None,                       ipv6Gateway = None,
                       metric = 1, pdnInterface = None):

   # NOTE:
   # Double escaping is required for \ and " in "configuration" string!
   # 1. Python
   # 2. bash -c "<command>"
   # That is: $ => \$ ; \ => \\ ; " => \\\"

   configuration = 'auto ' + name + '\\\\n'

   # ====== Helper function =================================================
   def makePDNRules(pdnInterface, interface, gateway):
      rules = \
         '\\\\tpost-up /bin/ip rule add from ' + str(interface.network) + ' lookup 1000 pref 100\\\\n' + \
         '\\\\tpost-up /bin/ip rule add iif pdn lookup 1000 pref 100\\\\n' + \
         '\\\\tpost-up /bin/ip route add ' + str(interface.network) + ' scope link dev ' + name + ' table 1000\\\\n' + \
         '\\\\tpost-up /bin/ip route add default via ' + str(gateway) + ' dev ' + name + ' table 1000\\\\n' + \
         '\\\\tpre-down /bin/ip route del default via ' + str(gateway) + ' dev ' + name + ' table 1000 || true\\\\n' + \
         '\\\\tpre-down /bin/ip route del ' + str(interface.network) + ' scope link dev ' + name + ' table 1000 || true\\\\n' + \
         '\\\\tpre-down /bin/ip rule del iif pdn lookup 1000 pref 100 || true\\\\n' + \
         '\\\\tpre-down /bin/ip rule del from ' + str(interface.network) + ' lookup 1000 pref 100 || true\\\\n'
      return rules

   # ====== IPv4 ============================================================
   if ipv4Interface == IPv4Interface('0.0.0.0/0'):
      configuration = configuration + 'iface ' + name + ' inet dhcp'
   else:
      configuration = configuration + \
         'iface ' + name + ' inet static\\\\n' + \
         '\\\\taddress ' + str(ipv4Interface.ip)      + '\\\\n' + \
         '\\\\tnetmask ' + str(ipv4Interface.netmask) + '\\\\n'
      if ((ipv4Gateway != None) and (ipv4Gateway != IPv4Address('0.0.0.0'))):
         configuration = configuration + \
            '\\\\tgateway ' + str(ipv4Gateway) + '\\\\n' + \
            '\\\\tmetric '  + str(metric)      + '\\\\n'
      if pdnInterface != None:
         configuration = configuration + makePDNRules(pdnInterface, ipv4Interface, ipv4Gateway)
      configuration = configuration + '\\\\n'

   # ====== IPv6 ============================================================
   if ipv6Interface == None:
      configuration = configuration + \
         '\\\\niface ' + name + ' inet6 manual\\\\n' + \
         '\\\\tautoconf 0\\\\n'
   elif ipv6Interface == IPv6Interface('::/0'):
      configuration = configuration + \
         '\\\\niface ' + name + ' inet6 dhcp\\\\n' + \
         '\\\\tautoconf 0\\\\n'
   else:
      configuration = configuration + \
         '\\\\niface ' + name + ' inet6 static\\\\n' + \
         '\\\\tautoconf 0\\\\n' + \
         '\\\\taddress ' + str(ipv6Interface.ip)                + '\\\\n' + \
         '\\\\tnetmask ' + str(ipv6Interface.network.prefixlen) + '\\\\n'
      if ((ipv6Gateway != None) and (ipv6Gateway != IPv6Address('::'))):
         configuration = configuration + \
            '\\\\tgateway ' + str(ipv6Gateway) + '\\\\n' + \
            '\\\\tmetric '  + str(metric)      + '\\\\n'
      if pdnInterface != None:
         configuration = configuration + makePDNRules(pdnInterface, ipv6Interface, ipv6Gateway)

   return configuration




# ###### prepare-cassandra-hss-build function ###############################
@when('actions.prepare-cassandra-hss-build')
@when('hsscharm.installed')
@when_not('hsscharm.prepared-cassandra-hss-build')
def prepare_cassandra_hss_build():

   # ====== Install Cassandra and the HSS ===================================
   # For a documentation of the installation procedure, see:
   # https://github.com/OPENAIRINTERFACE/openair-cn/wiki/OpenAirSoftwareSupport#install-hss

   gitRepository = action_get('hss-git-repository')
   gitCommit     = action_get('hss-git-commit')
   gitDirectory  = 'openair-cn'

   # Prepare network configuration:
   hssS6a_IfName    = 'ens4'
   configurationS6a = configureInterface(hssS6a_IfName, IPv4Interface('0.0.0.0/0'))

   # NOTE:
   # Double escaping is required for \ and " in "command" string!
   # 1. Python
   # 2. bash -c "<command>"
   # That is: $ => \$ ; \ => \\ ; " => \\\"

   commands = """\
echo \\\"###### Preparing system ###############################################\\\" && \\
echo -e \\\"{configurationS6a}\\\" | sudo tee /etc/network/interfaces.d/61-{hssS6a_IfName} && sudo ifup {hssS6a_IfName} || true && \\
if [ \\\"`find /etc/apt/sources.list.d -name 'rmescandon-ubuntu-yq-*.list'`\\\" == \\\"\\\" ] ; then sudo add-apt-repository -y ppa:rmescandon/yq ; fi && \\
sudo apt update && \
DEBIAN_FRONTEND=noninteractive sudo apt install -y -o Dpkg::Options::=--force-confold -o Dpkg::Options::=--force-confdef --no-install-recommends yq && \\
echo \\\"###### Preparing sources ##############################################\\\" && \\
cd /home/nornetpp/src && \\
if [ ! -d \\\"{gitDirectory}\\\" ] ; then git clone --quiet {gitRepository} {gitDirectory} && cd {gitDirectory} ; else cd {gitDirectory} && git pull ; fi && \\
git checkout {gitCommit} && \\
cd scripts && \\
echo \\\"###### Done! ##########################################################\\\"""".format(
      gitRepository    = gitRepository,
      gitDirectory     = gitDirectory,
      gitCommit        = gitCommit,
      hssS6a_IfName    = hssS6a_IfName,
      configurationS6a = configurationS6a
   )

   runShellCommands(commands, 'prepare_cassandra_hss_build: preparing Cassandra/HSS build',
                    'actions.prepare-cassandra-hss-build', 'hsscharm.prepared-cassandra-hss-build')


# ###### configure-cassandra function #######################################
@when('actions.configure-cassandra')
@when('hsscharm.prepared-cassandra-hss-build')
def configure_cassandra():

   # ====== Install Cassandra and the HSS ===================================
   # For a documentation of the installation procedure, see:
   # https://github.com/OPENAIRINTERFACE/openair-cn/wiki/OpenAirSoftwareSupport#install-hss

   gitDirectory      = 'openair-cn'
   cassandraServerIP = action_get('cassandra-server-ip')

   # NOTE:
   # Double escaping is required for \ and " in "command" string!
   # 1. Python
   # 2. bash -c "<command>"
   # That is: $ => \$ ; \ => \\ ; " => \\\"

   commands = """\
echo \\\"###### Building Cassandra #############################################\\\" && \\
export MAKEFLAGS=\\\"-j`nproc`\\\" && \\
cd /home/nornetpp/src && \\
cd {gitDirectory} && \\
cd scripts && \\
mkdir -p logs && \\
sudo rm -f /etc/apt/sources.list.d/cassandra.sources.list && \\
./build_cassandra --check-installed-software --force >logs/build_cassandra.log 2>&1 && \\
sudo update-alternatives --set java /usr/lib/jvm/java-8-openjdk-amd64/jre/bin/java && \\
sudo service cassandra stop && \\
sudo rm -rf /var/lib/cassandra/data/system/* && \\
sudo rm -rf /var/lib/cassandra/commitlog/* && \\
sudo rm -rf /var/lib/cassandra/data/system_traces/* && \\
sudo rm -rf /var/lib/cassandra/saved_caches/* && \\
sudo yq w -i /etc/cassandra/cassandra.yaml \\\"cluster_name\\\" \\\"HSS Cluster\\\" && \\
sudo yq w -i /etc/cassandra/cassandra.yaml \\\"seed_provider[0].class_name\\\" \\\"org.apache.cassandra.locator.SimpleSeedProvider\\\" && \\
sudo yq w -i /etc/cassandra/cassandra.yaml \\\"seed_provider[0].parameters[0].seeds\\\" \\\"{cassandraServerIP}\\\" && \\
sudo yq w -i /etc/cassandra/cassandra.yaml \\\"listen_address\\\" \\\"{cassandraServerIP}\\\" && \\
sudo yq w -i /etc/cassandra/cassandra.yaml \\\"rpc_address\\\" \\\"{cassandraServerIP}\\\" && \\
sudo yq w -i /etc/cassandra/cassandra.yaml \\\"endpoint_snitch\\\" \\\"GossipingPropertyFileSnitch\\\" && \\
sudo service cassandra start && \\
sleep 10 && \\
sudo service cassandra status | cat && \\
echo \\\"###### Done! ##########################################################\\\"""".format(
      gitDirectory      = gitDirectory,
      cassandraServerIP = cassandraServerIP
   )

   runShellCommands(commands, 'configure_cassandra: configuring Cassandra',
                    'actions.configure-cassandra', 'hsscharm.configured-cassandra')


# ###### configure-hss function #############################################
@when('actions.configure-hss')
@when('hsscharm.configured-cassandra')
def configure_hss():

   # ====== Install Cassandra and the HSS ===================================
   # For a documentation of the installation procedure, see:
   # https://github.com/OPENAIRINTERFACE/openair-cn/wiki/OpenAirSoftwareSupport#install-hss

   gitDirectory       = 'openair-cn'
   cassandraServerIP  = action_get('cassandra-server-ip')
   networkRealm       = action_get('network-realm')
   networkOP          = action_get('network-op')
   networkK           = action_get('network-k')
   networkIMSIFirst   = action_get('network-imsi-first')
   networkMSISDNFirst = action_get('network-msisdn-first')
   networkUsers       = int(action_get('network-users'))

   hssS6a_IPv4Address = IPv4Address(action_get('hss-S6a-address'))
   mmeS6a_IPv4Address = IPv4Address(action_get('mme-S6a-address'))

   # NOTE:
   # Double escaping is required for \ and " in "command" string!
   # 1. Python
   # 2. bash -c "<command>"
   # That is: $ => \$ ; \ => \\ ; " => \\\"

   commands = """\
echo \\\"###### Building HSS ###################################################\\\" && \\
export MAKEFLAGS=\\\"-j`nproc`\\\" && \\
cd /home/nornetpp/src && \\
cd {gitDirectory} && \\
cd scripts && \\
mkdir -p logs && \\
echo \\\"====== Building dependencies ... ======\\\" && \\
./build_hss_rel14 --check-installed-software --force >logs/build_hss_rel14-1.log 2>&1 && \\
echo \\\"====== Building service ... ======\\\" && \\
./build_hss_rel14 --clean >logs/build_hss_rel14-2.log 2>&1 && \\
cqlsh --file ../src/hss_rel14/db/oai_db.cql {cassandraServerIP} >logs/oai_db.log 2>&1 && \\
echo \\\"====== Provisioning users ... ======\\\" && \\
./data_provisioning_users --apn default.{networkRealm} --apn2 internet.{networkRealm} --key {networkK} --imsi-first {networkIMSIFirst} --msisdn-first {networkMSISDNFirst} --mme-identity mme.{networkRealm} --no-of-users {networkUsers} --realm {networkRealm} --truncate True  --verbose True --cassandra-cluster {cassandraServerIP} >logs/data_provisioning_users.log 2>&1 && \\
echo \\\"====== Provisioning MME ... ======\\\" && \\
./data_provisioning_mme --id 3 --mme-identity mme.{networkRealm} --realm {networkRealm} --ue-reachability 1 --truncate True  --verbose True -C {cassandraServerIP} >logs/data_provisioning_mme.log 2>&1 && \\
echo \\\"###### Creating HSS configuration files ###############################\\\" && \\
echo \\\"{hssS6a_IPv4Address}   hss.{networkRealm} hss\\\" | sudo tee -a /etc/hosts && \\
echo \\\"{mmeS6a_IPv4Address}   mme.{networkRealm} mme\\\" | sudo tee -a /etc/hosts && \\
openssl rand -out \$HOME/.rnd 128 && \\
echo \\\"====== Configuring Diameter ... ======\\\" && \\
PREFIX='/usr/local/etc/oai' && \\
sudo mkdir -m 0777 -p \$PREFIX && \\
sudo mkdir -m 0777 -p \$PREFIX/freeDiameter && \\
sudo cp ../etc/acl.conf ../etc/hss_rel14_fd.conf \$PREFIX/freeDiameter && \\
sudo cp ../etc/hss_rel14.conf ../etc/hss_rel14.json \$PREFIX && \\
sudo sed -i -e 's/#ListenOn/ListenOn/g' \$PREFIX/freeDiameter/hss_rel14_fd.conf && \\
echo \\\"====== Updating configuration files ... ======\\\" && \\
declare -A HSS_CONF && \\
HSS_CONF[@PREFIX@]=\$PREFIX && \\
HSS_CONF[@REALM@]='{networkRealm}' && \\
HSS_CONF[@HSS_FQDN@]='hss.{networkRealm}' && \\
HSS_CONF[@cassandra_Server_IP@]='{cassandraServerIP}' && \\
HSS_CONF[@cassandra_IP@]='{cassandraServerIP}' && \\
HSS_CONF[@OP_KEY@]='{networkOP}' && \\
HSS_CONF[@ROAMING_ALLOWED@]='true' && \\
for K in \\\"\${{!HSS_CONF[@]}}\\\"; do echo \\\"K=\$K ...\\\" && sudo egrep -lRZ \\\"\$K\\\" \$PREFIX | xargs -0 -l sudo sed -i -e \\\"s|\$K|\${{HSS_CONF[\$K]}}|g\\\" ; done && \\
../src/hss_rel14/bin/make_certs.sh hss {networkRealm} \$PREFIX && \\
echo \\\"====== Updating key ... ======\\\" && \\
oai_hss -j \$PREFIX/hss_rel14.json --onlyloadkey >logs/onlyloadkey.log 2>&1 && \\
echo \\\"====== Preparing SystemD Unit ... ======\\\" && \\
( echo \\\"[Unit]\\\" && \\
echo \\\"Description=Home Subscriber Server (HSS)\\\" && \\
echo \\\"After=ssh.target\\\" && \\
echo \\\"\\\" && \\
echo \\\"[Service]\\\" && \\
echo \\\"ExecStart=/bin/sh -c \\\'exec /usr/local/bin/oai_hss -j /usr/local/etc/oai/hss_rel14.json >>/var/log/hss.log 2>&1\\\'\\\" && \\
echo \\\"KillMode=process\\\" && \\
echo \\\"Restart=on-failure\\\" && \\
echo \\\"RestartPreventExitStatus=255\\\" && \\
echo \\\"WorkingDirectory=/home/nornetpp/src/openair-cn/scripts\\\" && \\
echo \\\"\\\" && \\
echo \\\"[Install]\\\" && \\
echo \\\"WantedBy=multi-user.target\\\" ) | sudo tee /lib/systemd/system/hss.service && \\
sudo systemctl daemon-reload && \\
echo \\\"###### Installing sysstat #############################################\\\" && \\
DEBIAN_FRONTEND=noninteractive sudo apt install -y -o Dpkg::Options::=--force-confold -o Dpkg::Options::=--force-confdef --no-install-recommends sysstat && \\
sudo sed -e \\\"s/^ENABLED=.*$/ENABLED=\\\\\\"true\\\\\\"/g\\\" -i /etc/default/sysstat && \\
sudo sed -e \\\"s/^SADC_OPTIONS=.*$/SADC_OPTIONS=\\\\\\"-S ALL\\\\\\"/g\\\" -i /etc/sysstat/sysstat && \\
sudo service sysstat restart && \\
echo \\\"###### Done! ##########################################################\\\"""".format(
      gitDirectory       = gitDirectory,
      cassandraServerIP  = cassandraServerIP,
      hssS6a_IPv4Address = hssS6a_IPv4Address,
      mmeS6a_IPv4Address = mmeS6a_IPv4Address,
      networkRealm       = networkRealm,
      networkOP          = networkOP,
      networkK           = networkK,
      networkIMSIFirst   = networkIMSIFirst,
      networkMSISDNFirst = networkMSISDNFirst,
      networkUsers       = networkUsers
   )

   runShellCommands(commands, 'configure_hss: configuring HSS',
                    'actions.configure-hss', 'hsscharm.configured-hss')




# ###### prepare-mme-build function #########################################
@when('actions.prepare-mme-build')
@when('mmecharm.installed')
@when_not('mmecharm.prepared-mme-build')
def prepare_mme_build():

   # ====== Install MME =====================================================
   # For a documentation of the installation procedure, see:
   # https://github.com/OPENAIRINTERFACE/openair-cn/wiki/OpenAirSoftwareSupport#install-mme

   gitRepository        = action_get('mme-git-repository')
   gitCommit            = action_get('mme-git-commit')
   gitDirectory         = 'openair-cn'

   mmeS1C_IPv4Interface = IPv4Interface(action_get('mme-S1C-ipv4-interface'))
   mmeS1C_IPv4Gateway   = IPv4Address(action_get('mme-S1C-ipv4-gateway'))
   if action_get('mme-S1C-ipv6-interface') != '':
      mmeS1C_IPv6Interface = IPv6Interface(action_get('mme-S1C-ipv6-interface'))
   else:
      mmeS1C_IPv6Interface = None
   if action_get('mme-S1C-ipv6-gateway') != '':
      mmeS1C_IPv6Gateway   = IPv6Address(action_get('mme-S1C-ipv6-gateway'))
   else:
      mmeS1C_IPv6Gateway = None

   # Prepare network configurations:
   mmeS6a_IfName = 'ens4'
   mmeS11_IfName = 'ens5'
   mmeS1C_IfName = 'ens6'

   configurationS6a = configureInterface(mmeS6a_IfName, IPv4Interface('0.0.0.0/0'))
   configurationS11 = configureInterface(mmeS11_IfName, IPv4Interface('0.0.0.0/0'))
   configurationS1C = configureInterface(mmeS1C_IfName, mmeS1C_IPv4Interface, mmeS1C_IPv4Gateway,
                                                        mmeS1C_IPv6Interface, mmeS1C_IPv6Gateway)

   # S10 dummy interface:
   mmeS10_IfName    = 'dummy0:m10'
   configurationS10 = configureInterface(mmeS10_IfName, IPv4Interface('192.168.10.110/24'))

   # NOTE:
   # Double escaping is required for \ and " in "command" string!
   # 1. Python
   # 2. bash -c "<command>"
   # That is: $ => \$ ; \ => \\ ; " => \\\"

   commands = """\
echo \\\"###### Preparing system ###############################################\\\" && \\
echo -e \\\"{configurationS6a}\\\" | sudo tee /etc/network/interfaces.d/61-{mmeS6a_IfName} && sudo ifup {mmeS6a_IfName} || true && \\
echo -e \\\"{configurationS11}\\\" | sudo tee /etc/network/interfaces.d/62-{mmeS11_IfName} && sudo ifup {mmeS11_IfName} || true && \\
echo -e \\\"{configurationS1C}\\\" | sudo tee /etc/network/interfaces.d/63-{mmeS1C_IfName} && sudo ifup {mmeS1C_IfName} || true && \\
sudo ip link add dummy0 type dummy || true && \\
echo -e \\\"{configurationS10}\\\" | sudo tee /etc/network/interfaces.d/64-{mmeS10_IfName} && sudo ifup {mmeS10_IfName} || true && \\
echo \\\"###### Preparing sources ##############################################\\\" && \\
cd /home/nornetpp/src && \\
if [ ! -d \\\"{gitDirectory}\\\" ] ; then git clone --quiet {gitRepository} {gitDirectory} && cd {gitDirectory} ; else cd {gitDirectory} && git pull ; fi && \\
git checkout {gitCommit} && \\
cd scripts && \\
echo \\\"###### Done! ##########################################################\\\"""".format(
      gitRepository    = gitRepository,
      gitDirectory     = gitDirectory,
      gitCommit        = gitCommit,
      mmeS6a_IfName    = mmeS6a_IfName,
      mmeS11_IfName    = mmeS11_IfName,
      mmeS1C_IfName    = mmeS1C_IfName,
      mmeS10_IfName    = mmeS10_IfName,
      configurationS6a = configurationS6a,
      configurationS11 = configurationS11,
      configurationS1C = configurationS1C,
      configurationS10 = configurationS10
   )

   runShellCommands(commands, 'prepare_mme_build: preparing MME build',
                    'actions.prepare-mme-build', 'mmecharm.prepared-mme-build')


# ###### configure-mme function #############################################
@when('actions.configure-mme')
@when('mmecharm.prepared-mme-build')
def configure_mme():

   # ====== Install MME =====================================================
   # For a documentation of the installation procedure, see:
   # https://github.com/OPENAIRINTERFACE/openair-cn/wiki/OpenAirSoftwareSupport#install-mme

   gitDirectory           = 'openair-cn'

   hssS6a_IPv4Address     = IPv4Address(action_get('hss-S6a-address'))
   mmeS1C_IPv4Interface   = IPv4Interface(action_get('mme-S1C-ipv4-interface'))
   mmeS11_IPv4Interface   = IPv4Interface(action_get('mme-S11-ipv4-interface'))
   mmeS10_IPv4Interface   = IPv4Interface('192.168.10.110/24')
   spwgcS11_IPv4Interface = IPv4Interface(action_get('spgwc-S11-ipv4-interface'))
   networkRealm           = action_get('network-realm')
   networkMCC             = int(action_get('network-mcc'))
   networkMNC             = int(action_get('network-mnc'))
   networkOP              = action_get('network-op')
   networkK               = action_get('network-k')
   networkIMSIFirst       = action_get('network-imsi-first')
   networkMSISDNFirst     = action_get('network-msisdn-first')
   networkUsers           = int(action_get('network-users'))

   TAC_SGW_TEST = 7
   TAC_SGW_0    = 600
   TAC_MME_0    = 601
   TAC_MME_1    = 602

   tac_sgw_test = '{:04x}'.format(TAC_SGW_TEST)
   tac_sgw_0    = '{:04x}'.format(TAC_SGW_0)
   tac_mme_0    = '{:04x}'.format(TAC_MME_0)
   tac_mme_1    = '{:04x}'.format(TAC_MME_1)

   # Prepare network configurations:
   mmeS6a_IfName = 'ens4'
   mmeS11_IfName = 'ens5'
   mmeS1C_IfName = 'ens6'
   mmeS10_IfName = 'dummy0:m10'

   # NOTE:
   # Double escaping is required for \ and " in "command" string!
   # 1. Python
   # 2. bash -c "<command>"
   # That is: $ => \$ ; \ => \\ ; " => \\\"

   commands = """\
echo \\\"###### Building MME ####################################################\\\" && \\
export MAKEFLAGS=\\\"-j`nproc`\\\" && \\
cd /home/nornetpp/src && \\
cd {gitDirectory} && \\
cd scripts && \\
mkdir -p logs && \\
echo \\\"====== Building dependencies ... ======\\\" && \\
./build_mme --check-installed-software --force >logs/build_mme-1.log 2>&1 && \\
echo \\\"====== Building service ... ======\\\" && \\
./build_mme --clean >logs/build_mme-2.log 2>&1 && \\
echo \\\"###### Creating MME configuration files ###############################\\\" && \\
echo \\\"127.0.1.1        mme.{networkRealm} mme\\\" | sudo tee -a /etc/hosts && \\
echo \\\"{hssS6a_IPv4Address}     hss.{networkRealm} hss\\\" | sudo tee -a /etc/hosts && \\
openssl rand -out \$HOME/.rnd 128 && \\
INSTANCE=1 && \\
PREFIX='/usr/local/etc/oai' && \\
sudo mkdir -m 0777 -p \$PREFIX && \\
sudo mkdir -m 0777 -p \$PREFIX/freeDiameter && \\
sudo cp ../etc/mme_fd.sprint.conf  \$PREFIX/freeDiameter/mme_fd.conf && \\
sudo cp ../etc/mme.conf  \$PREFIX && \\
declare -A MME_CONF && \\
MME_CONF[@MME_S6A_IP_ADDR@]=\\\"127.0.0.11\\\" && \\
MME_CONF[@INSTANCE@]=\$INSTANCE && \\
MME_CONF[@PREFIX@]=\$PREFIX && \\
MME_CONF[@REALM@]='{networkRealm}' && \\
MME_CONF[@PID_DIRECTORY@]='/var/run' && \\
MME_CONF[@MME_FQDN@]=\\\"mme.{networkRealm}\\\" && \\
MME_CONF[@HSS_HOSTNAME@]='hss' && \\
MME_CONF[@HSS_FQDN@]=\\\"hss.{networkRealm}\\\" && \\
MME_CONF[@HSS_IP_ADDR@]='{hssS6a_IPv4Address}' && \\
MME_CONF[@MCC@]='{networkMCC}' && \\
MME_CONF[@MNC@]='{networkMNC}' && \\
MME_CONF[@MME_GID@]='32768' && \\
MME_CONF[@MME_CODE@]='3' && \\
MME_CONF[@TAC_0@]='600' && \\
MME_CONF[@TAC_1@]='601' && \\
MME_CONF[@TAC_2@]='602' && \\
MME_CONF[@MME_INTERFACE_NAME_FOR_S1_MME@]='{mmeS1C_IfName}' && \\
MME_CONF[@MME_IPV4_ADDRESS_FOR_S1_MME@]='{mmeS1C_IPv4Interface}' && \\
MME_CONF[@MME_INTERFACE_NAME_FOR_S11@]='{mmeS11_IfName}' && \\
MME_CONF[@MME_IPV4_ADDRESS_FOR_S11@]='{mmeS11_IPv4Interface}' && \\
MME_CONF[@MME_INTERFACE_NAME_FOR_S10@]='{mmeS10_IfName}' && \\
MME_CONF[@MME_IPV4_ADDRESS_FOR_S10@]='{mmeS10_IPv4Interface}' && \\
MME_CONF[@OUTPUT@]='CONSOLE' && \\
MME_CONF[@SGW_IPV4_ADDRESS_FOR_S11_TEST_0@]='{spwgcS11_IPv4Interface}' && \\
MME_CONF[@SGW_IPV4_ADDRESS_FOR_S11_0@]='{spwgcS11_IPv4Interface}' && \\
MME_CONF[@PEER_MME_IPV4_ADDRESS_FOR_S10_0@]='0.0.0.0/24' && \\
MME_CONF[@PEER_MME_IPV4_ADDRESS_FOR_S10_1@]='0.0.0.0/24' && \\
MME_CONF[@TAC-LB_SGW_TEST_0@]={tac_sgw_test_lo} && \\
MME_CONF[@TAC-HB_SGW_TEST_0@]={tac_sgw_test_hi} && \\
MME_CONF[@MCC_SGW_0@]={networkMCC} && \\
MME_CONF[@MNC3_SGW_0@]={networkMNC:03d} && \\
MME_CONF[@TAC-LB_SGW_0@]={tac_sgw_0_lo} && \\
MME_CONF[@TAC-HB_SGW_0@]={tac_sgw_0_hi} && \\
MME_CONF[@MCC_MME_0@]={networkMCC} && \\
MME_CONF[@MNC3_MME_0@]={networkMNC:03d} && \\
MME_CONF[@TAC-LB_MME_0@]={tac_mme_0_lo} && \\
MME_CONF[@TAC-HB_MME_0@]={tac_mme_0_hi} && \\
MME_CONF[@MCC_MME_1@]={networkMCC} && \\
MME_CONF[@MNC3_MME_1@]={networkMNC:03d} && \\
MME_CONF[@TAC-LB_MME_1@]={tac_mme_1_lo} && \\
MME_CONF[@TAC-HB_MME_1@]={tac_mme_1_hi} && \\
for K in \\\"\${{!MME_CONF[@]}}\\\"; do sudo egrep -lRZ \\\"\$K\\\" \$PREFIX | xargs -0 -l sudo sed -i -e \\\"s|\$K|\${{MME_CONF[\$K]}}|g\\\" ; ret=\$?;[[ ret -ne 0 ]] && echo \\\"Tried to replace \$K with \${{MME_CONF[\$K]}}\\\" || true ; done && \\
sudo ./check_mme_s6a_certificate \$PREFIX/freeDiameter mme.{networkRealm} >logs/check_mme_s6a_certificate.log 2>&1 && \\
echo \\\"====== Preparing SystemD Unit ... ======\\\" && \\
( echo \\\"[Unit]\\\" && \\
echo \\\"Description=Mobility Management Entity (MME)\\\" && \\
echo \\\"After=ssh.target\\\" && \\
echo \\\"\\\" && \\
echo \\\"[Service]\\\" && \\
echo \\\"ExecStart=/bin/sh -c \\\'exec /usr/local/bin/mme -c /usr/local/etc/oai/mme.conf >>/var/log/mme.log 2>&1\\\'\\\" && \\
echo \\\"KillMode=process\\\" && \\
echo \\\"Restart=on-failure\\\" && \\
echo \\\"RestartPreventExitStatus=255\\\" && \\
echo \\\"WorkingDirectory=/home/nornetpp/src/openair-cn/scripts\\\" && \\
echo \\\"\\\" && \\
echo \\\"[Install]\\\" && \\
echo \\\"WantedBy=multi-user.target\\\" ) | sudo tee /lib/systemd/system/mme.service && \\
sudo systemctl daemon-reload && \\
echo \\\"###### Installing sysstat #############################################\\\" && \\
DEBIAN_FRONTEND=noninteractive sudo apt install -y -o Dpkg::Options::=--force-confold -o Dpkg::Options::=--force-confdef --no-install-recommends sysstat && \\
sudo sed -e \\\"s/^ENABLED=.*$/ENABLED=\\\\\\"true\\\\\\"/g\\\" -i /etc/default/sysstat && \\
sudo sed -e \\\"s/^SADC_OPTIONS=.*$/SADC_OPTIONS=\\\\\\"-S ALL\\\\\\"/g\\\" -i /etc/sysstat/sysstat && \\
sudo service sysstat restart && \\
echo \\\"###### Done! ##########################################################\\\"""".format(
      gitDirectory           = gitDirectory,
      hssS6a_IPv4Address     = hssS6a_IPv4Address,
      mmeS1C_IfName          = mmeS1C_IfName,
      mmeS1C_IPv4Interface   = mmeS1C_IPv4Interface,
      mmeS11_IfName          = mmeS11_IfName,
      mmeS11_IPv4Interface   = mmeS11_IPv4Interface,
      mmeS10_IfName          = mmeS10_IfName,
      mmeS10_IPv4Interface   = mmeS10_IPv4Interface,

      spwgcS11_IPv4Interface = spwgcS11_IPv4Interface,
      networkRealm           = networkRealm,
      networkMCC             = networkMCC,
      networkMNC             = networkMNC,
      networkOP              = networkOP,
      networkK               = networkK,
      networkIMSIFirst       = networkIMSIFirst,
      networkMSISDNFirst     = networkMSISDNFirst,
      networkUsers           = networkUsers,

      tac_sgw_test_hi        = tac_sgw_test[0:2],
      tac_sgw_test_lo        = tac_sgw_test[2:4],
      tac_sgw_0_hi           = tac_sgw_0[0:2],
      tac_sgw_0_lo           = tac_sgw_0[2:4],
      tac_mme_0_hi           = tac_mme_0[0:2],
      tac_mme_0_lo           = tac_mme_0[2:4],
      tac_mme_1_hi           = tac_mme_1[0:2],
      tac_mme_1_lo           = tac_mme_1[2:4]
   )

   runShellCommands(commands, 'configure_mme: configuring MME',
                    'actions.configure-mme', 'mmecharm.configured-mme')




# ###### prepare-spgwu-build function #######################################
@when('actions.prepare-spgwu-build')
@when('spgwucharm.installed')
@when_not('spgwucharm.prepared-spgwu-build')
def prepare_spgwu_build():

   # ====== Install SPGW-U ==================================================
   # For a documentation of the installation procedure, see:
   # https://github.com/OPENAIRINTERFACE/openair-cn-cups/wiki/OpenAirSoftwareSupport#install-spgw-u

   gitRepository          = action_get('spgwu-git-repository')
   gitCommit              = action_get('spgwu-git-commit')
   gitDirectory           = 'openair-cn-cups'

   spgwuS1U_IPv4Interface = IPv4Interface(action_get('spgwu-S1U-ipv4-interface'))
   spgwuS1U_IPv4Gateway   = IPv4Address(action_get('spgwu-S1U-ipv4-gateway'))

   spgwuSGi_IPv4Interface = IPv4Interface(action_get('spgwu-SGi-ipv4-interface'))
   spgwuSGi_IPv4Gateway   = IPv4Address(action_get('spgwu-SGi-ipv4-gateway'))
   if action_get('spgwu-SGi-ipv6-interface') == '':
      spgwuSGi_IPv6Interface = None
   else:
      spgwuSGi_IPv6Interface = IPv6Interface(action_get('spgwu-SGi-ipv6-interface'))
   if action_get('spgwu-SGi-ipv6-gateway') == '':
      spgwuSGi_IPv6Gateway = None
   else:
      spgwuSGi_IPv6Gateway = IPv6Address(action_get('spgwu-SGi-ipv6-gateway'))

   # Prepare network configurations:
   spgwuSXab_IfName       = 'ens4'
   spgwuS1U_IfName        = 'ens5'
   spgwuSGi_IfName        = 'ens6'

   configurationSXab = configureInterface(spgwuSXab_IfName, IPv4Interface('0.0.0.0/0'), metric=61)
   configurationS1U  = configureInterface(spgwuS1U_IfName, spgwuS1U_IPv4Interface, spgwuS1U_IPv4Gateway, metric=62)
   configurationSGi  = configureInterface(spgwuSGi_IfName, spgwuSGi_IPv4Interface, spgwuSGi_IPv4Gateway,
                                                           spgwuSGi_IPv6Interface, spgwuSGi_IPv6Gateway,
                                                           metric=1, pdnInterface = 'pdn')

   # NOTE:
   # Double escaping is required for \ and " in "command" string!
   # 1. Python
   # 2. bash -c "<command>"
   # That is: $ => \$ ; \ => \\ ; " => \\\"

   commands = """\
echo \\\"###### Preparing system ###############################################\\\" && \\
echo -e \\\"{configurationSXab}\\\" | sudo tee /etc/network/interfaces.d/61-{spgwuSXab_IfName} && sudo ifup {spgwuSXab_IfName} || true && \\
echo -e \\\"{configurationS1U}\\\" | sudo tee /etc/network/interfaces.d/62-{spgwuS1U_IfName} && sudo ifup {spgwuS1U_IfName} || true && \\
echo -e \\\"{configurationSGi}\\\" | sudo tee /etc/network/interfaces.d/63-{spgwuSGi_IfName} && sudo ifup {spgwuSGi_IfName} || true && \\
echo \\\"###### Preparing sources ##############################################\\\" && \\
cd /home/nornetpp/src && \\
if [ ! -d \\\"{gitDirectory}\\\" ] ; then git clone --quiet {gitRepository} {gitDirectory} && cd {gitDirectory} ; else cd {gitDirectory} && git pull ; fi && \\
git checkout {gitCommit} && \\
cd build/scripts && \\
echo \\\"###### Done! ##########################################################\\\"""".format(
      gitRepository     = gitRepository,
      gitDirectory      = gitDirectory,
      gitCommit         = gitCommit,
      spgwuSXab_IfName  = spgwuSXab_IfName,
      spgwuS1U_IfName   = spgwuS1U_IfName,
      spgwuSGi_IfName   = spgwuSGi_IfName,
      configurationSXab = configurationSXab,
      configurationS1U  = configurationS1U,
      configurationSGi  = configurationSGi
   )

   runShellCommands(commands, 'prepare_spgwu_build: preparing SPGW-U build',
                    'actions.prepare-spgwu-build', 'spgwucharm.prepared-spgwu-build')


# ###### configure-spgwu function ###########################################
@when('actions.configure-spgwu')
@when('spgwucharm.prepared-spgwu-build')
def configure_spgwu():
   status_set('active', 'configure-spgwu: configuring SPGW-U ...')

   # ====== Install SPGW-U ==================================================
   # For a documentation of the installation procedure, see:
   # https://github.com/OPENAIRINTERFACE/openair-cn-cups/wiki/OpenAirSoftwareSupport#install-spgw-u

   gitRepository    = 'https://github.com/OPENAIRINTERFACE/openair-cn-cups.git'
   gitDirectory     = 'openair-cn-cups'
   gitCommit        = 'develop'

   spgwuSXab_IfName = 'ens4'
   spgwuS1U_IfName  = 'ens5'
   spgwuSGi_IfName  = 'ens6'

   spgwcListString  = action_get('spgwu-spgwc-list').split(',')
   spgwcList        = ''
   for spgwc in spgwcListString:
      spgwcAddress = IPv4Address(spgwc)
      if len(spgwcList) > 0:
         spgwcList = spgwcList + ', '
      spgwcList = spgwcList + '{{ IPV4_ADDRESS=\\\\\\"{spgwcAddress}\\\\\\"; }}'.format(spgwcAddress = str(spgwcAddress))

   # NOTE:
   # Double escaping is required for \ and " in "command" string!
   # 1. Python
   # 2. bash -c "<command>"
   # That is: $ => \$ ; \ => \\ ; " => \\\"

   commands = """\
echo \\\"###### Building SPGW-U ################################################\\\" && \\
export MAKEFLAGS=\\\"-j`nproc`\\\" && \\
cd /home/nornetpp/src && \\
cd {gitDirectory} && \\
cd build/scripts && \\
mkdir -p logs && \\
echo \\\"====== Building dependencies ... ======\\\" && \\
./build_spgwu -I -f >logs/build_spgwu-1.log 2>&1 && \\
echo \\\"====== Building service ... ======\\\" && \\
./build_spgwu -c -V -b Debug -j >logs/build_spgwu-2.log 2>&1 && \\
INSTANCE=1 && \\
PREFIX='/usr/local/etc/oai' && \\
sudo mkdir -m 0777 -p \$PREFIX && \\
sudo cp ../../etc/spgw_u.conf  \$PREFIX && \\
declare -A SPGWU_CONF && \\
SPGWU_CONF[@INSTANCE@]=\$INSTANCE && \\
SPGWU_CONF[@PREFIX@]=\$PREFIX && \\
SPGWU_CONF[@PID_DIRECTORY@]='/var/run' && \\
SPGWU_CONF[@SGW_INTERFACE_NAME_FOR_S1U_S12_S4_UP@]='{spgwuS1U_IfName}' && \\
SPGWU_CONF[@SGW_INTERFACE_NAME_FOR_SX@]='{spgwuSXab_IfName}' && \\
SPGWU_CONF[@SGW_INTERFACE_NAME_FOR_SGI@]='{spgwuSGi_IfName}' && \\
for K in \\\"\${{!SPGWU_CONF[@]}}\\\"; do sudo egrep -lRZ \\\"\$K\\\" \$PREFIX | xargs -0 -l sudo sed -i -e \\\"s|\$K|\${{SPGWU_CONF[\$K]}}|g\\\" ; ret=\$?;[[ ret -ne 0 ]] && echo \\\"Tried to replace \$K with \${{SPGWU_CONF[\$K]}}\\\" || true ; done && \\
sudo sed -e \\\"s/{{.*IPV4_ADDRESS=\\\\\\"192.168.160.100\\\\\\".*;.*}}/{spgwcList}/g\\\" -i /usr/local/etc/oai/spgw_u.conf && \\
echo \\\"====== Preparing SystemD Unit ... ======\\\" && \\
( echo \\\"[Unit]\\\" && \\
echo \\\"Description=Serving and Packet Data Network Gateway -- User Plane (SPGW-U)\\\" && \\
echo \\\"After=ssh.target\\\" && \\
echo \\\"\\\" && \\
echo \\\"[Service]\\\" && \\
echo \\\"ExecStart=/bin/sh -c \\\'exec /usr/local/bin/spgwu -c /usr/local/etc/oai/spgw_u.conf -o >>/var/log/spgwu.log 2>&1\\\'\\\" && \\
echo \\\"KillMode=process\\\" && \\
echo \\\"Restart=on-failure\\\" && \\
echo \\\"RestartPreventExitStatus=255\\\" && \\
echo \\\"WorkingDirectory=/home/nornetpp/src/openair-cn-cups/build/scripts\\\" && \\
echo \\\"\\\" && \\
echo \\\"[Install]\\\" && \\
echo \\\"WantedBy=multi-user.target\\\" ) | sudo tee /lib/systemd/system/spgwu.service && \\
sudo systemctl daemon-reload && \\
echo \\\"###### Installing sysstat #############################################\\\" && \\
DEBIAN_FRONTEND=noninteractive sudo apt install -y -o Dpkg::Options::=--force-confold -o Dpkg::Options::=--force-confdef --no-install-recommends sysstat && \\
sudo sed -e \\\"s/^ENABLED=.*$/ENABLED=\\\\\\"true\\\\\\"/g\\\" -i /etc/default/sysstat && \\
sudo sed -e \\\"s/^SADC_OPTIONS=.*$/SADC_OPTIONS=\\\\\\"-S ALL\\\\\\"/g\\\" -i /etc/sysstat/sysstat && \\
sudo service sysstat restart && \\
echo \\\"###### Done! ##########################################################\\\"""".format(
      gitRepository     = gitRepository,
      gitDirectory      = gitDirectory,
      gitCommit         = gitCommit,
      spgwuSXab_IfName  = spgwuSXab_IfName,
      spgwuS1U_IfName   = spgwuS1U_IfName,
      spgwuSGi_IfName   = spgwuSGi_IfName,
      spgwcList         = spgwcList
   )

   runShellCommands(commands, 'configure_spgwu: configuring SPGW-U',
                    'actions.configure-spgwu', 'spgwucharm.configured-spgwu')




# ###### prepare-spgwc-build function #######################################
@when('actions.prepare-spgwc-build')
@when('spgwccharm.installed')
@when_not('spgwccharm.prepared-spgwc-build')
def prepare_spgwc_build():

   # ====== Install SPGW-C ==================================================
   # For a documentation of the installation procedure, see:
   # https://github.com/OPENAIRINTERFACE/openair-cn-cups/wiki/OpenAirSoftwareSupport#install-spgw-c

   gitRepository     = action_get('spgwc-git-repository')
   gitCommit         = action_get('spgwc-git-commit')
   gitDirectory      = 'openair-cn-cups'

   # Prepare network configurations:
   spgwcS11_IfName   = 'ens5'
   spgwcSXab_IfName  = 'ens4'
   configurationS11  = configureInterface(spgwcS11_IfName,  IPv4Interface('0.0.0.0/0'))
   configurationSXab = configureInterface(spgwcSXab_IfName, IPv4Interface('0.0.0.0/0'))

   # S5S8 dummy interfaces:
   spgwcS5S8_SGW_IfName  = 'dummy0:s5c'
   configurationS5S8_SGW = configureInterface(spgwcS5S8_SGW_IfName, IPv4Interface('172.58.58.102/24'))
   spgwcS5S8_PGW_IfName  = 'dummy0:p5c'
   configurationS5S8_PGW = configureInterface(spgwcS5S8_PGW_IfName, IPv4Interface('172.58.58.101/24'))

   # NOTE:
   # Double escaping is required for \ and " in "command" string!
   # 1. Python
   # 2. bash -c "<command>"
   # That is: $ => \$ ; \ => \\ ; " => \\\"

   commands = """\
echo \\\"###### Preparing system ###############################################\\\" && \\
echo -e \\\"{configurationS11}\\\" | sudo tee /etc/network/interfaces.d/61-{spgwcS11_IfName} && sudo ifup {spgwcS11_IfName} || true && \\
echo -e \\\"{configurationSXab}\\\" | sudo tee /etc/network/interfaces.d/62-{spgwcSXab_IfName} && sudo ifup {spgwcSXab_IfName} || true && \\
sudo ip link add dummy0 type dummy || true && \\
echo -e \\\"{configurationS5S8_SGW}\\\" | sudo tee /etc/network/interfaces.d/63-{spgwcS5S8_SGW_IfName} && sudo ifup {spgwcS5S8_SGW_IfName} || true && \\
echo -e \\\"{configurationS5S8_PGW}\\\" | sudo tee /etc/network/interfaces.d/64-{spgwcS5S8_PGW_IfName} && sudo ifup {spgwcS5S8_PGW_IfName} || true && \\
echo \\\"###### Preparing sources ##############################################\\\" && \\
cd /home/nornetpp/src && \\
if [ ! -d \\\"{gitDirectory}\\\" ] ; then git clone --quiet {gitRepository} {gitDirectory} && cd {gitDirectory} ; else cd {gitDirectory} && git pull ; fi && \\
git checkout {gitCommit} && \\
cd build/scripts && \\
echo \\\"###### Done! ##########################################################\\\"""".format(
      gitRepository          = gitRepository,
      gitDirectory           = gitDirectory,
      gitCommit              = gitCommit,
      spgwcS11_IfName        = spgwcS11_IfName,
      spgwcSXab_IfName       = spgwcSXab_IfName,
      spgwcS5S8_SGW_IfName   = spgwcS5S8_SGW_IfName,
      spgwcS5S8_PGW_IfName   = spgwcS5S8_PGW_IfName,
      configurationS11       = configurationS11,
      configurationSXab      = configurationSXab,
      configurationS5S8_SGW  = configurationS5S8_SGW,
      configurationS5S8_PGW  = configurationS5S8_PGW
   )

   runShellCommands(commands, 'prepare_spgwc_build: preparing SPGW-C build',
                    'actions.prepare-spgwc-build', 'spgwccharm.prepared-spgwc-build')


# ###### configure-spgwc function ###########################################
@when('actions.configure-spgwc')
@when('spgwccharm.prepared-spgwc-build')
def configure_spgwc():

   # ====== Install SPGW-C ==================================================
   # For a documentation of the installation procedure, see:
   # https://github.com/OPENAIRINTERFACE/openair-cn-cups/wiki/OpenAirSoftwareSupport#install-spgw-c

   gitDirectory         = 'openair-cn-cups'

   networkRealm         = action_get('network-realm')
   networkDNS1_IPv4     = IPv4Address(action_get('network-ipv4-dns1'))
   networkDNS2_IPv4     = IPv4Address(action_get('network-ipv4-dns2'))

   # Prepare network configurations:
   spgwcSXab_IfName     = 'ens4'
   spgwcS11_IfName      = 'ens5'
   spgwcS5S8_SGW_IfName = 'dummy0:s5c'
   spgwcS5S8_PGW_IfName = 'dummy0:p5c'

   # NOTE:
   # Double escaping is required for \ and " in "command" string!
   # 1. Python
   # 2. bash -c "<command>"
   # That is: $ => \$ ; \ => \\ ; " => \\\"

   commands = """\
echo \\\"###### Building SPGW-C ################################################\\\" && \\
export MAKEFLAGS=\\\"-j`nproc`\\\" && \\
cd /home/nornetpp/src && \\
cd {gitDirectory} && \\
cd build/scripts && \\
mkdir -p logs && \\
echo \\\"====== Building dependencies ... ======\\\" && \\
./build_spgwc -I -f >logs/build_spgwc-1.log 2>&1 && \\
echo \\\"====== Building service ... ======\\\" && \\
./build_spgwc -c -V -b Debug -j >logs/build_spgwc-2.log 2>&1 && \\
echo \\\"###### Creating SPGW-C configuration files ############################\\\" && \\
INSTANCE=1 && \\
PREFIX='/usr/local/etc/oai' && \\
sudo mkdir -m 0777 -p \$PREFIX && \\
sudo cp ../../etc/spgw_c.conf  \$PREFIX && \\
declare -A SPGWC_CONF && \\
SPGWC_CONF[@INSTANCE@]=\$INSTANCE && \\
SPGWC_CONF[@PREFIX@]=\$PREFIX && \\
SPGWC_CONF[@PID_DIRECTORY@]='/var/run' && \\
SPGWC_CONF[@SGW_INTERFACE_NAME_FOR_S11@]='{spgwcS11_IfName}' && \\
SPGWC_CONF[@SGW_INTERFACE_NAME_FOR_S5_S8_CP@]='{spgwcS5S8_SGW_IfName}' && \\
SPGWC_CONF[@PGW_INTERFACE_NAME_FOR_S5_S8_CP@]='{spgwcS5S8_PGW_IfName}' && \\
SPGWC_CONF[@PGW_INTERFACE_NAME_FOR_SX@]='{spgwcSXab_IfName}' && \\
SPGWC_CONF[@DEFAULT_DNS_IPV4_ADDRESS@]='{networkDNS1_IPv4}' && \\
SPGWC_CONF[@DEFAULT_DNS_SEC_IPV4_ADDRESS@]='{networkDNS2_IPv4}' && \\
for K in \\\"\${{!SPGWC_CONF[@]}}\\\"; do sudo egrep -lRZ \\\"\$K\\\" \$PREFIX | xargs -0 -l sudo sed -i -e \\\"s|\$K|\${{SPGWC_CONF[\$K]}}|g\\\" ; ret=\$?;[[ ret -ne 0 ]] && echo \\\"Tried to replace \$K with \${{SPGWC_CONF[\$K]}}\\\" || true ; done && \\
sudo sed -e \\\"s/APN_NI = \\\\\\"default\\\\\\"/APN_NI = \\\\\\"default.{networkRealm}\\\\\\"/g\\\" -i /usr/local/etc/oai/spgw_c.conf && \\
sudo sed -e \\\"s/APN_NI = \\\\\\"apn1\\\\\\"/APN_NI = \\\\\\"internet.{networkRealm}\\\\\\"/g\\\" -i /usr/local/etc/oai/spgw_c.conf && \\
echo \\\"====== Preparing SystemD Unit ... ======\\\" && \\
( echo \\\"[Unit]\\\" && \\
echo \\\"Description=Serving and Packet Data Network Gateway -- Control Plane (SPGW-C)\\\" && \\
echo \\\"After=ssh.target\\\" && \\
echo \\\"\\\" && \\
echo \\\"[Service]\\\" && \\
echo \\\"ExecStart=/bin/sh -c \\\'exec /usr/local/bin/spgwc -c /usr/local/etc/oai/spgw_c.conf -o >>/var/log/spgwc.log 2>&1\\\'\\\" && \\
echo \\\"KillMode=process\\\" && \\
echo \\\"Restart=on-failure\\\" && \\
echo \\\"RestartPreventExitStatus=255\\\" && \\
echo \\\"WorkingDirectory=/home/nornetpp/src/openair-cn-cups/build/scripts\\\" && \\
echo \\\"\\\" && \\
echo \\\"[Install]\\\" && \\
echo \\\"WantedBy=multi-user.target\\\" ) | sudo tee /lib/systemd/system/spgwc.service && \\
sudo systemctl daemon-reload && \\
echo \\\"###### Installing sysstat #############################################\\\" && \\
DEBIAN_FRONTEND=noninteractive sudo apt install -y -o Dpkg::Options::=--force-confold -o Dpkg::Options::=--force-confdef --no-install-recommends sysstat && \\
sudo sed -e \\\"s/^ENABLED=.*$/ENABLED=\\\\\\"true\\\\\\"/g\\\" -i /etc/default/sysstat && \\
sudo sed -e \\\"s/^SADC_OPTIONS=.*$/SADC_OPTIONS=\\\\\\"-S ALL\\\\\\"/g\\\" -i /etc/sysstat/sysstat && \\
sudo service sysstat restart && \\
echo \\\"###### Done! ##########################################################\\\"""".format(
      gitDirectory         = gitDirectory,
      networkRealm         = networkRealm,
      networkDNS1_IPv4     = networkDNS1_IPv4,
      networkDNS2_IPv4     = networkDNS2_IPv4,
      spgwcSXab_IfName     = spgwcSXab_IfName,
      spgwcS11_IfName      = spgwcS11_IfName,
      spgwcS5S8_SGW_IfName = spgwcS5S8_SGW_IfName,
      spgwcS5S8_PGW_IfName = spgwcS5S8_PGW_IfName
   )

   runShellCommands(commands, 'configure_spgwc: configuring SPGW-C',
                    'actions.configure-spgwc', 'spgwccharm.configured-spgwc')




# ###########################################################################
prepare_cassandra_hss_build()
configure_cassandra()
configure_hss()

prepare_mme_build()
configure_mme()

prepare_spgwu_build()
configure_spgwu()

prepare_spgwc_build()
configure_spgwc()
