Merge "Add module to output scripts"

This commit is contained in:
Zuul 2020-04-01 15:45:10 +00:00 committed by Gerrit Code Review
commit 0610e77817
3 changed files with 268 additions and 0 deletions

View File

@ -0,0 +1,144 @@
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Copyright 2020 Red Hat, Inc.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
from __future__ import absolute_import, division, print_function
__metaclass__ = type
from ansible.module_utils.basic import AnsibleModule
import os
import yaml
try: # py3
from shlex import quote
except ImportError: # py2
from pipes import quote
ANSIBLE_METADATA = {
'metadata_version': '1.1',
'status': ['preview'],
'supported_by': 'community'
}
DOCUMENTATION = """
---
module: tripleo_shell_script
author:
- Alex Schultz <aschultz@redhat.com>
version_added: '2.8'
short_description: Writes out a shell script with environment vars and command
notes: []
description:
- This module will write out a bash script from a shell environment dict
and a commandline string.
options:
dest:
description:
- Destination file path for the output shell script.
required: True
type: str
shell_command:
description:
- Shell command that will be run
required: True
type: str
shell_environment:
description:
- Environment dictionary for the shell execution.
default: {}
required: False
type: dict
"""
EXAMPLES = """
- name: Undercloud install
tripleo_shell_script:
dest: /home/stack/undercloud_install.sh
shell_command: "/usr/bin/openstack undercloud install"
shell_environment: {}
- name: Image upload
tripleo_shell_script:
dest: /home/stack/overcloud_image_upload.sh
shell_command: "/usr/bin/openstack overcloud image upload"
shell_environment:
OS_CLOUD: undercloud
"""
RETURN = """
"""
_SHELL_HEADER = """#!/bin/bash
# This file is managed by ansible
set -ex
"""
class TripleoShellScript(object):
"""Notes about this module.
This module will write out a bash script from the provided parameters.
"""
def __init__(self, module, results):
self.module = module
self.results = results
# parse args
args = self.module.params
# Set parameters
dest = args['dest']
shell_command = args['shell_command']
shell_environment = args.get('shell_environment', {})
if os.path.exists(dest):
self.module.debug('File exists, truncating %s' % dest)
try:
with open(dest, 'w') as fh:
fh.write(_SHELL_HEADER)
for k, v in shell_environment.items():
fh.write("export %(key)s=%(val)s\n" % {'key': k,
'val': quote(v)})
fh.write(shell_command)
fh.write("\n")
os.chmod(dest, 0o755)
self.results['changed'] = True
except Exception as e:
self.results['failed'] = True
self.results['error'] = str(e)
self.results['msg'] = ("Unable to output shell script %s: %s" % (
dest, e))
self.module.exit_json(**self.results)
def main():
module = AnsibleModule(
argument_spec=yaml.safe_load(DOCUMENTATION)['options'],
supports_check_mode=False
)
results = dict(
changed=False
)
TripleoShellScript(module, results)
if __name__ == '__main__':
main()

View File

View File

@ -0,0 +1,124 @@
# Copyright 2019 Red Hat, Inc.
# All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License"); you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
# http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.
import mock
from plugins.modules import tripleo_shell_script
from tests import base as tests_base
class TestTripleoShellScript(tests_base.TestCase):
@mock.patch('os.chmod')
def test_run(self, mock_chmod):
mock_module = mock.Mock()
mock_exit_json = mock.Mock()
mock_open = mock.mock_open()
mock_module.exit_json = mock_exit_json
params = {'dest': '/tmo/foo.sh',
'shell_command': 'foo'}
mock_module.params = params
results = {}
with mock.patch('plugins.modules.tripleo_shell_script.open',
mock_open):
tripleo_shell_script.TripleoShellScript(mock_module, results)
mock_calls = [
mock.call().write(tripleo_shell_script._SHELL_HEADER),
mock.call().write('foo'),
mock.call().write("\n")
]
mock_open.assert_has_calls(mock_calls)
mock_chmod.assert_called_once_with('/tmo/foo.sh', 0o755)
mock_exit_json.assert_called_once_with(changed=True)
@mock.patch('os.chmod')
def test_run_env(self, mock_chmod):
mock_module = mock.Mock()
mock_exit_json = mock.Mock()
mock_open = mock.mock_open()
mock_module.exit_json = mock_exit_json
params = {'dest': '/tmo/foo.sh',
'shell_command': 'foo',
'shell_environment': {
'OS_CLOUD': 'undercloud'}
}
mock_module.params = params
results = {}
with mock.patch('plugins.modules.tripleo_shell_script.open',
mock_open):
tripleo_shell_script.TripleoShellScript(mock_module, results)
mock_calls = [
mock.call().write(tripleo_shell_script._SHELL_HEADER),
mock.call().write('export OS_CLOUD=undercloud\n'),
mock.call().write('foo'),
mock.call().write("\n")
]
mock_open.assert_has_calls(mock_calls)
mock_chmod.assert_called_once_with('/tmo/foo.sh', 0o755)
mock_exit_json.assert_called_once_with(changed=True)
@mock.patch('os.chmod')
def test_run_env_quoted(self, mock_chmod):
mock_module = mock.Mock()
mock_exit_json = mock.Mock()
mock_open = mock.mock_open()
mock_module.exit_json = mock_exit_json
params = {'dest': '/tmo/foo.sh',
'shell_command': 'foo',
'shell_environment': {
'OS_CLOUD': 'undercloud',
'FILES': 'a.yaml b.yaml'}
}
mock_module.params = params
results = {}
with mock.patch('plugins.modules.tripleo_shell_script.open',
mock_open):
tripleo_shell_script.TripleoShellScript(mock_module, results)
mock_calls = [
mock.call().write(tripleo_shell_script._SHELL_HEADER),
mock.call().write('export OS_CLOUD=undercloud\n'),
mock.call().write('export FILES=\'a.yaml b.yaml\'\n'),
mock.call().write('foo'),
mock.call().write("\n")
]
mock_open.assert_has_calls(mock_calls)
mock_chmod.assert_called_once_with('/tmo/foo.sh', 0o755)
mock_exit_json.assert_called_once_with(changed=True)
@mock.patch('os.chmod')
def test_run_fail(self, mock_chmod):
mock_module = mock.Mock()
mock_exit_json = mock.Mock()
mock_open = mock.mock_open()
mock_open.side_effect = Exception('err')
mock_module.exit_json = mock_exit_json
params = {'dest': '/tmo/foo.sh',
'shell_command': 'foo'}
mock_module.params = params
results = {}
with mock.patch('plugins.modules.tripleo_shell_script.open',
mock_open):
tripleo_shell_script.TripleoShellScript(mock_module, results)
mock_exit_json.assert_called_once_with(
error='err',
failed=True,
msg='Unable to output shell script /tmo/foo.sh: err')