Commit c1a0e22b authored by rgaudin's avatar rgaudin
Browse files

rewrote ansiblecube management to accomodate new 3-phases behavior

	--extra-vars are now in JSON format and written into a file that is uploaded
	most of the work has been moved to ansiblecube. bootstrap (master-only) limited to installing ansible
	now using the latest (2.5) ansible
	run_for_image() to create the base image
	run_phase_one() to reconfigure the softwares for the content
	run_phase_two() to finish setup after content has been placed in data partition
parent c510aa26
#!/usr/bin/env python
# -*- coding: utf-8 -*-
# vim: ai ts=4 sts=4 et sw=4 nu
import os
import json
import tempfile
import posixpath
from data import mirror
from util import ONE_GB
from backend.catalog import CATALOGS
from backend.content import get_content
ansiblecube_path = "/var/lib/ansible/local"
def run(machine, tags, extra_vars={}, secret_keys=[]):
''' run ansiblecube in given machine with specified tags and extra-vars '''
# predefined defaults we want to superseed whichever in ansiblecube
ansible_vars = {
'mirror': mirror,
'catalogs': CATALOGS,
'kernel_version': get_content('raspbian_image').get('kernel_version'),
# save extra_vars to a file on guest
extra_vars_path = posixpath.join(ansiblecube_path, "extra_vars.json")
with tempfile.NamedTemporaryFile('w', delete=False) as fp:
json.dump(ansible_vars, fp, indent=4)
machine.put_file(, extra_vars_path)
# prepare ansible command
ansible_cmd = ['/usr/local/bin/ansible-playbook',
'--inventory hosts',
'--tags {}'.format(",".join(tags)),
# display sent configuration to logger
machine._logger.std("ansiblecube extra_vars")
json.dumps({k: '****' if k in secret_keys else v
for k, v in ansible_vars.items()}, indent=4))
# review the list of tasks so the logger can use it to track progression
tasks_cmd = ansible_cmd[0:1] + ['--list-tasks'] + ansible_cmd[1:]
machine.exec_cmd("sh -c 'cd {path} && tasks=$({cmd} | paste -sd \"^\" -) "
"&& echo \"### TASKS ### $tasks\"'"
cmd=" ".join(tasks_cmd)))
# run ansible-playbook
ansible_cmd = ansible_cmd[0:1] + ['-vvv'] + ansible_cmd[1:] # verbose
machine.exec_cmd("sudo sh -c 'cd {path} && {cmd}'"
cmd=" ".join(ansible_cmd)))
def run_for_image(machine, root_partition_size, disk_size):
''' initial launch of a bare raspbian to create a base (master) image '''
tags = ['master', 'rename', 'setup']
# machine must provide write_file and exec_cmd functions
def run(machine, name, timezone, wifi_pwd, edupi, wikifundi, aflatoun, kalite, zim_install, ansiblecube_path, admin_account):
machine.exec_cmd("sudo apt-get update")
machine.exec_cmd("sudo apt-get install -y python-pip python-yaml python-jinja2 python-httplib2 python-paramiko python-pkg-resources libffi-dev libssl-dev git lsb-release")
machine.exec_cmd("sudo pip install ansible==2.2.0")
# install ansible dependencies (packages)
machine.exec_cmd("sudo apt-get install -y "
"python-dev libffi-dev libssl-dev git lsb-release")
# install the latest pip
machine.exec_cmd("wget "
"-O /tmp/")
machine.exec_cmd("sudo python /tmp/")
# install latest ansible and important python dependencies
machine.exec_cmd("sudo sudo python -m pip install -U "
"pip virtualenv jinja2 paramiko pyyaml httplib2 ansible")
# prepare ansible files
machine.exec_cmd("sudo mkdir --mode 0755 -p /etc/ansible")
machine.exec_cmd("sudo cp %s/hosts /etc/ansible/hosts" % ansiblecube_path)
hostname = name.replace("_", "-")
machine.exec_cmd("sudo hostname %s" % hostname)
machine.exec_cmd("sudo sh -c 'echo \" %s\" >> /etc/hosts'" % hostname)
package_management = [{"name": x, "status": "present"} for x in zim_install]
device_list = {hostname: {
"kalite": {
"activated": str(kalite != None),
"version": "0.16.9",
"language": kalite or [],
"wikifundi": {
"activated": str(wikifundi != None),
"language": wikifundi or [],
"aflatoun": {
"activated": aflatoun,
"edupi": {
"activated": edupi,
"idc_import": {
"activated": "False",
"content_name": [],
"package_management": package_management,
"portal": {
"activated": "True",
facts_dir = "/etc/ansible/facts.d"
facts_path = facts_dir + "/device_list.fact"
machine.exec_cmd("sudo mkdir --mode 0755 -p %s" % facts_dir)
machine.exec_cmd("sudo sh -c 'cat > {} <<END_OF_CMD3267\n{}\nEND_OF_CMD3267'".format(facts_path, json.dumps(device_list, indent=4)))
extra_vars = "ideascube_project_name=%s" % name
extra_vars += " timezone=%s" % timezone
if wifi_pwd:
extra_vars += " wpa_pass=%s" % wifi_pwd
extra_vars += " git_branch=oneUpdateFile0.3"
extra_vars += " own_config_file=True"
extra_vars += " managed_by_bsf=False"
if admin_account is not None:
extra_vars += " admin_account='{login}' admin_password='{pwd}'"
machine.exec_cmd("sudo cp {path}/hosts /etc/ansible/hosts"
machine.exec_cmd("sudo mkdir --mode 0755 -p /etc/ansible/facts.d")
# default configuration on the master: all contents enabled for setup tag
extra_vars, _ = build_extra_vars(
name="default", timezone="UTC",
language="en", language_name="English", wifi_pwd="",
wikifundi_languages=['en', 'fr'],
aflatoun_languages=['en', 'fr'],
kalite_languages=['en', 'fr', 'es'],
ansible_args = "--inventory hosts"
ansible_args += " --tags master,custom"
ansible_args += " --extra-vars \"%s\"" % extra_vars
ansible_args += " main.yml"
run(machine, tags, extra_vars)
ansible_pull_cmd = "sudo sh -c 'cd {} && /usr/local/bin/ansible-playbook {}'".format(ansiblecube_path, ansible_args)
def build_extra_vars(name, timezone, language, language_name, wifi_pwd,
edupi, wikifundi_languages,
aflatoun_languages, kalite_languages, packages,
root_partition_size, disk_size):
''' extra-vars friendly format of the ansiblecube configuration '''
extra_vars = {
'root_partition_size': root_partition_size // ONE_GB,
'disk_size': disk_size // ONE_GB,
'project_name': name,
'timezone': timezone,
'language': language,
'language_name': language_name,
'kalite_languages': kalite_languages,
'wikifundi_languages': wikifundi_languages,
'aflatoun_languages': aflatoun_languages,
'edupi': edupi,
'packages': [{"name": x, "status": "present"} for x in packages],
'captive_portal': True,
'custom_branding_path': '/tmp',
'admin_account': "admin",
'admin_password': "admin",
if wifi_pwd:
extra_vars.update({'wpa_pass': wifi_pwd})
if admin_account is not None:
run_ansible_pull_cmd = ansible_pull_cmd.format(**admin_account)
displayed_ansible_pull_cmd = ansible_pull_cmd.format(login='****', pwd='****')
extra_vars.update({'admin_account': admin_account['login'],
'admin_password': admin_account['pwd']})
secret_keys = ['admin_account', 'admin_password']
run_ansible_pull_cmd = displayed_ansible_pull_cmd = ansible_pull_cmd
secret_keys = []
return extra_vars, secret_keys
def run_phase_one(machine, extra_vars, secret_keys,
logo=None, favicon=None, css=None):
''' run ansiblecube in machine to configure requested softwares '''
tags = ['resize', 'rename', 'reconfigure']
# copy branding files if set
branding = {'favicon.png': favicon,
'header-logo.png': logo, 'style.css': css}
has_custom_branding = False
for fname, item in [(k, v) for k, v in branding.items() if v is not None]:
has_custom_branding = True
machine.put_file(item, "/tmp/{}".format(fname))
extra_vars.update({'has_custom_branding': has_custom_branding})
run(machine, tags, extra_vars, secret_keys)
def run_phase_two(machine, extra_vars, secret_keys):
''' run ansiblecube to complete config now that content is in data part '''
tags = ['move-content', 'seal']
machine.exec_cmd(run_ansible_pull_cmd, displayed_ansible_pull_cmd)
run(machine, tags, extra_vars, secret_keys)
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment