Skip to content

Commit

Permalink
Implemented yaml inventory file
Browse files Browse the repository at this point in the history
Moved the generated host inventory from the proprietary "ini" format to
Ansible's new yaml format.

Fixes: ansible#683
  • Loading branch information
retr0h committed Jan 5, 2017
1 parent ccb4765 commit 14a7aef
Show file tree
Hide file tree
Showing 6 changed files with 143 additions and 154 deletions.
20 changes: 1 addition & 19 deletions molecule/config.py
Expand Up @@ -18,7 +18,6 @@
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE.

import collections
import os

import anyconfig
Expand Down Expand Up @@ -78,23 +77,6 @@ def lint(self):
def platforms(self):
return self.config['platforms']

@property
def platform_groups(self):
# [baz]
# instance-2-default
# [foo]
# instance-1-default
# instance-2-default
# [bar]
# instance-1-default
dd = collections.defaultdict(list)
for platform in self.config['platforms']:
for group in platform.get('groups', []):
name = '{}-{}'.format(platform['name'], self.scenario.name)
dd[group].append(name)

return dict(dd)

@property
def provisioner(self):
if self.config['provisioner']['name'] == 'ansible':
Expand Down Expand Up @@ -153,7 +135,7 @@ def _get_defaults(self):
'config_file': 'ansible.cfg',
'diff': True,
'host_key_checking': False,
'inventory_file': 'ansible_inventory',
'inventory_file': 'ansible_inventory.yml',
'limit': 'all',
'playbook': 'playbook.yml',
'raw_ssh_args': [
Expand Down
21 changes: 5 additions & 16 deletions molecule/driver/docker.py
Expand Up @@ -18,8 +18,6 @@
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE.

import collections

from molecule.driver import base


Expand All @@ -45,26 +43,17 @@ def __init__(self, config):
@property
def testinfra_options(self):
"""
Returns Testinfra specific options dict.
Returns a Testinfra specific options dict.
:returns: dict
"""
return {'connection': 'docker'}

@property
def inventory(self):
# TODO: This should belong in provisioner.
def connection_options(self):
"""
Construct a dict of hosts/connection options and returns a dict.
Returns a driver specific connection options dict.
:returns: dict
:returns: str
"""
# instance-1-default ansible_connection=docker
# instance-2-default ansible_connection=docker
host_options = 'ansible_connection=docker'
dd = collections.defaultdict(list)
for d in self._config.platforms:
name = '{}-{}'.format(d['name'], self._config.scenario.name)
dd[name].append(host_options)

return dict(dd)
return {'ansible_connection': 'docker'}
57 changes: 30 additions & 27 deletions molecule/provisioner.py
Expand Up @@ -18,8 +18,11 @@
# FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
# DEALINGS IN THE SOFTWARE.

import collections
import os

import yaml
import yaml.representer
import jinja2

from molecule import ansible_playbook
Expand Down Expand Up @@ -79,12 +82,30 @@ def options(self):

@property
def inventory(self):
return self._config.driver.inventory
# ungrouped:
# hosts:
# instance-1-default:
# instance-2-default:
# $group_name:
# hosts:
# instance-1-default:
# ansible_connection: docker
# instance-2-default:
# ansible_connection: docker
dd = vivify()
for platform in self._config.platforms:
for group in platform.get('groups', ['ungrouped']):
name = '{}-{}'.format(platform['name'],
self._config.scenario.name)
connection_options = self._config.driver.connection_options
dd[group]['hosts'][name] = connection_options

return dd

@property
def inventory_file(self):
return os.path.join(self._config.ephemeral_directory,
'ansible_inventory')
'ansible_inventory.yml')

@property
def config_file(self):
Expand All @@ -106,15 +127,12 @@ def write_inventory(self):
:return: None
"""

self._verify_inventory()
yaml.add_representer(collections.defaultdict,
yaml.representer.Representer.represent_dict)

template = jinja2.Environment().from_string(
self._get_inventory_template()).render(
host_data=self.inventory,
groups_data=self._config.platform_groups)
with open(self.inventory_file, 'w') as f:
f.write(template)
f.write(yaml.dump(self.inventory))

def write_config(self):
"""
Expand Down Expand Up @@ -152,25 +170,6 @@ def _verify_inventory(self):
util.print_error(msg)
util.sysexit()

def _get_inventory_template(self):
"""
Returns an inventory template string.
:return: str
"""
return """
# Molecule managed
{% for k, v in host_data.iteritems() -%}
{{ k }} {{ v|join(' ') }}
{% endfor -%}
{% for k, v in groups_data.iteritems() %}
[{{ k }}]
{{ v|join('\n') }}
{% endfor -%}
""".strip()

def _get_config_template(self):
"""
Returns a config template string.
Expand All @@ -186,3 +185,7 @@ def _get_config_template(self):
ansible_managed = Ansible managed: Do NOT edit this file manually!
retry_files_enabled = False
"""


def vivify():
return collections.defaultdict(vivify)
15 changes: 6 additions & 9 deletions test/unit/driver/test_docker.py
Expand Up @@ -45,18 +45,15 @@ def test_testinfra_options_property(docker_instance):
assert {'connection': 'docker'} == docker_instance.testinfra_options


def test_connection_options_property(docker_instance):
x = {'ansible_connection': 'docker'}

assert x == docker_instance.connection_options


def test_name_property(docker_instance):
assert 'docker' == docker_instance.name


def test_options_property(docker_instance):
assert {} == docker_instance.options


def test_inventory_property(docker_instance):
x = {
'instance-1-default': ['ansible_connection=docker'],
'instance-2-default': ['ansible_connection=docker']
}

assert x == docker_instance.inventory
45 changes: 0 additions & 45 deletions test/unit/test_config.py
Expand Up @@ -91,51 +91,6 @@ def test_platforms_property(config_instance):
assert x == config_instance.platforms


def test_platform_groups_property(config_instance):
x = {
'bar': ['instance-1-default'],
'foo': ['instance-1-default', 'instance-2-default'],
'baz': ['instance-2-default']
}

assert x == config_instance.platform_groups


@pytest.fixture
def platforms_data_incomplete_groups():
return {
'platforms': [{
'name': 'instance-1',
'groups': ['foo', 'bar'],
}, {
'name': 'instance-2',
}]
}


def test_platform_groups_property_handles_missing_group(
platforms_data_incomplete_groups, molecule_file, config_data):
configs = [platforms_data_incomplete_groups, config_data]
c = config.Config(molecule_file, configs=configs)

x = {'foo': ['instance-1-default'], 'bar': ['instance-1-default']}

assert x == c.platform_groups


@pytest.fixture
def platforms_data_no_groups():
return {'platforms': [{'name': 'instance-1', }, {'name': 'instance-2', }]}


def test_platform_groups_property_handles_no_groups(
platforms_data_no_groups, molecule_file, config_data):
configs = [platforms_data_no_groups, config_data]
c = config.Config(molecule_file, configs=configs)

assert {} == c.platform_groups


def test_provisioner_property(config_instance):
assert isinstance(config_instance.provisioner, provisioner.Ansible)

Expand Down

0 comments on commit 14a7aef

Please sign in to comment.