I have a fews questions:
1. Is there a way to turn on stdout for a task, to allow user prompting?
2. Is there support for creating a 'vars module', run before any tasks like 
vars and vars_prompt?
3. Any recommendations on another direction to get the desired results 
mentioned below?

I'm currently looking into creating a custom module that will read a file, 
take a user's input, and based on the input create a file on the system, 
with additional options like not prompting the user if the file already 
exists on the remote system.

The problem is I can't find a way to get the stdout to display when 
prompting the user, and it would be better to have a 'vars module' instead 
of 'task module' (run before the playbook, aka the same times vars_prompt 
is run).

I could do this with the vars_prompt, and a template, but then I loose 
flexibility and of the functionality currently in my app, and have more 
locations to update when changes are made.

Here's my example:
my_app/defaults.yaml (in revision control):  This has all the values that 
can be overridden, along with some defaults.  Some are perfectly fine to 
keep in revision control, so defaults are usually ok, others are not 
(passwords, etc).

# Program Defaults, do not edit this file!!!
# All values should be overridden in the 'settings.yaml' file.
sample_config:
  databases:
    database_name_1:
      user: user
      passwd: password
      host: db.example.com:5432
      db: postgres
      compress: true
      engine: postgresql
    database_name_2:
      user: user
      passwd: password
      host: anotherdb.example2.com:5432
      db: example
      compress: true
      engine: postgresql
  secret_key: example hard to guess flask secret key
  more_values: more_examples


remote_location/settings.yaml: Generated by user with, outside revision 
control. This doesn't need every values, as I want the defaults left out of 
this file, so if updated in rev control they won't be overridden.

sample_config:
  databases:
    database_name_1:
      user: kyle_walker
      passwd: my password is secure
    database_name_2:
      user: sample_app_login
      passwd: the apps password is secure also
  secret_key: secure flask secret key


Core logic of my module (work in progress): This would work well enough if 
the stdout can be enabled.  But I think it would be better to be have has 
run at prompt time, and then use a copy with no source, and this variable 
data as the default contents, or another custom module.

#!/usr/bin/python
# -*- coding: utf-8 -*-

import os
import yaml

from collections import OrderedDict

DOCUMENTATION = '''
---
module: yaml_prompt
... Not needed for example ...
author: Kyle Walker
'''

EXAMPLES = '''
... Not needed for example ...
'''


def ordered_load(stream, Loader=yaml.Loader, object_pairs_hook=OrderedDict):
    class OrderedLoader(Loader):
        pass
    OrderedLoader.add_constructor(
        yaml.resolver.BaseResolver.DEFAULT_MAPPING_TAG,
        lambda loader, node: 
object_pairs_hook(loader.construct_pairs(node)))
    return yaml.load(stream, OrderedLoader)


def ordered_dump(data, stream=None, Dumper=yaml.Dumper, **kwds):
    class OrderedDumper(Dumper):
        pass

    def _dict_representer(dumper, data):
        return dumper.represent_mapping(
            yaml.resolver.BaseResolver.DEFAULT_MAPPING_TAG,
            data.items())

    OrderedDumper.add_representer(OrderedDict, _dict_representer)
    return yaml.dump(data, stream, OrderedDumper, **kwds)


def prompt_user(module, settings, depth=1, defaults=True):
    if depth is 1:
        print 'Enter values for:'

    for key, val in settings.iteritems():
        indent = "  " * depth
        if isinstance(val, dict):
            print "{}{}:".format(indent, key)

            org_len = len(val)
            prompt_user(module, val, depth+1, defaults)

            # Remove if all values were default.
            if defaults is False and len(val) is 0 and org_len is not 0:
                settings.pop(key)
        else:
            new_val = raw_input("{}{}({}):".format(indent, key, val))
            if new_val:
                settings[key] = new_val
            elif defaults is False:
                settings.pop(key)


def main():
    module = AnsibleModule(
        # not checking because of daisy chain to file module
        argument_spec=dict(
            src=dict(required=True),
            dest=dict(required=True),
            copy_defaults=dict(default=True, type='bool'),
            override=dict(default=True, type='bool'),
        ),
        add_file_common_args=True,
    )

    src = os.path.expanduser(module.params['src'])
    dest = os.path.expanduser(module.params['dest'])
    copy_defaults = module.params.get('copy_defaults', None)
    override = module.params.get('validate', None)

    settings = ordered_load(open(src), yaml.SafeLoader, OrderedDict)
    prompt_user(module, settings, defaults=copy_defaults)
    content = ordered_dump(settings,
                           Dumper=yaml.SafeDumper,
                           default_flow_style=False)

    module.fail_json(msg="Still testing, stop here.\n{}".format(content))

    res_args = dict(
        dest=dest,
        src=src,
        md5sum=md5sum_src,
        changed=changed
    )

    # Copy the created contents to the server.
    module.params['src'] = None
    module.params['dest'] = dest
    module.params['content'] = content
    file_args = module.load_file_common_arguments(module.params)
    res_args['changed'] = module.set_file_attributes_if_different(
        file_args,
        res_args['changed']
    )

    module.exit_json(**res_args)

# import module snippets
from ansible.module_utils.basic import *
main()


-- 
You received this message because you are subscribed to the Google Groups 
"Ansible Project" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
To post to this group, send email to [email protected].
For more options, visit https://groups.google.com/groups/opt_out.

Reply via email to