Skip to content

Commit

Permalink
Creating playbook executor and dependent classes
Browse files Browse the repository at this point in the history
  • Loading branch information
jimi-c committed Dec 29, 2014
1 parent b6c3670 commit 62d7956
Show file tree
Hide file tree
Showing 158 changed files with 22,508 additions and 2,375 deletions.
2 changes: 2 additions & 0 deletions v2/ansible/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,3 +18,5 @@
# Make coding more python3-ish
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type

__version__ = '1.v2'
1 change: 1 addition & 0 deletions v2/ansible/constants.py
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,7 @@ def shell_expand_path(path):
DEFAULTS='defaults'

# configurable things
DEFAULT_DEBUG = get_config(p, DEFAULTS, 'debug', 'ANSIBLE_DEBUG', False, boolean=True)
DEFAULT_HOST_LIST = shell_expand_path(get_config(p, DEFAULTS, 'hostfile', 'ANSIBLE_HOSTS', '/etc/ansible/hosts'))
DEFAULT_MODULE_PATH = get_config(p, DEFAULTS, 'library', 'ANSIBLE_LIBRARY', None)
DEFAULT_ROLES_PATH = shell_expand_path(get_config(p, DEFAULTS, 'roles_path', 'ANSIBLE_ROLES_PATH', '/etc/ansible/roles'))
Expand Down
21 changes: 15 additions & 6 deletions v2/ansible/errors/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@

import os

from ansible.parsing.yaml.strings import *
from ansible.errors.yaml_strings import *

