Skip to content

Commit 1be6087

Browse files
Andrzej JoskowskiPiotr
authored andcommitted
DPNG-7667: Apployer can download artifacts from remote server
Signed-off-by: Andrzej Joskowski <[email protected]>
1 parent 156fdc0 commit 1be6087

File tree

3 files changed

+74
-2
lines changed

3 files changed

+74
-2
lines changed

apployer/main.py

Lines changed: 55 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,9 +22,11 @@
2222
import os
2323
import sys
2424
import time
25-
25+
import subprocess
26+
import shutil
2627
import click
2728
import yaml
29+
import validators
2830

2931
import apployer
3032
from .appstack import AppStack
@@ -35,6 +37,7 @@
3537

3638
DEFAULT_EXPANDED_APPSTACK_FILE = 'expanded_appstack.yml'
3739
DEFAULT_APPSTACK_FILE = 'appstack.yml'
40+
DEFAULT_ARTIFACTS_PATH = 'artifacts'
3841

3942
_log = logging.getLogger(__name__) #pylint: disable=invalid-name
4043

@@ -143,6 +146,10 @@ def deploy( #pylint: disable=too-many-arguments
143146
"""
144147
start_time = time.time()
145148

149+
if validators.url(artifacts_location):
150+
_download_artifacts_from_url(artifacts_location, appstack)
151+
artifacts_location = DEFAULT_ARTIFACTS_PATH
152+
146153
cf_info = CfInfo(api_url=cf_api_endpoint, password=cf_password, user=cf_user,
147154
org=cf_org, space=cf_space)
148155
filled_appstack = _get_filled_appstack(appstack, expanded_appstack, filled_appstack,
@@ -188,6 +195,53 @@ def fetch(artifacts_location, fetcher_config, expanded_appstack, appstack):
188195
_log.info('Content of %s file: \n %s', final_appstack_path, yaml.dump(filled_appstack_dict))
189196

190197

198+
@cli.command()
199+
@click.argument('ARTIFACTS_URL')
200+
@click.option('-a', '--appstack',
201+
default=DEFAULT_APPSTACK_FILE, show_default=True,
202+
help='Path to the file containing non-expanded appstack. Only used if expanded'
203+
'appstack has not been specified.')
204+
def download_apps(artifacts_url, appstack):
205+
"""
206+
Downloads applications artifacts from specified source. Url should include '{name}'
207+
parameter like here: http://artifacts.com/download/{name}
208+
"""
209+
if not validators.url(artifacts_url):
210+
_log.error('Value %s is not valid Url.', artifacts_url)
211+
raise ApployerArgumentError('Provided invalid url')
212+
213+
_download_artifacts_from_url(artifacts_url, appstack)
214+
215+
216+
def _download_artifacts_from_url(url, appstack):
217+
"""
218+
Does the neccessary things to download applications artifacts.
219+
220+
Args:
221+
url: address of artifacts server, i.e. http://artifacts.com/download/{name}
222+
where 'name' param is dynamically replaced to app name
223+
appstack: path to appstack file
224+
"""
225+
if os.path.exists(DEFAULT_ARTIFACTS_PATH):
226+
shutil.rmtree(DEFAULT_ARTIFACTS_PATH, ignore_errors=True)
227+
os.makedirs(DEFAULT_ARTIFACTS_PATH)
228+
229+
with open(appstack) as appstack_file:
230+
appstack_dict = yaml.load(appstack_file)
231+
232+
artifacts_names = set()
233+
for app in appstack_dict['apps']:
234+
artifacts_names.add(app.get('artifact_name', app.get('name')))
235+
236+
for artifact_name in artifacts_names:
237+
artifact_url = url.format(name=artifact_name)
238+
_log.info('Downloading artifact for %s app from %s', artifact_name, artifact_url)
239+
proc = subprocess.Popen(['wget', '--no-check-certificate', '--content-disposition',
240+
'-nv', artifact_url], cwd=DEFAULT_ARTIFACTS_PATH)
241+
if proc.wait() != 0:
242+
_log.error('Error during download! wget output:\n%s', proc.stdout.read())
243+
244+
191245
def _get_filled_appstack( #pylint: disable=too-many-arguments
192246
appstack_path,
193247
expanded_appstack_path,

requirements.txt

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,4 @@ paramiko== 1.16.0
1111
pycrypto==2.6.1
1212
pyyaml==3.11
1313
requests==2.9.1
14+
validators==0.10.1

tests/test_main.py

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -19,7 +19,7 @@
1919

2020
import pytest
2121

22-
from apployer.main import _get_filled_appstack, ApployerArgumentError, _seconds_to_time
22+
from apployer.main import _get_filled_appstack, _download_artifacts_from_url, ApployerArgumentError, _seconds_to_time
2323

2424
appstack_path = 'appstack_path'
2525
expanded_appstack_path = 'expanded_appstack_path'
@@ -82,6 +82,23 @@ def test_get_filled_appstack_with_none(monkeypatch):
8282
_get_filled_appstack(None, None, None, None, None)
8383

8484

85+
def test_download_artifacts_from_url(monkeypatch):
86+
monkeypatch.setattr('os.path.exists', lambda path: True)
87+
shutil_mock = MagicMock()
88+
monkeypatch.setattr('shutil.rmtree', shutil_mock)
89+
os_mock = MagicMock()
90+
monkeypatch.setattr('os.makedirs', os_mock)
91+
monkeypatch.setattr('__builtin__.open', mock.mock_open(read_data='{"apps": [{"artifact_name": "a"}]}'))
92+
wait_mock = MagicMock(return_value=0)
93+
subprocess_mock = MagicMock(return_value=wait_mock)
94+
monkeypatch.setattr('subprocess.Popen', subprocess_mock)
95+
_download_artifacts_from_url('url', None)
96+
assert shutil_mock.called
97+
assert os_mock.called
98+
assert subprocess_mock.called
99+
assert wait_mock.wait.called
100+
101+
85102
@pytest.mark.parametrize('string, seconds', [
86103
('0:02:03', 123.3),
87104
('0:12:13', 733),

0 commit comments

Comments
 (0)