コード例 #1
0
class TestDataLoaderWithVault(unittest.TestCase):
    def setUp(self):
        self._loader = DataLoader()
        vault_secrets = [('default', TextVaultSecret('ansible'))]
        self._loader.set_vault_secrets(vault_secrets)

    def tearDown(self):
        pass

    @patch.multiple(DataLoader,
                    path_exists=lambda s, x: True,
                    is_file=lambda s, x: True)
    def test_parse_from_vault_1_1_file(self):
        vaulted_data = """$ANSIBLE_VAULT;1.1;AES256
33343734386261666161626433386662623039356366656637303939306563376130623138626165
6436333766346533353463636566313332623130383662340a393835656134633665333861393331
37666233346464636263636530626332623035633135363732623332313534306438393366323966
3135306561356164310a343937653834643433343734653137383339323330626437313562306630
3035
"""
        if PY3:
            builtins_name = 'builtins'
        else:
            builtins_name = '__builtin__'

        with patch(builtins_name + '.open',
                   mock_open(read_data=vaulted_data.encode('utf-8'))):
            output = self._loader.load_from_file('dummy_vault.txt')
            self.assertEqual(output, dict(foo='bar'))
コード例 #2
0
    def _play_prereqs():
        options = context.CLIARGS

        # all needs loader
        loader = DataLoader()

        basedir = options.get('basedir', False)
        if basedir:
            loader.set_basedir(basedir)
            add_all_plugin_dirs(basedir)
            set_collection_playbook_paths(basedir)

        vault_ids = list(options['vault_ids'])
        default_vault_ids = C.DEFAULT_VAULT_IDENTITY_LIST
        vault_ids = default_vault_ids + vault_ids

        vault_secrets = CLI.setup_vault_secrets(loader,
                                                vault_ids=vault_ids,
                                                vault_password_files=list(options['vault_password_files']),
                                                ask_vault_pass=options['ask_vault_pass'],
                                                auto_prompt=False)
        loader.set_vault_secrets(vault_secrets)

        # create the inventory, and filter it based on the subset specified (if any)
        inventory = InventoryManager(loader=loader, sources=options['inventory'])

        # create the variable manager, which will be shared throughout
        # the code, ensuring a consistent view of global variables
        variable_manager = VariableManager(loader=loader, inventory=inventory, version_info=CLI.version_info(gitinfo=False))

        return loader, inventory, variable_manager
コード例 #3
0
def get_ansible_variablemanager(self, **kwargs):
    from ansible.parsing.dataloader import DataLoader
    from ansible.utils.vars import load_extra_vars
    from ansible.vars.manager import VariableManager
    if 'options' in kwargs:
        options = kwargs['options']
    else:
        options = AnsibleOptions()
    if 'loader' in kwargs:
        loader = kwargs['loader']
    else:
        loader = DataLoader()
        vault_secret = get_vault_password_source(self.master.main_config)
        if not isinstance(vault_secret, NullSource):
            loader.set_vault_secrets([(vault_secret.id, vault_secret)])
        basedir = get_playbooks_directory(self.master.ctrl.config)
        loader.set_basedir(basedir)
    if 'inventory' in kwargs:
        inventory = kwargs['inventory']
    else:
        inventory = self.get_ansible_inventorymanager()
    if 'variable_manager' in kwargs:
        variable_manager = kwargs['variable_manager']
    else:
        variable_manager = VariableManager(loader=loader, inventory=inventory)
        variable_manager.extra_vars = load_extra_vars(loader=loader, options=options)
    return (options, loader, inventory, variable_manager)
コード例 #4
0
ファイル: yamlmanifest.py プロジェクト: onecommons/unfurl
    def _configure_root(self, rootResource):
        rootResource.imports = self.imports
        if (
            self.manifest.vault and self.manifest.vault.secrets
        ):  # setBaseDir() may create a new templar
            rootResource._templar._loader.set_vault_secrets(self.manifest.vault.secrets)
        rootResource.envRules = self.context.get("variables") or CommentedMap()
        if not self.localEnv:
            return

        # use the password associated with the project the repository appears in.
        repos = set(self.repositories.values())
        project = self.localEnv.project or self.localEnv.homeProject
        while project:
            loader = DataLoader()
            vault = project.make_vault_lib()
            if vault:
                yaml = make_yaml(vault)
                loader.set_vault_secrets(vault.secrets)
                for repoview in project.workingDirs.values():
                    if repoview in repos:
                        repoview.load_secrets(loader)
                        repoview.yaml = yaml
                        repos.remove(repoview)
            project = project.parentProject

        # left over:
        for repository in repos:
            repository.load_secrets(rootResource._templar._loader)
            repository.yaml = self.yaml
コード例 #5
0
    def get_play_prereqs_2_4(self, options):
        loader = DataLoader()

        if self.vault_pass:
            loader.set_vault_secrets([
                ('default', VaultSecret(_bytes=to_bytes(self.vault_pass)))
            ])

        # create the inventory, and filter it based on the subset specified (if any)
        inventory = InventoryManager(loader=loader, sources=options.inventory)

        # create the variable manager, which will be shared throughout
        # the code, ensuring a consistent view of global variables
        try:
            # Ansible 2.8
            variable_manager = VariableManager(
                loader=loader,
                inventory=inventory,
                version_info=self.version_info(ansible_version))
            variable_manager._extra_vars = self.extra_vars
        except TypeError:
            variable_manager = VariableManager(loader=loader,
                                               inventory=inventory)
            variable_manager.extra_vars = self.extra_vars
            variable_manager.options_vars = {
                'ansible_version': self.version_info(ansible_version)
            }

        return loader, inventory, variable_manager
コード例 #6
0
	def _prepare_for_run(self, host, extra_vars, playbook):
		module_path = f'{self._base_plays_path}/modules'

		options = InventoryOptions(
			remote_user=self._remote_user,
			private_key_file=self._private_key_file,
			module_path=module_path)

		loader = DataLoader()
		loader.set_vault_secrets(self._default_secret)
		inventory = InventoryManager(loader=loader, sources=f'{host},')
		variable_manager = VariableManager(loader=loader, inventory=inventory)
		variable_manager.extra_vars = extra_vars

		self.play_executor = PlaybookExecutor(
			playbooks=[playbook],
			options=options,
			loader=loader,
			inventory=inventory,
			variable_manager=variable_manager,
			passwords={}
		)
		self.logger_cb = LogCallBack(self._verbosity)
		# TODO: make a PR to ansible core to allowing access to task queue
		# manager property in order to get all execution logs
		self.play_executor._tqm._stdout_callback = self.logger_cb
コード例 #7
0
ファイル: __init__.py プロジェクト: mrlesmithjr/ansible-1
    def _play_prereqs():
        options = context.CLIARGS

        # all needs loader
        loader = DataLoader()

        basedir = options.get('basedir', False)
        if basedir:
            loader.set_basedir(basedir)
            add_all_plugin_dirs(basedir)
            AnsibleCollectionConfig.playbook_paths = basedir
            default_collection = _get_collection_name_from_path(basedir)
            if default_collection:
                display.warning(u'running with default collection {0}'.format(default_collection))
                AnsibleCollectionConfig.default_collection = default_collection

        vault_ids = list(options['vault_ids'])
        default_vault_ids = C.DEFAULT_VAULT_IDENTITY_LIST
        vault_ids = default_vault_ids + vault_ids

        vault_secrets = CLI.setup_vault_secrets(loader,
                                                vault_ids=vault_ids,
                                                vault_password_files=list(options['vault_password_files']),
                                                ask_vault_pass=options['ask_vault_pass'],
                                                auto_prompt=False)
        loader.set_vault_secrets(vault_secrets)

        # create the inventory, and filter it based on the subset specified (if any)
        inventory = InventoryManager(loader=loader, sources=options['inventory'], cache=(not options.get('flush_cache')))

        # create the variable manager, which will be shared throughout
        # the code, ensuring a consistent view of global variables
        variable_manager = VariableManager(loader=loader, inventory=inventory, version_info=CLI.version_info(gitinfo=False))

        return loader, inventory, variable_manager
コード例 #8
0
ファイル: __init__.py プロジェクト: awiddersheim/ansible
    def _play_prereqs(options):

        # all needs loader
        loader = DataLoader()

        basedir = getattr(options, 'basedir', False)
        if basedir:
            loader.set_basedir(basedir)

        vault_ids = options.vault_ids
        default_vault_ids = C.DEFAULT_VAULT_IDENTITY_LIST
        vault_ids = default_vault_ids + vault_ids

        vault_secrets = CLI.setup_vault_secrets(loader,
                                                vault_ids=vault_ids,
                                                vault_password_files=options.vault_password_files,
                                                ask_vault_pass=options.ask_vault_pass,
                                                auto_prompt=False)
        loader.set_vault_secrets(vault_secrets)

        # create the inventory, and filter it based on the subset specified (if any)
        inventory = InventoryManager(loader=loader, sources=options.inventory)

        # create the variable manager, which will be shared throughout
        # the code, ensuring a consistent view of global variables
        variable_manager = VariableManager(loader=loader, inventory=inventory)

        # load vars from cli options
        variable_manager.extra_vars = load_extra_vars(loader=loader, options=options)
        variable_manager.options_vars = load_options_vars(options, CLI.version_info(gitinfo=False))

        return loader, inventory, variable_manager
