summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMatt Davis <nitzmahone@users.noreply.github.com>2016-09-15 11:25:56 -0700
committerGitHub <noreply@github.com>2016-09-15 11:25:56 -0700
commitf497d771c8bda7874382bbffbf641eaedf015f94 (patch)
treeed5f39dfb0f54d6b24cd26c09913ededce7312b6
parent81072fcba10d6436babe3e0cd7525f857143a985 (diff)
downloadansible-f497d771c8bda7874382bbffbf641eaedf015f94.tar.gz
win_shell/win_command changes + tests (#17557)
-rw-r--r--lib/ansible/cli/adhoc.py2
-rw-r--r--lib/ansible/constants.py4
-rw-r--r--lib/ansible/parsing/mod_args.py8
-rw-r--r--test/integration/roles/test_win_command/tasks/main.yml134
-rw-r--r--test/integration/roles/test_win_shell/tasks/main.yml175
-rw-r--r--test/integration/test_win_group3.yml2
6 files changed, 319 insertions, 6 deletions
diff --git a/lib/ansible/cli/adhoc.py b/lib/ansible/cli/adhoc.py
index 95ab640ded..1b615473e0 100644
--- a/lib/ansible/cli/adhoc.py
+++ b/lib/ansible/cli/adhoc.py
@@ -85,7 +85,7 @@ class AdHocCLI(CLI):
return True
def _play_ds(self, pattern, async, poll):
- check_raw = self.options.module_name in ('command', 'shell', 'script', 'raw')
+ check_raw = self.options.module_name in ('command', 'win_command', 'shell', 'win_shell', 'script', 'raw')
return dict(
name = "Ansible Ad-Hoc",
hosts = pattern,
diff --git a/lib/ansible/constants.py b/lib/ansible/constants.py
index 0cc4c343dc..606fb3c194 100644
--- a/lib/ansible/constants.py
+++ b/lib/ansible/constants.py
@@ -326,8 +326,8 @@ COLOR_DIFF_LINES = get_config(p, 'colors', 'diff_lines', 'ANSIBLE_COLOR_DIFF_LI
DIFF_CONTEXT = get_config(p, 'diff', 'context', 'ANSIBLE_DIFF_CONTEXT', 3, integer=True)
# non-configurable things
-MODULE_REQUIRE_ARGS = ['command', 'shell', 'raw', 'script']
-MODULE_NO_JSON = ['command', 'shell', 'raw']
+MODULE_REQUIRE_ARGS = ['command', 'win_command', 'shell', 'win_shell', 'raw', 'script']
+MODULE_NO_JSON = ['command', 'win_command', 'shell', 'win_shell', 'raw']
DEFAULT_BECOME_PASS = None
DEFAULT_SUDO_PASS = None
DEFAULT_REMOTE_PASS = None
diff --git a/lib/ansible/parsing/mod_args.py b/lib/ansible/parsing/mod_args.py
index dbe85b0bad..a311156ae9 100644
--- a/lib/ansible/parsing/mod_args.py
+++ b/lib/ansible/parsing/mod_args.py
@@ -29,7 +29,9 @@ from ansible.template import Templar
# For filtering out modules correctly below
RAW_PARAM_MODULES = ([
'command',
+ 'win_command',
'shell',
+ 'win_shell',
'script',
'include',
'include_vars',
@@ -161,7 +163,7 @@ class ModuleArgsParser:
# only internal variables can start with an underscore, so
# we don't allow users to set them directy in arguments
- if args and action not in ('command', 'shell', 'script', 'raw'):
+ if args and action not in ('command', 'win_command', 'shell', 'win_shell', 'script', 'raw'):
for arg in args:
if arg.startswith('_ansible_'):
raise AnsibleError("invalid parameter specified for action '%s': '%s'" % (action, arg))
@@ -191,7 +193,7 @@ class ModuleArgsParser:
args = thing
elif isinstance(thing, string_types):
# form is like: local_action: copy src=a dest=b ... pretty common
- check_raw = action in ('command', 'shell', 'script', 'raw')
+ check_raw = action in ('command', 'win_command', 'shell', 'win_shell', 'script', 'raw')
args = parse_kv(thing, check_raw=check_raw)
elif thing is None:
# this can happen with modules which take no params, like ping:
@@ -217,7 +219,7 @@ class ModuleArgsParser:
action = None
args = None
- actions_allowing_raw = ('command', 'shell', 'script', 'raw')
+ actions_allowing_raw = ('command', 'win_command', 'shell', 'win_shell', 'script', 'raw')
if isinstance(thing, dict):
# form is like: copy: { src: 'a', dest: 'b' } ... common for structured (aka "complex") args
thing = thing.copy()
diff --git a/test/integration/roles/test_win_command/tasks/main.yml b/test/integration/roles/test_win_command/tasks/main.yml
new file mode 100644
index 0000000000..98f39b3c27
--- /dev/null
+++ b/test/integration/roles/test_win_command/tasks/main.yml
@@ -0,0 +1,134 @@
+- name: execute a command
+ win_command: whoami /groups
+ register: cmdout
+
+- name: validate result
+ assert:
+ that:
+ - cmdout|success
+ - cmdout|changed
+ - cmdout.cmd == 'whoami /groups'
+ - cmdout.delta is match('^\d:(\d){2}:(\d){2}.(\d){6}$')
+ - cmdout.end is match('^(\d){4}\-(\d){2}\-(\d){2} (\d){2}:(\d){2}:(\d){2}.(\d){6}$')
+ - cmdout.rc == 0
+ - cmdout.start is match('^(\d){4}\-(\d){2}\-(\d){2} (\d){2}:(\d){2}:(\d){2}.(\d){6}$')
+ - cmdout.stderr == ""
+ - cmdout.stdout is search('GROUP INFORMATION')
+ - '"GROUP INFORMATION" in cmdout.stdout_lines'
+ - cmdout.warnings == []
+
+- name: execute something nonexistent
+ win_command: bogus_command1234
+ register: cmdout
+ ignore_errors: true
+
+- name: validate result
+ assert:
+ that:
+ - cmdout|failed
+ - not cmdout|changed
+ - cmdout.cmd == 'bogus_command1234'
+ - cmdout.rc == 2
+ - cmdout.msg is search('cannot find the file specified')
+
+- name: execute something with error output
+ win_command: cmd /c "echo some output & echo some error 1>&2"
+ register: cmdout
+
+- name: validate result
+ assert:
+ that:
+ - cmdout|success
+ - cmdout|changed
+ - cmdout.cmd == 'cmd /c "echo some output & echo some error 1>&2"'
+ - cmdout.delta is match('^\d:(\d){2}:(\d){2}.(\d){6}$')
+ - cmdout.end is match('^(\d){4}\-(\d){2}\-(\d){2} (\d){2}:(\d){2}:(\d){2}.(\d){6}$')
+ - cmdout.rc == 0
+ - cmdout.start is match('^(\d){4}\-(\d){2}\-(\d){2} (\d){2}:(\d){2}:(\d){2}.(\d){6}$')
+ - cmdout.stderr is search('some error')
+ - cmdout.stdout == "some output \r\n"
+ - cmdout.stdout_lines == ["some output "]
+ - cmdout.warnings == []
+
+- name: ensure test file is absent
+ win_file:
+ path: c:\testfile.txt
+ state: absent
+
+- name: run with creates, should create
+ win_command: cmd /c "echo $null >> c:\testfile.txt"
+ args:
+ creates: c:\testfile.txt
+ register: cmdout
+
+- name: validate result
+ assert:
+ that:
+ - cmdout|success
+ - cmdout|changed
+
+- name: run again with creates, should skip
+ win_command: cmd /c "echo $null >> c:\testfile.txt"
+ args:
+ creates: c:\testfile.txt
+ register: cmdout
+
+- name: validate result
+ assert:
+ that:
+ - cmdout|skipped
+ - cmdout.msg is search('exists')
+
+- name: ensure testfile is still present
+ win_stat:
+ path: c:\testfile.txt
+ register: statout
+
+- name: validate result
+ assert:
+ that:
+ - statout.stat.exists == true
+
+- name: run with removes, should remove
+ win_command: cmd /c "del c:\testfile.txt"
+ args:
+ removes: c:\testfile.txt
+ register: cmdout
+
+- name: validate result
+ assert:
+ that:
+ - cmdout|success
+ - cmdout|changed
+
+- name: run again with removes, should skip
+ win_command: cmd /c "del c:\testfile.txt"
+ args:
+ removes: c:\testfile.txt
+ register: cmdout
+
+- name: validate result
+ assert:
+ that:
+ - cmdout|skipped
+ - cmdout.msg is search('does not exist')
+
+- name: run something with known nonzero exit code
+ win_command: cmd /c "exit 254"
+ register: cmdout
+ ignore_errors: true
+
+- name: validate result
+ assert:
+ that:
+ - cmdout|failed
+ - cmdout.rc == 254
+
+- name: write large buffer to stdout
+ win_command: powershell /c "$ba = New-Object byte[] 16384; (New-Object System.Random 32).NextBytes($ba); [Convert]::ToBase64String($ba) | Write-Output"
+ register: cmdout
+
+# TODO: fix small buffer deadlock on large write to stderr before stdout has been consumed
+#- name: write large buffer to stderr
+# win_shell: $ba = New-Object byte[] 16384; (New-Object System.Random 32).NextBytes($ba); [Convert]::ToBase64String($ba) | Write-Error; Write-Output test
+# register: cmdout \ No newline at end of file
diff --git a/test/integration/roles/test_win_shell/tasks/main.yml b/test/integration/roles/test_win_shell/tasks/main.yml
new file mode 100644
index 0000000000..12e9870b9c
--- /dev/null
+++ b/test/integration/roles/test_win_shell/tasks/main.yml
@@ -0,0 +1,175 @@
+- name: execute a powershell cmdlet
+ win_shell: Write-Output "hello from Ansible"
+ register: shellout
+
+- name: validate result
+ assert:
+ that:
+ - shellout|success
+ - shellout|changed
+ - shellout.cmd == 'Write-Output "hello from Ansible"'
+ - shellout.delta is match('^\d:(\d){2}:(\d){2}.(\d){6}$')
+ - shellout.end is match('^(\d){4}\-(\d){2}\-(\d){2} (\d){2}:(\d){2}:(\d){2}.(\d){6}$')
+ - shellout.rc == 0
+ - shellout.start is match('^(\d){4}\-(\d){2}\-(\d){2} (\d){2}:(\d){2}:(\d){2}.(\d){6}$')
+ - shellout.stderr == ""
+ - shellout.stdout == "hello from Ansible\r\n"
+ - shellout.stdout_lines == ["hello from Ansible"]
+ - shellout.warnings == []
+
+- name: execute a powershell cmdlet with multi-line output
+ win_shell: Write-Output "hello from Ansible"; Write-Output "another line"; Write-Output "yet another line"
+ register: shellout
+
+- name: validate result
+ assert:
+ that:
+ - shellout|success
+ - shellout|changed
+ - shellout.cmd == 'Write-Output "hello from Ansible"; Write-Output "another line"; Write-Output "yet another line"'
+ - shellout.delta is match('^\d:(\d){2}:(\d){2}.(\d){6}$')
+ - shellout.end is match('^(\d){4}\-(\d){2}\-(\d){2} (\d){2}:(\d){2}:(\d){2}.(\d){6}$')
+ - shellout.rc == 0
+ - shellout.start is match('^(\d){4}\-(\d){2}\-(\d){2} (\d){2}:(\d){2}:(\d){2}.(\d){6}$')
+ - shellout.stderr == ""
+ - shellout.stdout == "hello from Ansible\r\nanother line\r\nyet another line\r\n"
+ - shellout.stdout_lines == ["hello from Ansible","another line", "yet another line"]
+ - shellout.warnings == []
+
+- name: execute something nonexistent
+ win_shell: bogus_command1234
+ register: shellout
+ ignore_errors: true
+
+- name: validate result
+ assert:
+ that:
+ - shellout|failed
+ - shellout|changed
+ - shellout.cmd == 'bogus_command1234'
+ - shellout.delta is match('^\d:(\d){2}:(\d){2}.(\d){6}$')
+ - shellout.end is match('^(\d){4}\-(\d){2}\-(\d){2} (\d){2}:(\d){2}:(\d){2}.(\d){6}$')
+ - shellout.rc == 1
+ - shellout.start is match('^(\d){4}\-(\d){2}\-(\d){2} (\d){2}:(\d){2}:(\d){2}.(\d){6}$')
+ - shellout.stderr is search('not recognized')
+ - shellout.stdout == ""
+ - shellout.stdout_lines == []
+ - shellout.warnings == []
+
+- name: execute something with error output
+ win_shell: Write-Error "it broke"; Write-Output "some output"
+ register: shellout
+
+- name: validate result
+ assert:
+ that:
+ - shellout|success
+ - shellout|changed
+ - shellout.cmd == 'Write-Error "it broke"; Write-Output "some output"'
+ - shellout.delta is match('^\d:(\d){2}:(\d){2}.(\d){6}$')
+ - shellout.end is match('^(\d){4}\-(\d){2}\-(\d){2} (\d){2}:(\d){2}:(\d){2}.(\d){6}$')
+ - shellout.rc == 0
+ - shellout.start is match('^(\d){4}\-(\d){2}\-(\d){2} (\d){2}:(\d){2}:(\d){2}.(\d){6}$')
+ - shellout.stderr is search('it broke')
+ - shellout.stdout == "some output\r\n"
+ - shellout.stdout_lines == ["some output"]
+ - shellout.warnings == []
+
+- name: ensure test file is absent
+ win_file:
+ path: c:\testfile.txt
+ state: absent
+
+- name: run with creates, should create
+ win_shell: echo $null >> c:\testfile.txt
+ args:
+ creates: c:\testfile.txt
+ register: shellout
+
+- name: validate result
+ assert:
+ that:
+ - shellout|success
+ - shellout|changed
+
+- name: run again with creates, should skip
+ win_shell: echo $null >> c:\testfile.txt
+ args:
+ creates: c:\testfile.txt
+ register: shellout
+
+- name: validate result
+ assert:
+ that:
+ - shellout|skipped
+ - shellout.msg is search('exists')
+
+- name: ensure testfile is still present
+ win_stat:
+ path: c:\testfile.txt
+ register: statout
+
+- name: validate result
+ assert:
+ that:
+ - statout.stat.exists == true
+
+- name: run with removes, should remove
+ win_shell: Remove-Item c:\testfile.txt
+ args:
+ removes: c:\testfile.txt
+ register: shellout
+
+- name: validate result
+ assert:
+ that:
+ - shellout|success
+ - shellout|changed
+
+- name: run again with removes, should skip
+ win_shell: echo $null >> c:\testfile.txt
+ args:
+ removes: c:\testfile.txt
+ register: shellout
+
+- name: validate result
+ assert:
+ that:
+ - shellout|skipped
+ - shellout.msg is search('does not exist')
+
+- name: run something with known nonzero exit code
+ win_shell: exit 254
+ register: shellout
+ ignore_errors: true
+
+- name: validate result
+ assert:
+ that:
+ - shellout|failed
+ - shellout.rc == 254
+
+- name: run something via cmd that will fail in powershell
+ win_shell: echo line1 & echo.line2
+ args:
+ executable: cmd
+ register: shellout
+
+- name: validate result
+ assert:
+ that:
+ - shellout|success
+ - shellout|changed
+ - shellout.rc == 0
+ - shellout.stdout == "line1 \r\nline2\r\n"
+ - shellout.stdout_lines == ["line1 ", "line2"]
+ - shellout.stderr == ""
+
+- name: write large buffer to stdout
+ win_shell: $ba = New-Object byte[] 16384; (New-Object System.Random 32).NextBytes($ba); [Convert]::ToBase64String($ba) | Write-Output
+ register: shellout
+
+# TODO: fix small buffer deadlock on large write to stderr before stdout has been consumed
+#- name: write large buffer to stderr
+# win_shell: $ba = New-Object byte[] 16384; (New-Object System.Random 32).NextBytes($ba); [Convert]::ToBase64String($ba) | Write-Error; Write-Output test
+# register: shellout \ No newline at end of file
diff --git a/test/integration/test_win_group3.yml b/test/integration/test_win_group3.yml
index 7ade0cb122..43afe1c446 100644
--- a/test/integration/test_win_group3.yml
+++ b/test/integration/test_win_group3.yml
@@ -5,3 +5,5 @@
- { role: test_win_feature, tags: test_win_feature }
- { role: test_win_user, tags: test_win_user }
- { role: test_win_async_wrapper, tags: test_win_async_wrapper }
+ - { role: test_win_shell, tags: test_win_shell }
+ - { role: test_win_command, tags: test_win_command }