Upload
jose-ignacio-galarza
View
2.092
Download
1
Tags:
Embed Size (px)
DESCRIPTION
An introduction about how to use salt-stack and how to improve it developing new modules and states with Python
Citation preview
salt-stack
Jose Ignacio Galarza @igalarzab
IndexWhy it’s so cool?
Developing for salt-stack
How to use it?
devops+
python
salt-stack
infrastructure management
master
not a polling model,
PUSHING
send instructions to the minions telling them what to do
PUB/SUB system on 4505
REP system on 4506
master
minion minionminion
SUB REPPUB
awesome diagram
MessagePack to serialize the messages
everything is
encrypted
it uses first public keys for authentication
master needs to know public keys of the minions
then, it uses AES for communication* (symmetric, faster)
how to accept minion keys?$ salt-key Unaccepted Keys: minion_1 !
$ salt-key -a minion_1
$ !
!
!
let’s go!salt ‘*’ test.pingminion_1:
True
minions
controlled machines
receive instructions via
PUB/SUB ZeroMQ
masterless configuration
* (salt-call)
modules
they provide the
functionality
aliases
pip
mysql
filenginxapache
aptssh
upstart
S3
quota
pamiptables mount
execute them with the cli!
$ salt ‘*’ state.highstate ...
$ salt ‘*’ cmd.run ‘ls /’ ...
states
what to manage or
configure in your
hosts
salt-stack states are just DATA
* usually in YAML
they usually map to module functions
!
!
!
!
!
!
!
!
!
/etc/init/nginx.conf:file:
- managed- template: jinja- user: root- require:
- pkg: nginx
understanding states
nginx: pkg.installed: - name: nginx file: - managed - name: /etc/init/nginx.conf - source: salt://nginx.conf - require: - pkg: nginx service: - running - enable: True - watch: - file: /etc/nginx/nginx.conf
there are a lot of directives
require watch
includeextend
returners
where to save the
minion output
stdout
SQL DB
mongo
redis
renderers
language of the state
configuration
python
...
YAML
JSON
grains
configuration of the machine
* read-only data
** populated at the beginning
{% if grains['os'] == 'RedHat' %} httpd: pkg: - installed {% elif grains['os'] == 'Debian' %} apache2: pkg: - installed {% endif %}
using grains...
list the grains$ salt ‘*’ grains.ls ...
you can use them everywheredev: ‘os:Debian’: - match: grain - python_server
pillar
think of pillar as a
variable container
it’s data, just as same as the states
{% if grains['os'] == 'RedHat' %} apache: httpd git: git {% elif grains['os'] == 'Debian' %} apache: apache2 git: git-core {% endif %}
create a pillar of salt...
apache: pkg: - installed - name: {{ pillar['apache'] }}
and use it!
only salt-stack?
salt-vagrant
salt-cloud
halite
salt-bootstrap
developing for salt-stack
developing modules
it’s like developing a normal python module!
just create a file inside the _modules dir
every callable is exported*
* (with some exceptions)
import re!!import salt.utils!from salt.utils.decorators import memoize!!REVIEW_RE = re.compile(‘([\w\d_\-]+)==([\d\.]+) is available \(you have ([\d\.]+)\)’)!!!@memoize!def _detect_install():! return salt.utils.which('pip-review')!!!def __virtual__():! return 'piputils' if _detect_install() else False!
creating a module (for the pip-tools package)
!def review(autoinstall=False):! command_ret = __salt__['cmd.run'](! 'pip-review {0}'.format('-a' if autoinstall else '')! )!! packages = command_ret.split('\n')! updates = {}!! for package in packages:! match = REVIEW_RE.match(package)! if match:! name, old_v, new_v = match.groups()! updates[name] = (old_v, new_v)!! return updates!
creating a module (for the pip-tools package)
syncing the modules$ salt-call saltutil.sync_modules ...
and use it!$ salt-call piptools.review machine: ---------- Jinja2: - 2.7.1 - 2.6
useful variables like:
__salt__
__grains__
__outputter__
developing states
it’s (also) like developing a normal python module!
just create a file inside the _states dir
every callable is exported*
* (with some exceptions)
the renderer structure
maps directly to the state python module
def keep_updated(name, min_version=None, max_version=None):! updatable_packages = __salt__['piptools.review']()! pkg_info = updatable_packages.get(name, None)!! ret = {! 'name': name,! 'result': pkg_info is not None,! }!
creating a state (for the pip-tools package)
! if package_info:! ret['comment'] = 'Update {0} from {2} to {1}'.format(! name, *pkg_info! )! ret['changes'] = {! name: {! 'old': package_info[1],! 'new': package_info[0]! }! }! else:! ret['comment'] = 'Inexistent package {0}'.format(name)!! if __opts__['test']:! ret['result'] = None! else:! pass # Perform the update!! return ret!
creating a state (for the pip-tools package)
!Jinja2: # maps to "name" argument pip_package: # maps to pip_package state - keep_updated # maps to keep_updated funct - min_version: 1.0 # maps to min_version arg
mapping the file
and that’s all!
http://twitter.com/igalarzabhttp://github.com/igalarzab
questions?
thank you!