コード例 #9
0
ファイル: playbooks.py プロジェクト: allanhung/pyansible
class Runner(object):

    def __init__(self, hosts_file, playbook_file, cfg_file=None, vault_id=None, private_key_file=None, module_path=None, become_pass=None, verbosity=0):

        self.hosts_file = hosts_file
        self.playbook_file = playbook_file
        self.vault_id = vault_id

        if cfg_file:
            os.environ['ANSIBLE_CONFIG']=cfg_file
        self.options = Options()
        if private_key_file:
            self.options.private_key_file = private_key_file
        self.options.verbosity = verbosity
        if module_path:
            self.options.module_path = module_path
        self.options.connection = 'ssh'

        # set verbosity
        self.display = Display()
        self.display.verbosity = self.options.verbosity
        playbook_executor.verbosity = self.options.verbosity

        # Become Pass Needed if not logging in as user root
        if become_pass:
            self.options.become = True
            self.options.become_method = 'sudo'
            self.options.become_user = '******'
            passwords = {'become_pass': become_pass}
        else:
            passwords = {}

        # Gets data from YAML/JSON files
        self.loader = DataLoader()

        # vault secrets valut_id=name@password
        vault_secrets = []
        if self.vault_id:
            vault_ids = vault_id.split(',', vault_id) if ',' in vault_id else [vault_id]
            for vid in vault_ids:
                vault_secrets.append(tuple(vid.split(',',1)))
        if vault_secrets: 
            self.loader.set_vault_secrets(vault_secrets)

        # Set inventory, using most of above objects
        self.inventory = InventoryManager(loader=self.loader, sources=self.hosts_file)
        self.variable_manager = VariableManager(loader=self.loader, inventory=self.inventory)

        # Setup playbook executor, but don't run until run() called
        self.pbex = playbook_executor.PlaybookExecutor(
            playbooks=[self.playbook_file],
            inventory=self.inventory, 
            variable_manager=self.variable_manager,
            loader=self.loader, 
            options=self.options, 
            passwords=passwords)

    def run(self):
        # Results of PlaybookExecutor
        self.pbex.run()
コード例 #10
0
ファイル: __init__.py プロジェクト: zhaoxiaoke/ansible
    def _play_prereqs(options):

        # all needs loader
        loader = DataLoader()

        vault_ids = options.vault_ids
        default_vault_ids = C.DEFAULT_VAULT_IDENTITY_LIST
        vault_ids = default_vault_ids + vault_ids

        vault_secrets = CLI.setup_vault_secrets(
            loader,
            vault_ids=vault_ids,
            vault_password_files=options.vault_password_files,
            ask_vault_pass=options.ask_vault_pass,
            auto_prompt=False)
        loader.set_vault_secrets(vault_secrets)

        # create the inventory, and filter it based on the subset specified (if any)
        inventory = InventoryManager(loader=loader, sources=options.inventory)

        # create the variable manager, which will be shared throughout
        # the code, ensuring a consistent view of global variables
        variable_manager = VariableManager(loader=loader, inventory=inventory)

        # load vars from cli options
        variable_manager.extra_vars = load_extra_vars(loader=loader,
                                                      options=options)
        variable_manager.options_vars = load_options_vars(
            options, CLI.version_info(gitinfo=False))

        return loader, inventory, variable_manager
コード例 #11
0
def runplaybook(inventory, playbook, project, bname, secret):
    loader = DataLoader()
    invlist = []
    invlist.append(inventory)
    inv = InventoryManager(loader=loader, sources=invlist)

    variable_manager = VariableManager(loader=loader, inventory=inv)
    pblist = []

    pblist.append(playbook)

    if secret != '':
        loader.set_vault_secrets([('default',
                                   VaultSecret(_bytes=to_bytes(secret)))])

    passwords = {}
    Options = namedtuple('Options', [
        'connection', 'remote_user', 'ask_sudo_pass', 'verbosity', 'ack_pass',
        'module_path', 'forks', 'become', 'become_method', 'become_user',
        'check', 'listhosts', 'listtasks', 'listtags', 'syntax', 'sudo_user',
        'sudo', 'diff'
    ])
    options = Options(connection='smart',
                      remote_user=None,
                      ack_pass=None,
                      sudo_user=None,
                      forks=5,
                      sudo=None,
                      ask_sudo_pass=False,
                      verbosity=5,
                      module_path=None,
                      become=None,
                      become_method=None,
                      become_user=None,
                      check=False,
                      diff=False,
                      listhosts=None,
                      listtasks=None,
                      listtags=None,
                      syntax=None)

    pb = PlaybookExecutor(loader=loader,
                          playbooks=pblist,
                          inventory=inv,
                          variable_manager=variable_manager,
                          passwords=passwords,
                          options=options)

    f = open('/opt/Projects/' + project + '/logs/' + bname + 'out.log', 'a+')
    # ferr=open('/opt/Projects/'+project+'/logs/'+bname+'err.log','a+')
    sys.stdout = f
    # sys.stderr = ferr
    result = pb.run()
    # ferr.close()
    f.close()
    return result
コード例 #12
0
def ansibleHelper(vault=None):
    '''
    Creates the ansible inventory object
    
    TODO: Split out into its own class???
    '''
    global ANSIBLE_DL
    ANSIBLE_DL = DataLoader()

    if vault is not None:
        ANSIBLE_DL.set_vault_secrets(vault)

    inv = InventoryManager(loader=ANSIBLE_DL, sources=[ANSIBLE_HOSTS])
    return inv
コード例 #13
0
ファイル: vault.py プロジェクト: fakegit/eclogue
    def run(self):
        loader = DataLoader()
        vault_ids = self.options.vault_ids
        default_vault_ids = C.DEFAULT_VAULT_IDENTITY_LIST
        vault_ids = default_vault_ids + vault_ids
        encrypt_vault_id = None
        vault_secrets = self.setup_vault_secrets(loader,
                                                 vault_ids=vault_ids,
                                                 vault_password_files=self.options.vault_password_files,
                                                 vault_pass=self.options.vault_pass)
        encrypt_secret = match_encrypt_secret(vault_secrets,
                                              encrypt_vault_id=encrypt_vault_id)

        self.encrypt_vault_id = encrypt_secret[0]
        self.encrypt_secret = encrypt_secret[1]
        loader.set_vault_secrets(vault_secrets)
        vault = VaultLib(vault_secrets)
        self.editor = VaultEditor(vault)
コード例 #14
0
ファイル: inventory.py プロジェクト: fhlmbrg/td4a
def inventory_load(inventory_sources, vault_secret):
    """ Load the inventory
    """
    loader = DataLoader()
    vault_secrets = [('default', TextVaultSecret(vault_secret))]
    loader.set_vault_secrets(vault_secrets)
    inventory = InventoryManager(loader=loader, sources=inventory_sources)
    result = {}
    for hostname in inventory.hosts:
        host = inventory.get_host(hostname)
        variable_manager = VariableManager(loader=loader, inventory=inventory)
        magic_vars = ['ansible_playbook_python', 'groups', 'group_names', 'inventory_dir',
                      'inventory_file', 'inventory_hostname', 'inventory_hostname_short',
                      'omit', 'playbook_dir']
        all_vars = variable_manager.get_vars(host=host, include_hostvars=True)
        cleaned = ({k: v for (k, v) in all_vars.items() if k not in magic_vars})
        result[hostname] = cleaned
    return result
コード例 #15
0
ファイル: __init__.py プロジェクト: wdrury-uk/ansible-1
    def _play_prereqs():
        options = context.CLIARGS

        # all needs loader
        loader = DataLoader()

        basedir = options.get('basedir', False)
        if basedir:
            loader.set_basedir(basedir)

        vault_ids = list(options['vault_ids'])
        default_vault_ids = C.DEFAULT_VAULT_IDENTITY_LIST
        vault_ids = default_vault_ids + vault_ids

        vault_secrets = CLI.setup_vault_secrets(
            loader,
            vault_ids=vault_ids,
            vault_password_files=list(options['vault_password_files']),
            ask_vault_pass=options['ask_vault_pass'],
            auto_prompt=False)
        loader.set_vault_secrets(vault_secrets)

        # create the inventory, and filter it based on the subset specified (if any)
        inventory = InventoryManager(loader=loader,
                                     sources=options['inventory'])

        # create the variable manager, which will be shared throughout
        # the code, ensuring a consistent view of global variables
        variable_manager = VariableManager(loader=loader, inventory=inventory)

        # If the basedir is specified as the empty string then it results in cwd being used.  This
        # is not a safe location to load vars from
        if options.get('basedir', False) is not False:
            if basedir:
                variable_manager.safe_basedir = True
        else:
            variable_manager.safe_basedir = True

        # load vars from cli options
        variable_manager.extra_vars = load_extra_vars(loader=loader)
        variable_manager.options_vars = load_options_vars(
            CLI.version_info(gitinfo=False))

        return loader, inventory, variable_manager
コード例 #16
0
    def _initialize_ssh_agent(self, password):
        """Initializes the SSH agent and loads the required private keys.
           This to prevent private key material being stored on disk."""

        dl = DataLoader()
        dl.set_vault_secrets(self._initialize_vault_secrets(self, password))

        # databaaaaaaase
        # maybe make distinction between multiple secrets depending on deploy
        ds = dl.load_from_file('/etc/ansible/key.ssh')
        key = self._return_valid_key(self, bytes(ds, encoding='utf-8'))

        ssh_add_cmd = "ssh-add -"

        ret = Popen((ssh_add_cmd.split()), stdin=PIPE)
        ret.communicate(key)

        if ret.returncode:
            raise OSError('--- something went wrong while loading the key')
コード例 #17
0
    def _initialize_play(cls,
                         play_source,
                         vault_key,
                         canary,
                         added_by,
                         source,
                         spath=None):
        """Initializes Ansible playbook with the default and required
           options."""

        Options = namedtuple('Options', [
            'connection', 'module_path', 'forks', 'become', 'become_method',
            'become_user', 'check', 'diff'
        ])

        options = Options(connection='ssh',
                          module_path=False,
                          forks=10,
                          become=False,
                          become_method='sudo',
                          become_user='******',
                          check=False,
                          diff=False)

        loader = DataLoader()

        vault_secrets = cls._initialize_vault_secrets(cls, vault_key)
        loader.set_vault_secrets(vault_secrets)

        inventory = InventoryManager(loader=loader, sources=source)

        if not inventory.parse_source(source, loader):
            raise ValueError('Invalid inventory source specified.')

        variable_manager = VariableManager(loader=loader, inventory=inventory)

        play = Play().load(play_source,
                           variable_manager=variable_manager,
                           loader=loader)

        return cls._run_task(play, inventory, variable_manager, loader,
                             options, canary, added_by, play_source, spath)
