laforge has submitted this change. ( https://gerrit.osmocom.org/c/pysim/+/41148?usp=email )
Change subject: Fix typos
......................................................................
Fix typos
Found via `codespell -S tests -L ist,adn,ciph,ue,ot,readd,te,oce,tye`
Change-Id: I00a72e4f479dcef88f7d1058ce53edd0129d336a
---
M contrib/es2p_client.py
M contrib/es9p_client.py
M contrib/saip-tool.py
M contrib/saip-tool_example_add-app.sh
M contrib/unber.py
M docs/legacy.rst
M docs/osmo-smdpp.rst
M docs/sim-rest.rst
M docs/suci-tutorial.rst
M osmo-smdpp.py
M pySim-prog.py
M pySim-read.py
M pySim-shell.py
M pySim-smpp2sim.py
M pySim-trace.py
M pySim/ara_m.py
M pySim/card_key_provider.py
M pySim/cat.py
M pySim/commands.py
M pySim/esim/es2p.py
M pySim/esim/es9p.py
M pySim/esim/http_json_api.py
M pySim/esim/rsp.py
M pySim/esim/saip/__init__.py
M pySim/esim/saip/validation.py
M pySim/filesystem.py
M pySim/global_platform/__init__.py
M pySim/global_platform/uicc.py
M pySim/javacard.py
M pySim/legacy/cards.py
M pySim/legacy/utils.py
M pySim/profile.py
M pySim/runtime.py
M pySim/secure_channel.py
M pySim/transport/__init__.py
M pySim/ts_31_102.py
M pySim/ts_31_103_shared.py
M pySim/ts_51_011.py
M pySim/utils.py
39 files changed, 81 insertions(+), 81 deletions(-)
Approvals:
laforge: Looks good to me, approved
Jenkins Builder: Verified
diff --git a/contrib/es2p_client.py b/contrib/es2p_client.py
index 8eda6d0..5c8ea33 100755
--- a/contrib/es2p_client.py
+++ b/contrib/es2p_client.py
@@ -24,7 +24,7 @@
MATCHID_HELP='MatchingID that shall be used by profile download'
parser = argparse.ArgumentParser(description="""
-Utility to manuall issue requests against the ES2+ API of an SM-DP+ according to GSMA SGP.22.""")
+Utility to manually issue requests against the ES2+ API of an SM-DP+ according to GSMA SGP.22.""")
parser.add_argument('--url', required=True, help='Base URL of ES2+ API endpoint')
parser.add_argument('--id', required=True, help='Entity identifier passed to SM-DP+')
parser.add_argument('--client-cert', help='X.509 client certificate used to authenticate to server')
@@ -63,7 +63,7 @@
data = {}
for k, v in vars(opts).items():
if k in ['url', 'id', 'client_cert', 'server_ca_cert', 'command']:
- # remove keys from dict that shold not end up in JSON...
+ # remove keys from dict that should not end up in JSON...
continue
if v is not None:
data[k] = v
diff --git a/contrib/es9p_client.py b/contrib/es9p_client.py
index d4c91f3..15a96ae 100755
--- a/contrib/es9p_client.py
+++ b/contrib/es9p_client.py
@@ -68,7 +68,7 @@
# notification
parser_ntf = subparsers.add_parser('notification', help='ES9+ (other) notification')
parser_ntf.add_argument('operation', choices=['enable','disable','delete'],
- help='Profile Management Opreation whoise occurrence shall be notififed')
+ help='Profile Management Operation whoise occurrence shall be notififed')
parser_ntf.add_argument('--sequence-nr', type=int, required=True,
help='eUICC global notification sequence number')
parser_ntf.add_argument('--notification-address', help='notificationAddress, if different from URL')
diff --git a/contrib/saip-tool.py b/contrib/saip-tool.py
index 9fc111c..fd6d373 100755
--- a/contrib/saip-tool.py
+++ b/contrib/saip-tool.py
@@ -56,7 +56,7 @@
parser_rpe.add_argument('--identification', default=[], type=int, action='append', help='Remove PEs matching specified identification')
parser_rpe.add_argument('--type', default=[], action='append', help='Remove PEs matching specified type')
-parser_rn = subparsers.add_parser('remove-naa', help='Remove speciifed NAAs from PE-Sequence')
+parser_rn = subparsers.add_parser('remove-naa', help='Remove specified NAAs from PE-Sequence')
parser_rn.add_argument('--output-file', required=True, help='Output file name')
parser_rn.add_argument('--naa-type', required=True, choices=NAAs.keys(), help='Network Access Application type to remove')
# TODO: add an --naa-index or the like, so only one given instance can be removed
diff --git a/contrib/saip-tool_example_add-app.sh b/contrib/saip-tool_example_add-app.sh
index 5605a4b..a1a1588 100755
--- a/contrib/saip-tool_example_add-app.sh
+++ b/contrib/saip-tool_example_add-app.sh
@@ -27,5 +27,5 @@
# Display the contents of the resulting application PE:
PYTHONPATH=$PYSIMPATH python3 $PYSIMPATH/contrib/saip-tool.py $OUTPATH info --apps
-# For an explaination of --uicc-toolkit-app-spec-pars, see:
+# For an explanation of --uicc-toolkit-app-spec-pars, see:
# ETSI TS 102 226, section 8.2.1.3.2.2.1
diff --git a/contrib/unber.py b/contrib/unber.py
index 50831cb..0a79ff4 100755
--- a/contrib/unber.py
+++ b/contrib/unber.py
@@ -1,6 +1,6 @@
#!/usr/bin/env python3
-# A more useful verion of the 'unber' tool provided with asn1c:
+# A more useful version of the 'unber' tool provided with asn1c:
# Give a hierarchical decode of BER/DER-encoded ASN.1 TLVs
import sys
diff --git a/docs/legacy.rst b/docs/legacy.rst
index 45dddde..b571145 100644
--- a/docs/legacy.rst
+++ b/docs/legacy.rst
@@ -49,7 +49,7 @@
Ki and OPc will be generated during each programming cycle. This means fresh keys are generated, even when the
``--num`` remains unchanged.
- The parameter ``--num`` specifies a card individual number. This number will be manged into the random seed so that
+ The parameter ``--num`` specifies a card individual number. This number will be managed into the random seed so that
it serves as an identifier for a particular set of randomly generated parameters.
In the example above the parameters ``--mcc``, and ``--mnc`` are specified as well, since they identify the GSM
@@ -77,7 +77,7 @@
Specifying the card reader:
-It is most common to use ``pySim-prog`` together whith a PCSC reader. The PCSC reader number is specified via the
+It is most common to use ``pySim-prog`` together with a PCSC reader. The PCSC reader number is specified via the
``--pcsc-device`` or ``-p`` option. However, other reader types (such as serial readers and modems) are supported. Use
the ``--help`` option of ``pySim-prog`` for more information.
diff --git a/docs/osmo-smdpp.rst b/docs/osmo-smdpp.rst
index 0eab290..3502003 100644
--- a/docs/osmo-smdpp.rst
+++ b/docs/osmo-smdpp.rst
@@ -21,9 +21,9 @@
* [by default] uses test certificates copied from GSMA SGP.26 into `./smdpp-data/certs`, assuming that your
osmo-smdpp would be running at the host name `testsmdpplus1.example.com`. You can of course replace those
- certificates with your own, whether SGP.26 derived or part of a *private root CA* setup with mathcing eUICCs.
+ certificates with your own, whether SGP.26 derived or part of a *private root CA* setup with matching eUICCs.
* doesn't understand profile state. Any profile can always be downloaded any number of times, irrespective
- of the EID or whether it was donwloaded before. This is actually very useful for R&D and testing, as it
+ of the EID or whether it was downloaded before. This is actually very useful for R&D and testing, as it
doesn't require you to generate new profiles all the time. This logic of course is unsuitable for
production usage.
* doesn't perform any personalization, so the IMSI/ICCID etc. are always identical (the ones that are stored in
diff --git a/docs/sim-rest.rst b/docs/sim-rest.rst
index 41a6d1d..2949b61 100644
--- a/docs/sim-rest.rst
+++ b/docs/sim-rest.rst
@@ -75,7 +75,7 @@
#. key freshness failure
#. unspecified card error
-Example (succcess):
+Example (success):
::
{
diff --git a/docs/suci-tutorial.rst b/docs/suci-tutorial.rst
index cdf44c9..6d9a0db 100644
--- a/docs/suci-tutorial.rst
+++ b/docs/suci-tutorial.rst
@@ -30,7 +30,7 @@
For specific information on sysmocom SIM cards, refer to
-* the `sysmoISIM-SJA5 User Manual <https://sysmocom.de/manuals/sysmoisim-sja5-manual.pdf>`__ for the curent
+* the `sysmoISIM-SJA5 User Manual <https://sysmocom.de/manuals/sysmoisim-sja5-manual.pdf>`__ for the current
sysmoISIM-SJA5 product
* the `sysmoISIM-SJA2 User Manual <https://sysmocom.de/manuals/sysmousim-manual.pdf>`__ for the older
sysmoISIM-SJA2 product
diff --git a/osmo-smdpp.py b/osmo-smdpp.py
index 94e64e8..a45f842 100755
--- a/osmo-smdpp.py
+++ b/osmo-smdpp.py
@@ -651,7 +651,7 @@
# there's currently no other option in the ctxParams1 choice, so this cannot happen
raise ApiError('1.3.1', '2.2', 'ctxParams1 missing mandatory ctxParamsForCommonAuthentication')
- # FIXME: we actually want to perform the profile binding herr, and read the profile metadat from the profile
+ # FIXME: we actually want to perform the profile binding herr, and read the profile metadata from the profile
# Put together profileMetadata + _bin
ss.profileMetadata = ProfileMetadata(iccid_bin=h2b(swap_nibbles(iccid_str)), spn="OsmocomSPN", profile_name=matchingId)
@@ -738,14 +738,14 @@
# Perform actual protection + binding of profile package (or return pre-bound one)
with open(os.path.join(self.upp_dir, ss.matchingId)+'.der', 'rb') as f:
upp = UnprotectedProfilePackage.from_der(f.read(), metadata=ss.profileMetadata)
- # HACK: Use empty PPP as we're still debuggin the configureISDP step, and we want to avoid
+ # HACK: Use empty PPP as we're still debugging the configureISDP step, and we want to avoid
# cluttering the log with stuff happening after the failure
#upp = UnprotectedProfilePackage.from_der(b'', metadata=ss.profileMetadata)
if False:
# Use random keys
bpp = BoundProfilePackage.from_upp(upp)
else:
- # Use sesssion keys
+ # Use session keys
ppp = ProtectedProfilePackage.from_upp(upp, BspInstance(b'\x00'*16, b'\x11'*16, b'\x22'*16))
bpp = BoundProfilePackage.from_ppp(ppp)
diff --git a/pySim-prog.py b/pySim-prog.py
index b6c86af..760a650 100755
--- a/pySim-prog.py
+++ b/pySim-prog.py
@@ -586,7 +586,7 @@
else:
row['mnc'] = row.get('mnc', mnc_from_imsi(row.get('imsi'), False))
- # NOTE: We might concider to specify a new CSV field "mnclen" in our
+ # NOTE: We might consider to specify a new CSV field "mnclen" in our
# CSV files for a better automatization. However, this only makes sense
# when the tools and databases we export our files from will also add
# such a field.
diff --git a/pySim-read.py b/pySim-read.py
index 91e17ae..9829a15 100755
--- a/pySim-read.py
+++ b/pySim-read.py
@@ -1,7 +1,7 @@
#!/usr/bin/env python3
#
-# Utility to display some informations about a SIM card
+# Utility to display some information about a SIM card
#
#
# Copyright (C) 2009 Sylvain Munaut <tnt(a)246tNt.com>
diff --git a/pySim-shell.py b/pySim-shell.py
index c59e481..977666c 100755
--- a/pySim-shell.py
+++ b/pySim-shell.py
@@ -265,7 +265,7 @@
def do_apdu(self, opts):
"""Send a raw APDU to the card, and print SW + Response.
CAUTION: this command bypasses the logical channel handling of pySim-shell and card state changes are not
- tracked. Dpending on the raw APDU sent, pySim-shell may not continue to work as expected if you e.g. select
+ tracked. Depending on the raw APDU sent, pySim-shell may not continue to work as expected if you e.g. select
a different file."""
# When sending raw APDUs we access the scc object through _scc member of the card object. It should also be
@@ -336,7 +336,7 @@
def _process_card(self, first, script_path):
- # Early phase of card initialzation (this part may fail with an exception)
+ # Early phase of card initialization (this part may fail with an exception)
try:
rs, card = init_card(self.sl)
rc = self.equip(card, rs)
@@ -377,7 +377,7 @@
bulk_script_parser = argparse.ArgumentParser()
bulk_script_parser.add_argument('SCRIPT_PATH', help="path to the script file")
- bulk_script_parser.add_argument('--halt_on_error', help='stop card handling if an exeption occurs',
+ bulk_script_parser.add_argument('--halt_on_error', help='stop card handling if an exception occurs',
action='store_true')
bulk_script_parser.add_argument('--tries', type=int, default=2,
help='how many tries before trying the next card')
@@ -731,7 +731,7 @@
body = {}
for t in tags:
result = self._cmd.lchan.retrieve_data(t)
- (tag, l, val, remainer) = bertlv_parse_one(h2b(result[0]))
+ (tag, l, val, remainder) = bertlv_parse_one(h2b(result[0]))
body[t] = b2h(val)
else:
raise RuntimeError('Unsupported structure "%s" of file "%s"' % (structure, filename))
diff --git a/pySim-smpp2sim.py b/pySim-smpp2sim.py
index 70eb622..fa670e5 100755
--- a/pySim-smpp2sim.py
+++ b/pySim-smpp2sim.py
@@ -84,7 +84,7 @@
logger.error("%s: connected!" % p)
class ProactChannel:
- """Representation of a single proective channel."""
+ """Representation of a single protective channel."""
def __init__(self, channels: 'ProactChannels', chan_nr: int):
self.channels = channels
self.chan_nr = chan_nr
diff --git a/pySim-trace.py b/pySim-trace.py
index a45fcfc..09e9584 100755
--- a/pySim-trace.py
+++ b/pySim-trace.py
@@ -151,7 +151,7 @@
global_group.add_argument('--no-suppress-status', action='store_false', dest='suppress_status',
help="""
Don't suppress displaying STATUS APDUs. We normally suppress them as they don't provide any
- information that was not already received in resposne to the most recent SEELCT.""")
+ information that was not already received in response to the most recent SEELCT.""")
global_group.add_argument('--show-raw-apdu', action='store_true', dest='show_raw_apdu',
help="""Show the raw APDU in addition to its parsed form.""")
@@ -188,7 +188,7 @@
parser_tcaloader_log = subparsers.add_parser('tca-loader-log', help="""
Read APDUs from a TCA Loader log file.""")
parser_tcaloader_log.add_argument('-f', '--log-file', required=True,
- help='Name of te log file to be read')
+ help='Name of the log file to be read')
if __name__ == '__main__':
diff --git a/pySim/ara_m.py b/pySim/ara_m.py
index 9079a97..b338c43 100644
--- a/pySim/ara_m.py
+++ b/pySim/ara_m.py
@@ -317,7 +317,7 @@
store_ref_ar_do_parse = argparse.ArgumentParser()
# REF-DO
store_ref_ar_do_parse.add_argument(
- '--device-app-id', required=True, help='Identifies the specific device application that the rule appplies to. Hash of Certificate of Application Provider, or UUID. (20/32 hex bytes)')
+ '--device-app-id', required=True, help='Identifies the specific device application that the rule applies to. Hash of Certificate of Application Provider, or UUID. (20/32 hex bytes)')
aid_grp = store_ref_ar_do_parse.add_mutually_exclusive_group()
aid_grp.add_argument(
'--aid', help='Identifies the specific SE application for which rules are to be stored. Can be a partial AID, containing for example only the RID. (5-16 or 0 hex bytes)')
@@ -399,7 +399,7 @@
sw_aram = {
'ARA-M': {
'6381': 'Rule successfully stored but an access rule already exists',
- '6382': 'Rule successfully stored bu contained at least one unknown (discarded) BER-TLV',
+ '6382': 'Rule successfully stored but contained at least one unknown (discarded) BER-TLV',
'6581': 'Memory Problem',
'6700': 'Wrong Length in Lc',
'6981': 'DO is not supported by the ARA-M/ARA-C',
diff --git a/pySim/card_key_provider.py b/pySim/card_key_provider.py
index 72cfa85..d5541b0 100644
--- a/pySim/card_key_provider.py
+++ b/pySim/card_key_provider.py
@@ -163,7 +163,7 @@
provider_list : override the list of providers from the global default
"""
if not isinstance(provider, CardKeyProvider):
- raise ValueError("provider is not a card data provier")
+ raise ValueError("provider is not a card data provider")
provider_list.append(provider)
@@ -181,7 +181,7 @@
for p in provider_list:
if not isinstance(p, CardKeyProvider):
raise ValueError(
- "provider list contains element which is not a card data provier")
+ "provider list contains element which is not a card data provider")
result = p.get(fields, key, value)
if result:
return result
@@ -202,7 +202,7 @@
for p in provider_list:
if not isinstance(p, CardKeyProvider):
raise ValueError(
- "provider list contains element which is not a card data provier")
+ "provider list contains element which is not a card data provider")
result = p.get_field(field, key, value)
if result:
return result
diff --git a/pySim/cat.py b/pySim/cat.py
index 2d4b41b..d755545 100644
--- a/pySim/cat.py
+++ b/pySim/cat.py
@@ -316,19 +316,19 @@
_construct = Struct('number_of_files'/Int8ub,
'files'/GreedyRange(FileId))
-# TS 102 223 Secton 8.19
+# TS 102 223 Section 8.19
class LocationInformation(COMPR_TLV_IE, tag=0x93):
pass
-# TS 102 223 Secton 8.20
+# TS 102 223 Section 8.20
class IMEI(COMPR_TLV_IE, tag=0x94):
_construct = BcdAdapter(GreedyBytes)
-# TS 102 223 Secton 8.21
+# TS 102 223 Section 8.21
class HelpRequest(COMPR_TLV_IE, tag=0x95):
pass
-# TS 102 223 Secton 8.22
+# TS 102 223 Section 8.22
class NetworkMeasurementResults(COMPR_TLV_IE, tag=0x96):
_construct = BcdAdapter(GreedyBytes)
diff --git a/pySim/commands.py b/pySim/commands.py
index dd58109..f069db4 100644
--- a/pySim/commands.py
+++ b/pySim/commands.py
@@ -285,7 +285,7 @@
return self.send_apdu_checksw(self.cla_byte + "a40304")
def select_adf(self, aid: Hexstr) -> ResTuple:
- """Execute SELECT a given Applicaiton ADF.
+ """Execute SELECT a given Application ADF.
Args:
aid : application identifier as hex string
@@ -577,7 +577,7 @@
Args:
rand : 16 byte random data as hex string (RAND)
- autn : 8 byte Autentication Token (AUTN)
+ autn : 8 byte Authentication Token (AUTN)
context : 16 byte random data ('3g' or 'gsm')
"""
# 3GPP TS 31.102 Section 7.1.2.1
diff --git a/pySim/esim/es2p.py b/pySim/esim/es2p.py
index 954c7dc..b917b47 100644
--- a/pySim/esim/es2p.py
+++ b/pySim/esim/es2p.py
@@ -116,7 +116,7 @@
pass
class Es2PlusApiFunction(JsonHttpApiFunction):
- """Base classs for representing an ES2+ API Function."""
+ """Base class for representing an ES2+ API Function."""
pass
# ES2+ DownloadOrder function (SGP.22 section 5.3.1)
diff --git a/pySim/esim/es9p.py b/pySim/esim/es9p.py
index 2c4b10f..0d22219 100644
--- a/pySim/esim/es9p.py
+++ b/pySim/esim/es9p.py
@@ -1,4 +1,4 @@
-"""GSMA eSIM RSP ES9+ interface according ot SGP.22 v2.5"""
+"""GSMA eSIM RSP ES9+ interface according to SGP.22 v2.5"""
# (C) 2024 by Harald Welte <laforge(a)osmocom.org>
#
diff --git a/pySim/esim/http_json_api.py b/pySim/esim/http_json_api.py
index ae32ba1..8324bb9 100644
--- a/pySim/esim/http_json_api.py
+++ b/pySim/esim/http_json_api.py
@@ -159,7 +159,7 @@
return f'{self.status}("{self.subject_code}","{self.reason_code}","{self.subject_id}","{self.message}")'
class JsonHttpApiFunction(abc.ABC):
- """Base classs for representing an HTTP[s] API Function."""
+ """Base class for representing an HTTP[s] API Function."""
# the below class variables are expected to be overridden in derived classes
path = None
diff --git a/pySim/esim/rsp.py b/pySim/esim/rsp.py
index 6ab3fa3..bab9123 100644
--- a/pySim/esim/rsp.py
+++ b/pySim/esim/rsp.py
@@ -90,7 +90,7 @@
# FIXME: how to add the public key from smdp_otpk to an instance of EllipticCurvePrivateKey?
del state['_smdp_otsk']
del state['_smdp_ot_curve']
- # automatically recover all the remainig state
+ # automatically recover all the remaining state
self.__dict__.update(state)
diff --git a/pySim/esim/saip/__init__.py b/pySim/esim/saip/__init__.py
index 305a373..c97195f 100644
--- a/pySim/esim/saip/__init__.py
+++ b/pySim/esim/saip/__init__.py
@@ -334,7 +334,7 @@
self.fill_pattern = pefi['fillPattern']
self.fill_pattern_repeat = False
elif fdb_dec['file_type'] == 'df':
- # only set it, if an earlier call to from_template() didn't alrady set it, as
+ # only set it, if an earlier call to from_template() didn't already set it, as
# the template can differentiate between MF, DF and ADF (unlike FDB)
if not self.file_type:
self.file_type = 'DF'
@@ -427,7 +427,7 @@
class ProfileElement:
"""Generic Class representing a Profile Element (PE) within a SAIP Profile. This may be used directly,
- but ist more likely sub-classed with a specific class for the specific profile element type, like e.g
+ but it's more likely sub-classed with a specific class for the specific profile element type, like e.g
ProfileElementHeader, ProfileElementMF, ...
"""
FILE_BEARING = ['mf', 'cd', 'telecom', 'usim', 'opt-usim', 'isim', 'opt-isim', 'phonebook', 'gsm-access',
@@ -440,7 +440,7 @@
'genericFileManagement': 'gfm-header',
'akaParameter': 'aka-header',
'cdmaParameter': 'cdma-header',
- # note how they couldn't even consistently captialize the 'header' suffix :(
+ # note how they couldn't even consistently capitalize the 'header' suffix :(
'application': 'app-Header',
'pukCodes': 'puk-Header',
'pinCodes': 'pin-Header',
@@ -628,7 +628,7 @@
# this is a template that belongs into the [A]DF of another template
# 1) find the PE for the referenced template
parent_pe = self.pe_sequence.get_closest_prev_pe_for_templateID(self, template.parent.oid)
- # 2) resolve te [A]DF that forms the base of that parent PE
+ # 2) resolve the [A]DF that forms the base of that parent PE
pe_df = parent_pe.files[template.parent.base_df().pe_name].node
self.pe_sequence.cur_df = pe_df
self.pe_sequence.cur_df = self.pe_sequence.cur_df.add_file(file)
@@ -649,7 +649,7 @@
self.add_file(file)
def create_file(self, pename: str) -> File:
- """Programatically create a file by its PE-Name."""
+ """Programmatically create a file by its PE-Name."""
template = templates.ProfileTemplateRegistry.get_by_oid(self.templateID)
file = File(pename, None, template.files_by_pename.get(pename, None))
self.add_file(file)
@@ -1409,7 +1409,7 @@
iccid: Optional[Hexstr] = '0'*20, profile_type: Optional[str] = None,
**kwargs):
"""You would usually initialize an instance either with a "decoded" argument (as read from
- a DER-encoded SAIP file via asn1tools), or [some of] the othe arguments in case you're
+ a DER-encoded SAIP file via asn1tools), or [some of] the other arguments in case you're
constructing a Profile Header from scratch.
Args:
@@ -1562,7 +1562,7 @@
def _rebuild_pes_by_naa(self) -> None:
"""rebuild the self.pes_by_naa dict {naa: [ [pe, pe, pe], [pe, pe] ]} form,
- which basically means for every NAA there's a lsit of instances, and each consists
+ which basically means for every NAA there's a list of instances, and each consists
of a list of a list of PEs."""
self.pres_by_naa = {}
petype_not_naa_related = ['securityDomain', 'rfm', 'application', 'end']
@@ -1690,7 +1690,7 @@
i += 1
def get_index_by_pe(self, pe: ProfileElement) -> int:
- """Return a list with the indicies of all instances of PEs of petype."""
+ """Return a list with the indices of all instances of PEs of petype."""
ret = []
i = 0
for cur in self.pe_list:
@@ -1711,7 +1711,7 @@
self.insert_at_index(idx+1, pe_new)
def get_index_by_type(self, petype: str) -> List[int]:
- """Return a list with the indicies of all instances of PEs of petype."""
+ """Return a list with the indices of all instances of PEs of petype."""
ret = []
i = 0
for pe in self.pe_list:
@@ -1736,7 +1736,7 @@
for service in naa.mandatory_services:
if service in hdr.decoded['eUICC-Mandatory-services']:
del hdr.decoded['eUICC-Mandatory-services'][service]
- # remove any associaed mandatory filesystem templates
+ # remove any associated mandatory filesystem templates
for template in naa.templates:
if template in hdr.decoded['eUICC-Mandatory-GFSTEList']:
hdr.decoded['eUICC-Mandatory-GFSTEList'] = [x for x in hdr.decoded['eUICC-Mandatory-GFSTEList'] if not template.prefix_match(x)]
diff --git a/pySim/esim/saip/validation.py b/pySim/esim/saip/validation.py
index c115554..5e0323a 100644
--- a/pySim/esim/saip/validation.py
+++ b/pySim/esim/saip/validation.py
@@ -68,7 +68,7 @@
def check_optional_ordering(self, pes: ProfileElementSequence):
"""Check the ordering of optional PEs following the respective mandatory ones."""
- # ordering and required depenencies
+ # ordering and required dependencies
self._is_after_if_exists(pes,'opt-usim', 'usim')
self._is_after_if_exists(pes,'opt-isim', 'isim')
self._is_after_if_exists(pes,'gsm-access', 'usim')
diff --git a/pySim/filesystem.py b/pySim/filesystem.py
index 1d71e08..b5d1868 100644
--- a/pySim/filesystem.py
+++ b/pySim/filesystem.py
@@ -86,7 +86,7 @@
self.service = service
self.shell_commands = [] # type: List[CommandSet]
- # Note: the basic properties (fid, name, ect.) are verified when
+ # Note: the basic properties (fid, name, etc.) are verified when
# the file is attached to a parent file. See method add_file() in
# class Card DF
@@ -266,7 +266,7 @@
def get_profile(self):
"""Get the profile associated with this file. If this file does not have any
profile assigned, try to find a file above (usually the MF) in the filesystem
- hirarchy that has a profile assigned
+ hierarchy that has a profile assigned
"""
# If we have a profile set, return it
@@ -679,7 +679,7 @@
Args:
fid : File Identifier (4 hex digits)
sfid : Short File Identifier (2 hex digits, optional)
- name : Brief name of the file, lik EF_ICCID
+ name : Brief name of the file, like EF_ICCID
desc : Description of the file
parent : Parent CardFile object within filesystem hierarchy
size : tuple of (minimum_size, recommended_size)
@@ -982,11 +982,11 @@
Args:
fid : File Identifier (4 hex digits)
sfid : Short File Identifier (2 hex digits, optional)
- name : Brief name of the file, lik EF_ICCID
+ name : Brief name of the file, like EF_ICCID
desc : Description of the file
parent : Parent CardFile object within filesystem hierarchy
rec_len : Tuple of (minimum_length, recommended_length)
- leftpad: On write, data must be padded from the left to fit pysical record length
+ leftpad: On write, data must be padded from the left to fit physical record length
"""
super().__init__(fid=fid, sfid=sfid, name=name, desc=desc, parent=parent, **kwargs)
self.rec_len = rec_len
@@ -1422,7 +1422,7 @@
Args:
fid : File Identifier (4 hex digits)
sfid : Short File Identifier (2 hex digits, optional)
- name : Brief name of the file, lik EF_ICCID
+ name : Brief name of the file, like EF_ICCID
desc : Description of the file
parent : Parent CardFile object within filesystem hierarchy
size : tuple of (minimum_size, recommended_size)
@@ -1455,7 +1455,7 @@
export_str += "delete_all\n"
for t in tags:
result = lchan.retrieve_data(t)
- (tag, l, val, remainer) = bertlv_parse_one(h2b(result[0]))
+ (tag, l, val, remainder) = bertlv_parse_one(h2b(result[0]))
export_str += ("set_data 0x%02x %s\n" % (t, b2h(val)))
return export_str.strip()
@@ -1495,7 +1495,7 @@
self.name = name
self.adf = adf
self.sw = sw or {}
- # back-reference from ADF to Applicaiton
+ # back-reference from ADF to Application
if self.adf:
self.aid = aid or self.adf.aid
self.adf.application = self
@@ -1572,7 +1572,7 @@
p = p.split('/')
elif len(p) and isinstance(p[0], int):
p = ['%04x' % x for x in p]
- # make sure internal representation alwas is uppercase only
+ # make sure internal representation always is uppercase only
self.list = [x.upper() for x in p]
def __str__(self) -> str:
diff --git a/pySim/global_platform/__init__.py b/pySim/global_platform/__init__.py
index bfd5e5d..8a99677 100644
--- a/pySim/global_platform/__init__.py
+++ b/pySim/global_platform/__init__.py
@@ -627,7 +627,7 @@
kcv_bin = compute_kcv(opts.key_type[i], h2b(opts.key_data[i])) or b''
kcv = b2h(kcv_bin)
if self._cmd.lchan.scc.scp:
- # encrypte key data with DEK of current SCP
+ # encrypted key data with DEK of current SCP
kcb = b2h(self._cmd.lchan.scc.scp.encrypt_key(h2b(opts.key_data[i])))
else:
# (for example) during personalization, DEK might not be required)
@@ -755,7 +755,7 @@
inst_load_parser = argparse.ArgumentParser()
inst_load_parser.add_argument('--load-file-aid', type=is_hexstr, required=True,
- help='AID of the loded file')
+ help='AID of the loaded file')
inst_load_parser.add_argument('--security-domain-aid', type=is_hexstr, default='',
help='AID of the Security Domain into which the file shalle be added')
inst_load_parser.add_argument('--load-file-hash', type=is_hexstr, default='',
@@ -845,7 +845,7 @@
# TODO:tune chunk_len based on the overhead of the used SCP?
# build TLV according to GPC_SPE_034 section 11.6.2.3 / Table 11-58 for unencrypted case
remainder = b'\xC4' + bertlv_encode_len(len(contents)) + contents
- # transfer this in vaious chunks to the card
+ # transfer this in various chunks to the card
total_size = len(remainder)
block_nr = 0
while len(remainder):
diff --git a/pySim/global_platform/uicc.py b/pySim/global_platform/uicc.py
index 97c0df0..a29438e 100644
--- a/pySim/global_platform/uicc.py
+++ b/pySim/global_platform/uicc.py
@@ -104,4 +104,4 @@
# KID 0x02: SK.CASD.AUT (PK) and KS.CASD.AUT (Non-PK)
# KID 0x03: SK.CASD.CT (P) and KS.CASD.CT (Non-PK)
# KVN 0x75 KID 0x01: 16-byte DES key for Ciphered Load File Data Block
-# KVN 0xFF reserved for ISD with SCP02 without SCP80 s upport
+# KVN 0xFF reserved for ISD with SCP02 without SCP80 s support
diff --git a/pySim/javacard.py b/pySim/javacard.py
index 6005ab4..2d4fd34 100644
--- a/pySim/javacard.py
+++ b/pySim/javacard.py
@@ -97,7 +97,7 @@
raise ValueError("invalid cap file, %s missing!" % required_components[component])
def get_loadfile(self) -> bytes:
- """Get the executeable loadfile as hexstring"""
+ """Get the executable loadfile as hexstring"""
# Concatenate all cap file components in the specified order
# see also: Java Card Platform Virtual Machine Specification, v3.2, section 6.3
loadfile = self.__component['Header']
diff --git a/pySim/legacy/cards.py b/pySim/legacy/cards.py
index 3a68e18..9efa66b 100644
--- a/pySim/legacy/cards.py
+++ b/pySim/legacy/cards.py
@@ -495,7 +495,7 @@
class MagicSimBase(abc.ABC, SimCard):
"""
- Theses cards uses several record based EFs to store the provider infos,
+ These cards uses several record based EFs to store the provider infos,
each possible provider uses a specific record number in each EF. The
indexes used are ( where N is the number of providers supported ) :
- [2 .. N+1] for the operator name
@@ -644,7 +644,7 @@
class FakeMagicSim(SimCard):
"""
- Theses cards have a record based EF 3f00/000c that contains the provider
+ These cards have a record based EF 3f00/000c that contains the provider
information. See the program method for its format. The records go from
1 to N.
"""
diff --git a/pySim/legacy/utils.py b/pySim/legacy/utils.py
index 4bfd061..49c8633 100644
--- a/pySim/legacy/utils.py
+++ b/pySim/legacy/utils.py
@@ -296,7 +296,7 @@
elif addr_type == 0x01: # IPv4
# Skip address tye byte i.e. first byte in value list
- # Skip the unused byte in Octect 4 after address type byte as per 3GPP TS 31.102
+ # Skip the unused byte in Octet 4 after address type byte as per 3GPP TS 31.102
ipv4 = tlv[2][2:]
content = '.'.join(str(x) for x in ipv4)
return (content, '01')
diff --git a/pySim/profile.py b/pySim/profile.py
index ffb748e..360aa46 100644
--- a/pySim/profile.py
+++ b/pySim/profile.py
@@ -110,7 +110,7 @@
@abc.abstractmethod
def _try_match_card(cls, scc: SimCardCommands) -> None:
"""Try to see if the specific profile matches the card. This method is a
- placeholder that is overloaded by specific dirived classes. The method
+ placeholder that is overloaded by specific derived classes. The method
actively probes the card to make sure the profile class matches the
physical card. This usually also means that the card is reset during
the process, so this method must not be called at random times. It may
diff --git a/pySim/runtime.py b/pySim/runtime.py
index 2205957..5bb730e 100644
--- a/pySim/runtime.py
+++ b/pySim/runtime.py
@@ -150,7 +150,7 @@
# select MF to reset internal state and to verify card really works
self.lchan[0].select('MF', cmd_app)
self.lchan[0].selected_adf = None
- # store ATR as part of our card identies dict
+ # store ATR as part of our card identities dict
self.identity['ATR'] = atr
return atr
@@ -324,7 +324,7 @@
# If we succeed, we know that the file exists on the card and we may
# proceed with creating a new CardEF object in the local file model at
# run time. In case the file does not exist on the card, we just abort.
- # The state on the card (selected file/application) wont't be changed,
+ # The state on the card (selected file/application) won't be changed,
# so we do not have to update any state in that case.
(data, _sw) = self.scc.select_file(fid)
except SwMatchError as swm:
diff --git a/pySim/secure_channel.py b/pySim/secure_channel.py
index 34e84de..05fe1e5 100644
--- a/pySim/secure_channel.py
+++ b/pySim/secure_channel.py
@@ -32,7 +32,7 @@
pass
def send_apdu_wrapper(self, send_fn: callable, pdu: Hexstr, *args, **kwargs) -> ResTuple:
- """Wrapper function to wrap command APDU and unwrap repsonse APDU around send_apdu callable."""
+ """Wrapper function to wrap command APDU and unwrap response APDU around send_apdu callable."""
pdu_wrapped = b2h(self.wrap_cmd_apdu(h2b(pdu)))
res, sw = send_fn(pdu_wrapped, *args, **kwargs)
res_unwrapped = b2h(self.unwrap_rsp_apdu(h2b(sw), h2b(res)))
diff --git a/pySim/transport/__init__.py b/pySim/transport/__init__.py
index 767691c..099b018 100644
--- a/pySim/transport/__init__.py
+++ b/pySim/transport/__init__.py
@@ -200,7 +200,7 @@
# It *was* successful after all -- the extra pieces FETCH handled
# need not concern the caller.
rv = (rv[0], '9000')
- # proactive sim as per TS 102 221 Setion 7.4.2
+ # proactive sim as per TS 102 221 Section 7.4.2
# TODO: Check SW manually to avoid recursing on the stack (provided this piece of code stays in this place)
fetch_rv = self.send_apdu_checksw('80120000' + last_sw[2:], sw)
# Setting this in case we later decide not to send a terminal
@@ -228,7 +228,7 @@
# Structure as per TS 102 223 V4.4.0 Section 6.8
# Testing hint: The value of tail does not influence the behavior
- # of an SJA2 that sent ans SMS, so this is implemented only
+ # of an SJA2 that sent an SMS, so this is implemented only
# following TS 102 223, and not fully tested.
ti_list_bin = [x.to_tlv() for x in ti_list]
tail = b''.join(ti_list_bin)
diff --git a/pySim/ts_31_102.py b/pySim/ts_31_102.py
index d33ec44..4ee6621 100644
--- a/pySim/ts_31_102.py
+++ b/pySim/ts_31_102.py
@@ -208,7 +208,7 @@
5: '5G ProSe configuration data for usage information reporting',
}
-# Mapping between USIM Enbled Service Number and its description
+# Mapping between USIM Enabled Service Number and its description
EF_EST_map = {
1: 'Fixed Dialling Numbers (FDN)',
2: 'Barred Dialling Numbers (BDN)',
diff --git a/pySim/ts_31_103_shared.py b/pySim/ts_31_103_shared.py
index 3355217..eb21a8d 100644
--- a/pySim/ts_31_103_shared.py
+++ b/pySim/ts_31_103_shared.py
@@ -119,7 +119,7 @@
"""The use of this EF is eescribed in 3GPP TS 31.130"""
class AppletNafAccessControl(BER_TLV_IE, tag=0x80):
# the use of Int8ub as length field in Prefixed is strictly speaking incorrect, as it is a BER-TLV
- # length field whihc will consume two bytes from length > 127 bytes. However, AIDs and NAF IDs can
+ # length field which will consume two bytes from length > 127 bytes. However, AIDs and NAF IDs can
# safely be assumed shorter than that
_construct = Struct('aid'/Prefixed(Int8ub, GreedyBytes),
'naf_id'/Prefixed(Int8ub, GreedyBytes))
diff --git a/pySim/ts_51_011.py b/pySim/ts_51_011.py
index 2dc814b..e46a3e0 100644
--- a/pySim/ts_51_011.py
+++ b/pySim/ts_51_011.py
@@ -1007,7 +1007,7 @@
def _encode_hex(self, abstract, **kwargs):
return enc_iccid(abstract['iccid'])
-# TS 102 221 Section 13.3 / TS 31.101 Secction 13 / TS 51.011 Section 10.1.2
+# TS 102 221 Section 13.3 / TS 31.101 Section 13 / TS 51.011 Section 10.1.2
class EF_PL(TransRecEF):
_test_de_encode = [
( '6465', "de" ),
diff --git a/pySim/utils.py b/pySim/utils.py
index b0443c8..a8fd30c 100644
--- a/pySim/utils.py
+++ b/pySim/utils.py
@@ -331,7 +331,7 @@
mnc = 0
# 3-rd digit is optional for the MNC. If present
- # the algorythm is the same as for the MCC.
+ # the algorithm is the same as for the MCC.
if digit3 != 0x0f:
return derive_mcc(digit1, digit2, digit3)
@@ -411,7 +411,7 @@
fqdn_flag = True
for i in addr_list:
- # Only Alpha-numeric characters and hyphen - RFC 1035
+ # Only Alphanumeric characters and hyphen - RFC 1035
import re
if not re.match("^[a-zA-Z0-9]+(?:-[a-zA-Z0-9]+)?$", i):
fqdn_flag = False
@@ -477,7 +477,7 @@
"""Expand a given hexstring to a specified length by replacing "." or ".."
with a filler that is derived from the neighboring nibbles respective
bytes. Usually this will be the nibble respective byte before "." or
- "..", execpt when the string begins with "." or "..", then the nibble
+ "..", except when the string begins with "." or "..", then the nibble
respective byte after "." or ".." is used.". In case the string cannot
be expanded for some reason, the input string is returned unmodified.
@@ -717,7 +717,7 @@
class DataObject(abc.ABC):
"""A DataObject (DO) in the sense of ISO 7816-4. Contrary to 'normal' TLVs where one
simply has any number of different TLVs that may occur in any order at any point, ISO 7816
- has the habit of specifying TLV data but with very spcific ordering, or specific choices of
+ has the habit of specifying TLV data but with very specific ordering, or specific choices of
tags at specific points in a stream. This class tries to represent this."""
def __init__(self, name: str, desc: Optional[str] = None, tag: Optional[int] = None):
@@ -839,7 +839,7 @@
class DataObjectCollection:
- """A DataObjectCollection consits of multiple Data Objects identified by their tags.
+ """A DataObjectCollection consists of multiple Data Objects identified by their tags.
A given encoded DO may contain any of them in any order, and may contain multiple instances
of each DO."""
--
To view, visit https://gerrit.osmocom.org/c/pysim/+/41148?usp=email
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings?usp=email
Gerrit-MessageType: merged
Gerrit-Project: pysim
Gerrit-Branch: master
Gerrit-Change-Id: I00a72e4f479dcef88f7d1058ce53edd0129d336a
Gerrit-Change-Number: 41148
Gerrit-PatchSet: 2
Gerrit-Owner: laforge <laforge(a)osmocom.org>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: dexter <pmaier(a)sysmocom.de>
Gerrit-Reviewer: laforge <laforge(a)osmocom.org>
fixeria has submitted this change. ( https://gerrit.osmocom.org/c/erlang/osmo-s1gw/+/41098?usp=email )
Change subject: [REST] Integrate Erlang REST Framework
......................................................................
[REST] Integrate Erlang REST Framework
Change-Id: I20ad3208b8cd4f5483992e3bf22af30ff62b0311
Related: SYS#7066
---
M README.md
M config/sys.config
M rebar.config
M rebar.lock
M src/osmo_s1gw.app.src
M src/osmo_s1gw.erl
M src/osmo_s1gw_sup.erl
A src/rest_server.erl
8 files changed, 109 insertions(+), 4 deletions(-)
Approvals:
Jenkins Builder: Verified
pespin: Looks good to me, but someone else must approve
laforge: Looks good to me, approved
diff --git a/README.md b/README.md
index 6dc9fe3..a593ac0 100644
--- a/README.md
+++ b/README.md
@@ -170,6 +170,9 @@
for state introspection. The interface is specified using OpenAPI, with the
specification available in [contrib/openapi.yaml](contrib/openapi.yaml).
+You can explore the API and available endpoints interactively via
+the Swagger UI by opening <http://localhost:8080/swagger> in a browser.
+
The OpenAPI specification is provided in two formats:
* **YAML** (`contrib/openapi.yaml`) is the primary specification document.
diff --git a/config/sys.config b/config/sys.config
index 4e5a80c..5184ebb 100644
--- a/config/sys.config
+++ b/config/sys.config
@@ -25,7 +25,9 @@
%% {gtpu_kpi_table_name, "osmo-s1gw"}, %% the NFT table name to be used by this process
%% {gtpu_kpi_ul_addr, s1ap}, %% GTP-U UL address: s1ap | sctp (default: learn from S1AP)
%% {gtpu_kpi_dl_addr, s1ap}, %% GTP-U DL address: s1ap | sctp (default: learn from S1AP)
-%% {gtpu_kpi_interval, 3000} %% counter reporting interval (ms)
+%% {gtpu_kpi_interval, 3000}, %% counter reporting interval (ms)
+%% {rest_srv_port, 8080}, %% REST server port (default: 8080)
+%% {rest_srv_swagger_ui, true} %% REST Swagger UI (default: true)
]},
%% ================================================================================
%% kernel config
diff --git a/rebar.config b/rebar.config
index de8b023..d729401 100644
--- a/rebar.config
+++ b/rebar.config
@@ -16,7 +16,9 @@
{exometer_core,
{git, "https://github.com/Feuerlabs/exometer_core.git", {branch, "master"}}},
{exometer_report_statsd,
- {git, "https://github.com/osmocom/exometer_report_statsd.git", {branch, "counters"}}}
+ {git, "https://github.com/osmocom/exometer_report_statsd.git", {branch, "counters"}}},
+ {erf,
+ {git, "https://github.com/nomasystems/erf.git", {tag, "0.1.2"}}}
]}.
%% test deps
diff --git a/rebar.lock b/rebar.lock
index 647bca0..1efe90b 100644
--- a/rebar.lock
+++ b/rebar.lock
@@ -1,9 +1,17 @@
{"1.2.0",
[{<<"cut">>,{pkg,<<"cut">>,<<"1.0.3">>},1},
+ {<<"elli">>,
+ {git,"https://github.com/elli-lib/elli.git",
+ {ref,"3ec352293ef493c142767127f4113c85541c32cc"}},
+ 1},
{<<"enftables">>,
{git,"https://gitea.osmocom.org/erlang/enftables.git",
{ref,"8b9b4acd624b9d0d3a58d725f11afa96d31fe5d7"}},
0},
+ {<<"erf">>,
+ {git,"https://github.com/nomasystems/erf.git",
+ {ref,"0dac504f9988d3b96154c1e80b8af3defb772b58"}},
+ 0},
{<<"exometer_core">>,
{git,"https://github.com/Feuerlabs/exometer_core.git",
{ref,"fc744c45bbe5de2ab0ee550e2667f93f7abbb618"}},
@@ -25,6 +33,18 @@
{git,"https://gitea.osmocom.org/erlang/logger_gsmtap.git",
{ref,"5194badde912a8179f2a818155ee2b01f9e6377e"}},
0},
+ {<<"ncalendar">>,
+ {git,"https://github.com/nomasystems/ncalendar.git",
+ {ref,"aa5615f6723585e45e82fa5524cb976cdfe3d7f7"}},
+ 2},
+ {<<"ndto">>,
+ {git,"https://github.com/nomasystems/ndto.git",
+ {ref,"295281b72ea4ac85e7c4d5ca42337c68b1aac137"}},
+ 1},
+ {<<"njson">>,
+ {git,"https://github.com/nomasystems/njson.git",
+ {ref,"94c586b92a7e24c403089cdbe2994b7e7c87b9cc"}},
+ 1},
{<<"parse_trans">>,{pkg,<<"parse_trans">>,<<"3.4.1">>},1},
{<<"pfcplib">>,
{git,"https://github.com/travelping/pfcplib.git",
diff --git a/src/osmo_s1gw.app.src b/src/osmo_s1gw.app.src
index 13240dd..2885cc6 100644
--- a/src/osmo_s1gw.app.src
+++ b/src/osmo_s1gw.app.src
@@ -12,7 +12,8 @@
pfcplib,
enftables,
exometer_core,
- exometer_report_statsd
+ exometer_report_statsd,
+ erf
]},
{modules, []},
{mod, {osmo_s1gw_app, []}},
diff --git a/src/osmo_s1gw.erl b/src/osmo_s1gw.erl
index d5f9efd..e90d927 100644
--- a/src/osmo_s1gw.erl
+++ b/src/osmo_s1gw.erl
@@ -35,6 +35,7 @@
-module(osmo_s1gw).
-export([get_env/2,
+ get_priv/1,
main/1]).
-define(ENV_APP_NAME, osmo_s1gw).
@@ -52,6 +53,14 @@
application:get_env(?ENV_APP_NAME, Param, Default).
+-spec get_priv(Name) -> Path
+ when Name :: file:filename_all(),
+ Path :: file:filename_all().
+get_priv(Name) ->
+ PrivDir = code:priv_dir(?ENV_APP_NAME),
+ filename:join(PrivDir, Name).
+
+
main(_Args) ->
application:ensure_all_started(?MODULE),
timer:sleep(infinity).
diff --git a/src/osmo_s1gw_sup.erl b/src/osmo_s1gw_sup.erl
index 934f040..1616fe5 100644
--- a/src/osmo_s1gw_sup.erl
+++ b/src/osmo_s1gw_sup.erl
@@ -53,6 +53,8 @@
-define(ENV_DEFAULT_GTPU_KPI_ENABLE, false).
-define(ENV_DEFAULT_GTPU_KPI_TABLE_NAME, "osmo-s1gw").
-define(ENV_DEFAULT_GTPU_KPI_INTERVAL, 3000).
+-define(ENV_DEFAULT_REST_SRV_PORT, 8080).
+-define(ENV_DEFAULT_REST_SRV_SWAGGER_UI, true).
%% ------------------------------------------------------------------
%% supervisor API
@@ -87,9 +89,14 @@
5000,
worker,
[gtpu_kpi]},
+ RestServer = {rest_server, {erf, start_link, [rest_server_cfg()]},
+ permanent,
+ 5000,
+ worker,
+ [erf]},
s1gw_metrics:init(),
- {ok, {{one_for_one, 5, 10}, [EnbRegistry, SctpServer, PfcpPeer, GtpuKpi]}}.
+ {ok, {{one_for_one, 5, 10}, [EnbRegistry, SctpServer, PfcpPeer, GtpuKpi, RestServer]}}.
%% ------------------------------------------------------------------
@@ -126,4 +133,13 @@
table_name => osmo_s1gw:get_env(gtpu_kpi_table_name, ?ENV_DEFAULT_GTPU_KPI_TABLE_NAME),
interval => osmo_s1gw:get_env(gtpu_kpi_interval, ?ENV_DEFAULT_GTPU_KPI_INTERVAL)}.
+
+-spec rest_server_cfg() -> erf:conf().
+rest_server_cfg() ->
+ #{callback => rest_server,
+ spec_path => list_to_binary(osmo_s1gw:get_priv("openapi.json")),
+ port => osmo_s1gw:get_env(rest_srv_port, ?ENV_DEFAULT_REST_SRV_PORT),
+ swagger_ui => osmo_s1gw:get_env(rest_srv_swagger_ui, ?ENV_DEFAULT_REST_SRV_SWAGGER_UI)}.
+
+
%% vim:set ts=4 sw=4 et:
diff --git a/src/rest_server.erl b/src/rest_server.erl
new file mode 100644
index 0000000..c4e0373
--- /dev/null
+++ b/src/rest_server.erl
@@ -0,0 +1,52 @@
+%% Copyright (C) 2025 by sysmocom - s.f.m.c. GmbH <info(a)sysmocom.de>
+%% Author: Vadim Yanitskiy <vyanitskiy(a)sysmocom.de>
+%%
+%% All Rights Reserved
+%%
+%% SPDX-License-Identifier: AGPL-3.0-or-later
+%%
+%% This program is free software; you can redistribute it and/or modify
+%% it under the terms of the GNU Affero General Public License as
+%% published by the Free Software Foundation; either version 3 of the
+%% License, or (at your option) any later version.
+%%
+%% This program is distributed 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 General Public License for more details.
+%%
+%% You should have received a copy of the GNU Affero General Public License
+%% along with this program. If not, see <https://www.gnu.org/licenses/>.
+%%
+%% Additional Permission under GNU AGPL version 3 section 7:
+%%
+%% If you modify this Program, or any covered work, by linking or
+%% combining it with runtime libraries of Erlang/OTP as released by
+%% Ericsson on https://www.erlang.org (or a modified version of these
+%% libraries), containing parts covered by the terms of the Erlang Public
+%% License (https://www.erlang.org/EPLICENSE), the licensors of this
+%% Program grant you additional permission to convey the resulting work
+%% without the need to license the runtime libraries of Erlang/OTP under
+%% the GNU Affero General Public License. Corresponding Source for a
+%% non-source form of such a combination shall include the source code
+%% for the parts of the runtime libraries of Erlang/OTP used as well as
+%% that of the covered work.
+
+-module(rest_server).
+
+-export([]).
+
+-include_lib("kernel/include/logger.hrl").
+
+
+%% ------------------------------------------------------------------
+%% public API
+%% ------------------------------------------------------------------
+
+
+%% ------------------------------------------------------------------
+%% private API
+%% ------------------------------------------------------------------
+
+
+%% vim:set ts=4 sw=4 et:
--
To view, visit https://gerrit.osmocom.org/c/erlang/osmo-s1gw/+/41098?usp=email
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings?usp=email
Gerrit-MessageType: merged
Gerrit-Project: erlang/osmo-s1gw
Gerrit-Branch: master
Gerrit-Change-Id: I20ad3208b8cd4f5483992e3bf22af30ff62b0311
Gerrit-Change-Number: 41098
Gerrit-PatchSet: 7
Gerrit-Owner: fixeria <vyanitskiy(a)sysmocom.de>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: fixeria <vyanitskiy(a)sysmocom.de>
Gerrit-Reviewer: laforge <laforge(a)osmocom.org>
Gerrit-Reviewer: pespin <pespin(a)sysmocom.de>
fixeria has submitted this change. ( https://gerrit.osmocom.org/c/erlang/osmo-s1gw/+/41097?usp=email )
Change subject: [REST] osmo-s1gw-cli.py skeleton
......................................................................
[REST] osmo-s1gw-cli.py skeleton
This is an interactive shell based on Python's cmd2 library, providing
an alternative to the traditional VTY interface used in many Osmocom
projects. It communicates with the main process via the REST interface.
Currently there's only one command fetching the OpenAPI specification.
More commands will be introduced in follow-up commits.
Change-Id: I05600f2fa6d213b9cee28871761231722ff5b876
Related: SYS#7066
---
M Makefile
M README.md
A contrib/osmo-s1gw-cli.py
M debian/control
M debian/copyright
A debian/osmo-s1gw-cli.install
A doc/osmo-s1gw-cli.md
7 files changed, 230 insertions(+), 0 deletions(-)
Approvals:
laforge: Looks good to me, approved
pespin: Looks good to me, but someone else must approve
Jenkins Builder: Verified
diff --git a/Makefile b/Makefile
index a68877f..a4492f1 100644
--- a/Makefile
+++ b/Makefile
@@ -52,6 +52,8 @@
cp -r $(REBAR_BASE_DIR)/default/rel/osmo-s1gw $(DESTDIR)$(LIBDIR)/
install -Dm0755 contrib/osmo-s1gw.sh \
$(DESTDIR)$(BINDIR)/osmo-s1gw
+ install -Dm0755 contrib/osmo-s1gw-cli.py \
+ $(DESTDIR)$(BINDIR)/osmo-s1gw-cli
install -Dm0644 config/sys.config \
$(DESTDIR)$(CONFDIR)/osmo-s1gw.config
install -Dm0644 contrib/systemd/osmo-s1gw.service \
diff --git a/README.md b/README.md
index 3ff2091..6dc9fe3 100644
--- a/README.md
+++ b/README.md
@@ -126,6 +126,7 @@
* `/usr/lib/osmo-s1gw` - complete OTP release package
* `/usr/bin/osmo-s1gw` - convenience script for running `osmo-s1gw`
+* `/usr/bin/osmo-s1gw-cli` - interactive CLI for `osmo-s1gw`
* `/lib/systemd/system/osmo-s1gw.service` - systemd unit file
* `/etc/osmocom/osmo-s1gw.config` - the configuration file
@@ -178,3 +179,12 @@
> **Note:** Both files must be kept in sync. When making changes to the YAML
document, make sure to update the JSON counterpart by invoking `make openapi`.
+
+
+Interactive CLI
+---------------
+
+OsmoS1GW comes with [`osmo-s1gw-cli.py`](contrib/osmo-s1gw-cli.py) - an interactive
+shell based on Python's **cmd2** library. This script serves as an alternative to the
+traditional telnet/VTY interface found in many Osmocom projects. For more details,
+see (doc/osmo-s1gw-cli.md).
diff --git a/contrib/osmo-s1gw-cli.py b/contrib/osmo-s1gw-cli.py
new file mode 100755
index 0000000..8007314
--- /dev/null
+++ b/contrib/osmo-s1gw-cli.py
@@ -0,0 +1,119 @@
+#!/usr/bin/env python3
+
+# Copyright (C) 2025 by sysmocom - s.f.m.c. GmbH <info(a)sysmocom.de>
+# Author: Vadim Yanitskiy <vyanitskiy(a)sysmocom.de>
+#
+# All Rights Reserved
+#
+# SPDX-License-Identifier: GPL-3.0-or-later
+#
+# This program is free software: you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation, either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed 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
+# General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program. If not, see <http://www.gnu.org/licenses/>.
+
+import logging
+import argparse
+import cmd2
+import sys
+
+import tabulate
+import urllib.request
+import http.client
+import json
+
+# local logger for this module
+log = logging.getLogger(__name__)
+
+
+class RestIface:
+ ''' REST interface for OsmoS1GW '''
+
+ HTTPResponse = http.client.HTTPResponse
+ RESTResponse = dict | list[dict]
+
+ def __init__(self, host: str, port: int):
+ self.url = f'http://{host}:{port}'
+
+ def send_req(self, method: str,
+ path: str = '',
+ data: dict = {}) -> HTTPResponse:
+ ''' Send an HTTP request to the given endpoint (path) '''
+ req = urllib.request.Request(f'{self.url}/{path}', method=method)
+ req.add_header('Accept', 'application/json')
+ if data:
+ req.add_header('Content-Type', 'application/json')
+ req.data = json.dumps(data).encode('utf-8')
+ log.debug(f'HTTP {req.method} {req.full_url}')
+ return urllib.request.urlopen(req)
+
+ def send_get_req(self, path: str, query: dict = {}) -> HTTPResponse:
+ ''' Send an HTTP GET request to the given endpoint (path) '''
+ if query:
+ path += '?' + urllib.parse.urlencode(query)
+ return self.send_req('GET', path)
+
+ def send_post_req(self, path: str, data: dict = {}) -> HTTPResponse:
+ ''' Send an HTTP POST request to the given endpoint (path) '''
+ return self.send_req('POST', path, data)
+
+ def send_delete_req(self, path: str, data: dict = {}) -> HTTPResponse:
+ ''' Send an HTTP DELETE request to the given endpoint (path) '''
+ return self.send_req('DELETE', path, data)
+
+ def fetch_spec(self) -> RESTResponse:
+ ''' Fetch the OpenAPI specification (JSON) '''
+ with self.send_get_req('swagger/spec.json') as f:
+ return json.load(f)
+
+
+class OsmoS1GWCli(cmd2.Cmd):
+ DESC = 'Interactive CLI for OsmoS1GW'
+
+ def __init__(self, argv):
+ super().__init__(allow_cli_args=False, include_py=True)
+
+ if argv.verbose > 0:
+ logging.root.setLevel(logging.DEBUG)
+ self.debug = True
+
+ self.intro = cmd2.style('Welcome to %s!' % self.DESC, fg=cmd2.Fg.RED)
+ self.default_category = 'Built-in commands'
+ self.prompt = 'OsmoS1GW# '
+
+ self.tablefmt = 'github' # default table format for tabulate
+ self.add_settable(cmd2.Settable('tablefmt', str, 'Table format for tabulate', self,
+ choices=tabulate.tabulate_formats))
+
+ self.iface = RestIface(argv.HOST, argv.port)
+
+ def do_fetch_openapi_spec(self, opts):
+ ''' Fetch the OpenAPI specification (JSON), dump as text '''
+ spec = self.iface.fetch_spec()
+ self.poutput(json.dumps(spec, indent=4))
+
+
+ap = argparse.ArgumentParser(prog='osmo-s1gw-cli', description=OsmoS1GWCli.DESC)
+
+ap.add_argument('-v', '--verbose', action='count', default=0,
+ help='print debug logging')
+ap.add_argument('-p', '--port', metavar='PORT', type=int, default=8080,
+ help='OsmoS1GW REST port (default: %(default)s)')
+ap.add_argument('HOST', type=str, nargs='?', default='localhost',
+ help='OsmoS1GW REST host/address (default: %(default)s)')
+
+logging.basicConfig(
+ format='\r[%(levelname)s] %(filename)s:%(lineno)d %(message)s', level=logging.INFO)
+
+if __name__ == '__main__':
+ argv = ap.parse_args()
+ app = OsmoS1GWCli(argv)
+ sys.exit(app.cmdloop())
diff --git a/debian/control b/debian/control
index 45c3847..515e3b2 100644
--- a/debian/control
+++ b/debian/control
@@ -17,8 +17,22 @@
Depends: ${shlibs:Depends},
${misc:Depends},
${libsctp:Version}
+Suggests: osmo-s1gw-cli
Multi-Arch: foreign
Description: Osmocom S1 gateway
This can be used on the S1 interface between eNB and MME/CN, and
acts as separation between the eNB-facing IP network and the
CN-facing IP network, which may be separate without routing in between.
+
+Package: osmo-s1gw-cli
+Architecture: any
+Section: utils
+Depends: ${misc:Depends},
+ python3,
+ python3-cmd2,
+ python3-tabulate
+Suggests: osmo-s1gw
+Description: Interactive CLI for the Osmocom S1 gateway
+ This is an interactive shell for the Osmocom S1 gateway, providing
+ an alternative to the traditional VTY interface used in many Osmocom
+ projects. It communicates with OsmoS1GW via the REST interface.
diff --git a/debian/copyright b/debian/copyright
index 30d897e..997d2af 100644
--- a/debian/copyright
+++ b/debian/copyright
@@ -6,6 +6,7 @@
src/*.erl
include/*.hrl
contrib/yaml2json.py
+ contrib/osmo-s1gw-cli.py
Copyright: sysmocom - s.f.m.c. GmbH <info(a)sysmocom.de>
License: AGPL-3.0-or-later
diff --git a/debian/osmo-s1gw-cli.install b/debian/osmo-s1gw-cli.install
new file mode 100644
index 0000000..037a640
--- /dev/null
+++ b/debian/osmo-s1gw-cli.install
@@ -0,0 +1 @@
+usr/bin/osmo-s1gw-cli
diff --git a/doc/osmo-s1gw-cli.md b/doc/osmo-s1gw-cli.md
new file mode 100644
index 0000000..9cbac7b
--- /dev/null
+++ b/doc/osmo-s1gw-cli.md
@@ -0,0 +1,83 @@
+Interactive CLI
+===============
+
+[`osmo-s1gw-cli.py`](contrib/osmo-s1gw-cli.py) is an interactive shell based on
+Python's **cmd2** library. This script serves as an alternative to the traditional
+telnet/VTY interface found in many Osmocom projects. It communicates with the main
+process via the **REST interface**, allowing users to inspect and interact with
+OsmoS1GW in a familiar CLI style.
+
+Installation
+------------
+
+`osmo-s1gw-cli.py` has the following dependencies:
+
+* [`cmd2`](https://pypi.org/project/cmd2/)
+* [`tabulate`](https://pypi.org/project/tabulate/)
+
+You can install them using **pip**:
+
+```bash
+pip install cmd2 tabulate
+```
+
+Or using your system's package manager (Debian/Ubuntu example):
+
+```bash
+sudo apt install python3-cmd2 python3-tabulate
+```
+
+Usage
+-----
+
+By default, `osmo-s1gw-cli.py` is sending HTTP requests to `http://localhost:8080`.
+The hostname/address and port can be specified using command-line arguments:
+
+```bash
+./contrib/osmo-s1gw-cli.py --help
+usage: osmo-s1gw-cli [-h] [-v] [-p PORT] [HOST]
+
+Interactive CLI for OsmoS1GW
+
+positional arguments:
+ HOST OsmoS1GW REST host/address (default: localhost)
+
+options:
+ -h, --help show this help message and exit
+ -v, --verbose print debug logging
+ -p, --port PORT OsmoS1GW REST port (default: 8080)
+```
+
+Available commands can be listed by entering `help -v`:
+
+```
+Welcome to Interactive CLI for OsmoS1GW!
+OsmoS1GW# help -v
+...
+```
+
+Each command has its own detailed help, accessible with `help CMD`:
+
+```
+OsmoS1GW# help quit
+Usage: quit [-h]
+
+Exit this application
+
+optional arguments:
+ -h, --help show this help message and exit
+```
+
+In addition to tab-completion, you can filter (`CMD | grep ...`) and/or
+redirect (`CMD > FILE`) output of a command to a file. For more details
+on the available features and usage patterns, please refer to the
+[cmd2 documentation](https://cmd2.readthedocs.io/en/stable/features/).
+
+Commands
+--------
+
+Below is a list of currently supported commands and some examples.
+
+### `fetch_openapi_spec`
+
+Fetch the OpenAPI specification (JSON), dump as text.
--
To view, visit https://gerrit.osmocom.org/c/erlang/osmo-s1gw/+/41097?usp=email
To unsubscribe, or for help writing mail filters, visit https://gerrit.osmocom.org/settings?usp=email
Gerrit-MessageType: merged
Gerrit-Project: erlang/osmo-s1gw
Gerrit-Branch: master
Gerrit-Change-Id: I05600f2fa6d213b9cee28871761231722ff5b876
Gerrit-Change-Number: 41097
Gerrit-PatchSet: 7
Gerrit-Owner: fixeria <vyanitskiy(a)sysmocom.de>
Gerrit-Reviewer: Jenkins Builder
Gerrit-Reviewer: fixeria <vyanitskiy(a)sysmocom.de>
Gerrit-Reviewer: jolly <andreas(a)eversberg.eu>
Gerrit-Reviewer: laforge <laforge(a)osmocom.org>
Gerrit-Reviewer: pespin <pespin(a)sysmocom.de>