Commit 0d920a77 authored by Mark Beierl's avatar Mark Beierl
Browse files

Change srsLTE to Full Native Charm



Changes the charm from relying on a prepackaged image to
building srsue and srsenb from tagged source.
Updates the descriptor to use generic name for relation.
Signed-off-by: Mark Beierl's avatarbeierlm <mark.beierl@canonical.com>
parent 8bc30d96
Pipeline #71 passed with stage
in 1 minute and 22 seconds
[submodule "magma/hackfest_magma-agw-enb_vnfd/charms/enodeb/mod/operator"]
path = magma/hackfest_magma-agw-enb_vnfd/charms/enodeb/mod/operator
url = https://github.com/canonical/operator
[submodule "magma/hackfest_magma-agw-enb_vnfd/charms/magmagw/mod/operator"]
path = magma/hackfest_magma-agw-enb_vnfd/charms/magmagw/mod/operator
url = https://github.com/canonical/operator
......
# EnodeB Charm
This is a native charm used by Open Source Mano (OSM) to add day-2 primitive to an enodeB + radio emulator, written in the [Python Operator Framwork](https://github.com/canonical/operator)
../mod/operator/ops
\ No newline at end of file
name: enodeb
summary: A native charm for Enodeb
maintainer: David García <david.garcia@canonical.com>
description: |
A charm to add day-2 primitive to an enodeb and radio simulator VDU
series:
- xenial
- bionic
requires:
agw:
interface: lte-vepc
\ No newline at end of file
Subproject commit a84ce8776b368a8b2bccdb173716e342db9a6b36
#!/usr/bin/env python3
# Copyright 2020 Canonical Ltd.
#
# 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.
import sys
sys.path.append("lib")
from ops.charm import CharmBase
from ops.framework import StoredState
from ops.main import main
from ops.model import (
ActiveStatus,
BlockedStatus,
MaintenanceStatus,
WaitingStatus,
ModelError,
)
import subprocess
import logging
import asyncio
import random
logger = logging.getLogger(__name__)
class EnodebCharm(CharmBase):
state = StoredState()
def __init__(self, *args):
super().__init__(*args)
# An example of setting charm state
# that's persistent across events
self.state.set_default(is_started=False)
if not self.state.is_started:
self.state.is_started = True
# Register all of the events we want to observe
self.framework.observe(self.on.config_changed, self.on_config_changed)
self.framework.observe(self.on.install, self.on_install)
self.framework.observe(self.on.start, self.on_start)
self.framework.observe(self.on.upgrade_charm, self.on_upgrade_charm)
self.framework.observe(self.on.attach_ue_action, self.on_attach_ue_action)
self.framework.observe(self.on.detach_ue_action, self.on_detach_ue_action)
self.framework.observe(self.on.remove_default_gw_action, self.on_remove_default_gw_action)
self.framework.observe(self.on.agw_relation_changed, self.agw_relation_changed)
def on_config_changed(self, event):
"""Handle changes in configuration"""
def on_start(self, event):
"""Called when the charm starts"""
self.unit.status = ActiveStatus()
def on_install(self, event):
"""Called when the charm is being installed"""
def on_upgrade_charm(self, event):
"""Upgrade the charm."""
def agw_relation_changed(self, event):
"""Register to AGW (EPC)."""
self.unit.status = MaintenanceStatus("Getting MagmaGW data from relation")
relation = self.model.get_relation("agw")
if relation is None:
event.defer()
return
self._unregister()
mme_addr = relation.data[event.unit].get("mme-addr", None)
status = "Not registered"
if mme_addr is not None:
self.unit.status = MaintenanceStatus(f"Relation data {dict(relation.data[event.unit])}")
gtp_bind_addr = self._get_bind_address()
s1c_bind_addr = gtp_bind_addr
command = " ".join(
[
"/home/ubuntu/srsLTE/build/srsenb/src/srsenb",
"--enb.name=dummyENB01",
"--enb.mcc=901",
"--enb.mnc=70",
"--enb.mme_addr={}".format(mme_addr),
"--enb.gtp_bind_addr={}".format(gtp_bind_addr),
"--enb.s1c_bind_addr={}".format(s1c_bind_addr),
"--enb_files.rr_config=/configzmq/rr.conf",
"--enb_files.sib_config=/configzmq/sib.conf",
"--enb_files.drb_config=/configzmq/drb.conf",
"/configzmq/enb.conf",
"--rf.device_name=zmq",
"--rf.device_args='fail_on_disconnect=true,tx_port=tcp://*:2000,rx_port=tcp://localhost:2001,id=enb,base_srate=23.04e6'",
]
)
self._run_daemon(command)
status = "Registered"
self.unit.status = ActiveStatus(status)
def _get_bind_address(self):
output = subprocess.run(["hostname", "-I"], check=True, stdout=subprocess.PIPE, stderr=subprocess.PIPE)
return output.stdout.decode("utf-8").split(" ")[1]
def _unregister(self):
"""Unregister"""
self.unit.status = MaintenanceStatus("Unregistering")
subprocess.run("sudo killall -s KILL srsenb", shell=True)
def on_attach_ue_action(self, event):
"""Attach User Emulator to EnodeB."""
try:
usim_imsi = event.params["usim-imsi"]
usim_k = event.params["usim-k"]
usim_opc = event.params["usim-opc"]
command = " ".join(
[
"sudo",
"/home/ubuntu/srsLTE/build/srsue/src/srsue",
"--usim.imsi={}".format(usim_imsi),
"--usim.k={}".format(usim_k),
"--usim.algo=milenage",
"--usim.opc={}".format(usim_opc),
"--nas.apn=oai.ipv4",
"--rf.device_name=zmq",
"--rf.device_args='tx_port=tcp://*:2001,rx_port=tcp://localhost:2000,id=ue,base_srate=23.04e6'",
"/configzmq/ue.conf",
]
)
process = self._run_daemon(command)
event.set_results(
{"status": "ok", "pid": process.pid}
)
except subprocess.CalledProcessError as ex:
event.fail(ex)
def on_detach_ue_action(self, event):
"""Detach UE action"""
try:
command = "sudo killall -s KILL srsue"
output = subprocess.check_output(command, shell=True)
event.set_results(
{"status": "ok", "message": "Detached successfully", "output": output}
)
except subprocess.CalledProcessError as e:
event.fail("Command error: {}".format(e.output))
except Exception as e:
event.fail(e)
def on_remove_default_gw_action(self, event):
"""Remove default gw"""
try:
command = "sudo route del default"
output = subprocess.check_output(command, shell=True)
event.set_results(
{"status": "ok", "message": "Default route removed!", "output": output}
)
except subprocess.CalledProcessError as e:
event.fail("Command error: {}".format(e.output))
except Exception as e:
event.fail(e)
def _run_daemon(self, cmd):
log_basename = random.randint(1000, 100000)
stdout_file = f"/tmp/{log_basename}.stdout"
stderr_file = f"/tmp/{log_basename}.stderr"
with open(stdout_file, "wb") as o:
with open(stderr_file, "wb") as e:
return subprocess.Popen(cmd, shell=True, stdout=o, stderr=e)
if __name__ == "__main__":
main(EnodebCharm)
This diff is collapsed.
# srs-lte
## Description
Operations packages for SRS EnodeB and User Emulator
## Usage
### Prepare the environment
```bash
sudo snap install juju --classic --channel 2.8/stable
sudo snap install lxd
lxd.init
juju bootstrap lxd
juju add-model test-srs-enb-ue
```
### Deploy (from the Store)
```bash
juju deploy cs:~charmed-osm/srs-enb-ue --channel edge
```
### Deploy (locally)
Build the charm:
```bash
virtualenv -p python3 venv
source venv/bin/activate
pip install -r requirements-dev.txt
pip install charmcraft
./venv/bin/charmcraft build
```
Deploy:
```bash
juju deploy ./srs-enb-ue.charm
```
## Developing
Create and activate a virtualenv with the development requirements:
virtualenv -p python3 venv
source venv/bin/activate
pip install -r requirements-dev.txt
## Testing
The Python operator framework includes a very nice harness for testing
operator behaviour without full deployment. Just `run_tests`:
./run_tests
# Copyright 2020 David Garcia
# See LICENSE file for licensing details.
#
# This is only an example, and you should edit to suit your needs.
# If you don't need actions, you can remove the file entirely.
# It ties in to the example _on_fortune_action handler in src/charm.py
attach-ue:
description: Attach User Emulator to enodeB
params:
usim-imsi:
description: "USIM IMSI"
type: string
default: ""
usim-k:
description: "USIM K"
type: string
default: ""
usim-opc:
description: "USIM OPC"
type: string
default: ""
required:
- usim-imsi
- usim-k
......
# Copyright 2020 David Garcia
# See LICENSE file for licensing details.
#
# This is only an example, and you should edit to suit your needs.
# If you don't need config, you can remove the file entirely.
options:
bind-address-subnet:
type: string
description: |
The selected bind address will need to be part of this subnet.
If this is not set, it will use the IP address from the default interface.
default: ""
enb-name:
type: string
description: |
TODO
default: dummyENB01
enb-mcc:
type: int
description: |
TODO
default: 901
enb-mnc:
type: int
description: |
TODO
default: 70
enb-rf-device-name:
type: string
description: |
TODO
default: "zmq"
enb-rf-device-args:
type: string
description: |
TODO
default: fail_on_disconnect=true,tx_port=tcp://*:2000,rx_port=tcp://localhost:2001,id=enb,base_srate=23.04e6
ue-usim-algo:
type: string
description: |
TODO
default: milenage
ue-nas-apn:
type: string
description: |
TODO
default: oai.ipv4
ue-device-name:
type: string
description: |
TODO
default: zmq
ue-device-args:
type: string
description: |
TODO
default: tx_port=tcp://*:2001,rx_port=tcp://localhost:2000,id=ue,base_srate=23.04e6
#!/bin/sh
JUJU_DISPATCH_PATH="${JUJU_DISPATCH_PATH:-$0}" PYTHONPATH=lib:venv ./src/charm.py
# Copyright 2020 David Garcia
# See LICENSE file for licensing details.
name: srs-enb-ue
description: |
TODO: fill out the charm's description
summary: |
TODO: fill out the charm's summary
series:
- focal
requires:
mme:
interface: lte-vepc # s1c
\ No newline at end of file
-r requirements.txt
flake8
charmcraft
\ No newline at end of file
ops
psutil
netifaces
netaddr
jinja2
\ No newline at end of file
#!/bin/sh -e
# Copyright 2020 David Garcia
# See LICENSE file for licensing details.
if [ -z "$VIRTUAL_ENV" -a -d venv/ ]; then
. venv/bin/activate
fi
if [ -z "$PYTHONPATH" ]; then
export PYTHONPATH=src
else
export PYTHONPATH="src:$PYTHONPATH"
fi
flake8
python3 -m unittest -v "$@"
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment