README added
This commit is contained in:
parent
82107b01e2
commit
c9d219ccbf
1 changed files with 285 additions and 0 deletions
285
README.md
Normal file
285
README.md
Normal file
|
@ -0,0 +1,285 @@
|
||||||
|
# Ansible openwrt
|
||||||
|
|
||||||
|
An collection of ansible modules written in lua for Openwrt orchestration.
|
||||||
|
|
||||||
|
Ansible is build around a collection of modules that get send to the remote
|
||||||
|
host to execute different tasks or collect information. Those modules are
|
||||||
|
implemented in python. However on embedded systems such as routers, ressources,
|
||||||
|
in particular flash memory are scarse and a python runtime often not available.
|
||||||
|
|
||||||
|
Those modules communicate with the ansible-toolsuite via well defined interfaces
|
||||||
|
and are executed via ssh. As each module is a standalone program, there is no
|
||||||
|
dependency whatsoever on the implementation language. There are existing
|
||||||
|
attempts like [this](https://github.com/lefant/ansible-openwrt) which already
|
||||||
|
implement a small set of modules as bash-scripts.
|
||||||
|
|
||||||
|
However the primary author of this project disagrees with some of the
|
||||||
|
implementation decisons (e.g. sourcing files with key=value-pairs as a kind of
|
||||||
|
parsing) and is generally a fan of (even rather limited in luas case) typing. So
|
||||||
|
this project was born.
|
||||||
|
|
||||||
|
As the OpenWrt community seems to have a strange affection for lua, this
|
||||||
|
repository currently implements the following modules:
|
||||||
|
- [copy](https://docs.ansible.com/ansible/copy_module.html)
|
||||||
|
- [file](https://docs.ansible.com/ansible/file_module.html)
|
||||||
|
- [lineinfile](https://docs.ansible.com/ansible/lineinfile_module.html)
|
||||||
|
- opkg
|
||||||
|
- [stat](https://docs.ansible.com/ansible/stat_module.html)
|
||||||
|
- ubus
|
||||||
|
- uci
|
||||||
|
|
||||||
|
Copy, file, lineinfile, stat and opkg are mostly straightforward ports of the
|
||||||
|
official python modules included in the Ansible v2.1.1.0 release. However, there
|
||||||
|
were some simplifications made:
|
||||||
|
- selinux file attributes are not supported
|
||||||
|
- validation commands are not supported
|
||||||
|
- file-operations are not guaranteed to be atomic
|
||||||
|
- permissions can only be specified in octal mode
|
||||||
|
- check_mode is only partly implemented
|
||||||
|
|
||||||
|
Apart from that, the modules should behave exactly like the upstream modules,
|
||||||
|
making it possible to use local actions such as
|
||||||
|
"[template](https://docs.ansible.com/ansible/template_module.html)" which are
|
||||||
|
built upon those modules.
|
||||||
|
|
||||||
|
# Requirements
|
||||||
|
|
||||||
|
For building the modules, perl and the
|
||||||
|
[Data::Compare](http://search.cpan.org/~dcantrell/Data-Compare-1.25/lib/Data/Compare.pm)
|
||||||
|
library are required.
|
||||||
|
|
||||||
|
If you want to use the file related modules (copy, file, lineinfile, stat), the
|
||||||
|
following opkg packages are required, which are not part of the standard images:
|
||||||
|
- luaposix
|
||||||
|
- coreutils-sha1sum
|
||||||
|
|
||||||
|
However, as the opkg-module is independent from those packages, you can install
|
||||||
|
them in your playbook like this:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
- name: Installing dependencies for file-related modules
|
||||||
|
opkg: pkg=luaposix,coreutils-sha1sum state=present update_cache=yes
|
||||||
|
```
|
||||||
|
|
||||||
|
# Building/Installation
|
||||||
|
|
||||||
|
Ansible currently has no notion of libraries used within modules (only limited
|
||||||
|
support for ansibles own core python libraries is available). For more
|
||||||
|
information please see
|
||||||
|
[this issue](https://github.com/ansible/ansible/pull/10274). Therefore all
|
||||||
|
modules that should be used have to be fatpacked (that is, the module all
|
||||||
|
referenced libraries have to be packed into one giant lua script). This is done
|
||||||
|
by the [fatpack.pl](./src/fatpack.pl) script. Usage is like this:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
./src/fatpack.pl --input <module>.lua --output ./library/ --whitelist
|
||||||
|
io,os,posix.,ubus --truncate
|
||||||
|
```
|
||||||
|
|
||||||
|
To make this process easier, a Makefile is provided that packs all modules in
|
||||||
|
`./src/` and places the fatpacked variants in `library` for you. Just run `make`
|
||||||
|
in the projects top directory.
|
||||||
|
|
||||||
|
Please note, that this project is currenty **alpha** state. I used it to manage
|
||||||
|
my personal router (playbook coming soon), but it still might easily lock you
|
||||||
|
out of your device, eat your hamsters or worse. So pleace check your playbook
|
||||||
|
beforehand against a VM (e.g. the one from the openwrt-vagrant project which
|
||||||
|
can be built from the submodule in `./test/`) or be sure that your router has a
|
||||||
|
convenient reset/failsafe path.
|
||||||
|
|
||||||
|
# Documentation
|
||||||
|
|
||||||
|
For the following modules, please refer to the upstream documentation
|
||||||
|
- [copy](https://docs.ansible.com/ansible/copy_module.html)
|
||||||
|
- [file](https://docs.ansible.com/ansible/file_module.html)
|
||||||
|
- [lineinfile](https://docs.ansible.com/ansible/lineinfile_module.html)
|
||||||
|
- [opkg](https://docs.ansible.com/ansible/opkg_module.html)
|
||||||
|
- [stat](https://docs.ansible.com/ansible/stat_module.html)
|
||||||
|
|
||||||
|
## ubus module
|
||||||
|
|
||||||
|
As a replacement for then official setup module, information on the openwrt
|
||||||
|
system can be gatherd via the ubus interface and will automatically be
|
||||||
|
integrated into the host_facts for reuse in the playbook like this:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
ubus: cmd=facts
|
||||||
|
```
|
||||||
|
|
||||||
|
Otherwise, this module is a slim wrapper around the
|
||||||
|
[ubus rpc-bus](https://wiki.openwrt.org/doc/techref/ubus).
|
||||||
|
|
||||||
|
For a list of available ubus-service-providers and their functions, you can
|
||||||
|
issue a list call. Please note that this call is not really useful in an
|
||||||
|
automated setting:
|
||||||
|
```bash
|
||||||
|
$ ansible openwrt -i hosts -m ubus -a 'cmd=list'
|
||||||
|
openwrt | SUCCESS => {
|
||||||
|
"changed": false,
|
||||||
|
"invocations": {
|
||||||
|
"module_args": {
|
||||||
|
"command": "list"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"msg": "Gathered local signatures",
|
||||||
|
"signatures": {
|
||||||
|
[...]
|
||||||
|
"uci": {
|
||||||
|
[...]
|
||||||
|
"get": {
|
||||||
|
"config": 3,
|
||||||
|
"match": 2,
|
||||||
|
"option": 3,
|
||||||
|
"section": 3,
|
||||||
|
"type": 3,
|
||||||
|
"ubus_rpc_session": 3
|
||||||
|
},
|
||||||
|
[...]
|
||||||
|
},
|
||||||
|
[...]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Those signatures can then be used to make Calls via ubus:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
ubus: cmd=call path=uci method=get message='{"config":"uhttpd", "section":"main", "option":"listen_http"}"'
|
||||||
|
```
|
||||||
|
|
||||||
|
As you can see, the `ubus_rpc_session` parameter is automatically inserted for
|
||||||
|
you by the module. The ubus return value is returned in the `result` field of the returned object and can be accessed like this:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
- name: Query http listen ports
|
||||||
|
ubus: cmd=call path=uci method=get message='{"config":"uhttpd", "section":"main", "option":"listen_http"}"'
|
||||||
|
register: foo
|
||||||
|
|
||||||
|
- name: Do something
|
||||||
|
baz: param={{ result.value }}
|
||||||
|
```
|
||||||
|
|
||||||
|
## UCI-Module
|
||||||
|
|
||||||
|
As most ubus calls will most likely target the
|
||||||
|
[uci-system](https://wiki.openwrt.org/doc/uci) a dedicated module/ubus-wrapper
|
||||||
|
for the uci configuration is provided. Basic familiarity with uci is assumed, so
|
||||||
|
please refer to the upstream [documentation](https://wiki.openwrt.org/doc/uci)
|
||||||
|
otherwise. Most of the options should map quite naturally to the module
|
||||||
|
parameters:
|
||||||
|
|
||||||
|
A special warning about types: UCI has two types for values internally: `list`
|
||||||
|
and `option`. The module tries to infer the type by looking for `,` in the
|
||||||
|
input. If you need to force a singleentry list, please be sure to set the
|
||||||
|
`forcelist=yes` parameter.
|
||||||
|
|
||||||
|
|-----------+----------+---------+-----------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||||
|
| parameter | required | default | choices | comments |
|
||||||
|
|-----------+----------+---------+-----------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||||
|
| name | no | | | Path to the property to change. Syntax is `config.section.option`. _Aliases: path, key_ |
|
||||||
|
| value | no | | | For set: value to set the property to |
|
||||||
|
| forcelist | no | false | Boolean | The module trys to guess the uci config type (list or string) from the supplied value via the existance of `,` in the input. Single entry lists require `forcelist=yes` to be recognized correctly |
|
||||||
|
| state | no | present | present, absent, set, unset | State of the property |
|
||||||
|
| op | no | | configs, commit, revert | If specified, instead of enforcing a value, either list the available configurations, or execute a commit/revert operation |
|
||||||
|
| reload | no | | Boolean | Whether to reload the configuration from disk before executing. _Aliases: reload_configs, reload-configs_ |
|
||||||
|
| autocomit | no | true | Boolean | Whether to automatically commit the changes made |
|
||||||
|
| type | no | | | When creating a new section, a configuration-type is required. Aliases: _section-type_ |
|
||||||
|
| socket | no | | | Set a nonstandard path to the ubus socket if necessary |
|
||||||
|
| timeout | no | | | Change the default ubus timeout |
|
||||||
|
|-----------+----------+---------+-----------------------------+----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------|
|
||||||
|
|
||||||
|
Examples:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
# Set a value
|
||||||
|
uci: name="system.@system[0].hostname" value="mysuperduperrouter"
|
||||||
|
|
||||||
|
# Delete a value
|
||||||
|
uci: name="system.@system[0].hostname" state=absent
|
||||||
|
|
||||||
|
# Revert and commit globally
|
||||||
|
uci: op=revert
|
||||||
|
uci: op=commit
|
||||||
|
|
||||||
|
# Only commit/revert a single section
|
||||||
|
uci: path=dropbear op=revert
|
||||||
|
uci: path=dropbear op=commit
|
||||||
|
|
||||||
|
# Create the uhttpd.test section with type uhttp
|
||||||
|
# and set foo=bar
|
||||||
|
uci: name=uhttpd.test.foo value=bar type="uhttpd" autocommit=false'
|
||||||
|
|
||||||
|
# Remove the uttpd.test section
|
||||||
|
uci: name=uhttpd.test state="absent" autocommit=true'
|
||||||
|
|
||||||
|
# Get a list of all available configuration files
|
||||||
|
uci: op=configs
|
||||||
|
```
|
||||||
|
|
||||||
|
An more complex example showing the usage of forcelist:
|
||||||
|
|
||||||
|
```yaml
|
||||||
|
- name: Securing uhttpd - Disable listening on wan
|
||||||
|
uci: name={{ item.key }} value={{ uci.state.network.lan.ipaddr }}:{{ item.port }} forcelist=true autocommit=false
|
||||||
|
with_items:
|
||||||
|
- { key: 'uhttpd.main.listen_http', port: '80' }
|
||||||
|
- { key: 'uhttpd.main.listen_https', port: '443' }
|
||||||
|
notify:
|
||||||
|
- uci commit
|
||||||
|
```
|
||||||
|
|
||||||
|
# Contributing
|
||||||
|
|
||||||
|
Give me all your pullrequest :) If you find a bug in one of the provided modules
|
||||||
|
(quite possible) or want to contribute a new module, feel free to propose a
|
||||||
|
pullrequest.
|
||||||
|
To make develpment of the modules easier, two libraries are provided. The
|
||||||
|
ansible library in `./src/ansible.lua` tries to provide a easy starting point
|
||||||
|
for module development similar to ansibles `ansible.module_utils.basic` library.
|
||||||
|
|
||||||
|
It will handle argument parsing for you:
|
||||||
|
|
||||||
|
```lua
|
||||||
|
local module = Ansible.new({
|
||||||
|
name = { aliases = {"pkg"}, required=true , type='list'},
|
||||||
|
state = { default = "present", choices={"present", "installed", "absent", "removed"} },
|
||||||
|
force = { default = "", choices={"", "depends", "maintainer", "reinstall", "overwrite", "downgrade", "space", "postinstall", "remove", "checksum", "removal-of-dependent-packages"} } ,
|
||||||
|
update_cache = { default = "no", aliases={ "update-cache" }, type='bool' }
|
||||||
|
})
|
||||||
|
|
||||||
|
module:parse(arg[1])
|
||||||
|
|
||||||
|
local p = module:get_params()
|
||||||
|
```
|
||||||
|
|
||||||
|
And provides some convenience function such as `get_bin_path`, `run_command`,
|
||||||
|
`fail_json` and `exit_json`. Currently, those are badly underdocumented, but
|
||||||
|
the names are mostly selfexplanatory, so just look through the functions in the
|
||||||
|
file.
|
||||||
|
|
||||||
|
```lua
|
||||||
|
local opkg_path = module:get_bin_path('echo', true, {'/bin'})
|
||||||
|
local rc, out, err = module:run_command(string.format("%s foobar", opkg_path))
|
||||||
|
if rc ~= 0 then
|
||||||
|
module:fail_json({msg="failed to echo foobar", info={rc=rc, out=out, err=err}})
|
||||||
|
else
|
||||||
|
module:exit_json({msg="successfully echod foobar", changed=false})
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|
||||||
|
Additionaly, the `./src/fileutils.lua` module has various wrappers for various
|
||||||
|
filesystemrelated tasks. Again: Please look up the functions in the sourcefile
|
||||||
|
and look how they are used in the provided modules.
|
||||||
|
|
||||||
|
# License
|
||||||
|
|
||||||
|
The libraries and only included in this repository for convenience are available
|
||||||
|
under their own respective licenses:
|
||||||
|
- [dkjson](http://dkolf.de/src/dkjson-lua.fsl/home) MIT License
|
||||||
|
- [BinDecHex](http://www.dialectronics.com/Lua/code/BinDecHex.shtml) MIT
|
||||||
|
License
|
||||||
|
- [openwrt-in-vagrant](https://github.com/lifeeth/openwrt-in-vagrant) MIT
|
||||||
|
License
|
||||||
|
|
||||||
|
All other code is available under the terms and conditions of the AGPL3 license.
|
||||||
|
For more details please the the [LICENSE file](LICENSE).
|
Loading…
Add table
Reference in a new issue