PageRenderTime 21ms CodeModel.GetById 10ms app.highlight 9ms RepoModel.GetById 1ms app.codeStats 0ms

/lib/ansible/playbook/__init__.py

https://github.com/debfx/ansible
Python | 116 lines | 67 code | 22 blank | 27 comment | 20 complexity | bdcdb3f39a4e8a071b2def6d8d91f16b MD5 | raw file
  1# (c) 2012-2014, Michael DeHaan <michael.dehaan@gmail.com>
  2#
  3# This file is part of Ansible
  4#
  5# Ansible is free software: you can redistribute it and/or modify
  6# it under the terms of the GNU General Public License as published by
  7# the Free Software Foundation, either version 3 of the License, or
  8# (at your option) any later version.
  9#
 10# Ansible is distributed in the hope that it will be useful,
 11# but WITHOUT ANY WARRANTY; without even the implied warranty of
 12# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 13# GNU General Public License for more details.
 14#
 15# You should have received a copy of the GNU General Public License
 16# along with Ansible.  If not, see <http://www.gnu.org/licenses/>.
 17
 18# Make coding more python3-ish
 19from __future__ import (absolute_import, division, print_function)
 20__metaclass__ = type
 21
 22import os
 23
 24from ansible import constants as C
 25from ansible.errors import AnsibleParserError
 26from ansible.module_utils._text import to_bytes, to_text, to_native
 27from ansible.playbook.play import Play
 28from ansible.playbook.playbook_include import PlaybookInclude
 29from ansible.plugins.loader import get_all_plugin_loaders
 30from ansible.utils.display import Display
 31
 32display = Display()
 33
 34
 35__all__ = ['Playbook']
 36
 37
 38class Playbook:
 39
 40    def __init__(self, loader):
 41        # Entries in the datastructure of a playbook may
 42        # be either a play or an include statement
 43        self._entries = []
 44        self._basedir = to_text(os.getcwd(), errors='surrogate_or_strict')
 45        self._loader = loader
 46        self._file_name = None
 47
 48    @staticmethod
 49    def load(file_name, variable_manager=None, loader=None):
 50        pb = Playbook(loader=loader)
 51        pb._load_playbook_data(file_name=file_name, variable_manager=variable_manager)
 52        return pb
 53
 54    def _load_playbook_data(self, file_name, variable_manager, vars=None):
 55
 56        if os.path.isabs(file_name):
 57            self._basedir = os.path.dirname(file_name)
 58        else:
 59            self._basedir = os.path.normpath(os.path.join(self._basedir, os.path.dirname(file_name)))
 60
 61        # set the loaders basedir
 62        cur_basedir = self._loader.get_basedir()
 63        self._loader.set_basedir(self._basedir)
 64
 65        self._file_name = file_name
 66
 67        # dynamically load any plugins from the playbook directory
 68        for name, obj in get_all_plugin_loaders():
 69            if obj.subdir:
 70                plugin_path = os.path.join(self._basedir, obj.subdir)
 71                if os.path.isdir(to_bytes(plugin_path)):
 72                    obj.add_directory(plugin_path)
 73
 74        try:
 75            ds = self._loader.load_from_file(os.path.basename(file_name))
 76        except UnicodeDecodeError as e:
 77            raise AnsibleParserError("Could not read playbook (%s) due to encoding issues: %s" % (file_name, to_native(e)))
 78
 79        # check for errors and restore the basedir in case this error is caught and handled
 80        if not ds:
 81            self._loader.set_basedir(cur_basedir)
 82            raise AnsibleParserError("Empty playbook, nothing to do", obj=ds)
 83        elif not isinstance(ds, list):
 84            self._loader.set_basedir(cur_basedir)
 85            raise AnsibleParserError("A playbook must be a list of plays, got a %s instead" % type(ds), obj=ds)
 86
 87        # Parse the playbook entries. For plays, we simply parse them
 88        # using the Play() object, and includes are parsed using the
 89        # PlaybookInclude() object
 90        for entry in ds:
 91            if not isinstance(entry, dict):
 92                # restore the basedir in case this error is caught and handled
 93                self._loader.set_basedir(cur_basedir)
 94                raise AnsibleParserError("playbook entries must be either a valid play or an include statement", obj=entry)
 95
 96            if any(action in entry for action in ('import_playbook', 'include')):
 97                if 'include' in entry:
 98                    display.deprecated("'include' for playbook includes. You should use 'import_playbook' instead", version="2.12")
 99                pb = PlaybookInclude.load(entry, basedir=self._basedir, variable_manager=variable_manager, loader=self._loader)
100                if pb is not None:
101                    self._entries.extend(pb._entries)
102                else:
103                    which = entry.get('import_playbook', entry.get('include', entry))
104                    display.display("skipping playbook '%s' due to conditional test failure" % which, color=C.COLOR_SKIP)
105            else:
106                entry_obj = Play.load(entry, variable_manager=variable_manager, loader=self._loader, vars=vars)
107                self._entries.append(entry_obj)
108
109        # we're done, so restore the old basedir in the loader
110        self._loader.set_basedir(cur_basedir)
111
112    def get_loader(self):
113        return self._loader
114
115    def get_plays(self):
116        return self._entries[:]