コード例 #18
0
    def __init__(
            self,
            ansibleinventory,
            ansible_vault_password_file,
            moleculeenv):
        # Leverage the ansible python api
        # to run a playbook against a molecule host.
        #
        # see: ansible python api
        # https://docs.ansible.com/ansible/latest/dev_guide/developing_api.html

        self._moleculeenv = moleculeenv

        context.CLIARGS = ImmutableDict(
            connection='local',
            module_path=[''],
            forks=10,
            become=None,
            become_method=None,
            become_user=None,
            check=False,
            diff=False)

        loader = DataLoader()

        # Load ansible vault secrets if environment variable is set
        if ansible_vault_password_file:
            vault_id_name = 'default'
            file_vault_secret = get_file_vault_secret(
                filename=ansible_vault_password_file,
                vault_id=vault_id_name,
                loader=loader)
            file_vault_secret.load()
            loader.set_vault_secrets(
                [(ansible_vault_password_file, file_vault_secret)])

        self._loader = loader
        self._inventory = ansibleinventory
        self._variable_manager = VariableManager(
            loader=loader,
            inventory=ansibleinventory)
コード例 #19
0
def read_vault_yaml(path: str) -> dict:
    """Read YAML with vault-encrypted values.
    """
    # Read YAML without decrypting.
    raw_clean = open(path).read().replace('!vault', '')
    data = yaml.load(raw_clean, Loader=yaml.FullLoader)

    # Pop out PW file, if provided.
    pw_file = data.get('vault_password_file')
    pw_files = [pw_file] if pw_file else None

    loader = DataLoader()

    vault_secrets = CLI.setup_vault_secrets(
        loader=loader,
        vault_ids=C.DEFAULT_VAULT_IDENTITY_LIST,
        vault_password_files=pw_files,
    )

    loader.set_vault_secrets(vault_secrets)

    # Re-read with decryption.
    return loader.load_from_file(path)
コード例 #20
0
class TestDataLoaderWithVault(unittest.TestCase):
    def setUp(self):
        self._loader = DataLoader()
        vault_secrets = [('default', TextVaultSecret('ansible'))]
        self._loader.set_vault_secrets(vault_secrets)
        self.test_vault_data_path = os.path.join(os.path.dirname(__file__),
                                                 'fixtures', 'vault.yml')

    def tearDown(self):
        pass

    def test_get_real_file_vault(self):
        real_file_path = self._loader.get_real_file(self.test_vault_data_path)
        self.assertTrue(os.path.exists(real_file_path))

    def test_get_real_file_vault_no_vault(self):
        self._loader.set_vault_secrets(None)
        self.assertRaises(AnsibleParserError, self._loader.get_real_file,
                          self.test_vault_data_path)

    def test_get_real_file_vault_wrong_password(self):
        wrong_vault = [('default', TextVaultSecret('wrong_password'))]
        self._loader.set_vault_secrets(wrong_vault)
        self.assertRaises(AnsibleVaultError, self._loader.get_real_file,
                          self.test_vault_data_path)

    def test_get_real_file_not_a_path(self):
        self.assertRaisesRegexp(AnsibleParserError, 'Invalid filename',
                                self._loader.get_real_file, None)

    @patch.multiple(DataLoader,
                    path_exists=lambda s, x: True,
                    is_file=lambda s, x: True)
    def test_parse_from_vault_1_1_file(self):
        vaulted_data = """$ANSIBLE_VAULT;1.1;AES256
33343734386261666161626433386662623039356366656637303939306563376130623138626165
6436333766346533353463636566313332623130383662340a393835656134633665333861393331
37666233346464636263636530626332623035633135363732623332313534306438393366323966
3135306561356164310a343937653834643433343734653137383339323330626437313562306630
3035
"""
        if PY3:
            builtins_name = 'builtins'
        else:
            builtins_name = '__builtin__'

        with patch(builtins_name + '.open',
                   mock_open(read_data=vaulted_data.encode('utf-8'))):
            output = self._loader.load_from_file('dummy_vault.txt')
            self.assertEqual(output, dict(foo='bar'))
コード例 #21
0
ファイル: support.py プロジェクト: mccue/unfurl
def applyTemplate(value, ctx, overrides=None):
    if not isinstance(value, six.string_types):
        msg = "Error rendering template: source must be a string, not %s" % type(
            value)
        if ctx.strict:
            raise UnfurlError(msg)
        else:
            return "<<%s>>" % msg
    value = value.strip()

    # implementation notes:
    #   see https://github.com/ansible/ansible/test/units/template/test_templar.py
    #   dataLoader is only used by _lookup and to set _basedir (else ./)
    if not ctx.templar or (ctx.baseDir
                           and ctx.templar._basedir != ctx.baseDir):
        # we need to create a new templar
        loader = DataLoader()
        if ctx.baseDir:
            loader.set_basedir(ctx.baseDir)
        if ctx.templar and ctx.templar._loader._vault.secrets:
            loader.set_vault_secrets(ctx.templar._loader._vault.secrets)
        templar = Templar(loader)
        ctx.templar = templar
    else:
        templar = ctx.templar

    overrides = Templar.findOverrides(value, overrides)
    if overrides:
        # returns the original values
        overrides = templar._applyTemplarOverrides(overrides)

    templar.environment.trim_blocks = False
    # templar.environment.lstrip_blocks = False
    fail_on_undefined = ctx.strict

    vars = _VarTrackerDict(__unfurl=ctx)
    vars.update(ctx.vars)
    vars.ctx = ctx

    # replaces current vars
    # don't use setter to avoid isinstance(dict) check
    templar._available_variables = vars

    oldvalue = value
    index = ctx.referenced.start()
    # set referenced to track references (set by Ref.resolve)
    # need a way to turn on and off
    try:
        # strip whitespace so jinija native types resolve even with extra whitespace
        # disable caching so we don't need to worry about the value of a cached var changing
        # use do_template because we already know it's a template
        try:
            value = templar.template(value,
                                     fail_on_undefined=fail_on_undefined)
        except Exception as e:
            value = "<<Error rendering template: %s>>" % str(e)
            if ctx.strict:
                logger.debug(value, exc_info=True)
                raise UnfurlError(value)
            else:
                logger.warning(value[2:100] +
                               "... see debug log for full report")
                logger.debug(value, exc_info=True)
        else:
            if value != oldvalue:
                ctx.trace("successfully processed template:", value)
                for result in ctx.referenced.getReferencedResults(index):
                    if isSensitive(result):
                        # note: even if the template rendered a list or dict
                        # we still need to wrap the entire result as sensitive because we
                        # don't know how the referenced senstive results were transformed by the template
                        ctx.trace("setting template result as sensitive")
                        return wrapSensitiveValue(
                            value, templar._loader._vault
                        )  # mark the template result as sensitive

                if isinstance(value, Results):
                    # mapValue now because wrap_var() fails with Results types
                    value = mapValue(value, ctx, applyTemplates=False)

                # wrap result as AnsibleUnsafe so it isn't evaluated again
                return wrap_var(value)
    finally:
        ctx.referenced.stop()
        if overrides:
            # restore original values
            templar._applyTemplarOverrides(overrides)
    return value
コード例 #22
0
    def run(self):
        super(VaultCLI, self).run()
        loader = DataLoader()

        # set default restrictive umask
        old_umask = os.umask(0o077)

        vault_ids = list(context.CLIARGS['vault_ids'])

        # there are 3 types of actions, those that just 'read' (decrypt, view) and only
        # need to ask for a password once, and those that 'write' (create, encrypt) that
        # ask for a new password and confirm it, and 'read/write (rekey) that asks for the
        # old password, then asks for a new one and confirms it.

        default_vault_ids = C.DEFAULT_VAULT_IDENTITY_LIST
        vault_ids = default_vault_ids + vault_ids

        action = context.CLIARGS['action']

        # TODO: instead of prompting for these before, we could let VaultEditor
        #       call a callback when it needs it.
        if action in ['decrypt', 'view', 'rekey', 'edit']:
            vault_secrets = self.setup_vault_secrets(loader, vault_ids=vault_ids,
                                                     vault_password_files=list(context.CLIARGS['vault_password_files']),
                                                     ask_vault_pass=context.CLIARGS['ask_vault_pass'])
            if not vault_secrets:
                raise AnsibleOptionsError("A vault password is required to use Ansible's Vault")

        if action in ['encrypt', 'encrypt_string', 'create']:

            encrypt_vault_id = None
            # no --encrypt-vault-id context.CLIARGS['encrypt_vault_id'] for 'edit'
            if action not in ['edit']:
                encrypt_vault_id = context.CLIARGS['encrypt_vault_id'] or C.DEFAULT_VAULT_ENCRYPT_IDENTITY

            vault_secrets = None
            vault_secrets = \
                self.setup_vault_secrets(loader,
                                         vault_ids=vault_ids,
                                         vault_password_files=list(context.CLIARGS['vault_password_files']),
                                         ask_vault_pass=context.CLIARGS['ask_vault_pass'],
                                         create_new_password=True)

            if len(vault_secrets) > 1 and not encrypt_vault_id:
                raise AnsibleOptionsError("The vault-ids %s are available to encrypt. Specify the vault-id to encrypt with --encrypt-vault-id" %
                                          ','.join([x[0] for x in vault_secrets]))

            if not vault_secrets:
                raise AnsibleOptionsError("A vault password is required to use Ansible's Vault")

            encrypt_secret = match_encrypt_secret(vault_secrets,
                                                  encrypt_vault_id=encrypt_vault_id)

            # only one secret for encrypt for now, use the first vault_id and use its first secret
            # TODO: exception if more than one?
            self.encrypt_vault_id = encrypt_secret[0]
            self.encrypt_secret = encrypt_secret[1]

        if action in ['rekey']:
            encrypt_vault_id = context.CLIARGS['encrypt_vault_id'] or C.DEFAULT_VAULT_ENCRYPT_IDENTITY
            # print('encrypt_vault_id: %s' % encrypt_vault_id)
            # print('default_encrypt_vault_id: %s' % default_encrypt_vault_id)

            # new_vault_ids should only ever be one item, from
            # load the default vault ids if we are using encrypt-vault-id
            new_vault_ids = []
            if encrypt_vault_id:
                new_vault_ids = default_vault_ids
            if context.CLIARGS['new_vault_id']:
                new_vault_ids.append(context.CLIARGS['new_vault_id'])

            new_vault_password_files = []
            if context.CLIARGS['new_vault_password_file']:
                new_vault_password_files.append(context.CLIARGS['new_vault_password_file'])

            new_vault_secrets = \
                self.setup_vault_secrets(loader,
                                         vault_ids=new_vault_ids,
                                         vault_password_files=new_vault_password_files,
                                         ask_vault_pass=context.CLIARGS['ask_vault_pass'],
                                         create_new_password=True)

            if not new_vault_secrets:
                raise AnsibleOptionsError("A new vault password is required to use Ansible's Vault rekey")

            # There is only one new_vault_id currently and one new_vault_secret, or we
            # use the id specified in --encrypt-vault-id
            new_encrypt_secret = match_encrypt_secret(new_vault_secrets,
                                                      encrypt_vault_id=encrypt_vault_id)

            self.new_encrypt_vault_id = new_encrypt_secret[0]
            self.new_encrypt_secret = new_encrypt_secret[1]

        loader.set_vault_secrets(vault_secrets)

        # FIXME: do we need to create VaultEditor here? its not reused
        vault = VaultLib(vault_secrets)
        self.editor = VaultEditor(vault)

        context.CLIARGS['func']()

        # and restore umask
        os.umask(old_umask)