class AnsibleError(Exception):
'''
Expand All @@ -45,12 +45,12 @@ def __init__(self, message, obj=None, show_content=True):

self._obj = obj
self._show_content = show_content
if isinstance(self._obj, AnsibleBaseYAMLObject):
if obj and isinstance(obj, AnsibleBaseYAMLObject):
extended_error = self._get_extended_error()
if extended_error:
self.message = '%s\n\n%s' % (message, extended_error)
self.message = 'ERROR! %s\n\n%s' % (message, extended_error)
else:
self.message = message
self.message = 'ERROR! %s' % message

def __str__(self):
return self.message
Expand Down Expand Up @@ -98,8 +98,9 @@ def _get_extended_error(self):
(target_line, prev_line) = self._get_error_lines_from_file(src_file, line_number - 1)
if target_line:
stripped_line = target_line.replace(" ","")
arrow_line = (" " * (col_number-1)) + "^"
error_message += "%s\n%s\n%s\n" % (prev_line.rstrip(), target_line.rstrip(), arrow_line)
arrow_line = (" " * (col_number-1)) + "^ here"
#header_line = ("=" * 73)
error_message += "\nThe offending line appears to be:\n\n%s\n%s\n%s\n" % (prev_line.rstrip(), target_line.rstrip(), arrow_line)

# common error/remediation checking here:
# check for unquoted vars starting lines
Expand Down Expand Up @@ -158,3 +159,11 @@ class AnsibleModuleError(AnsibleRuntimeError):
class AnsibleConnectionFailure(AnsibleRuntimeError):
''' the transport / connection_plugin had a fatal error '''
pass

class AnsibleFilterError(AnsibleRuntimeError):
''' a templating failure '''
pass

class AnsibleUndefinedVariable(AnsibleRuntimeError):
''' a templating failure '''
pass
File renamed without changes.
167 changes: 167 additions & 0 deletions v2/ansible/executor/connection_info.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,167 @@
# (c) 2012-2014, Michael DeHaan <michael.dehaan@gmail.com>
#
# This file is part of Ansible
#
# Ansible is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Ansible is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.

# Make coding more python3-ish
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type

import pipes
import random

from ansible import constants as C


__all__ = ['ConnectionInformation']


class ConnectionInformation:

'''
This class is used to consolidate the connection information for
hosts in a play and child tasks, where the task may override some
connection/authentication information.
'''

def __init__(self, play=None, options=None):
# FIXME: implement the new methodology here for supporting
# various different auth escalation methods (becomes, etc.)

self.connection = C.DEFAULT_TRANSPORT
self.remote_user = 'root'
self.password = ''
self.port = 22
self.su = False
self.su_user = ''
self.su_pass = ''
self.sudo = False
self.sudo_user = ''
self.sudo_pass = ''
self.verbosity = 0
self.only_tags = set()
self.skip_tags = set()

if play:
self.set_play(play)

if options:
self.set_options(options)

def set_play(self, play):
'''
Configures this connection information instance with data from
the play class.
'''

if play.connection:
self.connection = play.connection

self.remote_user = play.remote_user
self.password = ''
self.port = int(play.port) if play.port else 22
self.su = play.su
self.su_user = play.su_user
self.su_pass = play.su_pass
self.sudo = play.sudo
self.sudo_user = play.sudo_user
self.sudo_pass = play.sudo_pass

def set_options(self, options):
'''
Configures this connection information instance with data from
options specified by the user on the command line. These have a
higher precedence than those set on the play or host.
'''

# FIXME: set other values from options here?

self.verbosity = options.verbosity
if options.connection:
self.connection = options.connection

# get the tag info from options, converting a comma-separated list
# of values into a proper list if need be
if isinstance(options.tags, list):
self.only_tags.update(options.tags)
elif isinstance(options.tags, basestring):
self.only_tags.update(options.tags.split(','))
if isinstance(options.skip_tags, list):
self.skip_tags.update(options.skip_tags)
elif isinstance(options.skip_tags, basestring):
self.skip_tags.update(options.skip_tags.split(','))

def copy(self, ci):
'''
Copies the connection info from another connection info object, used
when merging in data from task overrides.
'''

self.connection = ci.connection
self.remote_user = ci.remote_user
self.password = ci.password
self.port = ci.port
self.su = ci.su
self.su_user = ci.su_user
self.su_pass = ci.su_pass
self.sudo = ci.sudo
self.sudo_user = ci.sudo_user
self.sudo_pass = ci.sudo_pass
self.verbosity = ci.verbosity
self.only_tags = ci.only_tags.copy()
self.skip_tags = ci.skip_tags.copy()

def set_task_override(self, task):
'''
Sets attributes from the task if they are set, which will override
those from the play.
'''

new_info = ConnectionInformation()
new_info.copy(self)

for attr in ('connection', 'remote_user', 'su', 'su_user', 'su_pass', 'sudo', 'sudo_user', 'sudo_pass'):
if hasattr(task, attr):
attr_val = getattr(task, attr)
if attr_val:
setattr(new_info, attr, attr_val)

return new_info

def make_sudo_cmd(self, sudo_exe, executable, cmd):
"""
Helper function for wrapping commands with sudo.
Rather than detect if sudo wants a password this time, -k makes
sudo always ask for a password if one is required. Passing a quoted
compound command to sudo (or sudo -s) directly doesn't work, so we
shellquote it with pipes.quote() and pass the quoted string to the
user's shell. We loop reading output until we see the randomly-
generated sudo prompt set with the -p option.
"""

randbits = ''.join(chr(random.randint(ord('a'), ord('z'))) for x in xrange(32))
prompt = '[sudo via ansible, key=%s] password: ' % randbits
success_key = 'SUDO-SUCCESS-%s' % randbits

sudocmd = '%s -k && %s %s -S -p "%s" -u %s %s -c %s' % (
sudo_exe, sudo_exe, C.DEFAULT_SUDO_FLAGS, prompt,
self.sudo_user, executable or '$SHELL',
pipes.quote('echo %s; %s' % (success_key, cmd))
)

#return ('/bin/sh -c ' + pipes.quote(sudocmd), prompt, success_key)
return (sudocmd, prompt, success_key)

66 changes: 66 additions & 0 deletions v2/ansible/executor/manager.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
# (c) 2012-2014, Michael DeHaan <michael.dehaan@gmail.com>
#
# This file is part of Ansible
#
# Ansible is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# Ansible is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.

# Make coding more python3-ish
from __future__ import (absolute_import, division, print_function)
__metaclass__ = type

from multiprocessing.managers import SyncManager, BaseProxy
from ansible.playbook.handler import Handler
from ansible.playbook.task import Task
from ansible.playbook.play import Play
from ansible.errors import AnsibleError

__all__ = ['AnsibleManager']


class VariableManagerWrapper:
'''
This class simply acts as a wrapper around the VariableManager class,
since manager proxies expect a new object to be returned rather than
any existing one. Using this wrapper, a shared proxy can be created
and an existing VariableManager class assigned to it, which can then
be accessed through the exposed proxy methods.
'''

def __init__(self):
self._vm = None

def get_vars(self, loader, play=None, host=None, task=None):
return self._vm.get_vars(loader=loader, play=play, host=host, task=task)

def set_variable_manager(self, vm):
self._vm = vm

def set_host_variable(self, host, varname, value):
self._vm.set_host_variable(host, varname, value)

def set_host_facts(self, host, facts):
self._vm.set_host_facts(host, facts)

class AnsibleManager(SyncManager):
'''
This is our custom manager class, which exists only so we may register
the new proxy below
'''
pass

AnsibleManager.register(
typeid='VariableManagerWrapper',
callable=VariableManagerWrapper,
)

Loading

0 comments on commit 62d7956

Please sign in to comment.