Skip to content
This repository has been archived by the owner on Jul 30, 2020. It is now read-only.

Commit

Permalink
Add 'api_key' config item (fixes #249) (#268)
Browse files Browse the repository at this point in the history
This is the API key used when the Galaxy API needs to authenticate
a request. For example, for the POST request made when using the
'publish' sub command to upload collection artifacts.
'api_key' here is equilivent to the cli '--api-key'

The default value is unset or None.
The API key can be found at https://galaxy.ansible.com/me/preferences

Remove api_key arg to action publish.publish()

Add api_key to config 'server' dict by default

Also update action.publish unit tests to use requests_mock

Add info about config 'api_key' item to README

Fixes: #249
  • Loading branch information
alikins committed May 23, 2019
1 parent b2fe3ee commit d20c0ac
Show file tree
Hide file tree
Showing 8 changed files with 80 additions and 29 deletions.
10 changes: 10 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,16 @@ server:
#
ignore_certs: false

# This is the API key used when the Galaxy API needs to authenticate
# a request. For example, for the POST request made when using the
# 'publish' sub command to upload collection artifacts.
# 'api_key' here is equilivent to the cli '--api-key'
#
# The default value is unset or None.
#
# The API key can be found at https://galaxy.ansible.com/me/preferences
api_key: da39a3ee5e6b4b0d3255bfef95601890afd80709

# When installing content like ansible collection globally (using the '-g/--global' flag),
# mazer will install into sub directories of this path.
#
Expand Down
6 changes: 3 additions & 3 deletions ansible_galaxy/actions/publish.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@

def _publish(galaxy_context,
archive_path,
publish_api_key=None,
display_callback=None):

results = {
Expand All @@ -25,6 +24,8 @@ def _publish(galaxy_context,

api = GalaxyAPI(galaxy_context)

publish_api_key = galaxy_context.server.get('api_key', None)

data = {
'sha256': chksums.sha256sum_from_path(archive_path),
}
Expand Down Expand Up @@ -53,11 +54,10 @@ def _publish(galaxy_context,
return results


def publish(galaxy_context, archive_path, publish_api_key, display_callback):
def publish(galaxy_context, archive_path, display_callback):

results = _publish(galaxy_context,
archive_path,
publish_api_key=publish_api_key,
display_callback=display_callback)

log.debug('cli publish action results: %s', results)
Expand Down
3 changes: 2 additions & 1 deletion ansible_galaxy/config/defaults.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,8 @@ def get_config_path():
DEFAULTS = [
('server',
{'url': 'https://galaxy.ansible.com',
'ignore_certs': False}
'ignore_certs': False,
'api_key': None}
),

# In order of priority
Expand Down
3 changes: 2 additions & 1 deletion ansible_galaxy/models/context.py
Original file line number Diff line number Diff line change
Expand Up @@ -33,7 +33,8 @@ class GalaxyContext(object):

def __init__(self, collections_path=None, server=None):
self.server = server or {'url': None,
'ignore_certs': False}
'ignore_certs': False,
'api_key': None}
self.collections_path = collections_path

def __repr__(self):
Expand Down
4 changes: 3 additions & 1 deletion ansible_galaxy_cli/cli/galaxy.py
Original file line number Diff line number Diff line change
Expand Up @@ -185,6 +185,9 @@ def _get_galaxy_context(self, options, config):
# use ignore certs from options if available, but fallback to configured ignore_certs
server['ignore_certs'] = options.ignore_certs

if getattr(options, 'publish_api_key', None):
server['api_key'] = options.publish_api_key

galaxy_context = GalaxyContext(server=server, collections_path=collections_path)

return galaxy_context
Expand Down Expand Up @@ -296,7 +299,6 @@ def execute_publish(self):

return publish.publish(galaxy_context,
self.args[0],
self.options.publish_api_key,
display_callback=self.display)

def execute_remove(self):
Expand Down
78 changes: 56 additions & 22 deletions tests/ansible_galaxy/actions/test_publish_action.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import logging
import os

import pytest

from ansible_galaxy.actions import publish
from ansible_galaxy.models.context import GalaxyContext

Expand All @@ -11,51 +13,84 @@ def display_callback(msg, **kwargs):
log.debug(msg)


def test_publish(galaxy_context, mocker):
publish_api_key = "doesnt_matter_not_used"
@pytest.fixture
def mock_get_api(requests_mock):
requests_mock.get('http://notreal.invalid:8000/api/',
status_code=200,
json={'current_version': 'v1'})


def test_publish(galaxy_context, mocker):
mocker.patch('ansible_galaxy.actions.publish.GalaxyAPI.publish_file',
return_value={"task": "/api/v2/collection-imports/123456789"})
res = publish.publish(galaxy_context, "/dev/null", publish_api_key, display_callback)
res = publish.publish(galaxy_context, "/dev/null", display_callback)

log.debug('res: %s', res)
assert res == 0


def test__publish(galaxy_context, mocker):
publish_api_key = "doesnt_matter_not_used"
def test__publish(galaxy_context, mock_get_api, requests_mock):
faux_api_key = 'da39a3ee5e6b4b0d3255bfef95601890afd80709'
context = GalaxyContext(collections_path=galaxy_context.collections_path,
server={'url': 'http://notreal.invalid:8000',
'ignore_certs': False,
'api_key': faux_api_key})
log.debug('galaxy_context: %s', context)

mocker.patch('ansible_galaxy.actions.publish.GalaxyAPI.publish_file',
return_value={"task": "/api/v2/collection-imports/8675309"})
res = publish._publish(galaxy_context, "/dev/null", publish_api_key, display_callback)
response_body_202 = {"task": "/api/v2/collection-imports/8675309"}
post_mock = requests_mock.post('http://notreal.invalid:8000/api/v2/collections/',
status_code=202,
json=response_body_202)
res = publish._publish(context, "/dev/null", display_callback)

log.debug('res: %s', res)

assert post_mock.last_request.headers['Authorization'] == 'Token %s' % faux_api_key
assert post_mock.last_request.headers['Content-type'].startswith('multipart/form-data;')

assert res['errors'] == []
assert res['success'] is True
assert res['response_data']['task'] == "/api/v2/collection-imports/8675309"


def test__publish_api_error(galaxy_context, mocker, requests_mock):
publish_api_key = "doesnt_matter_not_used"
def test__publish_api_key_is_none(galaxy_context, mock_get_api, requests_mock):
context = GalaxyContext(collections_path=galaxy_context.collections_path,
server={'url': 'http://notreal.invalid:8000',
'ignore_certs': False,
'api_key': None})
log.debug('galaxy_context: %s', context)

response_body_202 = {}
post_mock = requests_mock.post('http://notreal.invalid:8000/api/v2/collections/',
status_code=202,
json=response_body_202)

publish._publish(context, "/dev/null", display_callback)

assert 'Authorization' not in post_mock.last_request.headers


def test__publish_api_error(galaxy_context, mock_get_api, requests_mock):
faux_api_key = 'da39a3ee5e6b4b0d3255bfef95601890afd80709'
context = GalaxyContext(collections_path=galaxy_context.collections_path,
server={'url': 'http://notreal.invalid:8000',
'ignore_certs': False})
'ignore_certs': False,
'api_key': faux_api_key})
log.debug('galaxy_context: %s', context)

err_409_conflict_json = {'code': 'conflict.collection_exists', 'message': 'Collection "testing-ansible_testing_content-4.0.4" already exists.'}
requests_mock.get('http://notreal.invalid:8000/api/',
status_code=200,
json={'current_version': 'v1'})
post_mock = requests_mock.post('http://notreal.invalid:8000/api/v2/collections/',
status_code=409,
reason='Conflict',
json=err_409_conflict_json)

requests_mock.post('http://notreal.invalid:8000/api/v2/collections/',
status_code=409,
reason='Conflict',
json=err_409_conflict_json)

res = publish._publish(context, "/dev/null", publish_api_key, display_callback)
res = publish._publish(context, "/dev/null", display_callback)

log.debug('res: %s', res)

assert post_mock.last_request.headers['Authorization'] == 'Token %s' % faux_api_key
assert post_mock.last_request.headers['Content-type'].startswith('multipart/form-data;')

assert res['errors'] == ['Error publishing null to http://notreal.invalid:8000/api/v2/collections/ '
+ '- Collection "testing-ansible_testing_content-4.0.4" already exists.']
assert res['success'] is False
Expand All @@ -70,8 +105,7 @@ def test_publish_api_errors(mocker):
mock_display_callback = mocker.Mock()

context = None
publish_api_key = None
res = publish.publish(context, "/dev/null", publish_api_key, mock_display_callback)
res = publish.publish(context, "/dev/null", mock_display_callback)

log.debug('res: %s', res)

Expand Down
1 change: 1 addition & 0 deletions tests/ansible_galaxy/models/test_context.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ def test_context_from_empty_server():
log.debug('server: %s', galaxy_context.server)
assert galaxy_context.server['url'] is None
assert galaxy_context.server['ignore_certs'] is False
assert galaxy_context.server['api_key'] is None


def test_context_server_none_collections_path_none():
Expand Down
4 changes: 3 additions & 1 deletion tests/conftest.py
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,9 @@ def inject_mazer_home(monkeypatch):
def galaxy_context(tmpdir):
# FIXME: mock
server = {'url': 'http://localhost:8000',
'ignore_certs': False}
'ignore_certs': False,
'api_key': None,
}
collections_path = tmpdir.mkdir('collections')

from ansible_galaxy.models.context import GalaxyContext
Expand Down

0 comments on commit d20c0ac

Please sign in to comment.