コード例 #23
0
ファイル: vault.py プロジェクト: tonin/ansible
    def run(self):
        super(VaultCLI, self).run()
        loader = DataLoader()

        # set default restrictive umask
        old_umask = os.umask(0o077)

        vault_ids = self.options.vault_ids

        # there are 3 types of actions, those that just 'read' (decrypt, view) and only
        # need to ask for a password once, and those that 'write' (create, encrypt) that
        # ask for a new password and confirm it, and 'read/write (rekey) that asks for the
        # old password, then asks for a new one and confirms it.

        default_vault_ids = C.DEFAULT_VAULT_IDENTITY_LIST
        vault_ids = default_vault_ids + vault_ids

        # TODO: instead of prompting for these before, we could let VaultEditor
        #       call a callback when it needs it.
        if self.action in ['decrypt', 'view', 'rekey', 'edit']:
            vault_secrets = self.setup_vault_secrets(loader,
                                                     vault_ids=vault_ids,
                                                     vault_password_files=self.options.vault_password_files,
                                                     ask_vault_pass=self.options.ask_vault_pass)
            if not vault_secrets:
                raise AnsibleOptionsError("A vault password is required to use Ansible's Vault")

        if self.action in ['encrypt', 'encrypt_string', 'create']:
            if len(vault_ids) > 1:
                raise AnsibleOptionsError("Only one --vault-id can be used for encryption")

            vault_secrets = None
            vault_secrets = \
                self.setup_vault_secrets(loader,
                                         vault_ids=vault_ids,
                                         vault_password_files=self.options.vault_password_files,
                                         ask_vault_pass=self.options.ask_vault_pass,
                                         create_new_password=True)
            if not vault_secrets:
                raise AnsibleOptionsError("A vault password is required to use Ansible's Vault")

            encrypt_secret = match_encrypt_secret(vault_secrets)
            # only one secret for encrypt for now, use the first vault_id and use its first secret
            # self.encrypt_vault_id = list(vault_secrets.keys())[0]
            # self.encrypt_secret = vault_secrets[self.encrypt_vault_id][0]
            self.encrypt_vault_id = encrypt_secret[0]
            self.encrypt_secret = encrypt_secret[1]

        if self.action in ['rekey']:
            new_vault_ids = []
            if self.options.new_vault_id:
                new_vault_ids.append(self.options.new_vault_id)

            new_vault_secrets = \
                self.setup_vault_secrets(loader,
                                         vault_ids=new_vault_ids,
                                         vault_password_files=self.options.new_vault_password_files,
                                         ask_vault_pass=self.options.ask_vault_pass,
                                         create_new_password=True)

            if not new_vault_secrets:
                raise AnsibleOptionsError("A new vault password is required to use Ansible's Vault rekey")

            # There is only one new_vault_id currently and one new_vault_secret
            new_encrypt_secret = match_encrypt_secret(new_vault_secrets)

            self.new_encrypt_vault_id = new_encrypt_secret[0]
            self.new_encrypt_secret = new_encrypt_secret[1]

        loader.set_vault_secrets(vault_secrets)

        # FIXME: do we need to create VaultEditor here? its not reused
        vault = VaultLib(vault_secrets)
        self.editor = VaultEditor(vault)

        self.execute()

        # and restore umask
        os.umask(old_umask)
コード例 #24
0
class SimpleProvider(object):
    __metaclass__ = ABCMeta

    def __init__(self, name, general_type=None, box_extra_type=None):
        self.env = Environment(name, general_type, box_extra_type)
        self.loader = DataLoader()
        self.provisioned = False
        self.tags = {}
        self.extra_vars = {'prudentia_dir': io.prudentia_python_dir()}
        self.load_tags()
        self.active_user = pwd.getpwuid(os.geteuid())[0]

    def boxes(self):
        return self.env.boxes.values()

    def get_box(self, box_name):
        b = self.env.get(box_name)
        if not b:
            print ('The box \'%s\' you entered does not exists.\n\n' \
                  'After typing the command press Tab for box suggestions.\n' % box_name)
            return None
        else:
            return b

    def _show_current_vars(self):
        print('Current set variables:\n%s\n' % '\n'.join(
            [n + ' -> ' + str(v) for n, v in self.extra_vars.iteritems()]))

    def set_var(self, var, value):
        if var in self.extra_vars:
            print ('NOTICE: Variable \'{0}\' is already set to this value: \'{1}\' ' \
                  'and it will be overwritten.'.format(var, self.extra_vars[var]))
        self.extra_vars[var] = value
        if provisioning.VERBOSITY > 0:
            print("Set \'{0}\' -> {1}\n".format(var, value))

    def unset_var(self, var):
        if not var:
            print('Please provide a valid variable name to unset.\n')
            self._show_current_vars()
        elif var not in self.extra_vars:
            print(
                'WARNING: Variable \'{0}\' is NOT present so cannot be unset.\n'
                .format(var))
            self._show_current_vars()
        else:
            self.extra_vars.pop(var, None)
            print("Unset \'{0}\'\n".format(var))

    def set_vault_password(self):
        vault_pwd = io.input_value('Ansible vault password', hidden=True)
        try:
            # Ansible 2.4
            self.loader.set_vault_secrets(vault_pwd)
        except:
            # Ansible 2.3
            self.loader.set_vault_password(vault_pwd)

    def load_vars(self, vars_file):
        if not vars_file:
            vars_file = io.input_path('path of the variables file')
        vars_dict = self.loader.load_from_file(vars_file)
        for key, value in vars_dict.items():
            self.set_var(key, value)

    def add_box(self, box):
        self.env.add(box)
        self.load_tags(box)

    def load_tags(self, box=None):
        for b in [box] if box else self.boxes():
            if not os.path.exists(b.playbook):
                print ('WARNING: Box \'{0}\' points to a NON existing playbook. ' \
                      'Please `reconfigure` or `unregister` the box.\n'.format(b.name))
            else:
                plays = Playbook.load(
                    b.playbook,
                    variable_manager=provisioning.get_variable_manager(
                        self.loader),
                    loader=self.loader).get_plays()
                all_tags = set()
                for p in plays:
                    for block in p.compile():
                        for task in block.block:
                            all_tags.update(task.tags)
                self.tags[b.name] = list(all_tags)

    def remove_box(self, box):
        if box.name in self.tags:
            self.tags.pop(box.name)
        return self.env.remove(box)

    def register(self):
        try:
            box = self.define_box()
            if box:
                self.add_box(box)
                print("\nBox %s added." % box)
        except Exception as ex:
            io.track_error('cannot add box', ex)

    @abstractmethod
    def define_box(self):
        pass

    def reconfigure(self, previous_box):
        try:
            box = self.redefine_box(previous_box)
            if box:
                self.remove_box(previous_box)
                self.add_box(box)
                print("\nBox %s reconfigured." % box)
        except Exception as ex:
            io.track_error('cannot reconfigure box', ex)

    @abstractmethod
    def redefine_box(self, previous_box):
        pass

    def unregister(self, box):
        self.remove_box(box)
        print("\nBox %s removed.\n" % box.name)

    def fetch_box_hosts(self, playbook):
        ds = self.loader.load_from_file(playbook)
        if ds:
            return ds[0][
                'hosts']  # a playbook is an array of plays we take the first one

    def suggest_name(self, hostname):
        if hostname not in self.env.boxes:
            return hostname
        else:
            return hostname + '-' + str(random.randint(0, 100))

    def provision(self, box, tags):
        self.provisioned = provisioning.run_playbook(
            playbook_file=box.playbook,
            inventory_file=provisioning.generate_inventory(box),
            loader=self.loader,
            remote_user=box.get_remote_user(),
            remote_pass=box.get_remote_pwd(),
            transport=box.get_transport(),
            extra_vars=self.extra_vars,
            only_tags=tags)

    @staticmethod
    def verbose(value):
        if value:
            try:
                iv = int(value)
            except ValueError:
                iv = -1
            if 0 <= iv <= 4:
                provisioning.VERBOSITY = iv
            else:
                print(
                    'Verbosity value \'{0}\' not allowed, should be a number between 0 and 4.'
                    .format(value))
        else:
            print('Current verbosity: {0}'.format(provisioning.VERBOSITY))

    def facts(self, box, regex='*'):
        return provisioning.gather_facts(box, regex, self.loader)
