Skip to content

Commit e5eab87

Browse files
authored
Merge pull request #32 from marcelmamula/role
sap_software_download: New role for downloading software
2 parents 1cc9d31 + 56f42ba commit e5eab87

27 files changed

+1527
-24
lines changed

.ansible-lint

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
---
2+
# Collection wide lint-file
3+
# DO NOT CHANGE
4+
exclude_paths:
5+
- .ansible/
6+
- .cache/
7+
- .github/
8+
# - docs/
9+
- changelogs/
10+
- playbooks/
11+
- tests/
12+
enable_list:
13+
- yaml
14+
skip_list:
15+
# We don't want to enforce new Ansible versions for Galaxy:
16+
- meta-runtime[unsupported-version]
17+
# We do not want to use checks which are marked as experimental:
18+
- experimental
19+
# We use ignore_errors for all the assert tasks, which should be acceptable:
20+
- ignore-errors
21+
# We want to allow single digit version numbers in a role's meta/main.yml file:
22+
- schema
23+
# Allow templating inside name because it creates more detailed output:
24+
- name[template]

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,3 +52,4 @@ __pycache__/
5252
# VSCode
5353
.vscode
5454

55+
.ansible

plugins/module_utils/sap_api_common.py

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -37,9 +37,23 @@ def _request(url, **kwargs):
3737
method = 'POST' if kwargs.get('data') or kwargs.get('json') else 'GET'
3838
res = https_session.request(method, url, **kwargs)
3939

40-
if (res.status_code == 403
41-
and res.json()['errorMessage'].startswith('Account Temporarily Locked Out')):
42-
raise Exception('SAP ID Service has reported `Account Temporarily Locked Out`. Please reset password to regain access and try again.')
40+
# Validating against `res.text` can cause long execution time, because fuzzy search result can contain large `res.text`.
41+
# This can be prevented by validating `res.status_code` check before `res.text`.
42+
# Example: 'Two-Factor Authentication' is only in `res.text`, which can lead to long execution.
43+
44+
if res.status_code == 403:
45+
if 'You are not authorized to download this file' in res.text:
46+
raise Exception(f'You are not authorized to download this file.')
47+
elif 'Account Temporarily Locked Out' in res.text:
48+
raise Exception(f'Account Temporarily Locked Out. Please reset password to regain access and try again.')
49+
else:
50+
res.raise_for_status()
51+
52+
if res.status_code == 404:
53+
if 'The file you have requested cannot be found' in res.text:
54+
raise Exception(f'The file you have requested cannot be found.')
55+
else:
56+
res.raise_for_status()
4357

4458
res.raise_for_status()
4559

plugins/modules/maintenance_planner_stack_xml_download.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,7 @@
3030
- Transaction Name or Transaction Display ID from Maintenance Planner.
3131
required: true
3232
type: str
33-
download_path:
33+
dest:
3434
description:
3535
- Destination folder path.
3636
required: true
@@ -46,7 +46,7 @@
4646
suser_id: 'SXXXXXXXX'
4747
suser_password: 'password'
4848
transaction_name: 'MP_NEW_INST_20211015_044854'
49-
download_path: "/tmp/"
49+
dest: "/tmp/"
5050
register: sap_mp_register
5151
- name: Display the list of download links and filenames
5252
debug:
@@ -79,7 +79,7 @@ def run_module():
7979
suser_id=dict(type='str', required=True),
8080
suser_password=dict(type='str', required=True, no_log=True),
8181
transaction_name=dict(type='str', required=True),
82-
download_path=dict(type='str', required=True)
82+
dest=dict(type='str', required=True)
8383
)
8484

8585
# Define result dictionary objects to be passed back to Ansible
@@ -102,7 +102,7 @@ def run_module():
102102
username = module.params.get('suser_id')
103103
password = module.params.get('suser_password')
104104
transaction_name = module.params.get('transaction_name')
105-
download_path = module.params.get('download_path')
105+
dest = module.params.get('dest')
106106

107107
# Main run
108108

@@ -118,7 +118,7 @@ def run_module():
118118
transaction_id = get_transaction_id(transaction_name)
119119

120120
# EXEC: Download the MP Stack XML file
121-
get_transaction_stack_xml(transaction_id, download_path)
121+
get_transaction_stack_xml(transaction_id, dest)
122122

123123
# Process return dictionary for Ansible
124124
result['changed'] = True

plugins/modules/software_center_download.py

Lines changed: 16 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@
4848
- Download filename of the SAP software.
4949
required: false
5050
type: str
51-
download_path:
51+
dest:
5252
description:
5353
- Destination folder path.
5454
required: true
@@ -80,14 +80,14 @@
8080
suser_password: 'password'
8181
search_query:
8282
- 'SAPCAR_1324-80000936.EXE'
83-
download_path: "/tmp/"
83+
dest: "/tmp/"
8484
- name: Download using direct link and filename
8585
community.sap_launchpad.software_center_download:
8686
suser_id: 'SXXXXXXXX'
8787
suser_password: 'password'
8888
download_link: 'https://softwaredownloads.sap.com/file/0010000000048502015'
8989
download_filename: 'IW_FNDGC100.SAR'
90-
download_path: "/tmp/"
90+
dest: "/tmp/"
9191
'''
9292

9393
RETURN = r'''
@@ -116,21 +116,21 @@
116116
from ..module_utils.sap_launchpad_software_center_download_runner import *
117117
from ..module_utils.sap_id_sso import sap_sso_login
118118

