diff --git a/community-apps/Makefile.config b/community-apps/Makefile.config index f292226..5ba2968 100644 --- a/community-apps/Makefile.config +++ b/community-apps/Makefile.config @@ -7,7 +7,7 @@ VERBOSE := 1 PACKER_LOG := 0 PACKER_HEADLESS := true -SERVICES := service_Lithops +SERVICES := service_Lithops service_UERANSIM .DEFAULT_GOAL := help diff --git a/community-apps/appliances/UERANSIM/appliance.sh b/community-apps/appliances/UERANSIM/appliance.sh new file mode 100644 index 0000000..1966329 --- /dev/null +++ b/community-apps/appliances/UERANSIM/appliance.sh @@ -0,0 +1,259 @@ +# ---------------------------------------------------------------------------- # +# Copyright 2024, OpenNebula Project, OpenNebula Systems # +# # +# Licensed under the Apache License, Version 2.0 (the "License"); you may # +# not use this file except in compliance with the License. You may obtain # +# a copy of the License at # +# # +# http://www.apache.org/licenses/LICENSE-2.0 # +# # +# Unless required by applicable law or agreed to in writing, software # +# distributed under the License is distributed on an "AS IS" BASIS, # +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # +# See the License for the specific language governing permissions and # +# limitations under the License. # +# ---------------------------------------------------------------------------- # + +# UERANSIM Appliance for for OpenNebula Marketplace + +# ------------------------------------------------------------------------------ +# List of contextualization parameters +# ------------------------------------------------------------------------------ +ONE_SERVICE_PARAMS=( + 'ONEAPP_UERAN_NETWORK_MCC' 'configure' 'Mobile Country Code value' 'O|text' + 'ONEAPP_UERAN_NETWORK_MNC' 'configure' 'Mobile Network Code value (2 or 3 digits)' 'O|text' + 'ONEAPP_UERAN_CELL_ID' 'configure' 'NR Cell Identity (36-bit)' 'O|text' + 'ONEAPP_UERAN_GNB_ID' 'configure' 'NR gNB ID length in bits [22...32]' 'O|text' + 'ONEAPP_UERAN_TAC_ID' 'configure' 'Tracking Area Code' 'O|text' + 'ONEAPP_UERAN_AMF_IP' 'configure' 'AMF IP Address' 'O|text' + 'ONEAPP_UERAN_AMF_PORT' 'configure' 'AMF_PORT' 'O|text' + 'ONEAPP_UERAN_SST_ID' 'configure' 'List of supported S-NSSAIs by this gNB slices' 'O|text' + 'ONEAPP_UERAN_UE_IMSI' 'configure' 'IMSI number of the UE. IMSI = [MCC|MNC|MSISDN] (In total 15 digits)' 'O|text' + 'ONEAPP_UERAN_SUBSCRIPTOIN_KEY' 'configure' 'Permanent subscription key' 'O|text' + 'ONEAPP_UERAN_OPERATOR_CODE' 'configure' 'Operator code (OP or OPC) of the UE' 'O|text' + 'ONEAPP_UERAN_VNF_IP' 'configure' 'IP of the virtual router to connect to the OneKE cluster' 'O|text' + 'ONEAPP_UERAN_CORE_SUBNET' 'configure' 'Subnet assigned to the 5G core services' 'O|text' +) + +# ------------------------------------------------------------------------------ +# Appliance metadata +# ------------------------------------------------------------------------------ + +# Appliance metadata +ONE_SERVICE_NAME='UERANSIM - KVM' +ONE_SERVICE_VERSION='1.0.0' #latest +ONE_SERVICE_BUILD=$(date +%s) +ONE_SERVICE_SHORT_DESCRIPTION='Appliance with UERANSIM 5G simulator' +ONE_SERVICE_DESCRIPTION=$(cat < Installs requirements, downloads and unpacks Harbor +# ------------------------------------------------------------------------------ +service_install() { + + msg info "Checking internet access..." + + if ping -c 1 8.8.8.8 &> /dev/null; then + msg info "Internet access OK" + else + msg error "No internet access detected." + exit 1 + fi + + msg info "Installing build dependencies..." + + BUILD_PACKAGES="make gcc g++ cmake" + DEBIAN_FRONTEND=noninteractive + + apt-get update && apt install -y ${BUILD_PACKAGES} curl libsctp-dev lksctp-tools + + msg info "Building UERANSIM..." + + cd /opt + [ ! -d /opt/UERANSIM ] && git clone https://github.com/aligungr/UERANSIM + + if [ ! -f /opt/UERANSIM/build/nr-gnb ]; then + cd UERANSIM + make -j 8 + fi + + if [ $? -ne 0 ]; then + msg error "Error building UERANSIM" + exit 1 + fi + + create_one_service_metadata + + msg info "Purging build dependencies..." + + apt-get purge -y ${BUILD_PACKAGES} + apt-get autoclean + + rm -rf /var/lib/apt/lists/* + + msg info "Installation phase finished" +} + + +# ------------------------------------------------------------------------------ +# Configuration Stage => Senerates gNodeB and UE config files +# ------------------------------------------------------------------------------ +service_configure() { + msg info "Starting configuration..." + + ip route add ${CORE_SUBNET} via ${VNF_IP} + + config_gnb + + config_ue + + msg info "Configuration phase finished" +} + +# Will start gNB and UE +service_bootstrap() { + msg info "Starting bootstrap..." + + # Starting gNB process + /opt/UERANSIM/build/nr-gnb -c /opt/UERANSIM/config/ueransim-gnb.yaml > /var/log/gnb.log & + if [ $? -ne 0 ]; then + msg error "Error starting gNodeB, aborting..." + exit 1 + else + msg info "gNodeB was strarted..." + fi + + sleep 5 + + # Starting UE + /opt/UERANSIM/build/nr-ue -c /opt/UERANSIM/config/ueransim-ue.yaml > /var/log/ue.log & + if [ $? -ne 0 ]; then + msg error "Error starting UE, aborting..." + exit 1 + else + msg info "UE was strarted..." + fi + + msg info "Bootstrap phase finished" +} + +# ------------------------------------------------------------------------------ +# ------------------------------------------------------------------------------ +# Function Definitions +# ------------------------------------------------------------------------------ +# ------------------------------------------------------------------------------ +config_gnb(){ + LOCALIP=$(hostname -I | awk '{print $1}') + # Assuming config/open5gs-gnb.yaml as the default UE config file + cat << EOF > /opt/UERANSIM/config/ueransim-gnb.yaml +mcc: '${NETWORK_MCC}' +mnc: '${NETWORK_MNC}' + +nci: '${CELL_ID}' +idLength: ${GNB_ID_LENGTH} +tac: ${TAC_ID} + +linkIp: 127.0.0.1 # gNB's local IP address for Radio Link Simulation (Usually same with local IP) +ngapIp: ${LOCALIP} # gNB's local IP address for N2 Interface (Usually same with local IP) +gtpIp: ${LOCALIP} # gNB's local IP address for N3 Interface (Usually same with local IP) + +amfConfigs: + - address: ${AMF_IP} + port: ${AMF_PORT} + +slices: + - sst: ${SST_ID} + sd: 0x111111 + +ignoreStreamIds: true + +EOF +} + +config_ue(){ + cat << EOF > /opt/UERANSIM/config/ueransim-ue.yaml +supi: '${UE_IMSI}' +mcc: '${NETWORK_MCC}' +mnc: '${NETWORK_MNC}' + +key: '${SUBSCRIPTOIN_KEY}' +op: '${OPERATOR_CODE}' + +opType: 'OPC' +amf: '8000' + +gnbSearchList: + - 127.0.0.1 + +uacAic: + mps: false + mcs: false + +uacAcc: + normalClass: 0 + class11: false + class12: false + class13: false + class14: false + class15: false + +sessions: + - apn: internet + emergency: false + slice: + sd: "0x111111" + sst: 1 + type: IPv4 + +configured-nssai: + - sst: 1 + sd: 0x111111 + +default-nssai: + - sst: 1 + sd: 0x111111 + +integrity: + IA1: true + IA2: true + IA3: true + +ciphering: + EA1: true + EA2: true + EA3: true + +integrityMaxRate: + uplink: 'full' + downlink: 'full' + +EOF +} diff --git a/community-apps/packer/service_UERANSIM/81-configure-ssh.sh b/community-apps/packer/service_UERANSIM/81-configure-ssh.sh new file mode 100644 index 0000000..856839c --- /dev/null +++ b/community-apps/packer/service_UERANSIM/81-configure-ssh.sh @@ -0,0 +1,29 @@ +#!/usr/bin/env bash + +# Configures critical settings for OpenSSH server. + +exec 1>&2 +set -eux -o pipefail + +gawk -i inplace -f- /etc/ssh/sshd_config <<'EOF' +BEGIN { update = "PasswordAuthentication no" } +/^[#\s]*PasswordAuthentication\s/ { $0 = update; found = 1 } +{ print } +ENDFILE { if (!found) print update } +EOF + +gawk -i inplace -f- /etc/ssh/sshd_config <<'EOF' +BEGIN { update = "PermitRootLogin without-password" } +/^[#\s]*PermitRootLogin\s/ { $0 = update; found = 1 } +{ print } +ENDFILE { if (!found) print update } +EOF + +gawk -i inplace -f- /etc/ssh/sshd_config <<'EOF' +BEGIN { update = "UseDNS no" } +/^[#\s]*UseDNS\s/ { $0 = update; found = 1 } +{ print } +ENDFILE { if (!found) print update } +EOF + +sync diff --git a/community-apps/packer/service_UERANSIM/82-configure-context.sh b/community-apps/packer/service_UERANSIM/82-configure-context.sh new file mode 100644 index 0000000..2278ea9 --- /dev/null +++ b/community-apps/packer/service_UERANSIM/82-configure-context.sh @@ -0,0 +1,14 @@ +#!/usr/bin/env bash + +# Configure and enable service context. + +exec 1>&2 +set -eux -o pipefail + +mv /etc/one-appliance/net-90-service-appliance /etc/one-context.d/ +mv /etc/one-appliance/net-99-report-ready /etc/one-context.d/ + +chown root:root /etc/one-context.d/* +chmod u=rwx,go=rx /etc/one-context.d/* + +sync diff --git a/community-apps/packer/service_UERANSIM/UERANSIM.pkr.hcl b/community-apps/packer/service_UERANSIM/UERANSIM.pkr.hcl new file mode 100644 index 0000000..ae0657c --- /dev/null +++ b/community-apps/packer/service_UERANSIM/UERANSIM.pkr.hcl @@ -0,0 +1,107 @@ +source "null" "null" { communicator = "none" } + +build { + sources = ["source.null.null"] + + provisioner "shell-local" { + inline = [ + "mkdir -p ${var.input_dir}/context", + "${var.input_dir}/gen_context > ${var.input_dir}/context/context.sh", + "mkisofs -o ${var.input_dir}/${var.appliance_name}-context.iso -V CONTEXT -J -R ${var.input_dir}/context", + ] + } +} + +# Build VM image +source "qemu" "UERANSIM" { + cpus = 2 + memory = 2048 + accelerator = "kvm" + + iso_url = "../one-apps/export/ubuntu2204.qcow2" + iso_checksum = "none" + + headless = var.headless + + disk_image = true + disk_cache = "unsafe" + disk_interface = "virtio" + net_device = "virtio-net" + format = "qcow2" + disk_compression = false + disk_size = 10240 + + output_directory = var.output_dir + + qemuargs = [ + ["-cpu", "host"], + ["-cdrom", "${var.input_dir}/${var.appliance_name}-context.iso"], + ["-serial", "stdio"], + # MAC addr needs to mach ETH0_MAC from context iso + ["-netdev", "user,id=net0,hostfwd=tcp::{{ .SSHHostPort }}-:22"], + ["-device", "virtio-net-pci,netdev=net0,mac=00:11:22:33:44:55"] + ] + ssh_username = "root" + ssh_password = "opennebula" + ssh_timeout = "900s" + shutdown_command = "poweroff" + vm_name = "${var.appliance_name}" +} + +build { + sources = ["source.qemu.UERANSIM"] + + # revert insecure ssh options done by context start_script + provisioner "shell" { + scripts = ["${var.input_dir}/81-configure-ssh.sh"] + } + + provisioner "shell" { + inline_shebang = "/bin/bash -e" + inline = [ + "install -o 0 -g 0 -m u=rwx,g=rx,o= -d /etc/one-appliance/{,service.d/,lib/}", + "install -o 0 -g 0 -m u=rwx,g=rx,o=rx -d /opt/one-appliance/{,bin/}", + ] + } + + provisioner "file" { + sources = [ + "../one-apps/appliances/scripts/net-90-service-appliance", + "../one-apps/appliances/scripts/net-99-report-ready", + ] + destination = "/etc/one-appliance/" + } + provisioner "file" { + sources = [ + "../one-apps/appliances/lib/common.sh", + "../one-apps/appliances/lib/functions.sh", + ] + destination = "/etc/one-appliance/lib/" + } + provisioner "file" { + source = "../one-apps/appliances/service.sh" + destination = "/etc/one-appliance/service" + } + provisioner "file" { + sources = ["appliances/UERANSIM/appliance.sh"] + destination = "/etc/one-appliance/service.d/" + } + + provisioner "shell" { + scripts = ["${var.input_dir}/82-configure-context.sh"] + } + + provisioner "shell" { + inline_shebang = "/bin/bash -e" + inline = ["/etc/one-appliance/service install && sync"] + } + + post-processor "shell-local" { + execute_command = ["bash", "-c", "{{.Vars}} {{.Script}}"] + environment_vars = [ + "OUTPUT_DIR=${var.output_dir}", + "APPLIANCE_NAME=${var.appliance_name}", + ] + scripts = ["../one-apps/packer/postprocess.sh"] + } +} diff --git a/community-apps/packer/service_UERANSIM/gen_context b/community-apps/packer/service_UERANSIM/gen_context new file mode 100755 index 0000000..c62f16a --- /dev/null +++ b/community-apps/packer/service_UERANSIM/gen_context @@ -0,0 +1,33 @@ +#!/bin/bash +set -eux -o pipefail + +SCRIPT=$(cat <<'MAINEND' +gawk -i inplace -f- /etc/ssh/sshd_config <<'EOF' +BEGIN { update = "PasswordAuthentication yes" } +/^[#\s]*PasswordAuthentication\s/ { $0 = update; found = 1 } +{ print } +ENDFILE { if (!found) print update } +EOF + +gawk -i inplace -f- /etc/ssh/sshd_config <<'EOF' +BEGIN { update = "PermitRootLogin yes" } +/^[#\s]*PermitRootLogin\s/ { $0 = update; found = 1 } +{ print } +ENDFILE { if (!found) print update } +EOF + +systemctl reload sshd + +echo "nameserver 1.1.1.1" > /etc/resolv.conf +MAINEND +) + +cat<