コード例 #25
0
ファイル: vault.py プロジェクト: ernstp/ansible
    def run(self):
        super(VaultCLI, self).run()
        loader = DataLoader()

        # set default restrictive umask
        old_umask = os.umask(0o077)

        vault_ids = self.options.vault_ids

        # there are 3 types of actions, those that just 'read' (decrypt, view) and only
        # need to ask for a password once, and those that 'write' (create, encrypt) that
        # ask for a new password and confirm it, and 'read/write (rekey) that asks for the
        # old password, then asks for a new one and confirms it.

        default_vault_ids = C.DEFAULT_VAULT_IDENTITY_LIST
        vault_ids = default_vault_ids + vault_ids

        # TODO: instead of prompting for these before, we could let VaultEditor
        #       call a callback when it needs it.
        if self.action in ['decrypt', 'view', 'rekey', 'edit']:
            vault_secrets = self.setup_vault_secrets(loader,
                                                     vault_ids=vault_ids,
                                                     vault_password_files=self.options.vault_password_files,
                                                     ask_vault_pass=self.options.ask_vault_pass)
            if not vault_secrets:
                raise AnsibleOptionsError("A vault password is required to use Ansible's Vault")

        if self.action in ['encrypt', 'encrypt_string', 'create']:
            if len(vault_ids) > 1:
                raise AnsibleOptionsError("Only one --vault-id can be used for encryption")

            vault_secrets = None
            vault_secrets = \
                self.setup_vault_secrets(loader,
                                         vault_ids=vault_ids,
                                         vault_password_files=self.options.vault_password_files,
                                         ask_vault_pass=self.options.ask_vault_pass,
                                         create_new_password=True)

            if len(vault_secrets) > 1:
                raise AnsibleOptionsError("Only one --vault-id can be used for encryption. This includes passwords from configuration and cli.")

            if not vault_secrets:
                raise AnsibleOptionsError("A vault password is required to use Ansible's Vault")

            encrypt_secret = match_encrypt_secret(vault_secrets)
            # only one secret for encrypt for now, use the first vault_id and use its first secret
            # self.encrypt_vault_id = list(vault_secrets.keys())[0]
            # self.encrypt_secret = vault_secrets[self.encrypt_vault_id][0]
            self.encrypt_vault_id = encrypt_secret[0]
            self.encrypt_secret = encrypt_secret[1]

        if self.action in ['rekey']:
            new_vault_ids = []
            if self.options.new_vault_id:
                new_vault_ids.append(self.options.new_vault_id)

            new_vault_secrets = \
                self.setup_vault_secrets(loader,
                                         vault_ids=new_vault_ids,
                                         vault_password_files=self.options.new_vault_password_files,
                                         ask_vault_pass=self.options.ask_vault_pass,
                                         create_new_password=True)

            if not new_vault_secrets:
                raise AnsibleOptionsError("A new vault password is required to use Ansible's Vault rekey")

            # There is only one new_vault_id currently and one new_vault_secret
            new_encrypt_secret = match_encrypt_secret(new_vault_secrets)

            self.new_encrypt_vault_id = new_encrypt_secret[0]
            self.new_encrypt_secret = new_encrypt_secret[1]

        loader.set_vault_secrets(vault_secrets)

        # FIXME: do we need to create VaultEditor here? its not reused
        vault = VaultLib(vault_secrets)
        self.editor = VaultEditor(vault)

        self.execute()

        # and restore umask
        os.umask(old_umask)
