Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
82 changes: 82 additions & 0 deletions helper/quickstart-generator/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,82 @@
# quickstart-generator.py
This application creates a generic quickstart file, which can be used to provision a Session Smart Router (SSR) during OTP installation.

## Installation
The python application requires additional python packages, which are listed in the `requirements.txt` file.

To install all packages, a python virtualenv is recommended:

```
$ cd quickstart-generator
$ python3 -m venv venv
$ venv/bin/pip install -r requirements.txt
```

## OTP Preparation
An OTP installation requires a quickstart file, which can be downloaded from the SSR conductor.

During the first boot from internal disk the bootstrap process can incorporate a USB drive connected to the router.
This USB drive must have the label `BOOTSTRAP` and the downloaded quickstart file has to be named `bootstrap.quickstart`.
Additionally two scripts can be triggered during the bootstrap process. `pre-bootstrap` runs as the first action prior to the default actions (setting the node name, copy config file to disk, ...) `post-bootstrap` runs as the last action before the router is rebooted and becomes active.

Instead of using a router-specific quickstart file from conductor, this application can create a generic file, which just contains the IP address of the SSR conductor and network interface config needed to connect to the conductor. Afterwards the router gets it actual (router-specific) config by the conductor.

The application is configured by a file in yaml file like the following:

```
$ cp sample-parameters.yml parameters.yml
$ vi parameters.yml
# the conductor IP address(es) - specify both to connect to an HA conductor
conductors:
- 10.0.0.1
- 10.0.0.2

# network interfaces needed to create the conductor connection - used in this order
interfaces:
- name: wan1
proto: dhcp
pci_address: "0000:00:12.0"
# - name: wan2
# proto: dhcp
# pci_address: "0000:00:13.0"
# - name: lte1
# type: lte
# target_interface: wwp0s20u5i4
# apn: sample-apn
# user: jdoe
# password: secret
# auth: chap
```

After adjusting the `parameters.yml` call the application:

```
$ venv/bin/python3 quickstart-generator.py -p parameters.yml -q generic.quickstart
```

Now copy the `generic.quickstart` file to the USB drive.

On macOS:

```
$ disk=/dev/disk<n>
$ target=/Volumes/BOOTSTRAP
$ diskutil eraseDisk FAT32 BOOTSTRAP MBR $disk
$ cp generic.quickstart $target/bootstrap.quickstart
$ diskutil eject $disk
```

On Linux:

```
$ disk=/dev/sd<n>
$ target=/mnt
$ sudo mkfs.vfat -F32 -n BOOTSTRAP $disk || sudo mkfs.ext4 -L BOOTSTRAP $disk
$ sudo mount $disk $target
$ cp generic.quickstart $target/bootstrap.quickstart
$ sudo umount $target
```

The USB drive can be plugged into a freshly installed SSR router and router can be powered on.

Details on the bootstrap process can be found [here](https://docs.128technology.com/docs/intro_otp_iso_install).
90 changes: 90 additions & 0 deletions helper/quickstart-generator/quickstart-generator.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
#!/usr/bin/env python3

import argparse
from base64 import b64encode
from gzip import compress
from jinja2 import Environment, FileSystemLoader
import json
import os
import sys
from uuid import uuid4
import yaml


def parse_arguments():
"""Get commandline arguments."""
parser = argparse.ArgumentParser(
description='Generate a quickstart file for 128T OTP')
parser.add_argument('--parameters', '-p', required=True,
help='parameters file')
parser.add_argument('--quickstart', '-q', required=True,
help='quickstart file')
parser.add_argument('--template', '-t', default='quickstart.template',
help='template file (default: quickstart.template)')
parser.add_argument('--workdir', '-w', default='.',
help='working directory (default: current dir)')
parser.add_argument('--xml', '-x', action='store_true',
help='print xml config to stdout')
return parser.parse_args()


def error(*messages):
"""Show error message and quit."""
print('Error:', *messages)
sys.exit(1)


def read_parameters(file_name, work_dir='.'):
"""Read parameters from yaml file."""
cur_dir = os.getcwd()
os.chdir(work_dir)
with open(file_name) as f:
parameters = yaml.safe_load(f)
os.chdir(cur_dir)
return parameters


def generate_quickstart(parameters, template_name, xml):
"""Generate quickstart file based on template and parameters."""
dir = os.path.dirname(template_name)
file = os.path.basename(template_name)
env = Environment(loader=FileSystemLoader(dir))
template = env.get_template(file)
# add additional parameters
parameters['has_management'] = True
if 'interfaces' in parameters:
parameters['has_lte'] = 'lte' in [
i.get('type') for i in parameters['interfaces']]
management = [i.get('management', False) for i in parameters['interfaces']]
if management.count(True) > 1:
error('There is only one management interface allowed.')
parameters['has_management'] = any(management)
parameters['authority_id'] = uuid4()
parameters['asset_id'] = uuid4()
xml_config = template.render(**parameters)
if xml:
print('xml_config:', xml_config)
quickstart = {
'n': 'generic-quickstart-router',
'a': None,
'c': b64encode(compress(bytes(xml_config, 'ascii'))).decode('ascii'),
}
return quickstart


def write_quickstart_file(quickstart, filename, work_dir='.'):
"""Write a quickstart document in json format to file."""
os.chdir(work_dir)
with open(filename, 'w') as fd:
json.dump(quickstart, fd)


def main():
args = parse_arguments()
parameters = read_parameters(args.parameters, args.workdir)
quickstart = generate_quickstart(parameters, args.template, args.xml)
write_quickstart_file(quickstart, args.quickstart, args.workdir)


if __name__ == '__main__':
main()
Loading