119-
def _check_similar_files(download_path, filename):
119+
def _check_similar_files(dest, filename):
120120
"""
121121
Checks for similar files in the download path based on the given filename.
122122
123123
Args:
124-
download_path (str): The path where files are downloaded.
124+
dest (str): The path where files are downloaded.
125125
filename (str): The filename to check for similar files.
126126
127127
Returns:
128128
bool: True if similar files exist, False otherwise.
129129
filename_similar_names: A list of similar filenames if they exist, empty list otherwise.
130130
"""
131-
# pattern = download_path + '/**/' + os.path.splitext(filename)[0]
131+
# pattern = dest + '/**/' + os.path.splitext(filename)[0]
132132
filename_base = os.path.splitext(filename)[0]
133-
filename_pattern = os.path.join(download_path, "**", filename_base)
133+
filename_pattern = os.path.join(dest, "**", filename_base)
134134
filename_similar = glob.glob(filename_pattern, recursive=True)
135135

136136
if filename_similar:
@@ -150,7 +150,7 @@ def run_module():
150150
search_query=dict(type='str', required=False, default=''),
151151
download_link=dict(type='str', required=False, default=''),
152152
download_filename=dict(type='str', required=False, default=''),
153-
download_path=dict(type='str', required=True),
153+
dest=dict(type='str', required=True),
154154
dry_run=dict(type='bool', required=False, default=False),
155155
deduplicate=dict(type='str', required=False, default=''),
156156
search_alternatives=dict(type='bool', required=False, default=False)
@@ -174,7 +174,7 @@ def run_module():
174174
else:
175175
query = None
176176

177-
download_path = module.params['download_path']
177+
dest = module.params['dest']
178178
download_link= module.params.get('download_link')
179179
download_filename= module.params.get('download_filename')
180180
dry_run = module.params.get('dry_run')
@@ -207,7 +207,7 @@ def run_module():
207207

208208
# Search for existing files using exact filename
209209
filename = query if query else download_filename
210-
filename_exact = os.path.join(download_path, filename)
210+
filename_exact = os.path.join(dest, filename)
211211
result['filename'] = filename
212212

213213
if os.path.exists(filename_exact):
@@ -216,7 +216,7 @@ def run_module():
216216
module.exit_json(**result)
217217
else:
218218
# Exact file not found, search for similar files with pattern
219-
filename_similar_exists, filename_similar_names = _check_similar_files(download_path, filename)
219+
filename_similar_exists, filename_similar_names = _check_similar_files(dest, filename)
220220
if filename_similar_exists and not (query and search_alternatives):
221221
result['skipped'] = True
222222
result['msg'] = f"Similar file(s) already exist: {', '.join(filename_similar_names)}"
@@ -235,14 +235,14 @@ def run_module():
235235
result['filename'] = download_filename
236236
result['alternative'] = True
237237

238-
filename_alternative_exact = os.path.join(download_path, download_filename)
238+
filename_alternative_exact = os.path.join(dest, download_filename)
239239
if os.path.exists(filename_alternative_exact):
240240
result['skipped'] = True
241241
result['msg'] = f"Alternative file already exists: {download_filename} - original file {query} is not available to download"
242242
module.exit_json(**result)
243243
else:
244244
# Exact file not found, search for similar files with pattern
245-
filename_similar_exists, filename_similar_names = _check_similar_files(download_path, download_filename)
245+
filename_similar_exists, filename_similar_names = _check_similar_files(dest, download_filename)
246246
if filename_similar_exists:
247247
result['skipped'] = True
248248
result['msg'] = f"Similar alternative file(s) already exist: {', '.join(filename_similar_names)}"
@@ -252,13 +252,13 @@ def run_module():
252252
elif filename != download_filename and not alternative_found:
253253
result['filename'] = download_filename
254254

255-
if os.path.exists(os.path.join(download_path, download_filename)):
255+
if os.path.exists(os.path.join(dest, download_filename)):
256256
result['skipped'] = True
257257
result['msg'] = f"File already exists with correct name: {download_filename}"
258258
module.exit_json(**result)
259259
else:
260260
# Exact file not found, search for similar files with pattern
261-
filename_similar_exists, filename_similar_names = _check_similar_files(download_path, download_filename)
261+
filename_similar_exists, filename_similar_names = _check_similar_files(dest, download_filename)
262262
if filename_similar_exists:
263263
result['skipped'] = True
264264
result['msg'] = f"Similar file(s) already exist for correct name {download_filename}: {', '.join(filename_similar_names)}"
@@ -281,7 +281,7 @@ def run_module():
281281
else:
282282
module.fail_json(msg="Download link {} is not available".format(download_link))
283283

284-
download_software(download_link, download_filename, download_path)
284+
download_software(download_link, download_filename, dest)
285285

286286
# Update final results json
287287
result['changed'] = True

roles/.gitkeep

Whitespace-only changes.
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
# SPDX-License-Identifier: Apache-2.0
2+
---
3+
# Based on ansible-lint config
4+
extends: default
5+
6+
rules:
7+
braces: {max-spaces-inside: 1, level: error}
8+
brackets: {max-spaces-inside: 1, level: error}
9+
# colons: {max-spaces-after: -1, level: error}
10+
# commas: {max-spaces-after: -1, level: error}
11+
comments:
12+
require-starting-space: false
13+
min-spaces-from-content: 1
14+
comments-indentation: disable
15+
# document-start: disable
16+
# empty-lines: {max: 3, level: error}
17+
# hyphens: {level: error}
18+
# indentation: disable
19+
# key-duplicates: enable
20+
line-length: disable
21+
# new-line-at-end-of-file: disable
22+
# new-lines: {type: unix}
23+
# trailing-spaces: disable
24+
truthy: disable
25+
octal-values:
26+
forbid-implicit-octal: true
27+
forbid-explicit-octal: true

0 commit comments

Comments
 (0)