Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

win_get_url: Fixed a few issues with using FTP and added tests #39646

Merged
merged 2 commits into from
May 3, 2018
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 2 additions & 0 deletions changelogs/fragments/win_get_url-ftp-support.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
bugfixes:
- win_get_url - fixed a few bugs around authentication and force no when using an FTP URL
27 changes: 18 additions & 9 deletions lib/ansible/modules/windows/win_get_url.ps1
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,7 @@
# Copyright: (c) 2017, Dag Wieers <dag@wieers.com>
# GNU General Public License v3.0+ (see COPYING or https://www.gnu.org/licenses/gpl-3.0.txt)

# WANT_JSON
# POWERSHELL_COMMON
#Requires -Module Ansible.ModuleUtils.Legacy

$ErrorActionPreference = 'Stop'

Expand Down Expand Up @@ -35,8 +34,8 @@ Function CheckModified-File($url, $dest, $headers, $credentials, $timeout, $use_
$fileLastMod = ([System.IO.FileInfo]$dest).LastWriteTimeUtc
$webLastMod = $null

$webRequest = [System.Net.HttpWebRequest]::Create($url)

$webRequest = [System.Net.WebRequest]::Create($url)
foreach ($header in $headers.GetEnumerator()) {
$webRequest.Headers.Add($header.Name, $header.Value)
}
Expand All @@ -53,14 +52,23 @@ Function CheckModified-File($url, $dest, $headers, $credentials, $timeout, $use_
}

if ($credentials) {
$webRequest.Credentials = $credentials
if ($force_basic_auth) {
$extWebClient.Headers.Add("Authorization","Basic $credentials")
} else {
$extWebClient.Credentials = $credentials
}
}

$webRequest.Method = "HEAD"
if ($webRequest -is [System.Net.FtpWebRequest]) {
$webRequest.Method = [System.Net.WebRequestMethods+Ftp]::GetDateTimestamp
} else {
$webRequest.Method = [System.Net.WebRequestMethods+Http]::Head
}

Try {
[System.Net.HttpWebResponse]$webResponse = $webRequest.GetResponse()
$webResponse = $webRequest.GetResponse()

$webLastMod = $webResponse.GetResponseHeader("Last-Modified")
$webLastMod = $webResponse.LastModified
} Catch [System.Net.WebException] {
$result.status_code = $_.Exception.Response.StatusCode
Fail-Json -obj $result -message "Error requesting '$url'. $($_.Exception.Message)"
Expand Down Expand Up @@ -174,7 +182,7 @@ if ($proxy_url) {
}

$credentials = $null
if ($url_username -and $url_password) {
if ($url_username) {
if ($force_basic_auth) {
$credentials = [convert]::ToBase64String([System.Text.Encoding]::ASCII.GetBytes($url_username+":"+$url_password))
} else {
Expand Down Expand Up @@ -241,3 +249,4 @@ if ($force -or -not (Test-Path -LiteralPath $dest)) {
}

Exit-Json -obj $result

14 changes: 10 additions & 4 deletions lib/ansible/modules/windows/win_get_url.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,10 @@
---
module: win_get_url
version_added: "1.7"
short_description: Fetches a file from a given URL
short_description: Downloads file from HTTP, HTTPS, or FTP to node
description:
- Fetches a file from a URL and saves it locally.
- Downloads files from HTTP, HTTPS, or FTP to the remote server. The remote
server I(must) have direct access to the remote resource.
- For non-Windows targets, use the M(get_url) module instead.
author:
- Paul Durivage (@angstwad)
Expand Down Expand Up @@ -101,8 +102,6 @@
- Timeout in seconds for URL request.
default: 10
version_added : '2.4'
notes:
- For non-Windows targets, use the M(get_url) module instead.
'''

EXAMPLES = r'''
Expand All @@ -124,6 +123,13 @@
proxy_url: http://10.0.0.1:8080
proxy_username: username
proxy_password: password

- name: Download file from FTP with authentication
win_get_url:
url: ftp://server/file.txt
dest: '%TEMP%\ftp-file.txt'
url_username: ftp-user
url_password: ftp-password
'''

RETURN = r'''
Expand Down
8 changes: 2 additions & 6 deletions test/integration/targets/win_get_url/defaults/main.yml
Original file line number Diff line number Diff line change
@@ -1,8 +1,4 @@
---

test_win_get_url_path: '{{win_output_dir}}\win_get_url'
test_win_get_url_host: www.redhat.com
test_win_get_url_link: "https://{{ test_win_get_url_host }}"
test_win_get_url_invalid_link: https://www.redhat.com/skynet_module.html
test_win_get_url_invalid_path: 'Q:\Filez\Cyberdyne.html'
test_win_get_url_invalid_path_dir: 'Q:\Filez\'
test_win_get_url_path: '%TEMP%\docs_index.html'
test_win_get_url_env_var: WIN_GET_URL
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ftp/anon/file.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ftp/anon/file2.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ftp/user-pass/file.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
ftp/user/file.txt
200 changes: 58 additions & 142 deletions test/integration/targets/win_get_url/tasks/main.yml
Original file line number Diff line number Diff line change
@@ -1,143 +1,59 @@
# test code for the win_get_url module
# (c) 2014, Chris Church <chris@ninemoreminutes.com>

# 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/>.

- setup:

- name: Remove test file if it exists
---
- name: ensure testing folder is present
win_file:
path: '{{ test_win_get_url_path }}'
state: absent

- name: Test win_get_url module
win_get_url:
url: '{{ test_win_get_url_link }}'
dest: '{{ test_win_get_url_path }}'
register: win_get_url_result

- name: Check that url was downloaded
assert:
that:
- win_get_url_result is not failed
- win_get_url_result is changed
- win_get_url_result.url
- win_get_url_result.dest

- name: Test win_get_url module again (force should be yes by default)
win_get_url:
url: '{{ test_win_get_url_link }}'
dest: '{{ test_win_get_url_path }}'
register: win_get_url_result_again

- name: Check that url was downloaded again
assert:
that:
- win_get_url_result_again is not failed
- win_get_url_result_again is changed

- name: Test win_get_url module again with force=no
win_get_url:
url: '{{ test_win_get_url_link }}'
dest: '{{ test_win_get_url_path }}'
force: no
register: win_get_url_result_noforce

- name: Check that url was not downloaded again
assert:
that:
- win_get_url_result_noforce is not failed
- win_get_url_result_noforce is not changed

- name: Test win_get_url module with url that returns a 404
win_get_url:
url: '{{ test_win_get_url_invalid_link }}'
dest: '{{ test_win_get_url_path }}'
register: win_get_url_result_invalid_link
ignore_errors: true

- name: Check that the download failed for an invalid url
assert:
that:
- win_get_url_result_invalid_link is failed
- win_get_url_result_invalid_link.status_code == 404

- name: Test win_get_url module with an invalid path
win_get_url:
url: '{{ test_win_get_url_link }}'
dest: '{{ test_win_get_url_invalid_path }}'
register: win_get_url_result_invalid_path
ignore_errors: true

- name: Check that the download failed for an invalid path
assert:
that:
- win_get_url_result_invalid_path is failed

- name: Test win_get_url module with a valid path that is a directory
win_get_url:
url: '{{ test_win_get_url_link }}'
dest: '%TEMP%'
register: win_get_url_result_dir_path
ignore_errors: true

- name: Check that the download did NOT fail, even though dest was directory
assert:
that:
- win_get_url_result_dir_path is changed

- name: Test win_get_url with a valid url path and a dest that is a directory (from 2.4 should use url path as filename)
win_get_url:
url: '{{ test_win_get_url_link }}'
dest: '%TEMP%'
register: win_get_url_result_dir_path_urlpath
ignore_errors: true

- name: Set expected destination path fact
set_fact:
expected_dest_path: '{{ ansible_env.TEMP }}\{{ test_win_get_url_host }}'

- name: Check that the download succeeded (changed) and dest is as expected
assert:
that:
- win_get_url_result_dir_path_urlpath is changed
- win_get_url_result_dir_path_urlpath.dest == expected_dest_path

- name: Check you get a helpful message if the parent folder of the dest doesn't exist
win_get_url:
url: '{{ test_win_get_url_link }}'
dest: 'Q:\Filez\'
register: win_get_url_result_invalid_dest
ignore_errors: true

- name: Check if dest parent dir does not exist, module fails and you get a specific error message
assert:
that:
- win_get_url_result_invalid_dest is failed
- win_get_url_result_invalid_dest.msg is search('does not exist, or is not visible to the current user')

- name: Check you get a helpful message if the parent folder of the dest doesn't exist
win_get_url:
url: '{{ test_win_get_url_link }}'
dest: 'C:\Filez\'
register: win_get_url_result_invalid_dest2
ignore_errors: true

- name: Check if dest parent dir does not exist, module fails and you get a specific error message
assert:
that:
- win_get_url_result_invalid_dest2 is failed
- win_get_url_result_invalid_dest2.msg is search('does not exist')
path: '{{test_win_get_url_path}}'
state: directory

- name: copy across testing files
win_copy:
src: files/
dest: '{{test_win_get_url_path}}\'

- name: download SlimFTPd binary
win_get_url:
url: https://s3.amazonaws.com/ansible-ci-files/test/integration/roles/test_win_get_url/SlimFTPd.exe
dest: '{{test_win_get_url_path}}\SlimFTPd.exe'

- name: template SlimFTPd configuration file
win_template:
src: slimftpd.conf.tmpl
dest: '{{test_win_get_url_path}}\slimftpd.conf'

- name: create SlimFTPd service
win_service:
name: SlimFTPd
path: '"{{test_win_get_url_path}}\SlimFTPd.exe" -service'
state: started
dependencies:
- tcpip

- name: create env var for win_get_url tests
win_environment:
name: '{{test_win_get_url_env_var}}'
level: machine
value: '{{test_win_get_url_path}}'
state: present

- block:
- name: run URL tests
include_tasks: tests_url.yml

- name: run FTP tests
include_tasks: tests_ftp.yml

always:
- name: remove SlimFTPd service
win_service:
name: SlimFTPd
state: absent

- name: remove test env var for tests
win_environment:
name: '{{test_win_get_url_env_var}}'
level: machine
state: absent

- name: remove testing folder
win_file:
path: '{{test_win_get_url_path}}'
state: absent