mirror of
https://github.com/ansible-collections/community.general.git
synced 2025-07-02 14:40:19 -07:00
Various tests using datafiles are being moved into the integration test framework (tests_new right now).
The unit test infrastructure will remain for things that are mocked out and testable with out filesystem side effects, and a few cases of things that might not be quite so much (like inventory) that can still benefit from heavy access to the API. See the 'tests_new/integration' directory, this will soon fold into tests_new.
This commit is contained in:
parent
0581746a80
commit
fe7d3773ae
42 changed files with 0 additions and 1607 deletions
|
@ -1,4 +0,0 @@
|
|||
---
|
||||
# could test something different here but want people running tests on
|
||||
# different OS platforms to still have passing tests
|
||||
testing: default
|
|
@ -1,62 +0,0 @@
|
|||
# (C) 2013, Michael Scherer, <misc@zarb.org>
|
||||
|
||||
# This file is part of Ansible
|
||||
#
|
||||
# Ansible is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Ansible is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
import os
|
||||
import unittest
|
||||
import subprocess
|
||||
|
||||
# if you change here, also change in the plugin
|
||||
FILE_DISABLE = '/tmp/ansible_test_disable'
|
||||
FILE_RUN = '/tmp/ansible_test_finish'
|
||||
|
||||
|
||||
class TestInventory(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
self.cwd = os.getcwd()
|
||||
os.chdir(os.path.join(os.path.dirname(__file__), 'test_callbacks'))
|
||||
|
||||
def clean_file(self):
|
||||
if os.path.exists(FILE_RUN):
|
||||
os.unlink(FILE_RUN)
|
||||
if os.path.exists(FILE_DISABLE):
|
||||
os.unlink(FILE_DISABLE)
|
||||
|
||||
def tearDown(self):
|
||||
os.chdir(self.cwd)
|
||||
|
||||
def run_ansible_playbook(self):
|
||||
subprocess.call(('source ../../hacking/env-setup 2>&1 >/dev/null;'
|
||||
'ansible-playbook -i "127.0.0.1," test_playbook.yml 2>&1 >/dev/null'),
|
||||
shell=True, executable='/bin/bash')
|
||||
|
||||
def test_callback(self):
|
||||
self.clean_file()
|
||||
|
||||
self.run_ansible_playbook()
|
||||
assert os.path.exists(FILE_RUN)
|
||||
self.clean_file()
|
||||
|
||||
def test_callback_disabled(self):
|
||||
self.clean_file()
|
||||
open(FILE_DISABLE, 'w').close()
|
||||
|
||||
self.run_ansible_playbook()
|
||||
assert not os.path.exists(FILE_RUN)
|
||||
|
||||
self.clean_file()
|
|
@ -1,443 +0,0 @@
|
|||
|
||||
# tests are fairly 'live' (but safe to run)
|
||||
# setup authorized_keys for logged in user such
|
||||
# that the user can log in as themselves before running tests
|
||||
|
||||
import unittest
|
||||
import getpass
|
||||
import ansible.playbook
|
||||
import ansible.utils as utils
|
||||
import ansible.callbacks as ans_callbacks
|
||||
import os
|
||||
import shutil
|
||||
import ansible.constants as C
|
||||
|
||||
EVENTS = []
|
||||
|
||||
class TestCallbacks(object):
|
||||
# using same callbacks class for both runner and playbook
|
||||
|
||||
def __init__(self):
|
||||
pass
|
||||
|
||||
def set_playbook(self, playbook):
|
||||
self.playbook = playbook
|
||||
|
||||
def on_no_hosts_remaining(self):
|
||||
pass
|
||||
|
||||
def on_start(self):
|
||||
EVENTS.append('start')
|
||||
|
||||
def on_skipped(self, host, item=None):
|
||||
EVENTS.append([ 'skipped', [ host ]])
|
||||
|
||||
def on_import_for_host(self, host, filename):
|
||||
EVENTS.append([ 'import', [ host, filename ]])
|
||||
|
||||
def on_error(self, host, msg):
|
||||
EVENTS.append([ 'stderr', [ host, msg ]])
|
||||
|
||||
def on_not_import_for_host(self, host, missing_filename):
|
||||
pass
|
||||
|
||||
def on_notify(self, host, handler):
|
||||
EVENTS.append([ 'notify', [ host, handler ]])
|
||||
|
||||
def on_task_start(self, name, is_conditional):
|
||||
EVENTS.append([ 'task start', [ name, is_conditional ]])
|
||||
|
||||
def on_failed(self, host, results, ignore_errors):
|
||||
EVENTS.append([ 'failed', [ host, results, ignore_errors ]])
|
||||
|
||||
def on_ok(self, host, result):
|
||||
# delete certain info from host_result to make test comparisons easier
|
||||
host_result = result.copy()
|
||||
for k in [ 'ansible_job_id', 'results_file', 'md5sum', 'delta', 'start', 'end' ]:
|
||||
if k in host_result:
|
||||
del host_result[k]
|
||||
for k in host_result.keys():
|
||||
if k.startswith('facter_') or k.startswith('ohai_'):
|
||||
del host_result[k]
|
||||
EVENTS.append([ 'ok', [ host, host_result ]])
|
||||
|
||||
def on_play_start(self, pattern):
|
||||
EVENTS.append([ 'play start', [ pattern ]])
|
||||
|
||||
def on_async_ok(self, host, res, jid):
|
||||
EVENTS.append([ 'async ok', [ host ]])
|
||||
|
||||
def on_async_poll(self, host, res, jid, clock):
|
||||
EVENTS.append([ 'async poll', [ host ]])
|
||||
|
||||
def on_async_failed(self, host, res, jid):
|
||||
EVENTS.append([ 'async failed', [ host ]])
|
||||
|
||||
def on_unreachable(self, host, msg):
|
||||
EVENTS.append([ 'failed/dark', [ host, msg ]])
|
||||
|
||||
def on_setup(self):
|
||||
pass
|
||||
|
||||
def on_no_hosts(self):
|
||||
pass
|
||||
|
||||
|
||||
class TestPlaybook(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
self.user = getpass.getuser()
|
||||
self.cwd = os.getcwd()
|
||||
self.test_dir = os.path.join(self.cwd, 'test')
|
||||
self.stage_dir = self._prepare_stage_dir()
|
||||
|
||||
if os.path.exists('/tmp/ansible_test_data_copy.out'):
|
||||
os.unlink('/tmp/ansible_test_data_copy.out')
|
||||
if os.path.exists('/tmp/ansible_test_data_template.out'):
|
||||
os.unlink('/tmp/ansible_test_data_template.out')
|
||||
if os.path.exists('/tmp/ansible_test_messages.out'):
|
||||
os.unlink('/tmp/ansible_test_messages.out')
|
||||
if os.path.exists('/tmp/ansible_test_role_messages.out'):
|
||||
os.unlink('/tmp/ansible_test_role_messages.out')
|
||||
|
||||
def _prepare_stage_dir(self):
|
||||
stage_path = os.path.join(self.test_dir, 'test_data')
|
||||
if os.path.exists(stage_path):
|
||||
shutil.rmtree(stage_path, ignore_errors=False)
|
||||
assert not os.path.exists(stage_path)
|
||||
os.makedirs(stage_path)
|
||||
assert os.path.exists(stage_path)
|
||||
return stage_path
|
||||
|
||||
def _get_test_file(self, filename):
|
||||
# get a file inside the test input directory
|
||||
filename = os.path.join(self.test_dir, filename)
|
||||
assert os.path.exists(filename)
|
||||
return filename
|
||||
|
||||
def _get_stage_file(self, filename):
|
||||
# get a file inside the test output directory
|
||||
filename = os.path.join(self.stage_dir, filename)
|
||||
return filename
|
||||
|
||||
def _run(self, test_playbook, host_list='test/ansible_hosts', extra_vars=None):
|
||||
''' run a module and get the localhost results '''
|
||||
# This ensures tests are independent of eachother
|
||||
global EVENTS
|
||||
ansible.playbook.SETUP_CACHE.clear()
|
||||
EVENTS = []
|
||||
|
||||
self.test_callbacks = TestCallbacks()
|
||||
self.playbook = ansible.playbook.PlayBook(
|
||||
playbook = test_playbook,
|
||||
host_list = host_list,
|
||||
module_path = 'library/',
|
||||
forks = 1,
|
||||
timeout = 5,
|
||||
remote_user = self.user,
|
||||
remote_pass = None,
|
||||
extra_vars = extra_vars,
|
||||
stats = ans_callbacks.AggregateStats(),
|
||||
callbacks = self.test_callbacks,
|
||||
runner_callbacks = self.test_callbacks
|
||||
)
|
||||
result = self.playbook.run()
|
||||
return result
|
||||
|
||||
def test_playbook_vars(self):
|
||||
test_callbacks = TestCallbacks()
|
||||
playbook = ansible.playbook.PlayBook(
|
||||
playbook=os.path.join(self.test_dir, 'test_playbook_vars', 'playbook.yml'),
|
||||
host_list='test/test_playbook_vars/hosts',
|
||||
stats=ans_callbacks.AggregateStats(),
|
||||
callbacks=test_callbacks,
|
||||
runner_callbacks=test_callbacks
|
||||
)
|
||||
playbook.run()
|
||||
|
||||
def _test_playbook_undefined_vars(self, playbook, fail_on_undefined):
|
||||
# save DEFAULT_UNDEFINED_VAR_BEHAVIOR so we can restore it in the end of the test
|
||||
saved_undefined_var_behavior = C.DEFAULT_UNDEFINED_VAR_BEHAVIOR
|
||||
C.DEFAULT_UNDEFINED_VAR_BEHAVIOR = fail_on_undefined
|
||||
|
||||
test_callbacks = TestCallbacks()
|
||||
playbook = ansible.playbook.PlayBook(
|
||||
playbook=os.path.join(self.test_dir, 'test_playbook_undefined_vars', playbook),
|
||||
host_list='test/test_playbook_undefined_vars/hosts',
|
||||
stats=ans_callbacks.AggregateStats(),
|
||||
callbacks=test_callbacks,
|
||||
runner_callbacks=test_callbacks
|
||||
)
|
||||
actual = playbook.run()
|
||||
|
||||
C.DEFAULT_UNDEFINED_VAR_BEHAVIOR = saved_undefined_var_behavior
|
||||
|
||||
# if different, this will output to screen
|
||||
print "**ACTUAL**"
|
||||
print utils.jsonify(actual, format=True)
|
||||
expected = {
|
||||
"localhost": {
|
||||
"changed": 0,
|
||||
"failures": 0,
|
||||
"ok": int(not fail_on_undefined) + 1,
|
||||
"skipped": 0,
|
||||
"unreachable": int(fail_on_undefined)
|
||||
}
|
||||
}
|
||||
print "**EXPECTED**"
|
||||
print utils.jsonify(expected, format=True)
|
||||
|
||||
assert utils.jsonify(expected, format=True) == utils.jsonify(actual, format=True)
|
||||
|
||||
#def test_playbook_undefined_vars1_ignore(self):
|
||||
# self._test_playbook_undefined_vars('playbook1.yml', False)
|
||||
|
||||
#def test_playbook_undefined_vars1_fail(self):
|
||||
# self._test_playbook_undefined_vars('playbook1.yml', True)
|
||||
|
||||
#def test_playbook_undefined_vars2_ignore(self):
|
||||
# self._test_playbook_undefined_vars('playbook2.yml', False)
|
||||
|
||||
#def test_playbook_undefined_vars2_fail(self):
|
||||
# self._test_playbook_undefined_vars('playbook2.yml', True)
|
||||
|
||||
def test_yaml_hosts_list(self):
|
||||
# Make sure playbooks support hosts: [host1, host2]
|
||||
# TODO: Actually run the play on more than one host
|
||||
test_callbacks = TestCallbacks()
|
||||
playbook = ansible.playbook.PlayBook(
|
||||
playbook=os.path.join(self.test_dir, 'hosts_list.yml'),
|
||||
host_list='test/ansible_hosts',
|
||||
stats=ans_callbacks.AggregateStats(),
|
||||
callbacks=test_callbacks,
|
||||
runner_callbacks=test_callbacks
|
||||
)
|
||||
play = ansible.playbook.Play(playbook, playbook.playbook[0], os.getcwd())
|
||||
assert play.hosts == ';'.join(('host1', 'host2', 'host3'))
|
||||
|
||||
def test_playbook_hash_replace(self):
|
||||
# save default hash behavior so we can restore it in the end of the test
|
||||
saved_hash_behavior = C.DEFAULT_HASH_BEHAVIOUR
|
||||
C.DEFAULT_HASH_BEHAVIOUR = "replace"
|
||||
|
||||
test_callbacks = TestCallbacks()
|
||||
playbook = ansible.playbook.PlayBook(
|
||||
playbook=os.path.join(self.test_dir, 'test_hash_behavior', 'playbook.yml'),
|
||||
host_list='test/ansible_hosts',
|
||||
stats=ans_callbacks.AggregateStats(),
|
||||
callbacks=test_callbacks,
|
||||
runner_callbacks=test_callbacks
|
||||
)
|
||||
playbook.run()
|
||||
|
||||
filename = '/tmp/ansible_test_messages.out'
|
||||
expected_lines = [
|
||||
"goodbye: Goodbye World!"
|
||||
]
|
||||
self._compare_file_output(filename, expected_lines)
|
||||
|
||||
filename = '/tmp/ansible_test_role_messages.out'
|
||||
expected_lines = [
|
||||
"inside_a_role: Indeed!"
|
||||
]
|
||||
self._compare_file_output(filename, expected_lines)
|
||||
|
||||
# restore default hash behavior
|
||||
C.DEFAULT_HASH_BEHAVIOUR = saved_hash_behavior
|
||||
|
||||
def test_playbook_hash_merge(self):
|
||||
# save default hash behavior so we can restore it in the end of the test
|
||||
saved_hash_behavior = C.DEFAULT_HASH_BEHAVIOUR
|
||||
C.DEFAULT_HASH_BEHAVIOUR = "merge"
|
||||
|
||||
test_callbacks = TestCallbacks()
|
||||
playbook = ansible.playbook.PlayBook(
|
||||
playbook=os.path.join(self.test_dir, 'test_hash_behavior', 'playbook.yml'),
|
||||
host_list='test/ansible_hosts',
|
||||
stats=ans_callbacks.AggregateStats(),
|
||||
callbacks=test_callbacks,
|
||||
runner_callbacks=test_callbacks
|
||||
)
|
||||
playbook.run()
|
||||
|
||||
filename = '/tmp/ansible_test_messages.out'
|
||||
expected_lines = [
|
||||
"goodbye: Goodbye World!",
|
||||
"hello: Hello World!"
|
||||
]
|
||||
self._compare_file_output(filename, expected_lines)
|
||||
|
||||
filename = '/tmp/ansible_test_role_messages.out'
|
||||
expected_lines = [
|
||||
"goodbye: Goodbye World!",
|
||||
"hello: Hello World!",
|
||||
"inside_a_role: Indeed!"
|
||||
]
|
||||
self._compare_file_output(filename, expected_lines)
|
||||
|
||||
# restore default hash behavior
|
||||
C.DEFAULT_HASH_BEHAVIOUR = saved_hash_behavior
|
||||
|
||||
def test_playbook_ignore_errors(self):
|
||||
test_callbacks = TestCallbacks()
|
||||
playbook = ansible.playbook.PlayBook(
|
||||
playbook=os.path.join(self.test_dir, 'playbook-ignore-errors.yml'),
|
||||
host_list='test/ansible_hosts',
|
||||
stats=ans_callbacks.AggregateStats(),
|
||||
callbacks=test_callbacks,
|
||||
runner_callbacks=test_callbacks
|
||||
)
|
||||
actual = playbook.run()
|
||||
|
||||
# if different, this will output to screen
|
||||
print "**ACTUAL**"
|
||||
print utils.jsonify(actual, format=True)
|
||||
expected = {
|
||||
"localhost": {
|
||||
"changed": 1,
|
||||
"failures": 1,
|
||||
"ok": 1,
|
||||
"skipped": 0,
|
||||
"unreachable": 0
|
||||
}
|
||||
}
|
||||
print "**EXPECTED**"
|
||||
print utils.jsonify(expected, format=True)
|
||||
|
||||
assert utils.jsonify(expected, format=True) == utils.jsonify(actual,format=True)
|
||||
|
||||
def test_playbook_changed_when(self):
|
||||
test_callbacks = TestCallbacks()
|
||||
playbook = ansible.playbook.PlayBook(
|
||||
playbook=os.path.join(self.test_dir, 'playbook-changed_when.yml'),
|
||||
host_list='test/ansible_hosts',
|
||||
stats=ans_callbacks.AggregateStats(),
|
||||
callbacks=test_callbacks,
|
||||
runner_callbacks=test_callbacks
|
||||
)
|
||||
actual = playbook.run()
|
||||
|
||||
# if different, this will output to screen
|
||||
print "**ACTUAL**"
|
||||
print utils.jsonify(actual, format=True)
|
||||
expected = {
|
||||
"localhost": {
|
||||
"changed": 3,
|
||||
"failures": 0,
|
||||
"ok": 6,
|
||||
"skipped": 0,
|
||||
"unreachable": 0
|
||||
}
|
||||
}
|
||||
print "**EXPECTED**"
|
||||
print utils.jsonify(expected, format=True)
|
||||
|
||||
assert utils.jsonify(expected, format=True) == utils.jsonify(actual,format=True)
|
||||
|
||||
def test_playbook_failed_when(self):
|
||||
test_callbacks = TestCallbacks()
|
||||
playbook = ansible.playbook.PlayBook(
|
||||
playbook=os.path.join(self.test_dir, 'playbook-failed_when.yml'),
|
||||
host_list='test/ansible_hosts',
|
||||
stats=ans_callbacks.AggregateStats(),
|
||||
callbacks=test_callbacks,
|
||||
runner_callbacks=test_callbacks
|
||||
)
|
||||
actual = playbook.run()
|
||||
|
||||
# if different, this will output to screen
|
||||
print "**ACTUAL**"
|
||||
print utils.jsonify(actual, format=True)
|
||||
expected = {
|
||||
"localhost": {
|
||||
"changed": 2,
|
||||
"failures": 1,
|
||||
"ok": 2,
|
||||
"skipped": 0,
|
||||
"unreachable": 0
|
||||
}
|
||||
}
|
||||
print "**EXPECTED**"
|
||||
print utils.jsonify(expected, format=True)
|
||||
|
||||
assert utils.jsonify(expected, format=True) == utils.jsonify(actual,format=True)
|
||||
|
||||
|
||||
def test_playbook_always_run(self):
|
||||
test_callbacks = TestCallbacks()
|
||||
playbook = ansible.playbook.PlayBook(
|
||||
playbook=os.path.join(self.test_dir, 'playbook-always-run.yml'),
|
||||
host_list='test/ansible_hosts',
|
||||
stats=ans_callbacks.AggregateStats(),
|
||||
callbacks=test_callbacks,
|
||||
runner_callbacks=test_callbacks,
|
||||
check=True
|
||||
)
|
||||
actual = playbook.run()
|
||||
|
||||
# if different, this will output to screen
|
||||
print "**ACTUAL**"
|
||||
print utils.jsonify(actual, format=True)
|
||||
expected = {
|
||||
"localhost": {
|
||||
"changed": 4,
|
||||
"failures": 0,
|
||||
"ok": 4,
|
||||
"skipped": 8,
|
||||
"unreachable": 0
|
||||
}
|
||||
}
|
||||
print "**EXPECTED**"
|
||||
print utils.jsonify(expected, format=True)
|
||||
|
||||
assert utils.jsonify(expected, format=True) == utils.jsonify(actual,format=True)
|
||||
|
||||
#def test_playbook_logging_non_ascii(self):
|
||||
# pb = 'test/playbook-logging-non-ascii.yml'
|
||||
# actual = self._run(pb)
|
||||
#
|
||||
# expected = {
|
||||
# "localhost": {
|
||||
# "changed": 3,
|
||||
# "failures": 0,
|
||||
# "ok": 3,
|
||||
# "skipped": 0,
|
||||
# "unreachable": 0
|
||||
# }
|
||||
# }
|
||||
#
|
||||
# assert utils.jsonify(expected, format=True) == utils.jsonify(actual, format=True)
|
||||
|
||||
|
||||
# Disabled for now as there are permissions issues that happen if you are not the owner that created files
|
||||
# in the archive.
|
||||
# def test_unarchive(self):
|
||||
# pb = 'test/playbook-unarchive.yml'
|
||||
# actual = self._run(pb)
|
||||
#
|
||||
# expected = {
|
||||
# "localhost": {
|
||||
# "changed": 29,
|
||||
# "failures": 0,
|
||||
# "ok": 33,
|
||||
# "skipped": 12,
|
||||
# "unreachable": 0
|
||||
# }
|
||||
# }
|
||||
#
|
||||
# assert utils.jsonify(expected, format=True) == utils.jsonify(actual,format=True)
|
||||
|
||||
|
||||
def _compare_file_output(self, filename, expected_lines):
|
||||
actual_lines = []
|
||||
with open(filename) as f:
|
||||
actual_lines = [l.strip() for l in f.readlines()]
|
||||
actual_lines = sorted(actual_lines)
|
||||
|
||||
print "**ACTUAL**"
|
||||
print actual_lines
|
||||
|
||||
print "**EXPECTED**"
|
||||
print expected_lines
|
||||
|
||||
assert actual_lines == expected_lines
|
|
@ -1,129 +0,0 @@
|
|||
|
||||
# tests are fairly 'live' (but safe to run)
|
||||
# setup authorized_keys for logged in user such
|
||||
# that the user can log in as themselves before running tests
|
||||
|
||||
import unittest
|
||||
import getpass
|
||||
import ansible.runner
|
||||
import os
|
||||
import shutil
|
||||
import time
|
||||
import tempfile
|
||||
|
||||
from nose.plugins.skip import SkipTest
|
||||
|
||||
|
||||
def get_binary(name):
|
||||
for directory in os.environ["PATH"].split(os.pathsep):
|
||||
path = os.path.join(directory, name)
|
||||
if os.path.isfile(path) and os.access(path, os.X_OK):
|
||||
return path
|
||||
return None
|
||||
|
||||
|
||||
class TestRunner(unittest.TestCase):
|
||||
|
||||
def setUp(self):
|
||||
self.user = getpass.getuser()
|
||||
self.runner = ansible.runner.Runner(
|
||||
basedir='test/',
|
||||
module_name='ping',
|
||||
module_path='library/',
|
||||
module_args='',
|
||||
remote_user=self.user,
|
||||
remote_pass=None,
|
||||
host_list='test/ansible_hosts',
|
||||
timeout=5,
|
||||
forks=1,
|
||||
background=0,
|
||||
pattern='all',
|
||||
transport='local',
|
||||
)
|
||||
self.cwd = os.getcwd()
|
||||
self.test_dir = os.path.join(self.cwd, 'test')
|
||||
self.stage_dir = self._prepare_stage_dir()
|
||||
|
||||
def _prepare_stage_dir(self):
|
||||
stage_path = os.path.join(self.test_dir, 'test_data')
|
||||
if os.path.exists(stage_path):
|
||||
shutil.rmtree(stage_path, ignore_errors=False)
|
||||
assert not os.path.exists(stage_path)
|
||||
os.makedirs(stage_path)
|
||||
assert os.path.exists(stage_path)
|
||||
return stage_path
|
||||
|
||||
def _get_test_file(self, filename):
|
||||
# get a file inside the test input directory
|
||||
filename = os.path.join(self.test_dir, filename)
|
||||
assert os.path.exists(filename)
|
||||
return filename
|
||||
|
||||
def _get_stage_file(self, filename):
|
||||
# get a file inside the test output directory
|
||||
filename = os.path.join(self.stage_dir, filename)
|
||||
return filename
|
||||
|
||||
def _run(self, module_name, module_args, background=0, check_mode=False):
|
||||
''' run a module and get the localhost results '''
|
||||
self.runner.module_name = module_name
|
||||
args = ' '.join(module_args)
|
||||
self.runner.module_args = args
|
||||
self.runner.background = background
|
||||
self.runner.check = check_mode
|
||||
results = self.runner.run()
|
||||
# when using nosetests this will only show up on failure
|
||||
# which is pretty useful
|
||||
assert "localhost" in results['contacted']
|
||||
return results['contacted']['localhost']
|
||||
|
||||
def test_action_plugins(self):
|
||||
result = self._run("uncategorized_plugin", [])
|
||||
assert result.get("msg") == "uncategorized"
|
||||
result = self._run("categorized_plugin", [])
|
||||
assert result.get("msg") == "categorized"
|
||||
|
||||
def test_ping(self):
|
||||
result = self._run('ping', [])
|
||||
assert "ping" in result
|
||||
|
||||
def test_async(self):
|
||||
# test async launch and job status
|
||||
# of any particular module
|
||||
result = self._run('command', [get_binary("sleep"), "3"], background=20)
|
||||
assert 'ansible_job_id' in result
|
||||
assert 'started' in result
|
||||
jid = result['ansible_job_id']
|
||||
# no real chance of this op taking a while, but whatever
|
||||
time.sleep(5)
|
||||
# CLI will abstract this (when polling), but this is how it works internally
|
||||
result = self._run('async_status', ["jid=%s" % jid])
|
||||
# TODO: would be nice to have tests for supervisory process
|
||||
# killing job after X seconds
|
||||
assert 'finished' in result
|
||||
assert 'failed' not in result
|
||||
assert 'rc' in result
|
||||
assert 'stdout' in result
|
||||
assert result['ansible_job_id'] == jid
|
||||
|
||||
def test_assemble(self):
|
||||
input = self._get_test_file('assemble.d')
|
||||
output = self._get_stage_file('sample.out')
|
||||
result = self._run('assemble', [
|
||||
"src=%s" % input,
|
||||
"dest=%s" % output,
|
||||
])
|
||||
assert os.path.exists(output)
|
||||
out = file(output).read()
|
||||
assert out.find("first") != -1
|
||||
assert out.find("second") != -1
|
||||
assert out.find("third") != -1
|
||||
assert result['changed'] is True
|
||||
assert 'md5sum' in result
|
||||
assert 'failed' not in result
|
||||
result = self._run('assemble', [
|
||||
"src=%s" % input,
|
||||
"dest=%s" % output,
|
||||
])
|
||||
assert result['changed'] is False
|
||||
|
|
@ -16,94 +16,6 @@ sys.setdefaultencoding("utf8")
|
|||
|
||||
class TestUtils(unittest.TestCase):
|
||||
|
||||
#####################################
|
||||
### varReplace function tests
|
||||
|
||||
def test_varReplace_var_complex_var(self):
|
||||
vars = {
|
||||
'x': '$y',
|
||||
'y': {
|
||||
'foo': 'result',
|
||||
},
|
||||
}
|
||||
template = '${x.foo}'
|
||||
res = template2.template(None, template, vars)
|
||||
assert res == 'result'
|
||||
|
||||
#####################################
|
||||
### template_ds function tests
|
||||
|
||||
def test_template_ds_basic(self):
|
||||
vars = {
|
||||
'data': {
|
||||
'var': [
|
||||
'foo',
|
||||
'bar',
|
||||
'baz',
|
||||
],
|
||||
'types': [
|
||||
'str',
|
||||
u'unicode',
|
||||
1,
|
||||
1L,
|
||||
1.2,
|
||||
],
|
||||
'alphas': '$alphas',
|
||||
},
|
||||
'alphas': [
|
||||
'abc',
|
||||
'def',
|
||||
'ghi',
|
||||
],
|
||||
}
|
||||
|
||||
template = '${data.var}'
|
||||
res = template2.template(None, template, vars)
|
||||
assert sorted(res) == sorted(vars['data']['var'])
|
||||
|
||||
template = '${data.types}'
|
||||
res = template2.template(None, template, vars)
|
||||
assert sorted(res) == sorted(vars['data']['types'])
|
||||
|
||||
template = '${data.alphas}'
|
||||
res = template2.template(None, template, vars)
|
||||
assert sorted(res) == sorted(vars['alphas'])
|
||||
|
||||
template = '${data.nonexisting}'
|
||||
res = template2.template(None, template, vars)
|
||||
assert res == template
|
||||
|
||||
#####################################
|
||||
### Template function tests
|
||||
|
||||
def test_template_basic(self):
|
||||
vars = {
|
||||
'who': 'world',
|
||||
}
|
||||
|
||||
res = template2.template_from_file("test", "template-basic", vars)
|
||||
|
||||
assert res == 'hello world'
|
||||
|
||||
def test_template_whitespace(self):
|
||||
vars = {
|
||||
'who': 'world',
|
||||
}
|
||||
|
||||
res = template2.template_from_file("test", "template-whitespace", vars)
|
||||
|
||||
assert res == 'hello world\n'
|
||||
|
||||
def test_template_unicode(self):
|
||||
vars = {
|
||||
'who': u'wórld',
|
||||
}
|
||||
|
||||
res = template2.template_from_file("test", "template-basic", vars)
|
||||
|
||||
assert res == u'hello wórld'
|
||||
|
||||
|
||||
#####################################
|
||||
### check_conditional tests
|
||||
|
||||
|
@ -204,44 +116,3 @@ class TestUtils(unittest.TestCase):
|
|||
assert (ansible.utils.parse_kv('a=simple b="with space" c="this=that"') ==
|
||||
{'a': 'simple', 'b': 'with space', 'c': 'this=that'})
|
||||
|
||||
#####################################
|
||||
### plugins
|
||||
|
||||
def test_loaders_expanduser_each_dir(self):
|
||||
# Test that PluginLoader will call expanduser on each path
|
||||
# when it splits its "config" argument.
|
||||
home_dir = os.path.expanduser("~")
|
||||
if home_dir == "~":
|
||||
raise SkipTest("your platform doesn't expand ~ in paths")
|
||||
elif not os.path.isdir(home_dir):
|
||||
raise SkipTest("~ expands to non-directory %r" % (home_dir,))
|
||||
elif not os.path.isabs(home_dir):
|
||||
raise SkipTest("~ expands to non-absolute path %r" % (home_dir,))
|
||||
# Unfortunately we have to create temporary directories in
|
||||
# your home directory; the directories have to exist for
|
||||
# PluginLoader to accept them.
|
||||
abs_dirs, tilde_dirs = [], []
|
||||
try:
|
||||
for _ in range(2):
|
||||
temp_dir = tempfile.mkdtemp(prefix="ansible", dir=home_dir)
|
||||
abs_dirs.append(temp_dir)
|
||||
# Convert mkdtemp's absolute path to one starting with "~".
|
||||
tilde_dir = os.path.join("~", os.path.relpath(temp_dir,
|
||||
home_dir))
|
||||
tilde_dirs.append(tilde_dir)
|
||||
loader = ansible.utils.plugins.PluginLoader(
|
||||
"",
|
||||
"",
|
||||
os.pathsep.join(tilde_dirs),
|
||||
"something_under_basedir"
|
||||
)
|
||||
loader_paths = loader.print_paths().split(os.pathsep)
|
||||
for abs_dir in abs_dirs:
|
||||
assert abs_dir in loader_paths, \
|
||||
"%r not in %r" % (abs_dir, loader_paths)
|
||||
finally:
|
||||
for a_dir in abs_dirs:
|
||||
try:
|
||||
os.rmdir(a_dir)
|
||||
except os.error:
|
||||
pass
|
||||
|
|
|
@ -1,90 +0,0 @@
|
|||
-----BEGIN PGP PUBLIC KEY BLOCK-----
|
||||
Version: GnuPG v1.4.10 (GNU/Linux)
|
||||
|
||||
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
|
||||
hqsRKcw+Z9k=
|
||||
=sw5O
|
||||
-----END PGP PUBLIC KEY BLOCK-----
|
|
@ -1,2 +0,0 @@
|
|||
# This is the first comment.
|
||||
[somegroup]
|
|
@ -1,2 +0,0 @@
|
|||
# This is the second comment.
|
||||
localhost
|
|
@ -1,4 +0,0 @@
|
|||
# This is the third comment.
|
||||
[somegroup:vars]
|
||||
foo=bar
|
||||
# 無 可 無 非 常 無
|
|
@ -1,42 +0,0 @@
|
|||
-
|
||||
hosts: all
|
||||
gather_facts: no
|
||||
remote_user: root
|
||||
vars:
|
||||
color: brown
|
||||
tasks:
|
||||
- name: test 1
|
||||
cron: name="execution test 1" weekday="2,3" minute=0 hour=12 user="root" job="YUMINTERACTIVE=0 /usr/sbin/yum-autoupdate" cron_file=yum-autoupdate state=absent
|
||||
tags:
|
||||
- cron
|
||||
|
||||
- name: test 1-1
|
||||
cron: name="execution test 1" weekday="2,3" minute=0 hour=12 user="root" job="YUMINTERACTIVE=0 /usr/sbin/yum-autoupdate" cron_file=yum-autoupdate state=absent
|
||||
tags:
|
||||
- cron
|
||||
|
||||
- name: test 2-1
|
||||
cron: name="execution test 2" weekday="2,3" minute=0 hour=12 user="root" job="YUMINTERACTIVE=0 /usr/sbin/yum-autoupdate" state=absent
|
||||
tags:
|
||||
- cron
|
||||
|
||||
- name: test 2-2
|
||||
cron: name="execution test 2" weekday="2,3" minute=0 hour=12 user="root" job="YUMINTERACTIVE=0 /usr/sbin/yum-autoupdate" state=absent
|
||||
tags:
|
||||
- cron
|
||||
|
||||
- name: test 2-3
|
||||
cron: name="execution test 2" weekday="2,3" minute=0 hour=12 user="root" job="YUMINTERACTIVE=0 /usr/sbin/yum-autoupdate"
|
||||
tags:
|
||||
- cron
|
||||
|
||||
- name: test 3-1
|
||||
cron: name="execution test 3" weekday="2,3" minute=0 hour=12 user="root" job="YUMINTERACTIVE=0 /usr/sbin/yum-autoupdate" cron_file=yum-autoupdate state=absent
|
||||
tags:
|
||||
- cron
|
||||
|
||||
- name: test 3-2
|
||||
cron: name="execution test 3" weekday="2,3" minute=0 hour=12 user="root" job="YUMINTERACTIVE=0 /usr/sbin/yum-autoupdate" cron_file=yum-autoupdate
|
||||
tags:
|
||||
- cron
|
||||
|
|
@ -1,2 +0,0 @@
|
|||
---
|
||||
testing: default
|
|
@ -1,748 +0,0 @@
|
|||
#!/usr/bin/env python
|
||||
# Copyright 2013 Google Inc.
|
||||
#
|
||||
# This file is part of Ansible
|
||||
#
|
||||
# Ansible is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Ansible is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
# This is a custom functional test script for the Google Compute Engine
|
||||
# ansible modules. In order to run these tests, you must:
|
||||
# 1) Create a Google Cloud Platform account and enable the Google
|
||||
# Compute Engine service and billing
|
||||
# 2) Download, install, and configure 'gcutil'
|
||||
# see [https://developers.google.com/compute/docs/gcutil/]
|
||||
# 3) Convert your GCE Service Account private key from PKCS12 to PEM format
|
||||
# $ openssl pkcs12 -in pkey.pkcs12 -passin pass:notasecret \
|
||||
# > -nodes -nocerts | openssl rsa -out pkey.pem
|
||||
# 4) Make sure you have libcloud 0.13.3 or later installed.
|
||||
# 5) Make sure you have a libcloud 'secrets.py' file in your PYTHONPATH
|
||||
# 6) Set GCE_PARAMS and GCE_KEYWORD_PARMS in your 'secrets.py' file.
|
||||
# 7) Set up a simple hosts file
|
||||
# $ echo 127.0.0.1 > ~/ansible_hosts
|
||||
# $ echo "export ANSIBLE_HOSTS='~/ansible_hosts'" >> ~/.bashrc
|
||||
# $ . ~/.bashrc
|
||||
# 8) Set up your ansible 'hacking' environment
|
||||
# $ cd ~/ansible
|
||||
# $ . hacking/env-setup
|
||||
# $ export ANSIBLE_HOST_KEY_CHECKING=no
|
||||
# $ ansible all -m ping
|
||||
# 9) Set your PROJECT variable below
|
||||
# 10) Run and time the tests and log output, take ~30 minutes to run
|
||||
# $ time stdbuf -oL python test/gce_tests.py 2>&1 | tee log
|
||||
#
|
||||
# Last update: gcutil-1.11.0 and v1beta16
|
||||
|
||||
# Set this to your test Project ID
|
||||
PROJECT="google.com:erjohnso"
|
||||
|
||||
# debugging
|
||||
DEBUG=False # lots of debugging output
|
||||
VERBOSE=True # on failure, display ansible command and expected/actual result
|
||||
|
||||
# location - note that some tests rely on the module's 'default'
|
||||
# region/zone, which should match the settings below.
|
||||
REGION="us-central1"
|
||||
ZONE="%s-a" % REGION
|
||||
|
||||
# Peeking is a way to trigger looking at a specified set of resources
|
||||
# before and/or after a test run. The 'test_cases' data structure below
|
||||
# has a few tests with 'peek_before' and 'peek_after'. When those keys
|
||||
# are set and PEEKING_ENABLED is True, then these steps will be executed
|
||||
# to aid in debugging tests. Normally, this is not needed.
|
||||
PEEKING_ENABLED=False
|
||||
|
||||
# disks
|
||||
DNAME="aaaaa-ansible-disk"
|
||||
DNAME2="aaaaa-ansible-disk2"
|
||||
DNAME6="aaaaa-ansible-inst6"
|
||||
DNAME7="aaaaa-ansible-inst7"
|
||||
USE_PD="true"
|
||||
KERNEL="https://www.googleapis.com/compute/v1beta16/projects/google/global/kernels/gce-no-conn-track-v20130813"
|
||||
|
||||
# instances
|
||||
INAME="aaaaa-ansible-inst"
|
||||
INAME2="aaaaa-ansible-inst2"
|
||||
INAME3="aaaaa-ansible-inst3"
|
||||
INAME4="aaaaa-ansible-inst4"
|
||||
INAME5="aaaaa-ansible-inst5"
|
||||
INAME6="aaaaa-ansible-inst6"
|
||||
INAME7="aaaaa-ansible-inst7"
|
||||
TYPE="n1-standard-1"
|
||||
IMAGE="https://www.googleapis.com/compute/v1beta16/projects/debian-cloud/global/images/debian-7-wheezy-v20131014"
|
||||
NETWORK="default"
|
||||
SCOPES="https://www.googleapis.com/auth/userinfo.email,https://www.googleapis.com/auth/compute,https://www.googleapis.com/auth/devstorage.full_control"
|
||||
|
||||
# networks / firewalls
|
||||
NETWK1="ansible-network1"
|
||||
NETWK2="ansible-network2"
|
||||
NETWK3="ansible-network3"
|
||||
CIDR1="10.240.16.0/24"
|
||||
CIDR2="10.240.32.0/24"
|
||||
CIDR3="10.240.64.0/24"
|
||||
GW1="10.240.16.1"
|
||||
GW2="10.240.32.1"
|
||||
FW1="ansible-fwrule1"
|
||||
FW2="ansible-fwrule2"
|
||||
FW3="ansible-fwrule3"
|
||||
FW4="ansible-fwrule4"
|
||||
|
||||
# load-balancer tests
|
||||
HC1="ansible-hc1"
|
||||
HC2="ansible-hc2"
|
||||
HC3="ansible-hc3"
|
||||
LB1="ansible-lb1"
|
||||
LB2="ansible-lb2"
|
||||
|
||||
from commands import getstatusoutput as run
|
||||
import sys
|
||||
|
||||
test_cases = [
|
||||
{'id': '01', 'desc': 'Detach / Delete disk tests',
|
||||
'setup': ['gcutil addinstance "%s" --wait_until_running --zone=%s --machine_type=%s --network=%s --service_account_scopes="%s" --image="%s" --persistent_boot_disk=%s' % (INAME, ZONE, TYPE, NETWORK, SCOPES, IMAGE, USE_PD),
|
||||
'gcutil adddisk "%s" --size_gb=2 --zone=%s --wait_until_complete' % (DNAME, ZONE)],
|
||||
|
||||
'tests': [
|
||||
{'desc': 'DETACH_ONLY but disk not found [success]',
|
||||
'm': 'gce_pd',
|
||||
'a': 'name=%s instance_name=%s zone=%s detach_only=yes state=absent' % ("missing-disk", INAME, ZONE),
|
||||
'r': '127.0.0.1 | success >> {"changed": false, "detach_only": true, "detached_from_instance": "%s", "name": "missing-disk", "state": "absent", "zone": "%s"}' % (INAME, ZONE),
|
||||
},
|
||||
{'desc': 'DETACH_ONLY but instance not found [success]',
|
||||
'm': 'gce_pd',
|
||||
'a': 'name=%s instance_name=%s zone=%s detach_only=yes state=absent' % (DNAME, "missing-instance", ZONE),
|
||||
'r': '127.0.0.1 | success >> {"changed": false, "detach_only": true, "detached_from_instance": "missing-instance", "name": "%s", "size_gb": 2, "state": "absent", "zone": "%s"}' % (DNAME, ZONE),
|
||||
},
|
||||
{'desc': 'DETACH_ONLY but neither disk nor instance exists [success]',
|
||||
'm': 'gce_pd',
|
||||
'a': 'name=%s instance_name=%s zone=%s detach_only=yes state=absent' % ("missing-disk", "missing-instance", ZONE),
|
||||
'r': '127.0.0.1 | success >> {"changed": false, "detach_only": true, "detached_from_instance": "missing-instance", "name": "missing-disk", "state": "absent", "zone": "%s"}' % (ZONE),
|
||||
},
|
||||
{'desc': 'DETACH_ONLY but disk is not currently attached [success]',
|
||||
'm': 'gce_pd',
|
||||
'a': 'name=%s instance_name=%s zone=%s detach_only=yes state=absent' % (DNAME, INAME, ZONE),
|
||||
'r': '127.0.0.1 | success >> {"changed": false, "detach_only": true, "detached_from_instance": "%s", "name": "%s", "size_gb": 2, "state": "absent", "zone": "%s"}' % (INAME, DNAME, ZONE),
|
||||
},
|
||||
{'desc': 'DETACH_ONLY disk is attached and should be detached [success]',
|
||||
'setup': ['gcutil attachdisk --disk="%s,mode=READ_ONLY" --zone=%s %s' % (DNAME, ZONE, INAME), 'sleep 10'],
|
||||
'm': 'gce_pd',
|
||||
'a': 'name=%s instance_name=%s zone=%s detach_only=yes state=absent' % (DNAME, INAME, ZONE),
|
||||
'r': '127.0.0.1 | success >> {"attached_mode": "READ_ONLY", "attached_to_instance": "%s", "changed": true, "detach_only": true, "detached_from_instance": "%s", "name": "%s", "size_gb": 2, "state": "absent", "zone": "%s"}' % (INAME, INAME, DNAME, ZONE),
|
||||
'teardown': ['gcutil detachdisk --zone=%s --device_name=%s %s' % (ZONE, DNAME, INAME)],
|
||||
},
|
||||
{'desc': 'DETACH_ONLY but not instance specified [FAIL]',
|
||||
'm': 'gce_pd',
|
||||
'a': 'name=%s zone=%s detach_only=yes state=absent' % (DNAME, ZONE),
|
||||
'r': '127.0.0.1 | FAILED >> {"changed": false, "failed": true, "msg": "Must specify an instance name when detaching a disk"}',
|
||||
},
|
||||
{'desc': 'DELETE but disk not found [success]',
|
||||
'm': 'gce_pd',
|
||||
'a': 'name=%s zone=%s state=absent' % ("missing-disk", ZONE),
|
||||
'r': '127.0.0.1 | success >> {"changed": false, "name": "missing-disk", "state": "absent", "zone": "%s"}' % (ZONE),
|
||||
},
|
||||
{'desc': 'DELETE but disk is attached [FAIL]',
|
||||
'setup': ['gcutil attachdisk --disk="%s,mode=READ_ONLY" --zone=%s %s' % (DNAME, ZONE, INAME), 'sleep 10'],
|
||||
'm': 'gce_pd',
|
||||
'a': 'name=%s zone=%s state=absent' % (DNAME, ZONE),
|
||||
'r': "127.0.0.1 | FAILED >> {\"changed\": false, \"failed\": true, \"msg\": \"The disk resource 'projects/%s/zones/%s/disks/%s' is already being used by 'projects/%s/zones/%s/instances/%s'\"}" % (PROJECT, ZONE, DNAME, PROJECT, ZONE, INAME),
|
||||
'teardown': ['gcutil detachdisk --zone=%s --device_name=%s %s' % (ZONE, DNAME, INAME)],
|
||||
},
|
||||
{'desc': 'DELETE disk [success]',
|
||||
'm': 'gce_pd',
|
||||
'a': 'name=%s zone=%s state=absent' % (DNAME, ZONE),
|
||||
'r': '127.0.0.1 | success >> {"changed": true, "name": "%s", "size_gb": 2, "state": "absent", "zone": "%s"}' % (DNAME, ZONE),
|
||||
},
|
||||
],
|
||||
'teardown': ['gcutil deleteinstance -f "%s" --zone=%s' % (INAME, ZONE),
|
||||
'sleep 15',
|
||||
'gcutil deletedisk -f "%s" --zone=%s' % (INAME, ZONE),
|
||||
'sleep 10',
|
||||
'gcutil deletedisk -f "%s" --zone=%s' % (DNAME, ZONE),
|
||||
'sleep 10'],
|
||||
},
|
||||
|
||||
{'id': '02', 'desc': 'Create disk but do not attach (e.g. no instance_name param)',
|
||||
'setup': [],
|
||||
'tests': [
|
||||
{'desc': 'CREATE_NO_ATTACH "string" for size_gb [FAIL]',
|
||||
'm': 'gce_pd',
|
||||
'a': 'name=%s size_gb="foo" zone=%s' % (DNAME, ZONE),
|
||||
'r': '127.0.0.1 | FAILED >> {"changed": false, "failed": true, "msg": "Must supply a size_gb larger than 1 GB"}',
|
||||
},
|
||||
{'desc': 'CREATE_NO_ATTACH negative size_gb [FAIL]',
|
||||
'm': 'gce_pd',
|
||||
'a': 'name=%s size_gb=-2 zone=%s' % (DNAME, ZONE),
|
||||
'r': '127.0.0.1 | FAILED >> {"changed": false, "failed": true, "msg": "Must supply a size_gb larger than 1 GB"}',
|
||||
},
|
||||
{'desc': 'CREATE_NO_ATTACH size_gb exceeds quota [FAIL]',
|
||||
'm': 'gce_pd',
|
||||
'a': 'name=%s size_gb=9999 zone=%s' % ("big-disk", ZONE),
|
||||
'r': '127.0.0.1 | FAILED >> {"changed": false, "failed": true, "msg": "Requested disk size exceeds quota"}',
|
||||
},
|
||||
{'desc': 'CREATE_NO_ATTACH create the disk [success]',
|
||||
'm': 'gce_pd',
|
||||
'a': 'name=%s zone=%s' % (DNAME, ZONE),
|
||||
'r': '127.0.0.1 | success >> {"changed": true, "name": "%s", "size_gb": 10, "state": "present", "zone": "%s"}' % (DNAME, ZONE),
|
||||
},
|
||||
{'desc': 'CREATE_NO_ATTACH but disk already exists [success]',
|
||||
'm': 'gce_pd',
|
||||
'a': 'name=%s zone=%s' % (DNAME, ZONE),
|
||||
'r': '127.0.0.1 | success >> {"changed": false, "name": "%s", "size_gb": 10, "state": "present", "zone": "%s"}' % (DNAME, ZONE),
|
||||
},
|
||||
],
|
||||
'teardown': ['gcutil deletedisk -f "%s" --zone=%s' % (DNAME, ZONE),
|
||||
'sleep 10'],
|
||||
},
|
||||
|
||||
{'id': '03', 'desc': 'Create and attach disk',
|
||||
'setup': ['gcutil addinstance "%s" --zone=%s --machine_type=%s --network=%s --service_account_scopes="%s" --image="%s" --persistent_boot_disk=%s' % (INAME2, ZONE, TYPE, NETWORK, SCOPES, IMAGE, USE_PD),
|
||||
'gcutil addinstance "%s" --zone=%s --machine_type=%s --network=%s --service_account_scopes="%s" --image="%s" --persistent_boot_disk=%s' % (INAME, ZONE, "g1-small", NETWORK, SCOPES, IMAGE, USE_PD),
|
||||
'gcutil adddisk "%s" --size_gb=2 --zone=%s' % (DNAME, ZONE),
|
||||
'gcutil adddisk "%s" --size_gb=2 --zone=%s --wait_until_complete' % (DNAME2, ZONE),],
|
||||
'tests': [
|
||||
{'desc': 'CREATE_AND_ATTACH "string" for size_gb [FAIL]',
|
||||
'm': 'gce_pd',
|
||||
'a': 'name=%s size_gb="foo" instance_name=%s zone=%s' % (DNAME, INAME, ZONE),
|
||||
'r': '127.0.0.1 | FAILED >> {"changed": false, "failed": true, "msg": "Must supply a size_gb larger than 1 GB"}',
|
||||
},
|
||||
{'desc': 'CREATE_AND_ATTACH negative size_gb [FAIL]',
|
||||
'm': 'gce_pd',
|
||||
'a': 'name=%s size_gb=-2 instance_name=%s zone=%s' % (DNAME, INAME, ZONE),
|
||||
'r': '127.0.0.1 | FAILED >> {"changed": false, "failed": true, "msg": "Must supply a size_gb larger than 1 GB"}',
|
||||
},
|
||||
{'desc': 'CREATE_AND_ATTACH size_gb exceeds quota [FAIL]',
|
||||
'm': 'gce_pd',
|
||||
'a': 'name=%s size_gb=9999 instance_name=%s zone=%s' % ("big-disk", INAME, ZONE),
|
||||
'r': '127.0.0.1 | FAILED >> {"changed": false, "failed": true, "msg": "Requested disk size exceeds quota"}',
|
||||
},
|
||||
{'desc': 'CREATE_AND_ATTACH missing instance [FAIL]',
|
||||
'm': 'gce_pd',
|
||||
'a': 'name=%s instance_name=%s zone=%s' % (DNAME, "missing-instance", ZONE),
|
||||
'r': '127.0.0.1 | FAILED >> {"changed": false, "failed": true, "msg": "Instance %s does not exist in zone %s"}' % ("missing-instance", ZONE),
|
||||
},
|
||||
{'desc': 'CREATE_AND_ATTACH disk exists but not attached [success]',
|
||||
'peek_before': ["gcutil --format=csv listinstances --zone=%s --filter=\"name eq 'aaaa.*'\"" % (ZONE)],
|
||||
'm': 'gce_pd',
|
||||
'a': 'name=%s instance_name=%s zone=%s' % (DNAME, INAME, ZONE),
|
||||
'r': '127.0.0.1 | success >> {"attached_mode": "READ_ONLY", "attached_to_instance": "%s", "changed": true, "name": "%s", "size_gb": 2, "state": "present", "zone": "%s"}' % (INAME, DNAME, ZONE),
|
||||
'peek_after': ["gcutil --format=csv listinstances --zone=%s --filter=\"name eq 'aaaa.*'\"" % (ZONE)],
|
||||
},
|
||||
{'desc': 'CREATE_AND_ATTACH disk exists already attached [success]',
|
||||
'm': 'gce_pd',
|
||||
'a': 'name=%s instance_name=%s zone=%s' % (DNAME, INAME, ZONE),
|
||||
'r': '127.0.0.1 | success >> {"attached_mode": "READ_ONLY", "attached_to_instance": "%s", "changed": false, "name": "%s", "size_gb": 2, "state": "present", "zone": "%s"}' % (INAME, DNAME, ZONE),
|
||||
},
|
||||
{'desc': 'CREATE_AND_ATTACH attached RO, attempt RO to 2nd inst [success]',
|
||||
'peek_before': ["gcutil --format=csv listinstances --zone=%s --filter=\"name eq 'aaaa.*'\"" % (ZONE)],
|
||||
'm': 'gce_pd',
|
||||
'a': 'name=%s instance_name=%s zone=%s' % (DNAME, INAME2, ZONE),
|
||||
'r': '127.0.0.1 | success >> {"attached_mode": "READ_ONLY", "attached_to_instance": "%s", "changed": true, "name": "%s", "size_gb": 2, "state": "present", "zone": "%s"}' % (INAME2, DNAME, ZONE),
|
||||
'peek_after': ["gcutil --format=csv listinstances --zone=%s --filter=\"name eq 'aaaa.*'\"" % (ZONE)],
|
||||
},
|
||||
{'desc': 'CREATE_AND_ATTACH attached RO, attach RW to self [FAILED no-op]',
|
||||
'peek_before': ["gcutil --format=csv listinstances --zone=%s --filter=\"name eq 'aaaa.*'\"" % (ZONE)],
|
||||
'm': 'gce_pd',
|
||||
'a': 'name=%s instance_name=%s zone=%s mode=READ_WRITE' % (DNAME, INAME, ZONE),
|
||||
'r': '127.0.0.1 | success >> {"attached_mode": "READ_ONLY", "attached_to_instance": "%s", "changed": false, "name": "%s", "size_gb": 2, "state": "present", "zone": "%s"}' % (INAME, DNAME, ZONE),
|
||||
},
|
||||
{'desc': 'CREATE_AND_ATTACH attached RW, attach RW to other [FAIL]',
|
||||
'setup': ['gcutil attachdisk --disk=%s,mode=READ_WRITE --zone=%s %s' % (DNAME2, ZONE, INAME), 'sleep 10'],
|
||||
'peek_before': ["gcutil --format=csv listinstances --zone=%s --filter=\"name eq 'aaaa.*'\"" % (ZONE)],
|
||||
'm': 'gce_pd',
|
||||
'a': 'name=%s instance_name=%s zone=%s mode=READ_WRITE' % (DNAME2, INAME2, ZONE),
|
||||
'r': "127.0.0.1 | FAILED >> {\"changed\": false, \"failed\": true, \"msg\": \"Unexpected response: HTTP return_code[200], API error code[RESOURCE_IN_USE] and message: The disk resource 'projects/%s/zones/%s/disks/%s' is already being used in read-write mode\"}" % (PROJECT, ZONE, DNAME2),
|
||||
'peek_after': ["gcutil --format=csv listinstances --zone=%s --filter=\"name eq 'aaaa.*'\"" % (ZONE)],
|
||||
},
|
||||
{'desc': 'CREATE_AND_ATTACH attach too many disks to inst [FAIL]',
|
||||
'setup': ['gcutil adddisk aa-disk-dummy --size_gb=2 --zone=%s' % (ZONE),
|
||||
'gcutil adddisk aa-disk-dummy2 --size_gb=2 --zone=%s --wait_until_complete' % (ZONE),
|
||||
'gcutil attachdisk --disk=aa-disk-dummy --zone=%s %s' % (ZONE, INAME),
|
||||
'sleep 5'],
|
||||
'peek_before': ["gcutil --format=csv listinstances --zone=%s --filter=\"name eq 'aaaa.*'\"" % (ZONE)],
|
||||
'm': 'gce_pd',
|
||||
'a': 'name=%s instance_name=%s zone=%s' % ("aa-disk-dummy2", INAME, ZONE),
|
||||
'r': "127.0.0.1 | FAILED >> {\"changed\": false, \"failed\": true, \"msg\": \"Unexpected response: HTTP return_code[200], API error code[LIMIT_EXCEEDED] and message: Exceeded limit 'maximum_persistent_disks' on resource 'projects/%s/zones/%s/instances/%s'. Limit: 4\"}" % (PROJECT, ZONE, INAME),
|
||||
'teardown': ['gcutil detachdisk --device_name=aa-disk-dummy --zone=%s %s' % (ZONE, INAME),
|
||||
'sleep 3',
|
||||
'gcutil deletedisk -f aa-disk-dummy --zone=%s' % (ZONE),
|
||||
'sleep 10',
|
||||
'gcutil deletedisk -f aa-disk-dummy2 --zone=%s' % (ZONE),
|
||||
'sleep 10'],
|
||||
},
|
||||
],
|
||||
'teardown': ['gcutil deleteinstance -f "%s" --zone=%s' % (INAME2, ZONE),
|
||||
'sleep 15',
|
||||
'gcutil deleteinstance -f "%s" --zone=%s' % (INAME, ZONE),
|
||||
'sleep 15',
|
||||
'gcutil deletedisk -f "%s" --zone=%s' % (INAME, ZONE),
|
||||
'sleep 10',
|
||||
'gcutil deletedisk -f "%s" --zone=%s' % (INAME2, ZONE),
|
||||
'sleep 10',
|
||||
'gcutil deletedisk -f "%s" --zone=%s' % (DNAME, ZONE),
|
||||
'sleep 10',
|
||||
'gcutil deletedisk -f "%s" --zone=%s' % (DNAME2, ZONE),
|
||||
'sleep 10'],
|
||||
},
|
||||
|
||||
{'id': '04', 'desc': 'Delete / destroy instances',
|
||||
'setup': ['gcutil addinstance "%s" --zone=%s --machine_type=%s --image="%s" --persistent_boot_disk=false' % (INAME, ZONE, TYPE, IMAGE),
|
||||
'gcutil addinstance "%s" --zone=%s --machine_type=%s --image="%s" --persistent_boot_disk=false' % (INAME2, ZONE, TYPE, IMAGE),
|
||||
'gcutil addinstance "%s" --zone=%s --machine_type=%s --image="%s" --persistent_boot_disk=false' % (INAME3, ZONE, TYPE, IMAGE),
|
||||
'gcutil addinstance "%s" --zone=%s --machine_type=%s --image="%s" --persistent_boot_disk=false' % (INAME4, ZONE, TYPE, IMAGE),
|
||||
'gcutil addinstance "%s" --wait_until_running --zone=%s --machine_type=%s --image="%s" --persistent_boot_disk=false' % (INAME5, ZONE, TYPE, IMAGE)],
|
||||
'tests': [
|
||||
{'desc': 'DELETE instance, bad zone param [FAIL]',
|
||||
'm': 'gce',
|
||||
'a': 'name=missing-inst zone=bogus state=absent',
|
||||
'r': '127.0.0.1 | FAILED >> {"failed": true, "msg": "value of zone must be one of: us-central1-a,us-central1-b,us-central2-a,europe-west1-a,europe-west1-b, got: bogus"}',
|
||||
},
|
||||
{'desc': 'DELETE non-existent instance, no-op [success]',
|
||||
'm': 'gce',
|
||||
'a': 'name=missing-inst zone=%s state=absent' % (ZONE),
|
||||
'r': '127.0.0.1 | success >> {"changed": false, "name": "missing-inst", "state": "absent", "zone": "%s"}' % (ZONE),
|
||||
},
|
||||
{'desc': 'DELETE an existing named instance [success]',
|
||||
'm': 'gce',
|
||||
'a': 'name=%s zone=%s state=absent' % (INAME, ZONE),
|
||||
'r': '127.0.0.1 | success >> {"changed": true, "name": "%s", "state": "absent", "zone": "%s"}' % (INAME, ZONE),
|
||||
},
|
||||
{'desc': 'DELETE list of instances with a non-existent one [success]',
|
||||
'm': 'gce',
|
||||
'a': 'instance_names=%s,missing,%s zone=%s state=absent' % (INAME2,INAME3, ZONE),
|
||||
'r': '127.0.0.1 | success >> {"changed": true, "instance_names": ["%s", "%s"], "state": "absent", "zone": "%s"}' % (INAME2, INAME3, ZONE),
|
||||
},
|
||||
{'desc': 'DELETE list of instances all pre-exist [success]',
|
||||
'm': 'gce',
|
||||
'a': 'instance_names=%s,%s zone=%s state=absent' % (INAME4,INAME5, ZONE),
|
||||
'r': '127.0.0.1 | success >> {"changed": true, "instance_names": ["%s", "%s"], "state": "absent", "zone": "%s"}' % (INAME4, INAME5, ZONE),
|
||||
},
|
||||
],
|
||||
'teardown': ['gcutil deleteinstance -f "%s" --zone=%s' % (INAME, ZONE),
|
||||
'gcutil deleteinstance -f "%s" --zone=%s' % (INAME2, ZONE),
|
||||
'gcutil deleteinstance -f "%s" --zone=%s' % (INAME3, ZONE),
|
||||
'gcutil deleteinstance -f "%s" --zone=%s' % (INAME4, ZONE),
|
||||
'gcutil deleteinstance -f "%s" --zone=%s' % (INAME5, ZONE),
|
||||
'sleep 10'],
|
||||
},
|
||||
|
||||
{'id': '05', 'desc': 'Create instances',
|
||||
'setup': ['gcutil adddisk --source_image=%s --zone=%s %s --wait_until_complete' % (IMAGE, ZONE, DNAME7),
|
||||
'gcutil addinstance boo --wait_until_running --zone=%s --machine_type=%s --network=%s --disk=%s,mode=READ_WRITE,boot --kernel=%s' % (ZONE,TYPE,NETWORK,DNAME7,KERNEL),
|
||||
],
|
||||
'tests': [
|
||||
{'desc': 'CREATE_INSTANCE invalid image arg [FAIL]',
|
||||
'm': 'gce',
|
||||
'a': 'name=foo image=foo',
|
||||
'r': '127.0.0.1 | FAILED >> {"changed": false, "failed": true, "msg": "Missing required create instance variable"}',
|
||||
},
|
||||
{'desc': 'CREATE_INSTANCE metadata a list [FAIL]',
|
||||
'strip_numbers': True,
|
||||
'm': 'gce',
|
||||
'a': 'name=%s zone=%s metadata=\'[\\"foo\\":\\"bar\\",\\"baz\\":1]\'' % (INAME,ZONE),
|
||||
'r': '127.0.0.1 | FAILED >> {"failed": true, "msg": "bad metadata syntax"}',
|
||||
},
|
||||
{'desc': 'CREATE_INSTANCE metadata not a dict [FAIL]',
|
||||
'strip_numbers': True,
|
||||
'm': 'gce',
|
||||
'a': 'name=%s zone=%s metadata=\\"foo\\":\\"bar\\",\\"baz\\":1' % (INAME,ZONE),
|
||||
'r': '127.0.0.1 | FAILED >> {"failed": true, "msg": "bad metadata syntax"}',
|
||||
},
|
||||
{'desc': 'CREATE_INSTANCE with metadata form1 [FAIL]',
|
||||
'strip_numbers': True,
|
||||
'm': 'gce',
|
||||
'a': 'name=%s zone=%s metadata=\'{"foo":"bar","baz":1}\'' % (INAME,ZONE),
|
||||
'r': '127.0.0.1 | FAILED >> {"failed": true, "msg": "bad metadata: malformed string"}',
|
||||
},
|
||||
{'desc': 'CREATE_INSTANCE with metadata form2 [FAIL]',
|
||||
'strip_numbers': True,
|
||||
'm': 'gce',
|
||||
'a': 'name=%s zone=%s metadata={\'foo\':\'bar\',\'baz\':1}' % (INAME,ZONE),
|
||||
'r': '127.0.0.1 | FAILED >> {"failed": true, "msg": "bad metadata: malformed string"}',
|
||||
},
|
||||
{'desc': 'CREATE_INSTANCE with metadata form3 [FAIL]',
|
||||
'strip_numbers': True,
|
||||
'm': 'gce',
|
||||
'a': 'name=%s zone=%s metadata="foo:bar" '% (INAME,ZONE),
|
||||
'r': '127.0.0.1 | FAILED >> {"failed": true, "msg": "bad metadata syntax"}',
|
||||
},
|
||||
{'desc': 'CREATE_INSTANCE with metadata form4 [FAIL]',
|
||||
'strip_numbers': True,
|
||||
'm': 'gce',
|
||||
'a': 'name=%s zone=%s metadata="{\'foo\':\'bar\'}"'% (INAME,ZONE),
|
||||
'r': '127.0.0.1 | FAILED >> {"failed": true, "msg": "bad metadata: malformed string"}',
|
||||
},
|
||||
{'desc': 'CREATE_INSTANCE invalid image arg [FAIL]',
|
||||
'm': 'gce',
|
||||
'a': 'instance_names=foo,bar image=foo',
|
||||
'r': '127.0.0.1 | FAILED >> {"changed": false, "failed": true, "msg": "Missing required create instance variable"}',
|
||||
},
|
||||
{'desc': 'CREATE_INSTANCE single inst, using defaults [success]',
|
||||
'strip_numbers': True,
|
||||
'm': 'gce',
|
||||
'a': 'name=%s' % (INAME),
|
||||
'r': '127.0.0.1 | success >> {"changed": true, "instance_data": [{"image": "debian-7-wheezy-v20130816", "machine_type": "n1-standard-1", "metadata": {}, "name": "%s", "network": "default", "private_ip": "10.240.175.15", "public_ip": "173.255.120.190", "status": "RUNNING", "tags": [], "zone": "%s"}], "name": "%s", "state": "present", "zone": "%s"}' % (INAME, ZONE, INAME, ZONE),
|
||||
},
|
||||
{'desc': 'CREATE_INSTANCE the same instance again, no-op [success]',
|
||||
'strip_numbers': True,
|
||||
'm': 'gce',
|
||||
'a': 'name=%s' % (INAME),
|
||||
'r': '127.0.0.1 | success >> {"changed": false, "instance_data": [{"image": "debian-7-wheezy-v20130816", "machine_type": "n1-standard-1", "metadata": {}, "name": "%s", "network": "default", "private_ip": "10.240.175.15", "public_ip": "173.255.120.190", "status": "RUNNING", "tags": [], "zone": "%s"}], "name": "%s", "state": "present", "zone": "%s"}' % (INAME, ZONE, INAME, ZONE),
|
||||
},
|
||||
{'desc': 'CREATE_INSTANCE instance with alt type [success]',
|
||||
'strip_numbers': True,
|
||||
'm': 'gce',
|
||||
'a': 'name=%s machine_type=n1-standard-2' % (INAME2),
|
||||
'r': '127.0.0.1 | success >> {"changed": true, "instance_data": [{"image": "debian-7-wheezy-v20130816", "machine_type": "n1-standard-2", "metadata": {}, "name": "%s", "network": "default", "private_ip": "10.240.192.227", "public_ip": "173.255.121.233", "status": "RUNNING", "tags": [], "zone": "%s"}], "name": "%s", "state": "present", "zone": "%s"}' % (INAME2, ZONE, INAME2, ZONE),
|
||||
},
|
||||
{'desc': 'CREATE_INSTANCE instance with root pd [success]',
|
||||
'strip_numbers': True,
|
||||
'm': 'gce',
|
||||
'a': 'name=%s persistent_boot_disk=yes' % (INAME3),
|
||||
'r': '127.0.0.1 | success >> {"changed": true, "instance_data": [{"image": null, "machine_type": "n1-standard-1", "metadata": {}, "name": "%s", "network": "default", "private_ip": "10.240.178.140", "public_ip": "173.255.121.176", "status": "RUNNING", "tags": [], "zone": "%s"}], "name": "%s", "state": "present", "zone": "%s"}' % (INAME3, ZONE, INAME3, ZONE),
|
||||
},
|
||||
{'desc': 'CREATE_INSTANCE instance with root pd, that already exists [success]',
|
||||
'setup': ['gcutil adddisk --source_image=%s --zone=%s %s --wait_until_complete' % (IMAGE, ZONE, DNAME6),],
|
||||
'strip_numbers': True,
|
||||
'm': 'gce',
|
||||
'a': 'name=%s zone=%s persistent_boot_disk=yes' % (INAME6, ZONE),
|
||||
'r': '127.0.0.1 | success >> {"changed": true, "instance_data": [{"image": null, "machine_type": "n1-standard-1", "metadata": {}, "name": "%s", "network": "default", "private_ip": "10.240.178.140", "public_ip": "173.255.121.176", "status": "RUNNING", "tags": [], "zone": "%s"}], "name": "%s", "state": "present", "zone": "%s"}' % (INAME6, ZONE, INAME6, ZONE),
|
||||
},
|
||||
{'desc': 'CREATE_INSTANCE instance with root pd attached to other inst [FAIL]',
|
||||
'm': 'gce',
|
||||
'a': 'name=%s zone=%s persistent_boot_disk=yes' % (INAME7, ZONE),
|
||||
'r': '127.0.0.1 | FAILED >> {"failed": true, "msg": "Unexpected error attempting to create instance %s, error: The disk resource \'projects/%s/zones/%s/disks/%s\' is already being used in read-write mode"}' % (INAME7,PROJECT,ZONE,DNAME7),
|
||||
},
|
||||
{'desc': 'CREATE_INSTANCE use *all* the options! [success]',
|
||||
'strip_numbers': True,
|
||||
'm': 'gce',
|
||||
'a': 'instance_names=%s,%s metadata=\'{\\"foo\\":\\"bar\\", \\"baz\\":1}\' tags=t1,t2,t3 zone=%s image=centos-6-v20130731 persistent_boot_disk=yes' % (INAME4,INAME5,ZONE),
|
||||
'r': '127.0.0.1 | success >> {"changed": true, "instance_data": [{"image": null, "machine_type": "n1-standard-1", "metadata": {"baz": "1", "foo": "bar"}, "name": "%s", "network": "default", "private_ip": "10.240.130.4", "public_ip": "173.255.121.97", "status": "RUNNING", "tags": ["t1", "t2", "t3"], "zone": "%s"}, {"image": null, "machine_type": "n1-standard-1", "metadata": {"baz": "1", "foo": "bar"}, "name": "%s", "network": "default", "private_ip": "10.240.207.226", "public_ip": "173.255.121.85", "status": "RUNNING", "tags": ["t1", "t2", "t3"], "zone": "%s"}], "instance_names": ["%s", "%s"], "state": "present", "zone": "%s"}' % (INAME4, ZONE, INAME5, ZONE, INAME4, INAME5, ZONE),
|
||||
},
|
||||
],
|
||||
'teardown': ['gcutil deleteinstance -f "%s" --zone=%s' % (INAME, ZONE),
|
||||
'gcutil deleteinstance -f "%s" --zone=%s' % (INAME2, ZONE),
|
||||
'gcutil deleteinstance -f "%s" --zone=%s' % (INAME3, ZONE),
|
||||
'gcutil deleteinstance -f "%s" --zone=%s' % (INAME4, ZONE),
|
||||
'gcutil deleteinstance -f "%s" --zone=%s' % (INAME5, ZONE),
|
||||
'gcutil deleteinstance -f "%s" --zone=%s' % (INAME6, ZONE),
|
||||
'gcutil deleteinstance -f "%s" --zone=%s' % (INAME7, ZONE),
|
||||
'gcutil deleteinstance -f boo --zone=%s' % (ZONE),
|
||||
'sleep 10',
|
||||
'gcutil deletedisk -f "%s" --zone=%s' % (INAME3, ZONE),
|
||||
'gcutil deletedisk -f "%s" --zone=%s' % (INAME4, ZONE),
|
||||
'gcutil deletedisk -f "%s" --zone=%s' % (INAME5, ZONE),
|
||||
'gcutil deletedisk -f "%s" --zone=%s' % (INAME6, ZONE),
|
||||
'gcutil deletedisk -f "%s" --zone=%s' % (INAME7, ZONE),
|
||||
'sleep 10'],
|
||||
},
|
||||
|
||||
{'id': '06', 'desc': 'Delete / destroy networks and firewall rules',
|
||||
'setup': ['gcutil addnetwork --range="%s" --gateway="%s" %s' % (CIDR1, GW1, NETWK1),
|
||||
'gcutil addnetwork --range="%s" --gateway="%s" %s' % (CIDR2, GW2, NETWK2),
|
||||
'sleep 5',
|
||||
'gcutil addfirewall --allowed="tcp:80" --network=%s %s' % (NETWK1, FW1),
|
||||
'gcutil addfirewall --allowed="tcp:80" --network=%s %s' % (NETWK2, FW2),
|
||||
'sleep 5'],
|
||||
'tests': [
|
||||
{'desc': 'DELETE bogus named firewall [success]',
|
||||
'm': 'gce_net',
|
||||
'a': 'fwname=missing-fwrule state=absent',
|
||||
'r': '127.0.0.1 | success >> {"changed": false, "fwname": "missing-fwrule", "state": "absent"}',
|
||||
},
|
||||
{'desc': 'DELETE bogus named network [success]',
|
||||
'm': 'gce_net',
|
||||
'a': 'name=missing-network state=absent',
|
||||
'r': '127.0.0.1 | success >> {"changed": false, "name": "missing-network", "state": "absent"}',
|
||||
},
|
||||
{'desc': 'DELETE named firewall rule [success]',
|
||||
'm': 'gce_net',
|
||||
'a': 'fwname=%s state=absent' % (FW1),
|
||||
'r': '127.0.0.1 | success >> {"changed": true, "fwname": "%s", "state": "absent"}' % (FW1),
|
||||
'teardown': ['sleep 5'], # pause to give GCE time to delete fwrule
|
||||
},
|
||||
{'desc': 'DELETE unused named network [success]',
|
||||
'm': 'gce_net',
|
||||
'a': 'name=%s state=absent' % (NETWK1),
|
||||
'r': '127.0.0.1 | success >> {"changed": true, "name": "%s", "state": "absent"}' % (NETWK1),
|
||||
},
|
||||
{'desc': 'DELETE named network *and* fwrule [success]',
|
||||
'm': 'gce_net',
|
||||
'a': 'name=%s fwname=%s state=absent' % (NETWK2, FW2),
|
||||
'r': '127.0.0.1 | success >> {"changed": true, "fwname": "%s", "name": "%s", "state": "absent"}' % (FW2, NETWK2),
|
||||
},
|
||||
],
|
||||
'teardown': ['gcutil deletenetwork -f %s' % (NETWK1),
|
||||
'gcutil deletenetwork -f %s' % (NETWK2),
|
||||
'sleep 5',
|
||||
'gcutil deletefirewall -f %s' % (FW1),
|
||||
'gcutil deletefirewall -f %s' % (FW2)],
|
||||
},
|
||||
|
||||
{'id': '07', 'desc': 'Create networks and firewall rules',
|
||||
'setup': ['gcutil addnetwork --range="%s" --gateway="%s" %s' % (CIDR1, GW1, NETWK1),
|
||||
'sleep 5',
|
||||
'gcutil addfirewall --allowed="tcp:80" --network=%s %s' % (NETWK1, FW1),
|
||||
'sleep 5'],
|
||||
'tests': [
|
||||
{'desc': 'CREATE network without specifying ipv4_range [FAIL]',
|
||||
'm': 'gce_net',
|
||||
'a': 'name=fail',
|
||||
'r': "127.0.0.1 | FAILED >> {\"changed\": false, \"failed\": true, \"msg\": \"Missing required 'ipv4_range' parameter\"}",
|
||||
},
|
||||
{'desc': 'CREATE network with specifying bad ipv4_range [FAIL]',
|
||||
'm': 'gce_net',
|
||||
'a': 'name=fail ipv4_range=bad_value',
|
||||
'r': "127.0.0.1 | FAILED >> {\"changed\": false, \"failed\": true, \"msg\": \"Unexpected response: HTTP return_code[400], API error code[None] and message: Invalid value for field 'resource.IPv4Range': 'bad_value'. Must be a CIDR address range that is contained in the RFC1918 private address blocks: [10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16]\"}",
|
||||
},
|
||||
{'desc': 'CREATE existing network, not changed [success]',
|
||||
'm': 'gce_net',
|
||||
'a': 'name=%s ipv4_range=%s' % (NETWK1, CIDR1),
|
||||
'r': '127.0.0.1 | success >> {"changed": false, "ipv4_range": "%s", "name": "%s", "state": "present"}' % (CIDR1, NETWK1),
|
||||
},
|
||||
{'desc': 'CREATE new network, changed [success]',
|
||||
'm': 'gce_net',
|
||||
'a': 'name=%s ipv4_range=%s' % (NETWK2, CIDR2),
|
||||
'r': '127.0.0.1 | success >> {"changed": true, "ipv4_range": "10.240.32.0/24", "name": "%s", "state": "present"}' % (NETWK2),
|
||||
},
|
||||
{'desc': 'CREATE new fw rule missing params [FAIL]',
|
||||
'm': 'gce_net',
|
||||
'a': 'name=%s fwname=%s' % (NETWK1, FW1),
|
||||
'r': '127.0.0.1 | FAILED >> {"changed": false, "failed": true, "msg": "Missing required firewall rule parameter(s)"}',
|
||||
},
|
||||
{'desc': 'CREATE new fw rule bad params [FAIL]',
|
||||
'm': 'gce_net',
|
||||
'a': 'name=%s fwname=broken allowed=blah src_tags="one,two"' % (NETWK1),
|
||||
'r': "127.0.0.1 | FAILED >> {\"changed\": false, \"failed\": true, \"msg\": \"Unexpected response: HTTP return_code[400], API error code[None] and message: Invalid value for field 'resource.allowed[0].IPProtocol': 'blah'. Must be one of [\\\"tcp\\\", \\\"udp\\\", \\\"icmp\\\"] or an IP protocol number between 0 and 255\"}",
|
||||
},
|
||||
{'desc': 'CREATE existing fw rule [success]',
|
||||
'm': 'gce_net',
|
||||
'a': 'name=%s fwname=%s allowed="tcp:80" src_tags="one,two"' % (NETWK1, FW1),
|
||||
'r': '127.0.0.1 | success >> {"allowed": "tcp:80", "changed": false, "fwname": "%s", "ipv4_range": "%s", "name": "%s", "src_range": null, "src_tags": ["one", "two"], "state": "present"}' % (FW1, CIDR1, NETWK1),
|
||||
},
|
||||
{'desc': 'CREATE new fw rule [success]',
|
||||
'm': 'gce_net',
|
||||
'a': 'name=%s fwname=%s allowed="tcp:80" src_tags="one,two"' % (NETWK1, FW3),
|
||||
'r': '127.0.0.1 | success >> {"allowed": "tcp:80", "changed": true, "fwname": "%s", "ipv4_range": "%s", "name": "%s", "src_range": null, "src_tags": ["one", "two"], "state": "present"}' % (FW3, CIDR1, NETWK1),
|
||||
},
|
||||
{'desc': 'CREATE new network *and* fw rule [success]',
|
||||
'm': 'gce_net',
|
||||
'a': 'name=%s ipv4_range=%s fwname=%s allowed="tcp:80" src_tags="one,two"' % (NETWK3, CIDR3, FW4),
|
||||
'r': '127.0.0.1 | success >> {"allowed": "tcp:80", "changed": true, "fwname": "%s", "ipv4_range": "%s", "name": "%s", "src_range": null, "src_tags": ["one", "two"], "state": "present"}' % (FW4, CIDR3, NETWK3),
|
||||
},
|
||||
],
|
||||
'teardown': ['gcutil deletefirewall -f %s' % (FW1),
|
||||
'gcutil deletefirewall -f %s' % (FW2),
|
||||
'gcutil deletefirewall -f %s' % (FW3),
|
||||
'gcutil deletefirewall -f %s' % (FW4),
|
||||
'sleep 5',
|
||||
'gcutil deletenetwork -f %s' % (NETWK1),
|
||||
'gcutil deletenetwork -f %s' % (NETWK2),
|
||||
'gcutil deletenetwork -f %s' % (NETWK3),
|
||||
'sleep 5'],
|
||||
},
|
||||
|
||||
{'id': '08', 'desc': 'Create load-balancer resources',
|
||||
'setup': ['gcutil addinstance "%s" --zone=%s --machine_type=%s --network=%s --service_account_scopes="%s" --image="%s" --nopersistent_boot_disk' % (INAME, ZONE, TYPE, NETWORK, SCOPES, IMAGE),
|
||||
'gcutil addinstance "%s" --wait_until_running --zone=%s --machine_type=%s --network=%s --service_account_scopes="%s" --image="%s" --nopersistent_boot_disk' % (INAME2, ZONE, TYPE, NETWORK, SCOPES, IMAGE),
|
||||
],
|
||||
'tests': [
|
||||
{'desc': 'Do nothing [FAIL]',
|
||||
'm': 'gce_lb',
|
||||
'a': 'httphealthcheck_port=7',
|
||||
'r': '127.0.0.1 | FAILED >> {"changed": false, "failed": true, "msg": "Nothing to do, please specify a \\\"name\\\" or \\\"httphealthcheck_name\\\" parameter"}',
|
||||
},
|
||||
{'desc': 'CREATE_HC create basic http healthcheck [success]',
|
||||
'm': 'gce_lb',
|
||||
'a': 'httphealthcheck_name=%s' % (HC1),
|
||||
'r': '127.0.0.1 | success >> {"changed": true, "httphealthcheck_healthy_count": 2, "httphealthcheck_host": null, "httphealthcheck_interval": 5, "httphealthcheck_name": "%s", "httphealthcheck_path": "/", "httphealthcheck_port": 80, "httphealthcheck_timeout": 5, "httphealthcheck_unhealthy_count": 2, "name": null, "state": "present"}' % (HC1),
|
||||
},
|
||||
{'desc': 'CREATE_HC (repeat, no-op) create basic http healthcheck [success]',
|
||||
'm': 'gce_lb',
|
||||
'a': 'httphealthcheck_name=%s' % (HC1),
|
||||
'r': '127.0.0.1 | success >> {"changed": false, "httphealthcheck_healthy_count": 2, "httphealthcheck_host": null, "httphealthcheck_interval": 5, "httphealthcheck_name": "%s", "httphealthcheck_path": "/", "httphealthcheck_port": 80, "httphealthcheck_timeout": 5, "httphealthcheck_unhealthy_count": 2, "name": null, "state": "present"}' % (HC1),
|
||||
},
|
||||
{'desc': 'CREATE_HC create custom http healthcheck [success]',
|
||||
'm': 'gce_lb',
|
||||
'a': 'httphealthcheck_name=%s httphealthcheck_port=1234 httphealthcheck_path="/whatup" httphealthcheck_host="foo" httphealthcheck_interval=300' % (HC2),
|
||||
'r': '127.0.0.1 | success >> {"changed": true, "httphealthcheck_healthy_count": 2, "httphealthcheck_host": "foo", "httphealthcheck_interval": 300, "httphealthcheck_name": "%s", "httphealthcheck_path": "/whatup", "httphealthcheck_port": 1234, "httphealthcheck_timeout": 5, "httphealthcheck_unhealthy_count": 2, "name": null, "state": "present"}' % (HC2),
|
||||
},
|
||||
{'desc': 'CREATE_HC create (broken) custom http healthcheck [FAIL]',
|
||||
'm': 'gce_lb',
|
||||
'a': 'httphealthcheck_name=%s httphealthcheck_port="string" httphealthcheck_path=7' % (HC3),
|
||||
'r': '127.0.0.1 | FAILED >> {"changed": false, "failed": true, "msg": "Unexpected response: HTTP return_code[400], API error code[None] and message: Invalid value for: Expected a signed integer, got \'string\' (class java.lang.String)"}',
|
||||
},
|
||||
{'desc': 'CREATE_LB create lb, missing region [FAIL]',
|
||||
'm': 'gce_lb',
|
||||
'a': 'name=%s' % (LB1),
|
||||
'r': '127.0.0.1 | FAILED >> {"changed": false, "failed": true, "msg": "Missing required region name"}',
|
||||
},
|
||||
{'desc': 'CREATE_LB create lb, bogus region [FAIL]',
|
||||
'm': 'gce_lb',
|
||||
'a': 'name=%s region=bogus' % (LB1),
|
||||
'r': '127.0.0.1 | FAILED >> {"changed": false, "failed": true, "msg": "Unexpected response: HTTP return_code[404], API error code[None] and message: The resource \'projects/%s/regions/bogus\' was not found"}' % (PROJECT),
|
||||
},
|
||||
{'desc': 'CREATE_LB create lb, minimal params [success]',
|
||||
'strip_numbers': True,
|
||||
'm': 'gce_lb',
|
||||
'a': 'name=%s region=%s' % (LB1, REGION),
|
||||
'r': '127.0.0.1 | success >> {"changed": true, "external_ip": "173.255.123.245", "httphealthchecks": [], "members": [], "name": "%s", "port_range": "1-65535", "protocol": "tcp", "region": "%s", "state": "present"}' % (LB1, REGION),
|
||||
},
|
||||
{'desc': 'CREATE_LB create lb full params [success]',
|
||||
'strip_numbers': True,
|
||||
'm': 'gce_lb',
|
||||
'a': 'httphealthcheck_name=%s httphealthcheck_port=5055 httphealthcheck_path="/howami" name=%s port_range=8000-8888 region=%s members=%s/%s,%s/%s' % (HC3,LB2,REGION,ZONE,INAME,ZONE,INAME2),
|
||||
'r': '127.0.0.1 | success >> {"changed": true, "external_ip": "173.255.126.81", "httphealthcheck_healthy_count": 2, "httphealthcheck_host": null, "httphealthcheck_interval": 5, "httphealthcheck_name": "%s", "httphealthcheck_path": "/howami", "httphealthcheck_port": 5055, "httphealthcheck_timeout": 5, "httphealthcheck_unhealthy_count": 2, "httphealthchecks": ["%s"], "members": ["%s/%s", "%s/%s"], "name": "%s", "port_range": "8000-8888", "protocol": "tcp", "region": "%s", "state": "present"}' % (HC3,HC3,ZONE,INAME,ZONE,INAME2,LB2,REGION),
|
||||
},
|
||||
],
|
||||
'teardown': [
|
||||
'gcutil deleteinstance --zone=%s -f %s %s' % (ZONE, INAME, INAME2),
|
||||
'gcutil deleteforwardingrule --region=%s -f %s %s' % (REGION, LB1, LB2),
|
||||
'sleep 10',
|
||||
'gcutil deletetargetpool --region=%s -f %s-tp %s-tp' % (REGION, LB1, LB2),
|
||||
'sleep 10',
|
||||
'gcutil deletehttphealthcheck -f %s %s %s' % (HC1, HC2, HC3),
|
||||
],
|
||||
},
|
||||
|
||||
{'id': '09', 'desc': 'Destroy load-balancer resources',
|
||||
'setup': ['gcutil addhttphealthcheck %s' % (HC1),
|
||||
'sleep 5',
|
||||
'gcutil addhttphealthcheck %s' % (HC2),
|
||||
'sleep 5',
|
||||
'gcutil addtargetpool --health_checks=%s --region=%s %s-tp' % (HC1, REGION, LB1),
|
||||
'sleep 5',
|
||||
'gcutil addforwardingrule --target=%s-tp --region=%s %s' % (LB1, REGION, LB1),
|
||||
'sleep 5',
|
||||
'gcutil addtargetpool --region=%s %s-tp' % (REGION, LB2),
|
||||
'sleep 5',
|
||||
'gcutil addforwardingrule --target=%s-tp --region=%s %s' % (LB2, REGION, LB2),
|
||||
'sleep 5',
|
||||
],
|
||||
'tests': [
|
||||
{'desc': 'DELETE_LB: delete a non-existent LB [success]',
|
||||
'm': 'gce_lb',
|
||||
'a': 'name=missing state=absent',
|
||||
'r': '127.0.0.1 | success >> {"changed": false, "name": "missing", "state": "absent"}',
|
||||
},
|
||||
{'desc': 'DELETE_LB: delete a non-existent LB+HC [success]',
|
||||
'm': 'gce_lb',
|
||||
'a': 'name=missing httphealthcheck_name=alsomissing state=absent',
|
||||
'r': '127.0.0.1 | success >> {"changed": false, "httphealthcheck_name": "alsomissing", "name": "missing", "state": "absent"}',
|
||||
},
|
||||
{'desc': 'DELETE_LB: destroy standalone healthcheck [success]',
|
||||
'm': 'gce_lb',
|
||||
'a': 'httphealthcheck_name=%s state=absent' % (HC2),
|
||||
'r': '127.0.0.1 | success >> {"changed": true, "httphealthcheck_name": "%s", "name": null, "state": "absent"}' % (HC2),
|
||||
},
|
||||
{'desc': 'DELETE_LB: destroy standalone balancer [success]',
|
||||
'm': 'gce_lb',
|
||||
'a': 'name=%s state=absent' % (LB2),
|
||||
'r': '127.0.0.1 | success >> {"changed": true, "name": "%s", "state": "absent"}' % (LB2),
|
||||
},
|
||||
{'desc': 'DELETE_LB: destroy LB+HC [success]',
|
||||
'm': 'gce_lb',
|
||||
'a': 'name=%s httphealthcheck_name=%s state=absent' % (LB1, HC1),
|
||||
'r': '127.0.0.1 | success >> {"changed": true, "httphealthcheck_name": "%s", "name": "%s", "state": "absent"}' % (HC1,LB1),
|
||||
},
|
||||
],
|
||||
'teardown': [
|
||||
'gcutil deleteforwardingrule --region=%s -f %s %s' % (REGION, LB1, LB2),
|
||||
'sleep 10',
|
||||
'gcutil deletetargetpool --region=%s -f %s-tp %s-tp' % (REGION, LB1, LB2),
|
||||
'sleep 10',
|
||||
'gcutil deletehttphealthcheck -f %s %s' % (HC1, HC2),
|
||||
],
|
||||
},
|
||||
]
|
||||
|
||||
def main(tests_to_run=[]):
|
||||
for test in test_cases:
|
||||
if tests_to_run and test['id'] not in tests_to_run:
|
||||
continue
|
||||
print "=> starting/setup '%s:%s'"% (test['id'], test['desc'])
|
||||
if DEBUG: print "=debug>", test['setup']
|
||||
for c in test['setup']:
|
||||
(s,o) = run(c)
|
||||
test_i = 1
|
||||
for t in test['tests']:
|
||||
if DEBUG: print "=>debug>", test_i, t['desc']
|
||||
# run any test-specific setup commands
|
||||
if t.has_key('setup'):
|
||||
for setup in t['setup']:
|
||||
(status, output) = run(setup)
|
||||
|
||||
# run any 'peek_before' commands
|
||||
if t.has_key('peek_before') and PEEKING_ENABLED:
|
||||
for setup in t['peek_before']:
|
||||
(status, output) = run(setup)
|
||||
|
||||
# run the ansible test if 'a' exists, otherwise
|
||||
# an empty 'a' directive allows test to run
|
||||
# setup/teardown for a subsequent test.
|
||||
if t['a']:
|
||||
if DEBUG: print "=>debug>", t['m'], t['a']
|
||||
acmd = "ansible all -o -m %s -a \"%s\"" % (t['m'],t['a'])
|
||||
#acmd = "ANSIBLE_KEEP_REMOTE_FILES=1 ansible all -vvv -m %s -a \"%s\"" % (t['m'],t['a'])
|
||||
(s,o) = run(acmd)
|
||||
|
||||
# check expected output
|
||||
if DEBUG: print "=debug>", o.strip(), "!=", t['r']
|
||||
print "=> %s.%02d '%s':" % (test['id'], test_i, t['desc']),
|
||||
if t.has_key('strip_numbers'):
|
||||
# strip out all numbers so we don't trip over different
|
||||
# IP addresses
|
||||
is_good = (o.strip().translate(None, "0123456789") == t['r'].translate(None, "0123456789"))
|
||||
else:
|
||||
is_good = (o.strip() == t['r'])
|
||||
|
||||
if is_good:
|
||||
print "PASS"
|
||||
else:
|
||||
print "FAIL"
|
||||
if VERBOSE:
|
||||
print "=>", acmd
|
||||
print "=> Expected:", t['r']
|
||||
print "=> Got:", o.strip()
|
||||
|
||||
# run any 'peek_after' commands
|
||||
if t.has_key('peek_after') and PEEKING_ENABLED:
|
||||
for setup in t['peek_after']:
|
||||
(status, output) = run(setup)
|
||||
|
||||
# run any test-specific teardown commands
|
||||
if t.has_key('teardown'):
|
||||
for td in t['teardown']:
|
||||
(status, output) = run(td)
|
||||
test_i += 1
|
||||
|
||||
print "=> completing/teardown '%s:%s'" % (test['id'], test['desc'])
|
||||
if DEBUG: print "=debug>", test['teardown']
|
||||
for c in test['teardown']:
|
||||
(s,o) = run(c)
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
tests_to_run = []
|
||||
if len(sys.argv) == 2:
|
||||
if sys.argv[1] in ["--help", "--list"]:
|
||||
print "usage: %s [id1,id2,...,idN]" % sys.argv[0]
|
||||
print " * An empty argument list will execute all tests"
|
||||
print " * Do not need to specify tests in numerical order"
|
||||
print " * List test categories with --list or --help"
|
||||
print ""
|
||||
for test in test_cases:
|
||||
print "\t%s:%s" % (test['id'], test['desc'])
|
||||
sys.exit(0)
|
||||
else:
|
||||
tests_to_run = sys.argv[1].split(',')
|
||||
main(tests_to_run)
|
|
@ -1,10 +0,0 @@
|
|||
#jinja2: variable_end_string: @@, variable_start_string: @@
|
||||
|
||||
{% raw %}
|
||||
if this succeeds you should see '{{ ansible_hostname }}' with the hostname on the line above
|
||||
if this fails you should see '@@ ansible_hostname @@' with the hostname on the line beneath
|
||||
{% endraw %}
|
||||
|
||||
@@ ansible_hostname @@
|
||||
{{ ansible_hostname }}
|
||||
|
|
@ -1,113 +0,0 @@
|
|||
# simple test of lookup plugins in with_*
|
||||
---
|
||||
- hosts: all
|
||||
connection: local
|
||||
vars:
|
||||
empty_list: []
|
||||
tasks:
|
||||
- name: test with_items
|
||||
action: command true
|
||||
with_items:
|
||||
- 1
|
||||
- 2
|
||||
- 3
|
||||
- name: test with_items with empty list
|
||||
action: command true
|
||||
with_items: $empty_list
|
||||
|
||||
- name: test with_file and FILE
|
||||
action: command test "$item" = "$FILE(sample.j2)"
|
||||
with_file: sample.j2
|
||||
|
||||
- name: test with_pipe
|
||||
action: command test "$item" = "$PIPE(cat sample.j2)"
|
||||
with_pipe: cat sample.j2
|
||||
|
||||
- name: test LOOKUP and PIPE
|
||||
action: command test "$LOOKUP(pipe, cat sample.j2)" = "$PIPE(cat sample.j2)"
|
||||
|
||||
- name: test with_sequence, generate
|
||||
command: touch /tmp/seq-${item}
|
||||
with_sequence: 0-16/2:%02x
|
||||
|
||||
- name: test with_sequence, fenceposts 1
|
||||
copy: src=/tmp/seq-00 dest=/tmp/seq-10
|
||||
|
||||
- name: test with_sequence, fenceposts 2
|
||||
file: dest=/tmp/seq-${item} state=absent
|
||||
with_items: [11, 12]
|
||||
|
||||
- name: test with_sequence, missing
|
||||
file: dest=/tmp/seq-${item} state=absent
|
||||
with_sequence: 0x10/02:%02x
|
||||
|
||||
- name: test with_sequence,remove
|
||||
file: dest=/tmp/seq-${item} state=absent
|
||||
with_sequence: 0-0x10/02:%02x
|
||||
|
||||
- name: ensure test file doesnt exist
|
||||
# command because file will return differently
|
||||
action: command rm -f /tmp/ansible-test-with_lines-data
|
||||
- name: test with_lines
|
||||
action: shell echo "$item" >> /tmp/ansible-test-with_lines-data
|
||||
with_lines: cat sample.j2
|
||||
- name: verify with_lines
|
||||
action: copy src=sample.j2 dest=/tmp/ansible-test-with_lines-data
|
||||
- name: cleanup test file
|
||||
action: file path=/tmp/ansible-test-with_lines-data state=absent
|
||||
|
||||
# Test nested loop
|
||||
- name: test nested loop with more than 3 elements
|
||||
command: test "{{ item[0] }}, {{ item[1] }}, {{ item[2] }}, {{ item[3] }}" = "red, 1, up, top"
|
||||
with_nested:
|
||||
- [ 'red' ]
|
||||
- [ 1 ]
|
||||
- [ 'up']
|
||||
- [ 'top']
|
||||
|
||||
# password lookup plugin
|
||||
- name: ensure test file doesn't exist
|
||||
# command because file will return differently
|
||||
action: command rm -f /tmp/ansible-test-with_password
|
||||
- name: test LOOKUP and PASSWORD with non existing password file
|
||||
action: command test "$LOOKUP(password, /tmp/ansible-test-with_password)" = "$PASSWORD(/tmp/ansible-test-with_password)"
|
||||
- name: test LOOKUP and PASSWORD with existing password file
|
||||
action: command test "$LOOKUP(password, /tmp/ansible-test-with_password)" = "$PASSWORD(/tmp/ansible-test-with_password)"
|
||||
- name: now test existing password via $item and with_password
|
||||
action: command test "$PASSWORD(/tmp/ansible-test-with_password)" = "$item"
|
||||
with_password:
|
||||
- /tmp/ansible-test-with_password
|
||||
- name: cleanup test file
|
||||
action: file path=/tmp/ansible-test-with_password state=absent
|
||||
- name: now test a password of non-default length (default=20, but here length=8)
|
||||
action: command test "$PASSWORD(/tmp/ansible-test-with_password length=8)" = "$LOOKUP(password, /tmp/ansible-test-with_password)"
|
||||
# - name: did we really create a password of length=8?
|
||||
# action: command test "`expr length $PASSWORD(/tmp/ansible-test-with_password)`" = "8"
|
||||
- name: cleanup test file, again
|
||||
action: file path=/tmp/ansible-test-with_password state=absent
|
||||
|
||||
# indexed_items lookup plugin
|
||||
- name: create directory for indexed_items
|
||||
file: path=/tmp/ansible-test-with_indexed_items-data state=directory
|
||||
- name: test indexed_items
|
||||
shell: echo "{{ item.0 }}" > /tmp/ansible-test-with_indexed_items-data/{{ item.1 }}
|
||||
with_indexed_items:
|
||||
- a
|
||||
- b
|
||||
- c
|
||||
- name: check indexed_items content
|
||||
shell: test -f /tmp/ansible-test-with_indexed_items-data/{{ item.1 }} &&
|
||||
test "{{ item.0 }}" = "$(cat /tmp/ansible-test-with_indexed_items-data/{{ item.1 }})"
|
||||
with_indexed_items:
|
||||
- a
|
||||
- b
|
||||
- c
|
||||
- name: cleanup indexed_items test
|
||||
file: path=/tmp/ansible-test-with_indexed_items-data/{{ item.1 }} state=absent
|
||||
with_indexed_items:
|
||||
- a
|
||||
- b
|
||||
- c
|
||||
- name: remove with_indexed_items directory
|
||||
file: path=/tmp/ansible-test-with_indexed_items-data state=absent
|
||||
|
|
@ -1,48 +0,0 @@
|
|||
---
|
||||
- hosts: all
|
||||
connection: local
|
||||
gather_facts: False
|
||||
vars:
|
||||
var_true: True
|
||||
var_false: False
|
||||
var_empty_str: "''"
|
||||
var_null: ~
|
||||
|
||||
tasks:
|
||||
- action: command echo ping
|
||||
always_run: yes
|
||||
|
||||
- action: command echo pong 1
|
||||
|
||||
- action: command echo pong 2
|
||||
always_run: no
|
||||
|
||||
- action: command echo pong 3
|
||||
always_run: 1 + 1
|
||||
|
||||
- action: command echo pong 4
|
||||
always_run: "''"
|
||||
|
||||
- action: command echo pong 5
|
||||
always_run: False
|
||||
|
||||
- action: command echo pong 6
|
||||
always_run: True
|
||||
|
||||
- action: command echo pong 7
|
||||
always_run: var_true
|
||||
|
||||
- action: command echo pong 8
|
||||
always_run: var_false
|
||||
|
||||
- action: command echo pong 9
|
||||
always_run: var_empty_str
|
||||
|
||||
- action: command echo pong 10
|
||||
always_run: var_null
|
||||
|
||||
# this will never run...
|
||||
- action: command echo pong 11
|
||||
always_run: yes
|
||||
when: no
|
||||
|
|
@ -1,25 +0,0 @@
|
|||
---
|
||||
- hosts: all
|
||||
connection: local
|
||||
gather_facts: False
|
||||
|
||||
tasks:
|
||||
- action: command echo first action
|
||||
- action: command echo second action
|
||||
register: var
|
||||
changed_when: "'X' in var.stdout"
|
||||
- action: shell exit 2
|
||||
register: exit
|
||||
ignore_errors: yes
|
||||
changed_when: "exit.rc < 1"
|
||||
- action: command echo third action
|
||||
changed_when: false
|
||||
- action: file path=/ state=directory
|
||||
changed_when: true
|
||||
- action: command echo {{item}}
|
||||
register: out
|
||||
changed_when: "'e' in out.stdout"
|
||||
with_items:
|
||||
- hello
|
||||
- foo
|
||||
- bye
|
|
@ -1,15 +0,0 @@
|
|||
---
|
||||
- hosts: all
|
||||
connection: local
|
||||
gather_facts: False
|
||||
|
||||
tasks:
|
||||
- action: shell exit 0
|
||||
register: exit
|
||||
failed_when: not exit.rc in [0, 1]
|
||||
- action: shell exit 1
|
||||
register: exit
|
||||
failed_when: exit.rc not in [0, 1]
|
||||
- action: shell exit 2
|
||||
register: exit
|
||||
failed_when: exit.rc not in [0, 1]
|
|
@ -1,9 +0,0 @@
|
|||
---
|
||||
- hosts: all
|
||||
connection: local
|
||||
gather_facts: False
|
||||
|
||||
tasks:
|
||||
- action: command false
|
||||
ignore_errors: true
|
||||
- action: command false
|
|
@ -1,17 +0,0 @@
|
|||
---
|
||||
- hosts: localhost
|
||||
connection: local
|
||||
gather_facts: False
|
||||
|
||||
tasks:
|
||||
- name: Loggføring fungerer
|
||||
command: echo "Feilsøking"
|
||||
always_run: yes
|
||||
|
||||
- name: Die Süßigkeit
|
||||
command: echo "Die Süßigkeit"
|
||||
always_run: yes
|
||||
|
||||
- name: Logging works
|
||||
command: echo "Debugging"
|
||||
always_run: yes
|
|
@ -1,98 +0,0 @@
|
|||
---
|
||||
# run with option -i localhost
|
||||
# need root permissions
|
||||
|
||||
- name: host module testing
|
||||
hosts: localhost
|
||||
connection: local
|
||||
gather_facts: no
|
||||
sudo: yes
|
||||
|
||||
pre_tasks:
|
||||
- name: backup /etc/hosts
|
||||
command: cp /etc/hosts /etc/hosts.origin
|
||||
|
||||
post_tasks:
|
||||
- name: restore /etc/hosts
|
||||
command: cp /etc/hosts.origin /etc/hosts
|
||||
|
||||
tasks:
|
||||
- name: test add a record
|
||||
host: hostname=foobar ip=192.168.123.1
|
||||
register: result
|
||||
failed_when: not result.changed
|
||||
|
||||
- name: test error handling only hostname given on present
|
||||
host: hostname=foobar
|
||||
register: result
|
||||
failed_when: result.changed
|
||||
|
||||
- name: test error handling only ip given on present
|
||||
host: ip=192.168.123.1
|
||||
register: result
|
||||
failed_when: result.changed
|
||||
|
||||
- name: test record exists
|
||||
host: hostname=foobar ip=192.168.123.1
|
||||
register: result
|
||||
failed_when: result.changed
|
||||
|
||||
- name: test remove record using hostname
|
||||
host: hostname=foobar state=absent
|
||||
register: result
|
||||
failed_when: not result.changed
|
||||
|
||||
- name: test remove not existing record using hostname
|
||||
host: hostname=foobar state=absent
|
||||
register: result
|
||||
failed_when: result.changed
|
||||
|
||||
- name: test add a record again
|
||||
host: hostname=foobar ip=192.168.123.1
|
||||
register: result
|
||||
failed_when: not result.changed
|
||||
|
||||
- name: test remove record using ip
|
||||
host: ip=192.168.123.1 state=absent
|
||||
register: result
|
||||
failed_when: not result.changed
|
||||
|
||||
- name: test remove not existing record using ip
|
||||
host: ip=192.168.123.1 state=absent
|
||||
register: result
|
||||
failed_when: result.changed
|
||||
|
||||
- name: test add a record with alias
|
||||
host: hostname=foobar ip=192.168.123.1 aliases=foobar.com,foobar.net
|
||||
register: result
|
||||
failed_when: not result.changed
|
||||
|
||||
- name: test add an existing record with alias
|
||||
host: hostname=foobar ip=192.168.123.1 aliases=foobar.com,foobar.net
|
||||
register: result
|
||||
failed_when: result.changed
|
||||
|
||||
- name: test add an existing record with changed alias
|
||||
host: hostname=foobar ip=192.168.123.1 aliases=foobar.net,foobar.com
|
||||
register: result
|
||||
failed_when: not result.changed
|
||||
|
||||
- name: test remove aliases from existing record
|
||||
host: hostname=foobar ip=192.168.123.1
|
||||
register: result
|
||||
failed_when: not result.changed
|
||||
|
||||
- name: test add aliases for existing record
|
||||
host: hostname=foobar ip=192.168.123.1 aliases=foobar.net,foobar.com
|
||||
register: result
|
||||
failed_when: not result.changed
|
||||
|
||||
- name: test change ip on existing record
|
||||
host: hostname=foobar ip=192.168.123.2
|
||||
register: result
|
||||
failed_when: not result.changed
|
||||
|
||||
- name: test change hostname on existing record
|
||||
host: hostname=barfoo ip=192.168.123.2
|
||||
register: result
|
||||
failed_when: not result.changed
|
|
@ -1,133 +0,0 @@
|
|||
---
|
||||
# To run me manually, use: -i "localhost,"
|
||||
- hosts: localhost
|
||||
connection: local
|
||||
gather_facts: no
|
||||
vars:
|
||||
- testdir: /tmp/ansible-rcopy
|
||||
- filesdir: test_recursive_copy/files
|
||||
tasks:
|
||||
|
||||
#
|
||||
# First, regression tests for single-file behavior
|
||||
#
|
||||
|
||||
- name: "src single file, dest file"
|
||||
command: rm -rf {{testdir}}
|
||||
- file: state=directory dest={{testdir}}
|
||||
- copy: src={{filesdir}}/subdir/subdir2/subdir3/test1 dest={{testdir}}/file1
|
||||
register: res
|
||||
- command: test -f {{testdir}}/file1
|
||||
- command: test "{{res.changed}}" = "True"
|
||||
- copy: src={{filesdir}}/subdir/subdir2/subdir3/test1 dest={{testdir}}/file1
|
||||
register: res
|
||||
- command: test "{{res.changed}}" = "False"
|
||||
|
||||
- name: "src single file, dest dir w/trailing slash"
|
||||
command: rm -rf {{testdir}}
|
||||
- file: state=directory dest={{testdir}}
|
||||
- copy: src={{filesdir}}/subdir/subdir2/subdir3/test1 dest={{testdir}}/
|
||||
register: res
|
||||
- command: test -f {{testdir}}/test1
|
||||
- command: test "{{res.changed}}" = "True"
|
||||
- copy: src={{filesdir}}/subdir/subdir2/subdir3/test1 dest={{testdir}}/
|
||||
register: res
|
||||
- command: test "{{res.changed}}" = "False"
|
||||
|
||||
- name: "src single file, dest dir wo/trailing slash - doesn't behave in sane way"
|
||||
command: rm -rf {{testdir}}
|
||||
- file: state=directory dest={{testdir}}
|
||||
- copy: src={{filesdir}}/subdir/subdir2/subdir3/test1 dest={{testdir}}
|
||||
register: res
|
||||
- shell: test -f {{testdir}}/test1
|
||||
- command: test "{{res.changed}}" = "True"
|
||||
- copy: src={{filesdir}}/subdir/subdir2/subdir3/test1 dest={{testdir}}
|
||||
register: res
|
||||
- command: test "{{res.changed}}" = "False"
|
||||
|
||||
#
|
||||
# Now, test recursive behavior
|
||||
#
|
||||
|
||||
- name: "src dir w/trailing slash, dest w/trailing slash"
|
||||
command: rm -rf {{testdir}}
|
||||
- file: state=directory dest={{testdir}}
|
||||
- copy: src={{filesdir}}/subdir/ dest={{testdir}}/
|
||||
register: res
|
||||
- command: test -d {{testdir}}/subdir2
|
||||
- command: test -d {{testdir}}/subdir2/subdir3
|
||||
- command: test -d {{testdir}}/subdir2/subdir3
|
||||
- command: test -f {{testdir}}/subdir2/subdir3/test1
|
||||
- command: test -f {{testdir}}/subdir2/subdir3/test2
|
||||
- command: test "{{res.changed}}" = "True"
|
||||
- copy: src={{filesdir}}/subdir/ dest={{testdir}}/
|
||||
register: res
|
||||
- command: test "{{res.changed}}" = "False"
|
||||
|
||||
# Expecting the same behavior
|
||||
- name: "src dir w/trailing slash, dest wo/trailing slash"
|
||||
command: rm -rf {{testdir}}
|
||||
- file: state=directory dest={{testdir}}
|
||||
- copy: src={{filesdir}}/subdir/ dest={{testdir}}
|
||||
register: res
|
||||
- command: test -d {{testdir}}/subdir2
|
||||
- command: test -d {{testdir}}/subdir2/subdir3
|
||||
- command: test -d {{testdir}}/subdir2/subdir3
|
||||
- command: test -f {{testdir}}/subdir2/subdir3/test1
|
||||
- command: test -f {{testdir}}/subdir2/subdir3/test2
|
||||
- command: test "{{res.changed}}" = "True"
|
||||
- copy: src={{filesdir}}/subdir/ dest={{testdir}}
|
||||
register: res
|
||||
- command: test "{{res.changed}}" = "False"
|
||||
|
||||
- name: "src dir wo/trailing slash, dest w/trailing slash"
|
||||
command: rm -rf {{testdir}}
|
||||
- file: state=directory dest={{testdir}}
|
||||
- copy: src={{filesdir}}/subdir dest={{testdir}}/
|
||||
register: res
|
||||
- command: test -d {{testdir}}/subdir/subdir2
|
||||
- command: test -d {{testdir}}/subdir/subdir2/subdir3
|
||||
- command: test -d {{testdir}}/subdir/subdir2/subdir3
|
||||
- command: test -f {{testdir}}/subdir/subdir2/subdir3/test1
|
||||
- command: test -f {{testdir}}/subdir/subdir2/subdir3/test2
|
||||
- command: test "{{res.changed}}" = "True"
|
||||
- copy: src={{filesdir}}/subdir dest={{testdir}}/
|
||||
register: res
|
||||
- command: test "{{res.changed}}" = "False"
|
||||
|
||||
# Expecting the same behavior
|
||||
- name: "src dir wo/trailing slash, dest wo/trailing slash"
|
||||
command: rm -rf {{testdir}}
|
||||
- file: state=directory dest={{testdir}}
|
||||
- copy: src={{filesdir}}/subdir dest={{testdir}}
|
||||
register: res
|
||||
- command: test -d {{testdir}}/subdir/subdir2
|
||||
- command: test -d {{testdir}}/subdir/subdir2/subdir3
|
||||
- command: test -d {{testdir}}/subdir/subdir2/subdir3
|
||||
- command: test -f {{testdir}}/subdir/subdir2/subdir3/test1
|
||||
- command: test -f {{testdir}}/subdir/subdir2/subdir3/test2
|
||||
- command: test "{{res.changed}}" = "True"
|
||||
- copy: src={{filesdir}}/subdir dest={{testdir}}
|
||||
register: res
|
||||
- command: test "{{res.changed}}" = "False"
|
||||
|
||||
|
||||
- name: "Verifying notify handling for recursive files"
|
||||
command: rm -rf {{testdir}}
|
||||
- file: state=directory dest={{testdir}}
|
||||
- copy: src={{filesdir}}/subdir dest={{testdir}}
|
||||
notify:
|
||||
- files changed
|
||||
- meta: flush_handlers
|
||||
- command: test -f {{testdir}}/notify_fired
|
||||
|
||||
- command: rm {{testdir}}/notify_fired
|
||||
- copy: src={{filesdir}}/subdir dest={{testdir}}
|
||||
notify:
|
||||
- files changed
|
||||
- meta: flush_handlers
|
||||
- command: test ! -f {{testdir}}/notify_fired
|
||||
|
||||
handlers:
|
||||
- name: files changed
|
||||
command: touch {{testdir}}/notify_fired
|
|
@ -1,2 +0,0 @@
|
|||
---
|
||||
- include: "{{dir}}/playbook-included.yml variable=foobar"
|
|
@ -1,90 +0,0 @@
|
|||
---
|
||||
# To run me manually, use: -i "localhost,"
|
||||
- hosts: localhost
|
||||
connection: local
|
||||
gather_facts: no
|
||||
vars:
|
||||
- testdir: /tmp/ansible-unarchive
|
||||
- filesdir: test_unarchive/files
|
||||
tasks:
|
||||
|
||||
- name: "Simple tar unarchive."
|
||||
command: rm -rf {{testdir}}
|
||||
- file: state=directory dest={{testdir}}
|
||||
- unarchive: src={{filesdir}}/test.tar dest={{testdir}}
|
||||
register: res
|
||||
- command: test -f {{testdir}}/foo
|
||||
- fail: msg="Resource was expected to be changed."
|
||||
when: not res|changed
|
||||
- unarchive: src={{filesdir}}/test.tar dest={{testdir}}
|
||||
register: res
|
||||
- fail: msg="Resource was not expected to be changed."
|
||||
when: res|changed
|
||||
|
||||
- name: "Simple tar.gz unarchive."
|
||||
command: rm -rf {{testdir}}
|
||||
- file: state=directory dest={{testdir}}
|
||||
- unarchive: src={{filesdir}}/test.tar.gz dest={{testdir}}
|
||||
register: res
|
||||
- command: test -f {{testdir}}/foo
|
||||
- fail: msg="Resource was expected to be changed."
|
||||
when: not res|changed
|
||||
- unarchive: src={{filesdir}}/test.tar.gz dest={{testdir}}
|
||||
register: res
|
||||
- fail: msg="Resource was not expected to be changed."
|
||||
when: res|changed
|
||||
|
||||
- name: "Simple zip unarchive."
|
||||
command: rm -rf {{testdir}}
|
||||
- file: state=directory dest={{testdir}}
|
||||
- unarchive: src={{filesdir}}/test.zip dest={{testdir}}
|
||||
register: res
|
||||
- command: test -f {{testdir}}/foo
|
||||
- fail: msg="Resource was expected to be changed."
|
||||
when: not res|changed
|
||||
- unarchive: src={{filesdir}}/test.zip dest={{testdir}}
|
||||
register: res
|
||||
- fail: msg="Resource was expected to be changed."
|
||||
when: not res|changed
|
||||
|
||||
- name: "Unarchive a local tar file."
|
||||
command : rm -rf {{testdir}}
|
||||
- file: state=directory dest={{testdir}}
|
||||
- copy: src={{filesdir}}/test.tar dest={{testdir}}
|
||||
- unarchive: src={{testdir}}/test.tar dest={{testdir}}
|
||||
register: res
|
||||
- command: test -f {{testdir}}/foo
|
||||
- fail: msg="Resource was expected to be changed."
|
||||
when: not res|changed
|
||||
- unarchive: src={{testdir}}/test.tar dest={{testdir}}
|
||||
register: res
|
||||
- fail: msg="Resource was not expected to be changed."
|
||||
when: res|changed
|
||||
|
||||
- name: "Unarchive a local tar.gz file."
|
||||
command : rm -rf {{testdir}}
|
||||
- file: state=directory dest={{testdir}}
|
||||
- copy: src={{filesdir}}/test.tar.gz dest={{testdir}}
|
||||
- unarchive: src={{testdir}}/test.tar.gz dest={{testdir}}
|
||||
register: res
|
||||
- command: test -f {{testdir}}/foo
|
||||
- fail: msg="Resource was expected to be changed."
|
||||
when: not res|changed
|
||||
- unarchive: src={{testdir}}/test.tar.gz dest={{testdir}}
|
||||
register: res
|
||||
- fail: msg="Resource was not expected to be changed."
|
||||
when: res|changed
|
||||
|
||||
- name: "Unarchive a local zip file."
|
||||
command : rm -rf {{testdir}}
|
||||
- file: state=directory dest={{testdir}}
|
||||
- copy: src={{filesdir}}/test.zip dest={{testdir}}
|
||||
- unarchive: src={{testdir}}/test.zip dest={{testdir}}
|
||||
register: res
|
||||
- command: test -f {{testdir}}/foo
|
||||
- fail: msg="Resource was expected to be changed."
|
||||
when: not res|changed
|
||||
- unarchive: src={{testdir}}/test.zip dest={{testdir}}
|
||||
register: res
|
||||
- fail: msg="Resource was expected to be changed."
|
||||
when: not res|changed
|
|
@ -1,70 +0,0 @@
|
|||
# extremely simple test of the most basic of playbook engine/functions
|
||||
---
|
||||
- hosts: all
|
||||
connection: local
|
||||
|
||||
# the 'weasels' string should show up in the output
|
||||
|
||||
vars:
|
||||
answer: "Wuh, I think so, Brain, but if we didn't have ears, we'd look like weasels."
|
||||
port: 5150
|
||||
|
||||
# we should have import events for common_vars and CentOS.yml (if run on CentOS)
|
||||
# sorry, tests are a bit platform specific just for now
|
||||
|
||||
vars_files:
|
||||
- common_vars.yml
|
||||
- [ '{{facter_operatingsystem.yml}}', 'default_os.yml' ]
|
||||
|
||||
tasks:
|
||||
|
||||
- name: test basic success command
|
||||
action: command true
|
||||
|
||||
- name: test basic success command 2
|
||||
action: command true
|
||||
|
||||
- name: test basic shell, plus two ways to dereference a variable
|
||||
action: shell echo {{port}}
|
||||
|
||||
- name: test vars_files imports
|
||||
action: shell echo {{duck}} {{cow}} {{testing}}
|
||||
|
||||
# in the command below, the test file should contain a valid template
|
||||
# and trigger the change handler
|
||||
|
||||
- name: test copy
|
||||
action: copy src=sample.j2 dest=/tmp/ansible_test_data_copy.out
|
||||
notify:
|
||||
- on change 1
|
||||
|
||||
# there should be various poll events within the range
|
||||
|
||||
- name: async poll test
|
||||
action: shell sleep 5
|
||||
async: 10
|
||||
poll: 3
|
||||
|
||||
# the following command should be skipped
|
||||
|
||||
- name: this should be skipped
|
||||
action: shell echo 'if you see this, this is wrong'
|
||||
when: 2 == 3
|
||||
|
||||
handlers:
|
||||
|
||||
# in the above test example, this should fire ONCE (at the end)
|
||||
- name: on change 1
|
||||
action: shell echo 'this should fire once'
|
||||
|
||||
# in the above test example, this should fire ONCE (at the end)
|
||||
|
||||
- name: on change 2
|
||||
action: shell echo 'this should fire once also'
|
||||
|
||||
# in the above test example, this should NOT FIRE
|
||||
|
||||
- name: on change 3
|
||||
action: shell echo 'if you see this, this is wrong'
|
||||
|
||||
|
|
@ -1,20 +0,0 @@
|
|||
---
|
||||
# Test iterating over lines of stdout stored in a register.
|
||||
- hosts: localhost
|
||||
connection: local
|
||||
vars:
|
||||
small_file: /etc/resolv.conf
|
||||
temp_file: /tmp/ansible_result_list.tmp
|
||||
|
||||
tasks:
|
||||
- action: command cat $small_file
|
||||
register: result
|
||||
|
||||
- action: file dest=$temp_file state=absent
|
||||
|
||||
- action: shell echo '$item' >> $temp_file
|
||||
with_items: ${result.stdout_lines}
|
||||
|
||||
- action: command diff $small_file $temp_file
|
||||
|
||||
- action: file dest=$temp_file state=absent
|
|
@ -1,6 +0,0 @@
|
|||
An ansible is a fictitious machine capable of instantaneous or superluminal
|
||||
communication. Typically it is depicted as a lunch-box sized object with some
|
||||
combination of microphone, speaker, keyboard and display. It can send and
|
||||
receive messages to and from a corresponding device over any distance
|
||||
whatsoever with no delay. Ansibles occur as plot devices in science fiction
|
||||
literature.
|
|
@ -1,4 +0,0 @@
|
|||
Are you pondering what I'm pøndering?
|
||||
|
||||
I think so Brain, but {{ answer }}
|
||||
|
|
@ -1 +0,0 @@
|
|||
hello {{ who }}
|
|
@ -1 +0,0 @@
|
|||
hello {{ who }}
|
|
@ -1,5 +0,0 @@
|
|||
localhost
|
||||
|
||||
[all:vars]
|
||||
inventory_var_good="{{ playbook_var_good }}"
|
||||
inventory_var_bad="{{ playbook_var_bad }}"
|
|
@ -1,7 +0,0 @@
|
|||
- hosts: all
|
||||
vars:
|
||||
playbook_var_good: "ok"
|
||||
playbook_var_bad: "{{ undefined_var }}"
|
||||
tasks:
|
||||
- debug: msg="{{ playbook_var_good }}"
|
||||
- debug: msg="{{ playbook_var_bad }}"
|
|
@ -1,7 +0,0 @@
|
|||
- hosts: all
|
||||
vars:
|
||||
playbook_var_good: "ok"
|
||||
playbook_var_bad: "{{ undefined_var }}"
|
||||
tasks:
|
||||
- debug: msg="{{ inventory_var_good }}"
|
||||
- debug: msg="{{ inventory_var_bad }}"
|
|
@ -1,2 +0,0 @@
|
|||
---
|
||||
attr2: 2
|
|
@ -1,2 +0,0 @@
|
|||
---
|
||||
attr1: 1
|
|
@ -1,6 +0,0 @@
|
|||
host1
|
||||
host2
|
||||
|
||||
[group]
|
||||
host1
|
||||
host2
|
|
@ -1,2 +0,0 @@
|
|||
---
|
||||
- hosts: group
|
|
@ -1,2 +0,0 @@
|
|||
test1
|
||||
|
|
@ -1,2 +0,0 @@
|
|||
test2
|
||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
@ -1 +0,0 @@
|
|||
world
|
Loading…
Add table
Add a link
Reference in a new issue