Apps on Paradrop¶
This section of the documentation is devoted to describing the apps that run on Paradrop.
If this is your first time seeing Paradrop, please start with the Getting Started page.
Contents:
Getting Started¶
This will quickly take you through the process of bringing up a Hello World chute in a virtual machine on your computer.
NOTE: As of release 0.1, pdbuild is built around using Ubuntu. We will eliminate this requirement soon, work arounds can be found at What if I don’t have Ubuntu?.
Environment setup¶
- Prerequisites:
- Packages: Python 2.7, python-pip, python-dev, libffi-dev, libssl-dev
- PyPI: pex
- When you install build tools you may have to run:
sudo pip install pypubsub --allow-external pypubsub
- Install our build tools (
pip install pdtools). - Clone our instance tools.
- Setup instance tools
pdbuild.sh setup - Boot local testing VM
pdbuild.sh up - Install instance dependencies
pdbuild.sh install_deps - Build the tools to go into testing VM
pdbuild.sh build - Push tools into VM
pdbuild.sh install(NOTE: sometimes this fails, please check Known Issues) - Check the installation
pdbuild.sh check
Installing chutes¶
First you must register an account from our CLI: paradrop register.
This will setup a private key on your computer which allows you to access our platform.
- Clone the Paradrop example apps.
Install hello-world chute:
cd <apps-repo>/hello-world
paradrop chute install localhost 9999 ./config.yaml
Result:
...
Chute hello-world create success
As a simple use case, hello-world starts an nginx server in the chute. To access this, visit localhost:9000 in any web browser, you should see:
Hello World from Paradrop!
Running paradrop chute stop localhost 9999 hello-world will stop the chute, if you refresh the webpage, you should no longer see the Hello World message.
Paradrop Chute Tutorials¶
This page details out information about advanced chute architecture and installation. We assume you have already gone through Getting Started.
Testing on your development computer¶
To keep the development process for Paradrop as simple as possible, we heavily encourage and support developers testing their chutes on a virtual machine (VM).
Wi-Fi in virtual machines¶
In order to support development on a virtual machine, you most likely need a Wi-Fi device (otherwise it wouldn’t be a router would it??). The instructions below will show how to enable Wi-Fi specifically for USB adapters, but other internal Wi-Fi cards should follow similar steps.
Plug in the WiFi card, on Ubuntu, run lsusb, you should see:
Bus 002 Device 005: ID 148f:5372 Ralink Technology, Corp. RT5372 Wireless Adapter
Make note of the Bus and Device numbers, in this case 2 and 5.
When you go to launch your VM with a Wi-Fi device, simply run the command:
sudo pdbuild.sh up wifi-2-5
You need sudo access because the VM needs to pull in the USB device, which is privileged.
You can verify that the WiFi adapter is inside of the VM by running:
pdbuild connect
(amd64)ubuntu@localhost:~$ iw dev
phy#0
Interface wlan0
ifindex 4
wdev 0x1
addr 7c:dd:90:8f:c2:5e
type managed
This will SSH you into the VM and print out information about the WiFi adapter, if this print out is blank, also try iw phy which prints out physical information about the Wi-Fi radio.
Wi-Fi Enabled Chutes¶
Here we will describe how to install a chute that utilizes a WiFi radio in the router.
Chute: Virtual Router¶
The chute we will install is called virtual router it is as simple as it sounds. This chute will setup a fully functional virtual router inside of the real router hardware (or VM). This is useful to demonstrate the full capability of Paradrop, which will setup and establish the chute, and tie together the networking components needed to allow the chute to function as a router.
Setup:
- Make sure your VM is alive and has WiFi (explained above).
- Make sure you are logged in or registered using pdtools.
Install the chute:
cd <example_apps>/virtual-router
vim config.yaml
#Setup ssid and password (defaults to "Paradrop-Network" and "ParadropRocks!")
paradrop chute install localhost 9999 config.yaml
... (install output)
Chute virtual-router create success
Now use your laptop or phone and search for the SSID you created, you should be able to associate to it and use it normally. You can verify you are using the chute for internet by stopping it:
paradrop chute stop localhost 9999 virtual-router
Stopping chute...
Chute virtual-router stop success
Chute Configuration Files¶
There are 2 files that are important to the use of Paradrop and installing chutes.
- config.yaml - contains high level information about the chute for the host OS (like WiFi SSID’s that need to be setup)
- Dockerfile - contains internal chute actions to setup the chute (like what OS version to use)
Eventually these will all fold into one glorious configuration file, but at this early stage we keep them separate.
config.yaml¶
Check here for information specific to the config.yaml file and its options.
Dockerfile¶
Check here for information on the Dockerfile and how it works.
Installing Paradrop on hardware¶
Paradrop is distributed as a “snap” or an application that runs on Snappy Ubuntu. You can run snappy on any x86 or armv7 board (Raspberry Pi Gen 2 or Beagleboard Black supported!)
To setup Paradrop you need to install snappy on your hardware of choice and then have snappy install paradrop. This is a temporary method until more robust installation tools are finished.
First flash the board with the snappy image, see Flashing real hardware.
Next install docker:
ssh into the router
sudo snappy install docker
From your development machine (because you cannot install unauthorized snaps internally, only using snappy-remote for now).
Next install a few required programs not in the Snappy package system yet:
wget https://paradrop.io/storage/snaps/dnsmasq_2.74_all.snap
snappy-remote --url=ssh://<ip>:8022 install dnsmasq*.snap
wget https://paradrop.io/storage/snaps/hostapd_2.4_all.snap
snappy-remote --url=ssh://<ip>:8022 install hostapd*.snap
Finally, install Paradrop, unfortunately this is not an officially supported Snappy package yet so it must be installed manually using snappy tools:
#From the Paradrop github repo:
cd paradrop
python setup.py bdist_egg -d ../buildenv
cd ..
[ ! -f snap/bin/pipework ] && wget https://raw.githubusercontent.com/jpetazzo/pipework/3bccb3adefe81b6acd97c50cfc6cda11420be109/pipework -O snap/bin/pipework
chmod 755 snap/bin/pipework
rm -f snap/bin/pd
pex --disable-cache paradrop -o snap/bin/pd -m paradrop:main -f buildenv/
rm -rf *.egg-info
snappy build snap
snappy-remote --url=ssh://localhost:8022 install <snap-location>
Provisioning Devices¶
Once you’ve got paradrop up and running on hardware or on a virtual machine you’ll need to provision the software. When a brand new router starts for the first time, it doesn’t have a place in the world yet. It doesn’t even know its name! Additionally, the provisioning process secures your software to you and only you– its an important security step.
The steps listed here are an intermediate process. Provisioning will occur during the installation process, check back soon for updates.
Provisioning Routers v0.1¶
Before you begin, make sure you have an installed version of the CLI tools and an account with paradrop. You will need to be logged in for every instruction that follows:
pip install pdtools
paradrop register
or if you already have pdtools installed:
paradrop login
Please choose usernames and passwords that are at least 8 characters.
Create a new router with the server. All of your routers have to have unique names, but lets use aardvark:
paradrop router-create aardvark
Once the creation process is finished see all of your owned chutes and routers with:
paradrop list
If this is your first time, You’ll only see your single new router as part of its pdid (Link forthcoming.)
This is the id of your router to the rest of the world:
routers
pd.joe.aardvark
At this point, however, that identity hasn’t made it onto the router yet. When you used router-create to
name your new router, the server transmitted a wealth of information. To get that information to the router you need to know the host and port of the device. When running locally,
paradrop router-provision aardvark localhost 14231
To see the logs of your router while its running, try:
paradrop logs aardvark
But be warned! Currently they’ll only respond if the router is awake.
The Paradrop Instance System¶
This section focuses on the Instance Tools. This is the set of daemons and tools required to allow the Paradrop platform to function on virtual machines and real hardware. Use the information below to learn about Snappy Ubuntu and how we leverage it to create next generation smart routers.
Contents:
Build System¶
Paradrop includes a set of build tools to make development as easy as possible.
Currently this system takes the form of a bash script that automates installation and execution, but in time this may evolve into a published python package. This page outlines the steps required to manually build the components required to develop with paradrop.
Components in the build process:
Installing and running Ubuntu Snappy¶
[Snappy](https://developer.ubuntu.com/en/snappy/) is an Ubuntu release focusing on low-overhead for a large set of platforms. These instructions are for getting a Snappy instance up and running using ‘kvm’.
Download and unzip a snappy image:
wget http://releases.ubuntu.com/15.04/ubuntu-15.04-snappy-amd64-generic.img.xz
unxz ubuntu-15.04-snappy-amd64-generic.img.xz
Launch the snappy image using kvm:
kvm -m 512 -redir :8090::80 -redir :8022::22 ubuntu-15.04-snappy-amd64-generic.img
Connect to local instance using ssh:
ssh -p 8022 ubuntu@localhost
Building paradrop¶
Snappy is a closed system (by design!). Arbitrary program installation is not allowed, so to allow paradrop access to the wide world of pypi the build system relies on two tools.
virtualenvis a tool that creates encapsulated environments in which python packages can be installed.pexcan compress python packages into a zip file that can be executed by any python interpreter.
Dependancies for paradrop are packaged with the final snap as a pex file created by freezing a virtualenv. These are the steps needed to do this:
venv.pexis packaged with paradrop source code. This is a pex that contains only the virtualenv package. This file bootstraps virtualenv so it does not need to be installed on the local system.- A new virtual environment is created under
/buildenv/envby callingvenv.pex ./buildenv/env - The environment is activated with
source ./buildenv/env/bin/activate. Any python package installations will now be placed here. - Paradrop is installed with
pip install -e .. This installs paradrop in the virtual as well as all dependancies. Dependancies are listed insrc/setup.py. You must add depedencies here in order to include new python packages with paradrop. - Dependancies are saved into
bin/pddepedencies.pexwith the commandpex -r docs/requirements.txt -o bin/pddepedencies.pex. Note: requirements are written out to the file in step 4. This is done so that theparadropdependancy is not included in the pex, since pex won’t know how to look for it! The command used to do this ispip freeze | grep -v 'pex' | grep -v 'paradrop' > docs/requirements.txt.
At this point you can run paradrop by activating the virtualenv (step #3) and then simply calling paradrop. Note that the bundled dependancies pex does not affect locally running paradrop instances– its used in the next section.
Installing paradrop¶
All programs installed on snappy are called snaps. Snappy development tools are required to build snaps:
sudo add-apt-repository ppa:snappy-dev/tools
sudo apt-get update
sudo apt-get install snappy-tools bzr
To build a snap:
snappy build .
Push a snap to a running instance of snappy:
snappy-remote --url=ssh://localhost:8022 install SNAPNAME
Snappy Confinement¶
Snappy confines running applications in two ways: directory isolation and mandatory access control. Directory isolation means the application cannot leave its installed directory. MAC means the application cannot execute any system commands or access any files it does not have explicit, predetermined permissions to.
MAC is the more serious hurdle for paradrop development. Snaps declare permissions through an AppArmor profile.
Getting started with Profile Generation¶
Install tools and profiles:
sudo apt-get install apparmor-profiles apparmor-utils
List active profiles:
sudo apparmor_status
Profiles in complain mode log behavior, while those in enforce mode actively restrict it.sudo apt-get install apparmor-utils
The following steps assume paradrop is installed on the system and not on a virtualenv.
Create a new, blank profile:
cd /etc/apparmor.d/
sudo aa-autodep paradrop
Use aa-complain to put the profile in complain mode:
sudo aa-complain paradrop
Excercise the application! AppArmor will surreptitiously watch the program in the background and log all behavior. Once finished, use the following command to go through the resulting requests, approve or deny them, and autogenerate a profile:
sudo aa-logprof
Documentation and tests¶
Documentation is handled by sphinx and readthedocs.
Testing is a joint effort between nosetests, travis-ci, and coveralls.
Documentation¶
Information about docs creation, management, and display.
Sphinx reads files in reStructuredText and builds a set of HTML pages. Every time a new commit is pushed to github, readthedocs automatically updates documentation.
Additionally, sphinx knows all about python! The directives automodule, autoclass, autofunction and more instruct sphinx to inspect the code located in src/ and build documentation from the docstrings within.
For example, the directive .. automodule:: paradrop.backend will build all the documentation for the given package. See google for more instructions.
All docstring documentation is rebuilt on every commit (unless there’s a bug in the code.) Sphinx does not, however, know about structural changes in code! To alert sphinx of these changes, use the autodoc feature:
sphinx-apidoc -f -o docs/api paradrop/paradrop/
This scans packages in the src/paradrop directory and creates .rst files in docs/api. The root file index.rst links to modules.rst, connecting the newly generated api code with the main documentation.
To create the documentation locally, run:
cd docs
make html
python -m SimpleHTTPServer 9999
Open your web browser of choice and point it to http://localhost:9999/_build/html/index.html.
Testing¶
As mentioned above, all testing is automatically run by travis-ci, a continuous integration service.
To manually run tests, install nosetest:
pip install nose
Run all tests:
nosetests
Well thats easy. How does nose detect tests? All tests live in the tests/ directory. Nose adheres to a simple principle: anything marked with test in its name is most likely a test. When writing tests, make sure all functions begin with test.
Coverage analysis detects how much of the code is used by a test suite. If the result of the coverage is less than 100%, someone slacked. Install coveralls:
pip install coveralls
Run tests with coverage analysis:
nosetests --with-coverage --cover-package=paradrop
Architecture¶
This section details some of the non-obvious architectural features of paradrop.
This is a work in progress. Check back later!
Known Issues¶
Please check here for issues during setup.
Issues using pdbuild.sh¶
These issues are related to the Instance Tools found on github.
Issue 1: pdbuild.sh install fails¶
Docker snap is missing inside of virtual router, run pdbuild.sh install_deps:
issues while running ssh command: Installing /tmp/paradrop_0.1.0_all.snap
2015/08/11 21:22:57 Signature check failed, but installing anyway as requested
/tmp/paradrop_0.1.0_all.snap failed to install: missing frameworks: docker
Issue 2: pdbuild.sh install fails¶
This is a known issue for the Paradrop team, if you get this please email us at developers@paradrop.io:
Installing paradrop_0.1.0_all.snap from local environment
issues while running ssh command: Installing /tmp/paradrop_0.1.0_all.snap
2015/08/11 21:29:48 Signature check failed, but installing anyway as requested
/tmp/paradrop_0.1.0_all.snap failed to install: [start paradrop_pdconfd_0.1.0.service]
failed with exit status 1: Job for paradrop_pdconfd_0.1.0.service failed.
See "systemctl status paradrop_pdconfd_0.1.0.service" and "journalctl -xe" for details.
Issue 3: pdbuild.sh up fails¶
This is very common and will happen if you delete your VM and setup a fresh one, the solution is simple and is stated in the error message:
Failed to setup keys: failed to setup keys: issues while running ssh command:
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
@ WARNING: REMOTE HOST IDENTIFICATION HAS CHANGED! @
@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@
IT IS POSSIBLE THAT SOMEONE IS DOING SOMETHING NASTY!
Someone could be eavesdropping on you right now (man-in-the-middle attack)!
It is also possible that a host key has just been changed.
The fingerprint for the ECDSA key sent by the remote host is
e6:ec:b1:93:7d:91:84:50:19:36:14:8e:ce:ef:6a:0b.
Please contact your system administrator.
Issues using paradrop command (pdtools)¶
These issues are related to the Build Tools found on PyPI.
Issue 1: All paradrop commands fail¶
pdtools uses enum34 rather than the enum package from PyPI, make sure you have the right one:
Traceback (most recent call last):
File "/usr/local/bin/paradrop", line 7, in <module>
from pdtools.main import main
File "/usr/local/lib/python2.7/dist-packages/pdtools/__init__.py", line 1, in <module>
from . import main
File "/usr/local/lib/python2.7/dist-packages/pdtools/main.py", line 29, in <module>
from pdtools.lib import output, riffle, names
File "/usr/local/lib/python2.7/dist-packages/pdtools/lib/names.py", line 61, in <module>
NameTypes.user: re.compile(r'^pd\.%s$' % n),
AttributeError: 'Enum' object has no attribute 'user'
Frequently Asked Questions¶
Please check here for any FAQ’s.
paradrop¶
Subpackages¶
paradrop.backend package¶
Subpackages¶
paradrop.backend.exc package¶
Submodules¶
paradrop.backend.exc.executionplan module¶
-
abortPlans(update)[source]¶ This function should be called if one of the Plan objects throws an Exception. It takes the PlanMap argument and calls the getNextAbort function just like executePlans does with todoPlans. This dynamically generates an abort plan list based on what plans were originally executed. Returns:
True in error : This is really bad False otherwise : we were able to restore system state back to before the executeplans function was called
-
aggregatePlans(update)[source]¶ Takes the PlanMap provided which can be a combination of changes for multiple different chutes and it puts things into a sane order and removes duplicates where possible.
This keeps things like reloading networking from happening twice if 2 chutes make changes.
- Returns:
- A new PlanMap that should be executed
-
executePlans(update)[source]¶ Primary function that actually executes all the functions that were added to plans by all the exc modules. This function can heavily modify the OS/files/etc.. so the return value is very important. Returns:
True in error : abortPlans function should be called False otherwise : everything is OK
-
generatePlans(update)[source]¶ For an update object provided this function references the updateModuleList which lets all exc modules determine if they need to add functions to change the state of the system when new chutes are added to the OS.
Returns: True in error, as in we should stop with this update plan
paradrop.backend.exc.files module¶
-
generateFilesPlan(chuteStor, newChute, chutePlan)[source]¶ This function looks at a diff of the current Chute (in @chuteStor) and the @newChute, then adds Plan() calls to make the Chute match the @newChute.
- Returns:
- None : means continue to pass this chute update to the rest of the chain. True : means stop updating, but its ok (no errors or anything) str : means stop updating, but some error occured (contained in the string)
paradrop.backend.exc.name module¶
paradrop.backend.exc.plangraph module¶
-
class
Plan(func, *args)[source]¶ Helper class to hold onto the actual plan data associated with each plan
-
class
PlanMap(name)[source]¶ This class helps build a dependency graph required to determine what steps are required to update a Chute from a previous version of its configuration.
-
addMap(other)[source]¶ Takes another PlanMap object and appends whatever the plans are into this plans object.
-
addPlans(priority, todoPlan, abortPlan=[])[source]¶ Adds new Plan objects into the list of plans for this PlanMap.
- Arguments:
@priority : The priority number (1 is done first, 99 done last - see PRIORITYFLAGS section at top of this file) @todoPlan : A tuple of (function, (args)), this is the function that completes the actual task requested
the args can either be a single variable, a tuple of variables, or None.- @abortPlan : A tuple of (function, (args)) or None. This is what should be called if a plan somewhere in the chain
- fails and we need to undo the work we did here - this function is only called if a higher priority function fails (ie we were called, then something later on fails that would cause us to undo everything we did to setup/change the Chute).
-
getNextAbort()[source]¶ Like an iterator function, it returns each element in the list of abort plans in order.
- Returns:
- (function, args) : Each todo is returned just how the user first added it None : None is returned when there are no more todo’s
-
getNextTodo()[source]¶ Like an iterator function, it returns each element in the list of plans in order.
- Returns:
- (function, args) : Each todo is returned just how the user first added it None : None is returned when there are no more todo’s
-
paradrop.backend.exc.resource module¶
-
generatePlans(update)[source]¶ This function looks at a diff of the current Chute (in @chuteStor) and the @newChute, then adds Plan() calls to make the Chute match the @newChute.
- Returns:
- True: abort the plan generation process
-
generateResourcePlan(chuteStor, newChute, chutePlan)[source]¶ This function looks at a diff of the current Chute (in @chuteStor) and the @newChute, then adds Plan() calls to make the Chute match the @newChute.
- Returns:
- None : means continue to pass this chute update to the rest of the chain. True : means stop updating, but its ok (no errors or anything) str : means stop updating, but some error occured (contained in the string)
paradrop.backend.exc.runtime module¶
paradrop.backend.exc.state module¶
-
generatePlans(update)[source]¶ This function looks at a diff of the current Chute (in @chuteStor) and the @newChute, then adds Plan() calls to make the Chute match the @newChute.
- Returns:
- True: abort the plan generation process
-
generateStatePlan(chuteStor, newChute, chutePlan)[source]¶ This function looks at a diff of the current Chute (in @chuteStor) and the @newChute, then adds Plan() calls to make the Chute match the @newChute.
- Returns:
- None : means continue to pass this chute update to the rest of the chain. True : means stop updating, but its ok (no errors or anything) str : means stop updating, but some error occured (contained in the string)
paradrop.backend.exc.struct module¶
paradrop.backend.exc.traffic module¶
-
generatePlans(update)[source]¶ This function looks at a diff of the current Chute (in @chuteStor) and the @newChute, then adds Plan() calls to make the Chute match the @newChute.
- Returns:
- True: abort the plan generation process
-
generateTrafficPlan(chuteStor, newChute, chutePlan)[source]¶ This function looks at a diff of the current Chute (in @chuteStor) and the @newChute, then adds Plan() calls to make the Chute match the @newChute.
- Returns:
- None : means continue to pass this chute update to the rest of the chain. True : means stop updating, but its ok (no errors or anything) str : means stop updating, but some error occured (contained in the string)
Module contents¶
paradrop.backend.fc package¶
Submodules¶
paradrop.backend.fc.chutestorage module¶
-
class
ChuteStorage(filename=None, reactor=None)[source]¶ Bases:
paradrop.lib.utils.storage.PDStorageChuteStorage class.
This class holds onto the list of Chutes on this AP.
It implements the PDStorage class which allows us to save the chuteList to disk transparently
-
chuteList= {}¶
-
deleteChute(ch)[source]¶ Deletes a chute from the chute storage. Can be sent the chute object, or the chute name.
-
paradrop.backend.fc.configurer module¶
-
class
PDConfigurer(storage, lclReactor)[source]¶ ParaDropConfigurer class. This class is in charge of making the configuration changes required on the chutes. It utilizes the ChuteStorage class to hold onto the chute data.
- Use @updateChutes to make the configuration changes on the AP.
- This function is thread-safe, this class will only call one update set at a time. All others are held in a queue until the last update is complete.
-
performUpdates()[source]¶ This is the main working function of the PDConfigurer class. It should be executed as a separate thread, it does the following:
checks for any updates to perform does them responds to the server removes the update checks for more updates
if more exist it calls itself again more quickly else it puts itself to sleep for a little while
-
updateList(**updateObj)[source]¶ MUTEX: updateLock Take the list of Chutes and push the list into a queue object, this object will then call the real update function in another thread so the function that called us is not blocked.
We take a callable responseFunction to call, when we are done with this update we should call it.
paradrop.backend.fc.updateObject module¶
updateObject module.
This holds onto the UpdateObject class. It allows us to easily abstract away different update types and provide a uniform way to interpret the results through a set of basic actionable functions.
-
class
UpdateChute(obj)[source]¶ Bases:
paradrop.backend.fc.updateObject.UpdateObjectUpdates specifically tailored to chute actions like create, delete, etc...
-
saveState()[source]¶ For chutes specifically we need to change the chuteStor object to reflect the new state of the system after a chute update. Perform that update here.
-
updateModuleList= [<module 'paradrop.backend.exc.name' from '/home/docs/checkouts/readthedocs.org/user_builds/paradrop/checkouts/v0.1/paradrop/paradrop/backend/exc/name.pyc'>, <module 'paradrop.backend.exc.state' from '/home/docs/checkouts/readthedocs.org/user_builds/paradrop/checkouts/v0.1/paradrop/paradrop/backend/exc/state.pyc'>, <module 'paradrop.backend.exc.struct' from '/home/docs/checkouts/readthedocs.org/user_builds/paradrop/checkouts/v0.1/paradrop/paradrop/backend/exc/struct.pyc'>, <module 'paradrop.backend.exc.resource' from '/home/docs/checkouts/readthedocs.org/user_builds/paradrop/checkouts/v0.1/paradrop/paradrop/backend/exc/resource.pyc'>, <module 'paradrop.backend.exc.traffic' from '/home/docs/checkouts/readthedocs.org/user_builds/paradrop/checkouts/v0.1/paradrop/paradrop/backend/exc/traffic.pyc'>, <module 'paradrop.backend.exc.runtime' from '/home/docs/checkouts/readthedocs.org/user_builds/paradrop/checkouts/v0.1/paradrop/paradrop/backend/exc/runtime.pyc'>]¶
-
-
class
UpdateObject(obj)[source]¶ Bases:
objectThe base UpdateObject class, covers a few basic methods but otherwise all the intelligence exists in the inherited classes.
All update information passed by the API server is contained as variables of this class such as update.updateType, update.updateClass, etc...
- By default, the following variables should be utilized:
responses : an array of messages any module can choose to append warnings or errors to
- failure : the module that chose to fail this update can set a string message to return
- : to the user in the failure variable. It should be very clear as to why the : failure occurred, but if the user wants more information they may find it : in the responses variable which may contain debug information, etc...
-
complete(**kwargs)[source]¶ Signal to the API server that any action we need to perform is complete and the API server can finish its connection with the client that initiated the API request.
-
execute()[source]¶ The function that actually walks through the main process required to create the chute. It follows the executeplan module through the paces of:
- Generate the plans for each exc module
- Prioritize the plans
- Execute the plans
If at any point we fail then this function will directly take care of completing the update process with an error state and will close the API connection.
-
updateModuleList= []¶
Module contents¶
paradrop.backend.pdconfd package¶
Subpackages¶
-
class
ConfigObject[source]¶ Bases:
object-
classmethod
build(manager, source, name, options, comment)[source]¶ Build a config object instance from the UCI section.
Arguments: source – file containing this configuration section name – name of the configuration section
If None, a unique name will be generated.options – dictionary of options loaded from the section comment – comment string or None
-
lookup(allConfigs, sectionType, sectionName, addDependent=True)[source]¶ Look up a section by type and name.
If addDependent is True (default), the current object will be added as a dependent of the found section.
Will raise an exception if the section is not found.
-
nextId= 0¶
-
options= []¶
-
typename= None¶
-
classmethod
-
class
ConfigDhcp[source]¶ Bases:
paradrop.backend.pdconfd.config.base.ConfigObject-
options= [{'default': None, 'required': True, 'type': <type 'str'>, 'name': 'interface'}, {'default': '12h', 'required': True, 'type': <type 'str'>, 'name': 'leasetime'}, {'default': 150, 'required': True, 'type': <type 'int'>, 'name': 'limit'}, {'default': 100, 'required': True, 'type': <type 'int'>, 'name': 'start'}, {'default': '', 'required': False, 'type': <type 'list'>, 'name': 'dhcp_option'}]¶
-
typename= 'dhcp'¶
-
-
class
ConfigDnsmasq[source]¶ Bases:
paradrop.backend.pdconfd.config.base.ConfigObject-
options= [{'default': None, 'required': False, 'type': <type 'list'>, 'name': 'interface'}, {'default': False, 'required': False, 'type': <type 'bool'>, 'name': 'noresolv'}, {'default': None, 'required': False, 'type': <type 'list'>, 'name': 'server'}]¶
-
typename= 'dnsmasq'¶
-
-
class
ConfigRedirect[source]¶ Bases:
paradrop.backend.pdconfd.config.base.ConfigObject-
options= [{'default': None, 'required': False, 'type': <type 'str'>, 'name': 'src'}, {'default': None, 'required': False, 'type': <type 'str'>, 'name': 'src_ip'}, {'default': None, 'required': False, 'type': <type 'str'>, 'name': 'src_dip'}, {'default': None, 'required': False, 'type': <type 'str'>, 'name': 'src_port'}, {'default': None, 'required': False, 'type': <type 'str'>, 'name': 'src_dport'}, {'default': 'tcpudp', 'required': True, 'type': <type 'str'>, 'name': 'proto'}, {'default': None, 'required': False, 'type': <type 'str'>, 'name': 'dest'}, {'default': None, 'required': False, 'type': <type 'str'>, 'name': 'dest_ip'}, {'default': None, 'required': False, 'type': <type 'str'>, 'name': 'dest_port'}, {'default': 'DNAT', 'required': False, 'type': <type 'str'>, 'name': 'target'}]¶
-
typename= 'redirect'¶
-
-
class
ConfigZone[source]¶ Bases:
paradrop.backend.pdconfd.config.base.ConfigObject-
options= [{'default': None, 'required': True, 'type': <type 'str'>, 'name': 'name'}, {'default': None, 'required': False, 'type': <type 'list'>, 'name': 'network'}, {'default': False, 'required': False, 'type': <type 'bool'>, 'name': 'masq'}, {'default': 'DROP', 'required': False, 'type': <type 'str'>, 'name': 'input'}, {'default': 'DROP', 'required': False, 'type': <type 'str'>, 'name': 'forward'}, {'default': 'DROP', 'required': False, 'type': <type 'str'>, 'name': 'output'}]¶
-
typename= 'zone'¶
-
-
class
ConfigManager(writeDir)[source]¶ Bases:
object-
changingSet(files)[source]¶ Return the sections from the current configuration that may have changed.
This checks which sections from the current configuration came from files in the given file list. These are sections that may be changed or removed when we reload the files.
-
findMatchingConfig(config, byName=False)[source]¶ Check the current config for an identical section.
Returns the matching object or None.
-
loadConfig(search=None, execute=True)[source]¶ Load configuration files and apply changes to the system.
We process the configuration files in sections. Each section corresponds to an interface, firewall rule, DHCP server instance, etc. Each time we reload configuration files after the initial time, we check for changes against the current configuration. Here is the decision tree for handling differences in the newly loaded configuration vs. the existing configuration:
- Section exists in current config (by type and name)?
- No -> Add section, apply changes, and stop.
- Yes -> Continue.
Section is identical to the one in the current config (by option values)?
- No -> Revert current section, mark any affected dependents,
add new section, apply changes, and stop.
Yes -> Continue.
- Section has not changed but one of its dependencies has?
No -> Stop.
- Yes -> Revert current section, mark any affected dependents,
add new section, apply changes, and stop.
-
readConfig(files)[source]¶ Load configuration files and return configuration objects.
This method only loads the configuration files without making any changes to the system and returns configuration objects as a generator.
-
statusString()[source]¶ Return a JSON string representing status of the system.
The format will be a list of dictionaries. Each dictionary corresponds to a configuration block and contains at the following fields.
type: interface, wifi-device, etc. name: name of the section (may be autogenerated for some configs) comment: comment from the configuration file or None success: True if all setup commands succeeded
-
-
findConfigFiles(search=None)[source]¶ Look for and return a list of configuration files.
The behavior depends on whether the search argument is a file, a directory, or None.
If search is None, return a list of files in the system config directory. If search is a file name (not a path), look for it in the working directory first, and the system directory second. If search is a full path to a file, and it exists, then return that file. If search is a directory, return the files in that directory.
-
class
ConfigInterface[source]¶ Bases:
paradrop.backend.pdconfd.config.base.ConfigObject-
options= [{'default': None, 'required': True, 'type': <type 'str'>, 'name': 'proto'}, {'default': None, 'required': True, 'type': <type 'str'>, 'name': 'ifname'}, {'default': True, 'required': False, 'type': <type 'bool'>, 'name': 'enabled'}, {'default': None, 'required': False, 'type': <type 'str'>, 'name': 'ipaddr'}, {'default': None, 'required': False, 'type': <type 'str'>, 'name': 'netmask'}]¶
-
typename= 'interface'¶
-
-
class
ConfigWifiDevice[source]¶ Bases:
paradrop.backend.pdconfd.config.base.ConfigObject-
options= [{'default': None, 'required': True, 'type': <type 'str'>, 'name': 'type'}, {'default': 1, 'required': True, 'type': <type 'int'>, 'name': 'channel'}]¶
-
typename= 'wifi-device'¶
-
-
class
ConfigWifiIface[source]¶ Bases:
paradrop.backend.pdconfd.config.base.ConfigObject-
options= [{'default': None, 'required': True, 'type': <type 'str'>, 'name': 'device'}, {'default': 'ap', 'required': True, 'type': <type 'str'>, 'name': 'mode'}, {'default': 'Paradrop', 'required': True, 'type': <type 'str'>, 'name': 'ssid'}, {'default': 'lan', 'required': True, 'type': <type 'str'>, 'name': 'network'}, {'default': None, 'required': False, 'type': <type 'str'>, 'name': 'encryption'}, {'default': None, 'required': False, 'type': <type 'str'>, 'name': 'key'}]¶
-
typename= 'wifi-iface'¶
-
Submodules¶
paradrop.backend.pdconfd.client module¶
-
class
Blocking(deferred)[source]¶ Bases:
objectUses threading.Event to implement blocking on a twisted deferred object.
The wait method will wait for its completion and return its result.
Dear Lance. I hope you stub your toe.
-
reload(path, dbus=False)[source]¶ Reload file(s) specified by path.
This function blocks until the request completes. On completion it returns a status string, which is a JSON list of loaded configuration sections with a ‘success’ field. For critical errors such as failure to connect to the D-Bus service, it will return None.
-
reloadAll(dbus=False)[source]¶ Reload all files from the system configuration directory.
This function blocks until the request completes. On completion it returns a status string, which is a JSON list of loaded configuration sections with a ‘success’ field. For critical errors such as failure to connect to the D-Bus service, it will return None.
-
waitSystemUp(dbus=False)[source]¶ Wait for the configuration daemon to finish its first load.
This function blocks until the request completes. On completion it returns a status string, which is a JSON list of loaded configuration sections with a ‘success’ field. For critical errors such as failure to connect to the D-Bus service, it will return None.
paradrop.backend.pdconfd.main module¶
This module listens for D-Bus messages and triggers reloading of configuration files. This module is the service side of the implementation. If you want to issue reload commands to the service, see the client.py file instead.
- Operation:
- When triggered, read in UCI configuration files.
- Pass sections off to appropriate handlers (interface, etc.).
- Perform some validation (check for required options).
- Emit commands (start/stop daemon, ip, iw, etc.) into a queue.
- Issue commands, maybe rollback on failure.
- Update known state of the system.
Reference: http://excid3.com/blog/an-actually-decent-python-dbus-tutorial/
Module contents¶
paradrop.backend.pdfcd package¶
Submodules¶
paradrop.backend.pdfcd.apichute module¶
-
class
ChuteAPI(rest)[source]¶ The Chute API submodule. This class handles all API calls related to actionable items that directly effect chutes.
-
POST_createChute(theSelf, request, *args, **kwargs)¶
-
POST_deleteChute(theSelf, request, *args, **kwargs)¶
-
POST_startChute(theSelf, request, *args, **kwargs)¶
-
POST_stopChute(theSelf, request, *args, **kwargs)¶
-
paradrop.backend.pdfcd.apiinternal module¶
-
apiWrapper(target)[source]¶ Add a final line of error and success callbacks before going onto the wire
-
api_provision(*args, **kwargs)[source]¶ Provision this router with an id and a set of keys.
This is a temporary call until the provisioning process is finalized.
-
castFailure(failure)[source]¶ Converts an exception (or general failure) into an xmlrpc fault for transmission.
paradrop.backend.pdfcd.apiutils module¶
backend.pdfcd.apiutils. Contains helper functions specific to the backend API code.
-
addressInNetwork(ipaddr, netTuple)[source]¶ This function allows you to check if on IP belongs to a Network. Arguments:
unpacked IP address (use unpackIPAddr()) tuple of unpacked (addr, netmask) (use unpackIPAddrWithSlash())- Returns:
- True if in network False otherwise
-
getIP(req)[source]¶ Returns the str IP addr from the request. NOTE: This is required because when we use nginx servers it is used as a proxy, so the REAL IP addr is stored in a HTTP header called ‘X-Real-IP’, so we need to check for this first, otherwise the request.getClientIP() is always going to return ‘localhost’ to us.
paradrop.backend.pdfcd.server module¶
pdfcd.server. Contains the classes required to establish a RESTful API server using Twisted.
-
class
ParadropAPIServer(*args, **kwargs)[source]¶ Bases:
paradrop.lib.api.pdrest.APIResourceThe main API server module.
This sets up all of the submodules which should contain different types of RESTful API calls.
-
complete(update)[source]¶ Kicks off the properly threaded call to complete the API call that was passed to PDConfigurer. Since the PDConfigurer module has its own thread that runs outside of the main event loop, we have to call back into the event system properly in order to keep any issues of concurrency at bay.
-
failprocess(ip, request, logFailure, errorStmt, logUsage, errType)[source]¶ If logFailure is not None, Update the failureDict when the request does something wrong If logUsage is not None, log the usage track info.
- Arguments:
ip : IP of client request : the request we received logFailure : If none, we do not log this failure to failure dict. Otherwise it is a tuple of
key : the key to use in the failureDict failureDict : the dict record the failure attempt history- errorStmt : A string to return to the user, looks like ‘Malformed Body: %s’
- so that we can add things like “Number of attempts remaining: 2” to the response
logUsage : A tuple of (tictoc and devid) used for usage tracker errorResponse: The error code to set response code
- Returns:
- String to respond to the client
-
postprocess(request, key, failureDict, logUsage)[source]¶ If the client is successful in their request, we should: * reset their failure attempts if failureDict is not none. * set success response code * If usage is not none, add usage track info of the api call
-
preprocess(request, checkThresh, tictoc)[source]¶ Check if failure attempts for the user name has met the threshold. Arguments:
request : checkThresh : If None, no checking. Tuple of arguments for checking thresholds
ip: IP of client in string format token: sessionToken if found, or None username: username if signin, or None failureDict: the dict for failure historyticktoc: If none, do not track the usage. The start time of the API call
- Return:
- str: if threshold is met None: if ok
-
Module contents¶
Module contents¶
paradrop.lib package¶
Subpackages¶
paradrop.lib.api package¶
Submodules¶
paradrop.lib.api.pdapi module¶
-
exception
PDAPIError(etype, msg)[source]¶ Bases:
exceptions.ExceptionException class related to ParaDrop API calls.
-
getErrorToken()[source]¶ Generates a random string which is used to match client issues with log output.
paradrop.lib.api.pdrest module¶
-
ALL(regex)¶
-
APIDecorator(admin=False, permission=None, requiredArgs=[], optionalArgs=[])[source]¶ The decorator for the API functions to make the API functions focus on their job. This decorator do the following things:
- Set HTTP header
- Get some common values like ip, tictoc
- Do the preprocess
- Extract arguments from HTTP body and put them into APIPackage
- Get devid if token is shown and put devid into APIPackage
- Check admin authorization if devid is shown and admin argument is set to be true
- Do the failprocess if fails. Do the postProcess if success
This decorator will pass an APIPackage to an API function and the API function is supposed to put return value into the API package Arguments:
- admin: if the function needs admin authority to call
- requiredArgs: the required arguments for this API, this wrapper will parse the required args from HTTP body and check if they exist in the body.
- optionalArgs: the optional arguments for this API, the args will be parsed from HTTP body
- permission: choose from None, “AP Owner”, “Chute Owner”
- TODO:
- 1.Permission
- multiple permission/multiple level of permission??
- More permissions: such as Vnet Owner, Group Owner
-
class
APIPackage(request)[source]¶ This is a class that wrap up the input and return value of API The input arguments will be in the inputArgs as a dict Result is True means the API return success Result is False means the API return failure Result is None means the API return NOT_YET_DONE
-
DELETE(regex)¶
-
GET(regex)¶
-
POST(regex)¶
-
PUT(regex)¶
Module contents¶
paradrop.lib.config package¶
Submodules¶
paradrop.lib.config.configservice module¶
- configservice module:
- This module is responsible for “poking” the proper host OS services to change the host OS config. This would include things like changing the networking, DHCP server settings, wifi, etc..
paradrop.lib.config.devices module¶
Detect physical devices that can be used by chutes.
This module detects physical devices (for now just network interfaces) that can be used by chutes. This includes WAN interfaces for Internet connectivity and WiFi interfaces which can host APs.
It also makes sure certain entries exist in the system UCI files for these devices, for example “wifi-device” sections. These are shared between chutes, so they only need to be added when missing.
-
getSystemDevices(update)[source]¶ Detect devices on the system.
Store device information in cache key “networkDevices”.
paradrop.lib.config.dhcp module¶
paradrop.lib.config.firewall module¶
-
findMatchingInterface(iface_name, interfaces)[source]¶ Search an interface list for one matching a given name.
iface_name can contain shell-style wildcards (* and ?).
-
getDeveloperFirewallRules(update)[source]¶ Generate other firewall rules requested by the developer such as redirects. The object returned is a list of tuples (config, options).
paradrop.lib.config.network module¶
-
getNetworkConfig(update)[source]¶ For the Chute provided, return the dict object of a 100% filled out configuration set of network configuration. This would include determining what the IP addresses, interfaces names, etc...
-
getOSNetworkConfig(update)[source]¶ Takes the network interface obj created by NetworkManager.getNetworkConfiguration and returns a properly formatted object to be passed to the OpenWrtConfig class. The object returned is a list of tuples (config, options).
-
reclaimNetworkResources(chute)[source]¶ Reclaim network resources for a previously running chute.
This function only applies to the special case in which pd starts up and loads a list of chutes that were running. This function marks their IP addresses and interface names as taken so that new chutes will not use the same values.
paradrop.lib.config.osconfig module¶
- osconfig module:
- This module is in charge of changing configuration files for pdfcd on the host OS. This relates to things like network, dhcp, wifi, firewall changes. Pdfcd should be able to make simple abstracted calls into this module so that if we need to change what type of OS config we need to support only this module would change.
paradrop.lib.config.pool module¶
paradrop.lib.config.uciutils module¶
-
appendListItem(options, name, value)[source]¶ Add a list item to UCI options.
The way we store lists for UCI options is rather bizarre, so this function takes care of that.
options: dictionary of options for a UCI section name: string name of the list option value: string value to append
-
removeConfigs(chute, cacheKeys, filepath)[source]¶ used to modify config file of each various setting in /etc/config/
-
restoreConfigFile(chute, configname)[source]¶ Restore a system config file from backup.
This can only be used during a chute update operation to revert changes that were made during that update operation.
configname: name of configuration file (“network”, “wireless”, etc.)
paradrop.lib.config.wifi module¶
Module contents¶
paradrop.lib.utils package¶
Submodules¶
paradrop.lib.utils.addresses module¶
-
areWanPortsAvailable(portRange, takenPorts, chuteStor, name)[source]¶ Make sure that if we are forwarding a wan port, we have not already forwarded it.
-
checkPhyExists(radioid)[source]¶ Check if this chute exists at all, a directory /sys/class/ieee80211/phyX must exist.
-
getChuteIntf(name, netIntfs)[source]¶ This function takes a network interface name, and parses through the netIntfs object provided looking for a match, it returns name if none is found.
- Example:
- if ‘lan’ is the name, ‘lan’ will be returned. if ‘wifilxc’ is the name, ‘c####wifilxc’ will be returned.
- This function also deals with the usage of macro expansions:
- Example:
If the developer defines a ‘lan’ interface for their chute, but they also have a rule that needs to point to the HOST lan interface, a conflict will occur.
To solve this, the developer would specify the HOST lan with '@net.host.lan‘ and the chute lan with ‘lan’.
-
getGatewayIntf(ch)[source]¶ Looks at the key:networkInterfaces for the chute and determines what the gateway should be including the IP address and the internal interface name.
- Returns:
- A tuple (gatewayIP, gatewayInterface) None if networkInterfaces doesn’t exist or there is an error
-
getInternalIntfList(ch)[source]¶ Takes a chute object and uses the key:networkInterfaces to return a list of the internal network interfaces that will exist in the chute (e.g., eth0, eth1, ...)
- Returns:
- A list of interface names None if networkInterfaces doesn’t exist or there is an error
-
getWANIntf(ch)[source]¶ Looks at the key:networkInterfaces for the chute and finds the WAN interface.
- Returns:
- The dict from networkInterfaces None
-
incIpaddr(ipaddr, inc=1)[source]¶ Takes a quad dot format IP address string and adds the @inc value to it by converting it to a number.
- Returns:
- Incremented quad dot IP string or None if error
-
isIpAvailable(ipaddr, chuteStor, name)[source]¶ Make sure this IP address is available. Checks the IP addresses of all zones on all other chutes,
makes sure subnets are not the same.
-
isRadioPassedthrough(radioid, chuteStor, name)[source]¶ Check if any chute has already passed through to a chute.
-
isStaMeshAvailable(chuteStor, name)[source]¶ Make sure this sta/mesh is available. Only one per device because we attach to wan directly.
-
isStaMeshOnRadio(radioid, chuteStor, name)[source]¶ If we are a wifi chute, we cannot have an sta on this channel.
-
isStaticIpAvailable(ipaddr, chuteStor, name)[source]¶ Make sure this static IP address is available. Checks the IP addresses of all zones on all other chutes,
makes sure not equal.
-
isWifiIntAvailable(radioid, numWifi, chuteStor, name)[source]¶ Make sure that fewer than 7 wifi interfaces have been configured. Otherwise, the wireless card will fail.
paradrop.lib.utils.dockerapi module¶
Functions associated with deploying and cleaning up docker containers.
-
build_host_config(update)[source]¶ Build the host_config dict for a docker container based on the passed in update.
Parameters: update (obj) – The update object containing information about the chute. Returns: (dict) The host_config dict which docker needs in order to create the container.
-
failAndCleanUpDocker(validImages, validContainers)[source]¶ Clean up any intermediate containers that may have resulted from a failure and throw an Exception so that the abort process is called.
Parameters: Returns: None
-
removeChute(update)[source]¶ Remove a docker container and the image it was built on based on the passed in update.
Parameters: update (obj) – The update object containing information about the chute. Returns: None
-
restartChute(update)[source]¶ Start a docker container based on the passed in update.
Parameters: update (obj) – The update object containing information about the chute. Returns: None
-
setup_net_interfaces(update)[source]¶ Link interfaces in the host to the internal interface in the docker container using pipework.
Parameters: update (obj) – The update object containing information about the chute. Returns: None
-
startChute(update)[source]¶ Build and deploy a docker container based on the passed in update.
Parameters: update (obj) – The update object containing information about the chute. Returns: None
paradrop.lib.utils.pdos module¶
-
basename(x)¶
-
fixpath(p)[source]¶ This function is required because if we need to pass a path to something like tarfile, we cannot overwrite the function to fix the path, so we need to expose it somehow.
-
makeExecutable(*args)[source]¶ The function that takes the list of files provided and sets the X bit on them.
-
oscall(cmd, get=False)[source]¶ This function performs a OS subprocess call. All output is thrown away unless an error has occured or if @get is True Arguments:
@cmd: the string command to run [get] : True means return (stdout, stderr)- Returns:
- None if not @get and no error (stdout, retcode, stderr) if @get or yes error
-
readFile(filename, array=True, delimiter='\n')[source]¶ Reads in a file, the contents is NOT expected to be binary. Arguments:
@filename: absolute path to file @array : optional: return as array if true, return as string if False @delimiter: optional: if returning as a string, this str specifies what to use to join the lines- Returns:
- A list of strings, separated by newlines None: if the file doesn’t exist
paradrop.lib.utils.pdosq module¶
Quiet pdos module. Implements utility OS operations without relying on the output module. Therefore, this module can be used by output without circular dependency.
paradrop.lib.utils.restart module¶
lib.utils.restart Contains the functions required to restart chutes properly on power cycle of device. Checks with pdconfd to make sure it was able to properly bring up all interfaces before starting chutes.
-
reloadChutes()[source]¶ This function is called to restart any chutes that were running prior to the system being restarted. It waits for pdconfd to come up and report whether or not it failed to bring up any of the interfaces that existed before the power cycle. If pdconfd indicates something failed we then force a stop update in order to bring down all interfaces associated with that chute and mark it with a warning. If the stop fails we mark the chute with a warning manually and change its state to stopped and save to storage this isn’t great as it could mean our system still has interfaces up associated with that chute. If pdconfd doesn’t report failure we attempt to start the chute and if this fails we trust the abort process to restore the system to a consistent state and we manually mark the chute as stopped and add a warning to it. :param None :returns: (list) A list of update dicts to be used to create updateObjects that should be run before accepting new updates.
-
updateStatus(update)[source]¶ This function is a callback for the updates we do upon restarting the system. It checks whether or not the update completed successfully and if not it changes the state of the chute to stopped and adds a warning. :param update: The update object containing information about the chute that was created and whether it was successful or not. :type update: obj :returns: None
paradrop.lib.utils.storage module¶
-
class
PDStorage(filename, reactor, saveTimer)[source]¶ ParaDropStorage class.
This class is designed to be implemented by other classes. Its purpose is to make whatever data is considered important persistant to disk.
This is done by providing a reactor so a “LoopingCall” can be utilized to save to disk.
- The implementer can override functions in order to implement this class:
- getAttr() : Get the attr we need to save to disk setAttr() : Set the attr we got from disk importAttr(): Takes a payload and returns the properly formatted data exportAttr(): Takes the data and returns a payload attrSaveable(): Returns True if we should save this attr
paradrop.lib.utils.uci module¶
-
class
UCIConfig(filepath)[source]¶ - Wrapper around the UCI configuration files.
These files are found under /etc/config/, and are used by OpenWrt to keep track of configuration for modules typically found in /etc/init.d/
- The modules of interest and with current support are:
- firewall
- network
- wireless
- qos
- This class should work with any UCI module but ALL others are UNTESTED!
New configuration settings can be added to the UCI file via addConfig().
Each UCI config file is expected to contain the following syntax:
- config keyA [valueA]
- option key1 value1 ... list key2 value1 list key2 value2 ... list key3 value1 list key3 value2
- Based on the UCI file above, the config syntax would look like the following:
config is a list of tuples, containing 2 dict objects in each tuple:
- tuple[0] describes the first line (config keyA [valueA])
{‘type’: keyA, ‘name’: valueA} The value parameter is optional and if missing, then the ‘name’ key is also missing (rather than set to None).
- tuple[1] describes the options associated with the settings (both ‘option’ and ‘list’ lines)
{‘key1’: ‘value1’, ...}
- If a list is present, it looks like the following:
- {
..., ‘list’: {
‘key2’: [value1, value2, ...], ‘key3’: [value1, value2, ...] }
}
- So for the example above, the full config definition would look like:
- C = {‘type’: ‘keyA’, ‘name’: ‘valueA’} O = {‘key1’: ‘value1’, ‘list’: {‘key2’: [‘value1’, ‘value2’], ‘key3’: [‘value1’, ‘value2’]}} config = [(C, O)]
-
delConfig(config, options)[source]¶ Finds a match to the config input and removes it from the internal config data structure.
-
existsConfig(config, options)[source]¶ Tests if the (config, options) is in the current config file.
-
getConfigIgnoreComments(config)[source]¶ Returns a list of call configs with the given title. Comments are ignored.
-
restore(backupToken, saveBackup=True)[source]¶ Replaces real file (at /etc/config/) with backup copy from /tmp/-@backupToken location.
- Arguments:
- backupToken: The backup token appended at the end of the backup path saveBackup : A flag to keep a backup copy or delete it (default is keep backup)
-
chuteConfigsMatch(chutePre, chutePost)[source]¶ Takes two lists of objects, and returns whether or not they are identical.
Module contents¶
Submodules¶
paradrop.lib.chute module¶
-
class
Chute(descriptor, strip=None)[source]¶ Bases:
objectWrapper class for Chute objects.
-
appendCache(key, val)[source]¶ Finds the key they requested and appends the val into it, this function assumes the cache object is of list type, if the key hasn’t been defined yet then it will set it to an empty list.
-
dumpCache()[source]¶ Return a string of the contents of this chute’s cache. In case of catastrophic failure dump all cache content so we can debug.
-
fullDump()[source]¶ Return a dump of EVERYTHING in this chute including all API data and all internal cache data.
-
paradrop.lib.settings module¶
This file contains any settings required by ANY and ALL modules of the paradrop system. They are defaulted to some particular value and can be called by any module in the paradrop system with the following code:
from paradrop import settings print(settings.STUFF)
These settings can be overriden by a file defined which contains the following syntax:
# This changes a string default setting EXACT_SETTING_NAME0 “new string setting”
# This changes a int default setting EXACT_SETTING_NAME1 int0
If settings need to be changed, they should be done so by the initialization code (such as pdfcd, pdapi_server, pdfc_config, etc...)
- This is done by calling the following function:
- settings.updateSettings(filepath)
-
addSetting(key, value)[source]¶ Adds a new setting to this module so other modules can see it.
Parameters: - key (string.) – the setting name.
- value (variable.) – the value of the setting.
Returns: None
Module contents¶
Submodules¶
paradrop.main module¶
Core module. Contains the entry point into Paradrop and establishes all other modules. Does not implement any behavior itself.
Module contents¶
Paradrop¶
Paradrop is a software platform that enables apps to run on Wi-Fi routers. We call these apps “chutes” like a parachute. The name Paradrop comes from the fact that we are enabling the ability to “drop” supplies and resources (“apps”) into a difficult and not well-travelled environment - the home.
Our early versions of Paradrop relied on OpenWrt, however we are revamping the platform and tailoring it towards a broader developer community. Paradrop now runs on top of Snappy Ubuntu, a trimmed-down and secured operating system that can run on ARM and x86. We also enable our apps through containerization by leveraging Docker.
The Paradrop workflow¶
There are two components to the Paradrop platform:
- The build tools - our CLI that enables registration, login, and control.
- The instance tools - our configuration daemons and tools to launch apps on hardware.
As you can see from the image above, we will refer to Build Tools when we talk about the CLI program running on your development computer that controls and communicates with the rest of the Paradrop platform. Treat this tool as your window into the rest of the Paradrop world. Our Instance Tools leverage programs like Docker to allow Paradrop apps to run on router hardware. This “hardware” could be a Raspberry Pi, or even a virtual machine on your computer that acts as a router (which is why we call it an Instance sometimes). Using Paradrop, you can actually plug in a USB Wi-Fi adapter and turn a virtual machine on your computer into a real router with our platform!
Getting Started¶
Please visit the Getting Started page for a quick introduction to Paradrop.
Where to go from here?¶
We have advanced app examples found under Apps on Paradrop. If you are interested in working on the instance side of paradrop (our github code) than check out: The Paradrop Instance System.
What if I don’t have Ubuntu?¶
We will soon switch our development system to Vagrant, which will allow support across all major operating systems. We will also update the docs with notes on how to download precompiled versions of our Paradrop instance tools once they have been fully tested.