Introduction
Both ansible modules and sparrow plugins are building blocks to solve elementary tasks in configuration management and automation deployment. Ansible modules are used in higher level playbooks scenarios written in YAML, sparrow plugins used in high level sparrowdo scenarios written in Perl6.
Languages support
Ansible – you may choose any language to write modules. When developing modules out of the box ansible provides seamless support for Python only ( shortcuts ), for other languages you should use third-party libraries ( natively for language you write a plugin ) to make a plugin development and integration process easier.
Sparrow – you write plugins on one of three languages – Perl5, Bash or Ruby. When developing modules sparrow provides an unified ( available for all languages ) API to make plugins development and integration easy and seamless. Though such an API as not that extensive as Python shortcuts API for ansible modules.
System design
Ansible – ansible modules are autonomous units of code to solve elementary task. Under this hood it’s just single file of code. Ansible modules can’t depend neither call other modules.
Sparrow – sparrow plugins are very similar to ansible modules in way of autonomous, closed untis of code to solve an elementary tasks. But sparrow provides yet another level of freedom for plugin developer. Sparrow plugins actually is a suites of scripts. Scripts may call other scripts with parameters. Such a design make it easy split even elementary task into scripts “speaking” to each other. Consider a trivial example – install / removing software packages. We can think about plugin to cope with whole elementary task ( installing / remove packages ) but under the hood split all by two scripts – one for package installing, another for package removal. This idea is quite expressed at comprehensive post – Sparrow plugins evolution.
Here is a simple illustration of what I have said.
System integration
Anisble – ansible modules a smaller part of higher level configuration scenarios called playbooks. Ansible playbook is YAML driven dsl to declare a list of tasks – anisble modules with parameters.
Sparrow – like ansible modules, sparrow plugins are smaller part of overall system – spparowdo – configuration management tool written on Perl6. Sparrowdo scenarios are Perl6 code to run a sparrow tasks – sparrow plugins with parameters.
End user interface
Ansible – ansible modules gets called via playbooks using a YAML DSL to declare modules calls and pass parameters to. It is also possible to run ansible modules via command line client passing parameters as command line arguments.
Below is example of ansible playbook with ansible module yum to install httpd software package
$ cat playbook.yml --- - hosts: webservers tasks: - name: ensure apache is at the latest version yum: name=httpd state=latest
Sparrow – sparrow plugins gets called via sparrowdo scenarios using a Perl6 API. Plugin parameters gets passed as Perl6 Hashes. Also one may use sparrow console client to run sparrow plugins as is via command line, not using sparrowdo. There are a lot of options here – command line parameters, parameters in JSON / YMAL format, Config::General format parameters.
Below is sparrowdo equivalent to ansible module yum installing latest version of httpd.
Two flavours of API are shown – core-dsl and plugin API
$ cat sparrowfile
# you can use a short core-dsl API flavour:
package-install 'httpd';
# or low level plugin API flavour:
task-run 'ensure apache is at the latest version', 'package-generic', %(
list => 'httpd'
);
Processing input parameters
Ansible – input parameters as key=value pairs (*), when developing plugin you should parse an input and “split” it to the pieces of data to get a variables you need. There are plenty of “helpers” for many languages ( like Perl5, Ruby ) to simplify this process or else you have to parse input data explicitly inside anisble module.
(*) Nested input parameters are possible
Ansible provides a high level Python API for ansible modules called shortcuts allow you to automatically parse input and create parameter accessors, declare parameters types, set default values, check required parameters and do other useful things with regards to.
Below is example of module parameters processing using python ansible API:
$ cat library/greetings.py
from ansible.module_utils.basic import *
def main():
fields = { "message": {"default": "Hi!", "type": "str" } }
module = AnsibleModule(argument_spec=fields)
module.params['message']
# some other code here to return results
if __name__ == '__main__':
main()
Sparrow – the similar way sparrow provides a unified ( available for all languages ) API to access input parameters. So you don’t have to parse an input data at all.
Thus, irrespective the language you write a plugin you get a programming API to access input parameters. Plugin developers could define so called default configuration so that plugin input parameters ( if not set explicitly ) gets initialized with sane defaults.
Below is sparrow equivalent to the ansible module accessing named input parameter. We are going to use Bash here.
# this is plugin scenario: $ cat story.bash message=$(config message) # this is default configuration: $ cat story.ini message = Hi!
And this is how sparrow handles nested input parameters!
$ cat sparrowfile task-run "run my task", 'foo-plugin', %( foo => { bar => { baz => 'BAZ' } } ); $ cat story.bash baz=$(config foo.bar.baz)
Return results
Ansible – ansible modules return results as JSON. There are some essential points about how ansible modules return:
* an exit code of ansible module script gets ignored
* the only requirement to module – it should print a special formatted ( containing required fields ) JSON to STDOUT
* if no valid JSON is appeared at module’s output it is considered as failure
* a STDOUT/STDERR generated by module ( if any ) is not seen at playbook output
* Thus if module developer want to return some value he/she always has to pack the data into JSON format and return it via JSON string.
Below is example of ansible module to return a current time.
$ cat library/currentime.py import datetime import json date = str(datetime.datetime.now()) print json.dumps({ "time" : date })
Sparrow – sparrow plugins can return whatever , actually sparrow does not care ( but see “handle results” section ) about what is appeared at STDOUT/STDERR. There are some essential points about how sparrow plugins returns:
* an exit code is important, it should be 0, otherwise sparrow treat a plugins execution as failure
* a STDOUT from plugin simply gets redirected to sparrowdo output, so you always see what happening under the hood, no wrapping results into JSON is taken place like for ansible modules.
Below is sparrow equivalent to the ansible module returning a current time, we are going to use Perl5 here:
$ cat story.pl print scalar localtime;
Handle results
Ansible – as ansible module return structured JSON data, it is possible to assign data included in JSON to some ansible variables and use them in upper level ( inside playbooks ).
Below is example of simple echo module which just return what it gets as input
$ cat playbook.yml - hosts: localhost tasks: - name: tell me what I say echo: message: "hi there!" register: result - debug: var=result $ cat library/echo.py
from ansible.module_utils.basic import * def main(): module = AnsibleModule(argument_spec={}) response = {"you_said": module.params['message']} module.exit_json(changed=True, meta=response) if __name__ == '__main__': main()
Sparrow – as was told sparrow does not care about WHAT appears at plugin’s STDOUT. Well not that true. Plugins developers can defined check rules to validate STDOUT comes from plugin scripts. Such a validation consists of matching STDOUT lines against Perl regexs and many other things you can get acquainted with at Outthenitc::DSL documentation pages – a sparrow embedded DSL to validate text output. And output validation result impact the overall execution status of sparrow plugin, thus if validation checks fails it result in failure plugin itself. Such a embedded testing facilities make it east develop a plugins for automation testing or audit purposes.
Probably there is no to add here as example besides this dummy code 🙂
$ cat sparrowfile run-task "tell me what I say", "echo", %( message => 'hi there!' ) $ cat story.bash echo you said $(config message)
A trivial check rule for script output will be:
$ cat story.check generator: config()->{message}
Deployment process
Ansible – many ansible modules gets shipped as a core part of ansible itself – ready to use, no extra efforts for deployment should be taken. Users write a custom modules and host them at SCM ( github , gitlab , svn ), finally modules are just a files get check out into directory on master host where you push ansible tasks against remote hosts, so no special actions on deployment process should be taken besides getting ansible modules files downloaded. Ansible modules eco system thus consists of three large parts:
* main Ansible repository – modules gets shipped as ansible core
* custom ansible modules
So ansible follows pure agentless schema with push approach. No modules deployment gets happened gets happened at target host. Anisble only pushes modules as files where they are executed.
Below is a schematic view of ansible custom modules deployment:
Sparrow – sparrow plugins are actually a packaged scripts gets delivered like any kind software package – deb, rpm, rubygems, CPAN. Sparrow exposes a console manager to download and install sparrow plugins. A sparrowdo compiles a scenarios into list of meta data and copies this into remote host. Then a sparrow manager gets run ( over ssh ) on remote host to pick up the meta data and then download, install and execute the plugins.
So sparrow follows client server schema with push approach and plugins deployments get happened on the side of target host.
Sparrow plugins have versions, ownership and documentation. Sparrow plugins gets hosted at central plugins repository – SparrowHub
Here meta data example of sparrow plugin “package-generic” to install software packages:
{ "name" : "package-generic", "version" : "0.2.16", "description": "Generic package manager. Installs packages using OS specific package managers (yum,apt-get)", "url" : "https://github.com/melezhik/package-generic" }
There is no rigid separation between custom and “core” plugins at sparrow eco system Every plugin gets uploaded to SparrowHub immediately becomes accessible for end users and sparrowdo scenarios. For security reasons sparrow provides ability to host so called “private” plugins at remote git repositories. Such a plugins could be “mixed in” to standard sparrow pipeline.
Below is a schematic view of sparrow plugins deployment:
Dependencies
Ansible – ansible provides not built in facilities to manage dependencies at the level of ansible module, probably you would have it at level upper – ansible playbooks. Thus is you module depend on some software library you should care about such a dependency resolution at some other place.
Sparrow – sparrow provides facilities to manage dependencies at the level of sparrow plugin. Thus if plugin depends on software libraries you may declare such a dependencies at the plugin scope so that plugins manager will take care about dependency resolution at the moment of plugin installing. For the time being dependencies for Perl5 and Ruby languages are supported. CPAN modules for Perl5 via cpanfile and RubyGems for Ruby via Gemfile.
Summary
Ansible gained a big success due to extensive eco system of existed ansible modules. Though when comparing a module development process with those one exist at sparrow ( sparrow plugins ) I find some interesting and promising features a sparrow might shows at this field. To sum they up:
* Playbooks VS sparrowdo scenarios – sparrowdo provides imperative Perl6 language interface against declarative way of ansible playbooks written in YAML. As for the some task such a declarative approach is fine, there are cases when we need add imperative style to our configuration scenarios provided by any modern generic purpose language, where YAML for sure does not fit.
* Script oriented design – Due it’s script oriented design sparrow plugins provides you way to split a whole tasks into many simple scripts interacting with each other. This actually what we usually do when doing a regular scripting for routine tasks, so why not to bring it here? 🙂
* Modules/Plugins management and life cycle – sparrow plugins are even more loosely coupled with configuration management tool itself then we see it at ansible. They are developed, debugged, hosted and managed independently without even knowledge about sparrowdo configuration management tool. This makes process of plugin development more effective and less painless.
* Bash/Shell scripting – sparrow provides much better support for “straightforward” bash/shell scripting then ansible due to spoken limitation of the last on return results and “JSON” interface. It is hard to understand what is going wrong in case of executing ansible bash scripts as it hides all STDOUT/STDERR generated by. Meanwhile Sparrow honestly shows what comes from executes bash/shell commands.
* Programming API – sparrow provides an unified API for all the languages, it means every language has a “equal” rights at sparrow eco system and shares the same possibilities in term of API. Meanwhile ansible modules tends to be written on Python as it seems the most seamless way to develop asnible modules.
* Testing facilities – sparrow exposes builtin test facilities which expands sparrow usage to not only deployments tasks but also to testing/monitoring/audit needs.
Leave a comment