コード例 #26
0
class Runner(object):
    """
    wraps ansible playbook execution
    """
    def __init__(self,
                 hostnames,
                 action,
                 playbook,
                 private_key_file,
                 run_data,
                 internal_data,
                 location,
                 become_pass,
                 request_id,
                 started_at,
                 config,
                 dbsession,
                 tr,
                 verbosity=5):

        self.logger = app.logger
        self.logger.debug('initializing ansible runbook executor')

        self.action = action
        self.config = config
        self.dbsession = dbsession
        self.transition_request = tr

        self.location = location
        self.run_data = run_data
        self.internal_data = internal_data

        self.run_variables = {}
        self.run_variables.update(self.run_data)
        self.run_variables.update(self.location)
        self.run_variables.update(self.internal_data)

        self.logger.debug(str(self.location))
        self.logger.debug(str(self.run_data))
        self.logger.debug(str(self.run_variables))

        self.request_id = request_id
        self.started_at = started_at
        self.finished_at = None
        self.resInstance = {}

        # NEW 2.9
        # handles options now
        context.CLIARGS = ImmutableDict(
            connection='ssh',
            module_path=['/var/alm_ansible_rm/library'],
            forks=20,
            become=None,
            become_method='sudo',
            become_user='******',
            check=False,
            diff=False,
            ansible_python_interpreter='/usr/bin/python3',
            host_key_checking=False,
            vault_password_file='/etc/ansible/tslvault.txt',
            private_key_file=private_key_file,
            listhosts=None,
            listtasks=None,
            listtags=None,
            syntax=None,
            start_at_task=None)

        # Gets data from YAML/JSON files
        self.loader = DataLoader()
        self.loader.set_vault_secrets([
            ('default', VaultSecret(_bytes=to_bytes('TSLDem0')))
        ])

        # create temporary inventory file
        self.hosts = NamedTemporaryFile(delete=False)
        self.hosts.write(b'[run_hosts]\n')
        self.hosts.write(
            b'localhost ansible_connection=local ansible_python_interpreter="/usr/bin/env python3" host_key_checking=False'
        )
        self.hosts.close()

        # set Inventory
        self.inventory = InventoryManager(loader=self.loader,
                                          sources=self.hosts.name)

        # All the variables from all the various places
        self.variable_manager = VariableManager(loader=self.loader,
                                                inventory=self.inventory)
        # MOD 2.9 - has been renamed, not sure this is the proposed way to treat extra_vars, but it works
        self.variable_manager._extra_vars = self.run_variables

        # Become Pass Needed if not logging in as user root
        passwords = {'become_pass': become_pass}

        # Setup playbook executor, but don't run until run() called
        self.pbex = playbook_executor.PlaybookExecutor(
            playbooks=[playbook],
            inventory=self.inventory,
            variable_manager=self.variable_manager,
            loader=self.loader,
            passwords=passwords)

        if (self.transition_request) and (isinstance(self.transition_request,
                                                     TransitionRequest)):
            # log only if transition request, not for netowrk/image scans)
            self.logger.debug('transition request ' +
                              str(self.transition_request))
            self.log_request_status('PENDING', 'playbook initialized', '', '')

        self.logger.debug('ansible runbook executor instantiated for ' +
                          str(playbook))

        self.callback = OutputCallback(self.action, self.logger)
        self.pbex._tqm._stdout_callback = self.callback

    def run(self):
        """
        run an ansible playbook (sync mode) and return Results
        """
        self.logger.debug('request ' + str(self.request_id) + ' action ' +
                          self.action)

        self.pbex._tqm._stdout_callback = self.callback
        self.pbex.run()
        return self.callback.properties, self.callback.is_run_ok()

    def run_async(self):
        """
        run an ansible playbook asynchronously and return results when done
        """
        self.logger.debug('request ' + str(self.request_id) + ' action ' +
                          self.action)

        self.log_request_status('IN_PROGRESS', 'running playbook', '', '')
        self.pbex._tqm._stdout_callback = self.callback
        self.pbex.run()
        self.finished_at = datetime.now()

        self.logger.debug('request ' + str(self.request_id) + ' action ' +
                          self.action + " ansible facts" +
                          json.dumps(self.callback.facts))

        if self.callback.is_run_ok():
            #            if not self.callback.resource_id:
            #                self.logger.error(str(self.request_id) + ': ' + 'Resource ID MUST be set')
            #            else:
            #            resource_id = self.callback.resource_id
            #            self.logger.debug(str(self.request_id) + ': ' + 'resource created id ' + resource_id)

            if not self.callback.internal_resource_instances:
                if self.transition_request.transition_name in ('Install',
                                                               'Uninstall'):
                    self.logger.warning(
                        str(self.request_id) + ': ' +
                        'Internal Resources may be missing')
                internal_resources = []
            else:
                internal_resources = self.callback.internal_resource_instances
                self.logger.debug(
                    str(self.request_id) + ': ' + 'internal resources ' +
                    str(internal_resources))

            prop_output = {}
            prop_output.update(self.run_data)
            prop_output.update(self.callback.properties)

            # set resource_id=metric_key
            resource_id = prop_output['metric_key']
            self.logger.debug(
                str(self.request_id) + ': ' + 'resource created id ' +
                resource_id)

            # remove location and ansible variables (hard wired for now :-()
            del prop_output['user_id']
            del prop_output['keys_dir']
            del prop_output['metric_key']

            if 'request_id' in prop_output:
                del prop_output['request_id']

            # self.logger.debug(str(prop_output))
            # self.logger.debug(str(self.callback.properties))

            properties = dict(
                set(prop_output.items()) - set(self.location.items()))
            self.logger.debug(
                str(self.request_id) + ': ' + 'properties: ' + str(properties))

            internalProperties = self.internal_data
            internalProperties.update(self.callback.internal_properties)
            self.logger.debug(
                str(self.request_id) + ': ' + 'internal properties: ' +
                str(internalProperties))

            if self.transition_request.transition_name == 'Install':
                self.logger.debug(
                    str(self.request_id) + ': ' + 'creating instance')
                self.resInstance = self.create_instance(
                    resource_id, properties, internal_resources,
                    internalProperties)
            elif self.transition_request.transition_name == 'Uninstall':
                if not (('protocol' in prop_output) and
                        (prop_output['protocol'] == 'SOL003')):
                    self.logger.debug(
                        str(self.request_id) + ': ' + 'deleting instance')
                    self.delete_instance(
                        resource_id,
                        self.transition_request.deployment_location)
            elif self.transition_request.transition_name in ('Start', 'Stop',
                                                             'Configure',
                                                             'Integrity'):
                self.logger.debug(
                    str(self.request_id) + ': ' +
                    'updating instance properties')
                self.resInstance = self.update_instance_props(
                    resource_id, properties, internalProperties)
            else:
                self.logger.debug(
                    str(self.request_id) + ': ' +
                    'update internal properties ')
                self.resInstance = self.update_instance_props(
                    resource_id, None, internalProperties)

            if ('protocol' in prop_output) and (
                    prop_output['protocol']
                    == 'SOL003') and (self.transition_request.transition_name
                                      in ('Install', 'Uninstall')):
                self.log_request_status('IN_PROGRESS', '', '', resource_id)
            else:
                self.log_request_status(
                    'COMPLETED', 'Done in ' + str(
                        (self.finished_at - self.started_at).total_seconds()) +
                    ' seconds', '', resource_id)
            return

        else:
            if self.callback.failed_task != '':
                last_task = self.callback.failed_task
            else:
                last_task = 'Unknown'
            self.log_request_status(
                'FAILED', last_task + ' ' + self.callback.failure_reason,
                self.callback.failure_code, '')
            return

    def log_request_status(self, status, freason, fcode, resource_id):
        """
        write log status to db or push to kafka
        """
        is_async_mode = self.config.getSupportedFeatures(
        )['AsynchronousTransitionResponses']
        ttl = self.config.getTTL()

        #self.logger.info('async request mode is ' + str(is_async_mode))
        if (status == 'COMPLETED') or (status == 'FAILED'):
            finished = self.finished_at.strftime('%Y-%m-%dT%H:%M:%SZ')
        else:
            finished = ''

        started = self.started_at.strftime('%Y-%m-%dT%H:%M:%SZ')

        if resource_id != '':
            resource_id = uuid.UUID(resource_id)
        else:
            resource_id = None

        if status == 'FAILED':
            self.logger.error('request ' + str(self.request_id) + ' action ' +
                              self.action + ' FAILED:' + freason +
                              ' failure code: ' + fcode)
        elif status == 'COMPLETED':
            self.logger.info('request ' + str(self.request_id) + ' action ' +
                             self.action + ' finished OK')

        try:
            if status == 'PENDING':
                self.logger.debug(
                    str(self.request_id) + ': ' +
                    'Writing PENDING request to db')
                self.dbsession.execute(
                    """
                    INSERT INTO requests (requestId, requestState, requestStateReason,startedAt, context)
                    VALUES  (%s, %s, %s, %s, %s)
                    USING TTL """ + str(ttl) + """
                    """, (self.request_id, status, freason, started,
                          self.config.getSupportedFeatures()))
            else:
                self.logger.debug(
                    str(self.request_id) + ': ' +
                    'Writing COMPLETED or FAILED request to db')
                self.dbsession.execute(
                    """
                    INSERT INTO requests (requestId, requestState, requestStateReason, requestFailureCode, resourceId, finishedAt)
                    VALUES  (%s, %s, %s, %s, %s, %s)
                    USING TTL """ + str(ttl) + """
                    """, (self.request_id, status, freason, fcode, resource_id,
                          finished))
        except Exception as err:
            # handle any other exception
            self.logger.error(str(err))
            raise

        self.logger.debug('request result logged to DB: ' +
                          str(self.request_id))

        if is_async_mode:
            if (status == 'COMPLETED') or (status == 'FAILED'):
                # call kafka
                self.logger.debug(
                    str(self.request_id) + ': ' + 'async mode and status is ' +
                    status)
                kafkaClient = Kafka(self.logger)

                kmsg = {}
                kmsg['resourceInstance'] = dict(self.resInstance)
                kmsg['requestId'] = str(self.request_id)
                kmsg[
                    'resourceManagerId'] = self.transition_request.resource_manager_id
                kmsg[
                    'deploymentLocation'] = self.transition_request.deployment_location
                kmsg['resourceType'] = self.transition_request.resource_type
                kmsg[
                    'transitionName'] = self.transition_request.transition_name
                kmsg['context'] = {}
                kmsg['requestState'] = status
                kmsg['requestStateReason'] = freason
                kmsg['requestFailureCode'] = fcode
                kmsg['startedAt'] = started
                kmsg['finishedAt'] = finished

                self.logger.debug(
                    str(self.request_id) + ': ' +
                    'sending message to kafka: ' + str(kmsg))
                kafkaClient.sendLifecycleEvent(kmsg)

        return

    def create_instance(self, resource_id, out_props, internal_resources,
                        internal_properties):
        """
        save instance details to db
        """
        self.logger.debug('create instance  ' + resource_id)

        # a little cheating, need to get this from OS
        created_at = self.finished_at.strftime('%Y-%m-%dT%H:%M:%SZ')
        last_modified_at = created_at

        pitem = {
            'resourceId': resource_id,
            'deploymentLocation': self.transition_request.deployment_location,
            'resourceType': self.transition_request.resource_type,
            'resourceName': self.transition_request.resource_name,
            'resourceManagerId': self.transition_request.resource_manager_id,
            'properties': out_props,
            'internalProperties': internal_properties,
            'internalResourceInstances': internal_resources,
            'metricKey': self.transition_request.metric_key,
            'createdAt': created_at,
            'lastModifiedAt': last_modified_at
        }

        try:
            self.dbsession.execute(
                """
                INSERT INTO instances
                (resourceId, resourceType, resourceName, resourceManagerId,
                deploymentLocation, createdAt, lastModifiedAt,
                properties, internalProperties, internalResourceInstances, metricKey)
                VALUES  (%s, %s, %s, %s, %s, %s, %s, %s,%s, %s, %s)
                """, (uuid.UUID(pitem['resourceId']), pitem['resourceType'],
                      pitem['resourceName'], pitem['resourceManagerId'],
                      pitem['deploymentLocation'], pitem['createdAt'],
                      pitem['lastModifiedAt'], pitem['properties'],
                      pitem['internalProperties'],
                      pitem['internalResourceInstances'], pitem['metricKey']))
        except Exception as err:
            # handle any other exception
            self.logger.error(str(err))
            raise

        self.logger.debug('instance created and logger to database ' +
                          str(pitem))
        return pitem

    def update_instance_props(self, resource_id, out_props,
                              internal_properties):
        """
        update instance properties to db
        """
        self.logger.debug('update instance  ' + resource_id)

        # a little cheating, need to get this from OS
        created_at = self.finished_at.strftime('%Y-%m-%dT%H:%M:%SZ')
        last_modified_at = created_at

        pitem = {
            'resourceId': resource_id,
            'properties': out_props,
            'internalProperties': internal_properties,
            'deploymentLocation': self.transition_request.deployment_location,
            'lastModifiedAt': last_modified_at
        }

        try:
            if out_props is None:
                self.dbsession.execute(
                    """
                    UPDATE instances
                    SET
                    lastModifiedAt=%s,
                    internalProperties=%s
                    WHERE resourceId=%s
                    AND deploymentLocation=%s
                    """,
                    (pitem['lastModifiedAt'], pitem['internalProperties'],
                     uuid.UUID(
                         pitem['resourceId']), pitem['deploymentLocation']))
            else:
                self.dbsession.execute(
                    """
                    UPDATE instances
                    SET
                    lastModifiedAt=%s,
                    properties=%s,
                    internalProperties=%s
                    WHERE resourceId=%s
                    AND deploymentLocation=%s
                    """,
                    (pitem['lastModifiedAt'], pitem['properties'],
                     pitem['internalProperties'], uuid.UUID(
                         pitem['resourceId']), pitem['deploymentLocation']))
        except Exception as err:
            # handle any other exception
            self.logger.error(str(err))
            raise

        self.logger.debug('instance updated ' + str(pitem))
        return pitem

    def delete_instance(self, resource_id, deployment_location):
        """
        delete instance details from db
        """
        self.logger.debug('deleting instance  ' + resource_id)

        try:
            self.dbsession.execute(
                """
                DELETE FROM instances
                WHERE resourceId = %s and deploymentLocation = %s
                """, [uuid.UUID(resource_id), deployment_location])
        except Exception as err:
            # handle any other exception
            self.logger.error(str(err))
            raise

        self.logger.debug('instance deleted ' + resource_id)
        return
コード例 #27
0
ファイル: playbook.py プロジェクト: jchprj/learn-scripts
display = AnsibleDisplay(verbosity=0)

from ansible import context
from ansible.cli import CLI
from ansible.module_utils.common.collections import ImmutableDict
from ansible.executor.playbook_executor import PlaybookExecutor
from ansible.parsing.dataloader import DataLoader
from ansible.inventory.manager import InventoryManager
from ansible.vars.manager import VariableManager
from ansible.module_utils._text import to_bytes
from ansible.parsing.vault import VaultSecret

code_path = "../../.."

loader = DataLoader()
loader.set_vault_secrets([('default', VaultSecret(_bytes=to_bytes('123456')))])

context.CLIARGS = ImmutableDict(tags={},
                                listtags=False,
                                listtasks=False,
                                listhosts=False,
                                syntax=False,
                                module_path=None,
                                forks=100,
                                private_key_file=None,
                                start_at_task=None)

inventory = InventoryManager(loader=loader,
                             sources=[code_path + '/ansible/inventory'])

variable_manager = VariableManager(
コード例 #28
0
ファイル: vault.py プロジェクト: awiddersheim/ansible
    def run(self):
        super(VaultCLI, self).run()
        loader = DataLoader()

        # set default restrictive umask
        old_umask = os.umask(0o077)

        vault_ids = self.options.vault_ids

        # there are 3 types of actions, those that just 'read' (decrypt, view) and only
        # need to ask for a password once, and those that 'write' (create, encrypt) that
        # ask for a new password and confirm it, and 'read/write (rekey) that asks for the
        # old password, then asks for a new one and confirms it.

        default_vault_ids = C.DEFAULT_VAULT_IDENTITY_LIST
        vault_ids = default_vault_ids + vault_ids

        # TODO: instead of prompting for these before, we could let VaultEditor
        #       call a callback when it needs it.
        if self.action in ['decrypt', 'view', 'rekey', 'edit']:
            vault_secrets = self.setup_vault_secrets(loader,
                                                     vault_ids=vault_ids,
                                                     vault_password_files=self.options.vault_password_files,
                                                     ask_vault_pass=self.options.ask_vault_pass)
            if not vault_secrets:
                raise AnsibleOptionsError("A vault password is required to use Ansible's Vault")

        if self.action in ['encrypt', 'encrypt_string', 'create']:

            encrypt_vault_id = None
            # no --encrypt-vault-id self.options.encrypt_vault_id for 'edit'
            if self.action not in ['edit']:
                encrypt_vault_id = self.options.encrypt_vault_id or C.DEFAULT_VAULT_ENCRYPT_IDENTITY

            vault_secrets = None
            vault_secrets = \
                self.setup_vault_secrets(loader,
                                         vault_ids=vault_ids,
                                         vault_password_files=self.options.vault_password_files,
                                         ask_vault_pass=self.options.ask_vault_pass,
                                         create_new_password=True)

            if len(vault_secrets) > 1 and not encrypt_vault_id:
                raise AnsibleOptionsError("The vault-ids %s are available to encrypt. Specify the vault-id to encrypt with --encrypt-vault-id" %
                                          ','.join([x[0] for x in vault_secrets]))

            if not vault_secrets:
                raise AnsibleOptionsError("A vault password is required to use Ansible's Vault")

            encrypt_secret = match_encrypt_secret(vault_secrets,
                                                  encrypt_vault_id=encrypt_vault_id)

            # only one secret for encrypt for now, use the first vault_id and use its first secret
            # TODO: exception if more than one?
            self.encrypt_vault_id = encrypt_secret[0]
            self.encrypt_secret = encrypt_secret[1]

        if self.action in ['rekey']:
            encrypt_vault_id = self.options.encrypt_vault_id or C.DEFAULT_VAULT_ENCRYPT_IDENTITY
            # print('encrypt_vault_id: %s' % encrypt_vault_id)
            # print('default_encrypt_vault_id: %s' % default_encrypt_vault_id)

            # new_vault_ids should only ever be one item, from
            # load the default vault ids if we are using encrypt-vault-id
            new_vault_ids = []
            if encrypt_vault_id:
                new_vault_ids = default_vault_ids
            if self.options.new_vault_id:
                new_vault_ids.append(self.options.new_vault_id)

            new_vault_password_files = []
            if self.options.new_vault_password_file:
                new_vault_password_files.append(self.options.new_vault_password_file)

            new_vault_secrets = \
                self.setup_vault_secrets(loader,
                                         vault_ids=new_vault_ids,
                                         vault_password_files=new_vault_password_files,
                                         ask_vault_pass=self.options.ask_vault_pass,
                                         create_new_password=True)

            if not new_vault_secrets:
                raise AnsibleOptionsError("A new vault password is required to use Ansible's Vault rekey")

            # There is only one new_vault_id currently and one new_vault_secret, or we
            # use the id specified in --encrypt-vault-id
            new_encrypt_secret = match_encrypt_secret(new_vault_secrets,
                                                      encrypt_vault_id=encrypt_vault_id)

            self.new_encrypt_vault_id = new_encrypt_secret[0]
            self.new_encrypt_secret = new_encrypt_secret[1]

        loader.set_vault_secrets(vault_secrets)

        # FIXME: do we need to create VaultEditor here? its not reused
        vault = VaultLib(vault_secrets)
        self.editor = VaultEditor(vault)

        self.execute()

        # and restore umask
        os.umask(old_umask)
コード例 #29
0
ファイル: loader.py プロジェクト: orange888/infrastructure
class Loader:
    def __init__(self):
        self._config = ConfigManager()
        self._loader = DataLoader()
        self._file_vault_secrets = {}
        self._inventory: InventoryManager = None
        self._variables: VariableManager = None

    def _load_file_vault_secrets(self, password_file_path=None):
        if password_file_path is None:
            password_file_path = self._config.get_config_value(
                "DEFAULT_VAULT_PASSWORD_FILE")

        password_file = Path(password_file_path)

        if password_file.name in self._file_vault_secrets:
            return

        if not password_file.is_file():
            raise FileNotFoundError(password_file)

        self._file_vault_secrets[password_file.name] = get_file_vault_secret(
            filename=password_file, loader=self._loader)
        self._file_vault_secrets[password_file.name].load()
        self._loader.set_vault_secrets([
            (password_file.name, self._file_vault_secrets[password_file.name])
        ])

    def _get_inventory(self, source=None):
        if source is None:
            source = self._config.get_config_value("DEFAULT_HOST_LIST")

        if self._inventory is None:
            self._inventory = InventoryManager(loader=self._loader,
                                               sources=source)
        else:
            sources = source if isinstance(source, list) else [source]
            (self._inventory.parse_source(s) for s in sources)
            self._inventory.reconcile_inventory()

        return self._inventory

    def _get_variables(self, source=None):
        self._load_file_vault_secrets()
        if self._variables is None:
            self._variables = VariableManager(
                loader=self._loader, inventory=self._get_inventory(source))

        return self._variables

    def get_hosts(self, pattern='all', source=None):
        return self._get_inventory(source).get_hosts(pattern)

    def get_host(self, hostname, source=None):
        return self._get_inventory(source).get_host(hostname)

    def get_vars(self, host, data={}):
        play = Play.load(data,
                         loader=self._loader,
                         variable_manager=self._get_variables())
        return self._get_variables().get_vars(host=host, play=play)
コード例 #30
0
class Runner(object):
    """
    This is a General object for parallel execute modules.
    本接口依赖hosts文件,在调用本接口之前,需要先生成hosts文件,可以通过手动编辑或者动态生成的方式生成hosts文件。
    如果在hosts文件里指定了ansible_ssh_private_key_file、ansible_python_interpreter、ansible_ssh_user等变量,
    调用本接口时就无需再传入这些变量了,即使传了这些变量也没用,因为hosts文件中变量的优先级最高
    使用密码或公钥指定一个即可,另一个设为None。比如:如果传入了公钥参数,则self.passwords就设为None
    """

    def __init__(self, resource, *args, **kwargs):
        # resource: 可以为hosts文件的绝对路径(或者绝对路径列表), 也可以是以逗号隔开的ip字符串,如:'1.1.1.1,2.2.2.2,3.3.3.3',只有一个ip时也要加逗号,
        # 这个ip字符串会被ansible当做hosts文件
        self.resource = resource
        self.variable_manager = None
        self.loader = None
        self.options = None
        self.passwords = None  # 主机登录密码
        self.private_key_file = None  # 登录私钥
        self.ansible_vault_key = kwargs.get(
            'ansible_vault_key', '')  # ansible加解密密码
        self.callback = ResultsCollector()  # ansible回调函数,处理返回结果
        self.ansible_ssh_user = kwargs.get(
            'ansible_ssh_user', 'root')  # 主机登录用户
        self.become_user = kwargs.get('module_name', '')  # 登录主机后切换的用户
        self.ansible_python_interpreter = kwargs.get(
            'ansible_python_interpreter', "/usr/bin/python")   # 远程机器使用的python解释器
        self.__initializeData()
        self.results_raw = {}
        # ip_list是执行ansible任务的ip列表,这个ip列表中的ip必须全都在self.resource里
        self.ip_list = kwargs.get('ip_list', [])
        self.module_name = kwargs.get('module_name', '')  # ansible调用的模块名
        self.module_args = kwargs.get('module_args', '')  # 模块需要的参数

    def __initializeData(self):
        """
        初始化ansible
        """

        Options = namedtuple('Options',
                             ['ansible_python_interpreter', 'connection', 'module_path', 'forks', 'become',
                              'become_method', 'become_user', 'check',
                              'diff', 'private_key_file', 'remote_user'])
        self.loader = DataLoader()
        # 加载hosts文件解密密码
        self.loader.set_vault_secrets(
            [('default', VaultSecret(_bytes=to_bytes(self.ansible_vault_key)))])
        self.options = Options(ansible_python_interpreter=self.ansible_python_interpreter,
                               connection='ssh', module_path='', forks=100, become=None,
                               become_method=None, become_user=self.become_user,
                               check=False, diff=False, private_key_file=self.private_key_file,
                               remote_user=self.ansible_ssh_user)

        self.passwords = dict(conn_pass=self.passwords)

        self.inventory = InventoryManager(
            loader=self.loader, sources=self.resource)

        self.variable_manager = VariableManager(
            loader=self.loader, inventory=self.inventory)

    def get_all_hosts(self):
        inventory = InventoryManager(
            loader=self.loader, sources=self.resource)
        return inventory.get_hosts()

    def run(self):
        """
        运行ansible任务.

        """
        # create play with tasks
        play_source = dict(
            name="Ansible Play",
            hosts=self.ip_list,
            gather_facts='no',
            tasks=[
                dict(action=dict(module=self.module_name, args=self.module_args))
            ]
        )
        play = Play().load(play_source, variable_manager=self.variable_manager, loader=self.loader)

        # 运行
        tqm = None
        logger = mp.log_to_stderr()
        try:
            tqm = TaskQueueManager(
                inventory=self.inventory,
                variable_manager=self.variable_manager,
                loader=self.loader,
                options=self.options,
                passwords=self.passwords,
                stdout_callback='default',
            )

            tqm._stdout_callback = self.callback
            result = tqm.run(play)
        except Exception as e:
            logger.setLevel(logging.DEBUG)

        finally:
            if tqm is not None:
                tqm.cleanup()
        return result

    def get_result(self):

        # 将ansible返回的数据组装为自己需要的数据格式

        self.results_raw = {'success': {}, 'failed': {}, 'unreachable': {}}
        for host, result in self.callback.host_ok.items():
            self.results_raw['success'][host] = result._result

        for host, result in self.callback.host_failed.items():
            self.results_raw['failed'][host] = result._result

        for host, result in self.callback.host_unreachable.items():
            self.results_raw['unreachable'][host] = result._result['msg']

        return self.results_raw
コード例 #31
0
ファイル: support.py プロジェクト: onecommons/unfurl
def apply_template(value, ctx, overrides=None):
    if not isinstance(value, six.string_types):
        msg = f"Error rendering template: source must be a string, not {type(value)}"
        if ctx.strict:
            raise UnfurlError(msg)
        else:
            return f"<<{msg}>>"
    value = value.strip()

    # implementation notes:
    #   see https://github.com/ansible/ansible/test/units/template/test_templar.py
    #   dataLoader is only used by _lookup and to set _basedir (else ./)
    if not ctx.templar or (ctx.base_dir and ctx.templar._basedir != ctx.base_dir):
        # we need to create a new templar
        loader = DataLoader()
        if ctx.base_dir:
            loader.set_basedir(ctx.base_dir)
        if ctx.templar and ctx.templar._loader._vault.secrets:
            loader.set_vault_secrets(ctx.templar._loader._vault.secrets)
        templar = Templar(loader)
        ctx.templar = templar
    else:
        templar = ctx.templar

    overrides = Templar.find_overrides(value, overrides)
    if overrides:
        # returns the original values
        overrides = templar._apply_templar_overrides(overrides)

    templar.environment.trim_blocks = False
    # templar.environment.lstrip_blocks = False
    fail_on_undefined = ctx.strict
    if not fail_on_undefined:
        templar.environment.undefined = UnfurlUndefined

    vars = _VarTrackerDict(__unfurl=ctx, __python_executable=sys.executable)
    if hasattr(ctx.currentResource, "attributes"):
        vars['SELF'] = ctx.currentResource.attributes
    vars.update(ctx.vars)
    vars.ctx = ctx

    # replaces current vars
    # don't use setter to avoid isinstance(dict) check
    templar._available_variables = vars

    oldvalue = value
    index = ctx.referenced.start()
    # set referenced to track references (set by Ref.resolve)
    # need a way to turn on and off
    try:
        # strip whitespace so jinija native types resolve even with extra whitespace
        # disable caching so we don't need to worry about the value of a cached var changing
        # use do_template because we already know it's a template
        try:
            value = templar.template(value, fail_on_undefined=fail_on_undefined)
        except Exception as e:
            msg = str(e)
            match = re.search(r"has no attribute '(\w+)'", msg)
            if match:
                msg = f'missing attribute or key: "{match.group(1)}"'
            value = f"<<Error rendering template: {msg}>>"
            if ctx.strict:
                logger.debug(value, exc_info=True)
                raise UnfurlError(value)
            else:
                logger.warning(value[2:100] + "... see debug log for full report")
                logger.debug(value, exc_info=True)
                if ctx.task:
                    ctx.task._errors.append( UnfurlTaskError(ctx.task, msg) )
        else:
            if value != oldvalue:
                ctx.trace("successfully processed template:", value)
                external_result = None
                for result in ctx.referenced.getReferencedResults(index):
                    if is_sensitive(result):
                        # note: even if the template rendered a list or dict
                        # we still need to wrap the entire result as sensitive because we
                        # don't know how the referenced senstive results were transformed by the template
                        ctx.trace("setting template result as sensitive")
                        # mark the template result as sensitive
                        return wrap_sensitive_value(value)
                    if result.external:
                        external_result = result

                if (
                    external_result
                    and ctx.wantList == "result"
                    and value == external_result.external.get()
                ):
                    # return the external value instead
                    return external_result

                # wrap result as AnsibleUnsafe so it isn't evaluated again
                return wrap_var(value)
    finally:
        ctx.referenced.stop()
        if overrides:
            # restore original values
            templar._apply_templar_overrides(overrides)
    return value
コード例 #32
0
ファイル: vaultpw.py プロジェクト: commandprompt/ansible
class VaultpwCLI(CLI):
    '''
    '''

    VALID_ACTIONS = frozenset(("show", "store"))

    def __init__(self, args):
        super().__init__(args)

        self.encrypt_secret = None
        self.encrypt_vault_id = None

    def set_action(self):
        super().set_action()

        if self.action == "show":
            self.parser.set_usage(
                "usage: %prog show /path/to/example_password.yml")
        elif self.action == "store":
            self.parser.set_usage(
                "usage: %prog store /path/to/example_password.yml [-c command]"
            )
            self.parser.add_option('-c',
                                   '--command',
                                   dest='password_command',
                                   action='store',
                                   type='string',
                                   help="command to run to obtain a password")
            self.parser.add_option(
                '--encrypt-vault-id',
                default=[],
                dest='encrypt_vault_id',
                action='store',
                type='string',
                help=
                'the vault id used to encrypt (required if more than one vault-id is provided)'
            )

    def init_parser(self):
        super().init_parser(
            usage="usage: %%prog [%s] [options] /path/to/example_password.yml"
            % "|".join(sorted(self.VALID_ACTIONS)),
            desc=
            "utility to store or fetch vault-encrypted passwords in YAML inventory files",
            epilog=
            "\nSee '%s <command> --help' for more information on a specific command.\n\n"
            % os.path.basename(sys.argv[0]))
        opt_help.add_vault_options(self.parser)

        self.set_action()

    def post_process_args(self, options, args):
        options, args = super().post_process_args(options, args)
        self.validate_conflicts(options,
                                vault_opts=True,
                                vault_rekey_opts=False)

        display.verbosity = options.verbosity

        if options.vault_ids:
            for vault_id in options.vault_ids:
                if u';' in vault_id:
                    raise AnsibleOptionsError(
                        "Invalid character ';' found in vault id: %s" %
                        vault_id)

        return options, args

    def run(self):
        super().run()
        self.loader = DataLoader()

        vault_ids = C.DEFAULT_VAULT_IDENTITY_LIST + list(
            context.CLIARGS['vault_ids'])
        vault_secrets = self.setup_vault_secrets(
            self.loader,
            vault_ids=vault_ids,
            vault_password_files=list(context.CLIARGS['vault_password_files']),
            ask_vault_pass=context.CLIARGS['ask_vault_pass'])

        if not vault_secrets:
            raise AnsibleOptionsError(
                "A vault password is required to use ansible-vault")

        encrypt_vault_id = context.CLIARGS.get(
            'encrypt_vault_id') or C.DEFAULT_VAULT_ENCRYPT_IDENTITY
        if len(vault_secrets) > 1 and not encrypt_vault_id:
            raise AnsibleOptionsError(
                "Use '--encrypt-vault-id id' to choose one of the following vault ids to use for encryption: %s"
                % ','.join([x[0] for x in vault_secrets]))

        encrypt_secret = match_encrypt_secret(
            vault_secrets, encrypt_vault_id=encrypt_vault_id)

        self.encrypt_vault_id = encrypt_secret[0]
        self.encrypt_secret = encrypt_secret[1]

        self.loader.set_vault_secrets(vault_secrets)

        self.vault = VaultLib(vault_secrets)

        if len(context.CLIARGS['args']) != 1:
            raise AnsibleOptionsError(
                "Exactly one inventory file must be specified")

        self.file = os.path.expanduser(context.CLIARGS['args'][0])

        old_umask = os.umask(0o077)

        self.execute()

        os.umask(old_umask)

    def execute_store(self):
        '''
        Takes the path to an inventory file such as
        inventory/group_vars/tag_Cluster_xxx/secrets/example_password.yml and
        overwrites the file with an assignment of "example_password: password"
        in vault-encrypted YAML format. The password is obtained by prompting
        the user or, if a command is specified, by running the command and
        reading stdout.
        '''

        b_plaintext = b''

        command = context.CLIARGS['password_command']
        if command:
            try:
                pw = subprocess.run(command, capture_output=True)
                if pw.returncode != 0:
                    raise Exception('non-zero exit code: %s' % pw.returncode)
                b_plaintext = pw.stdout.strip()
            except Exception as e:
                print("ERROR: password command failed: %s" % str(e),
                      file=sys.stderr)
                sys.exit(-1)
        else:
            b_plaintext = to_bytes(display.prompt("Password: "******"ERROR: cannot encrypt password: %s" % str(e),
                  file=sys.stderr)
            sys.exit(-1)

        name = os.path.basename(self.file).replace('.yml', '')

        lines = []
        lines.append("%s: !vault |\n" % name)
        for l in to_text(b_ciphertext).splitlines():
            lines.append("    %s\n" % l)

        try:
            fh = open(self.file, 'wb')
            fh.write(to_bytes(''.join(lines)))
            fh.close()
        except Exception as e:
            print("ERROR: cannot write output to %s: %s" % (self.file, str(e)),
                  file=sys.stderr)
            sys.exit(-1)

    def execute_show(self):
        '''
        Takes the path to an inventory file such as
        inventory/group_vars/tag_Cluster_xxx/secrets/example_password.yml and
        prints the password defined therein. The file must contain a variable
        assignment of the form "example_password: password"; either the whole
        file is vault-encrypted, or only the password is.
        '''

        if not os.path.exists(self.file):
            print("ERROR: inventory file does not exist: %s" % self.file,
                  file=sys.stderr)
            sys.exit(-1)

        try:
            name = os.path.basename(self.file).replace('.yml', '')
            y = self.loader.load_from_file(self.file)
            print(y[name])
        except Exception as e:
            print("ERROR: cannot show password from %s: %s" %
                  (self.file, str(e)),
                  file=sys.stderr)
            sys.exit(-1)