Rework upload-forge role to use module
Renames the role to upload-forge because you can actually run your own Forge server if you want. This patch adds a custom module to the upload-forge role that provides the "forge_upload" module. This directly interacts with the a Forge API to upload the module. The only dependency is that the python requests module is installed. Change-Id: I5749364bd2c29ad6df866c2bd5a3584c8419f709
This commit is contained in:
parent
dd8c88354e
commit
a9322c04b6
24
roles/upload-forge/README.rst
Normal file
24
roles/upload-forge/README.rst
Normal file
@ -0,0 +1,24 @@
|
||||
Upload puppet module tarball to a Forge server
|
||||
|
||||
This role requires the python requests module to be
|
||||
installed where Ansible is executing this role.
|
||||
|
||||
**Role Variables**
|
||||
|
||||
.. zuul:rolevar:: forge_url
|
||||
:default: https://forgeapi.puppet.com
|
||||
|
||||
The URL to the Puppet Forge API.
|
||||
|
||||
.. zuul:rolevar:: forge_username
|
||||
|
||||
Username to use to log in to Puppet Forge.
|
||||
|
||||
.. zuul:rolevar:: forge_password
|
||||
|
||||
Password to use to log in to Puppet Forge.
|
||||
|
||||
.. zuul:rolevar:: forge_tarball
|
||||
|
||||
Absolute path to the module tarball that should be
|
||||
uploaded.
|
0
roles/upload-forge/__init__.py
Normal file
0
roles/upload-forge/__init__.py
Normal file
2
roles/upload-forge/defaults/main.yaml
Normal file
2
roles/upload-forge/defaults/main.yaml
Normal file
@ -0,0 +1,2 @@
|
||||
---
|
||||
forge_url: "https://forgeapi.puppet.com"
|
0
roles/upload-forge/library/__init__.py
Normal file
0
roles/upload-forge/library/__init__.py
Normal file
182
roles/upload-forge/library/forge_upload.py
Normal file
182
roles/upload-forge/library/forge_upload.py
Normal file
@ -0,0 +1,182 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
# Copyright (c) 2019 Binero
|
||||
# Author: Tobias Urdin <tobias.urdin@binero.se>
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
|
||||
ANSIBLE_METADATA = {
|
||||
'metadata_version': '1.0',
|
||||
'status': ['preview'],
|
||||
'supported_by': 'community'
|
||||
}
|
||||
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: forge_upload
|
||||
|
||||
short_description: Uploads a puppet module tarball to a Forge server.
|
||||
|
||||
description:
|
||||
- "Uploads a puppet module tarball to a Forge server."
|
||||
|
||||
options:
|
||||
username:
|
||||
description:
|
||||
- The username to the Forge account
|
||||
required: true
|
||||
password:
|
||||
description:
|
||||
- The password to the Forge account
|
||||
required: true
|
||||
tarball:
|
||||
description:
|
||||
- The absolute path to the tarball of the puppet module
|
||||
that should be uploaded
|
||||
required: true
|
||||
forgeapi:
|
||||
description:
|
||||
- This base url to the Forge server API, defaults to
|
||||
https://forgeapi.puppet.com
|
||||
required: false
|
||||
|
||||
author:
|
||||
- Tobias Urdin (@tobias-urdin)
|
||||
'''
|
||||
|
||||
|
||||
EXAMPLES = '''
|
||||
- name: Upload module
|
||||
forge_upload:
|
||||
username: 'myuser'
|
||||
password: 'mypass'
|
||||
tarball: '/home/myuser/test/pkg/myuser-test-0.1.0.tar.gz'
|
||||
'''
|
||||
|
||||
|
||||
RETURN = '''
|
||||
msg:
|
||||
description: The output message from the module.
|
||||
'''
|
||||
|
||||
|
||||
from ansible.module_utils.basic import AnsibleModule # noqa
|
||||
import os # noqa
|
||||
import requests # noqa
|
||||
|
||||
|
||||
# Client ID and secret from puppet-blacksmith
|
||||
CLIENT_ID = 'b93eb708fd942cfc7b4ed71db6ce219b814954619dbe537ddfd208584e8cff8d'
|
||||
CLIENT_SECRET = '216648059ad4afec3e4d77bd9e67817c095b2dcf94cdec18ac3d00584f863180' # noqa
|
||||
|
||||
FORGEAPI = 'https://forgeapi.puppet.com'
|
||||
|
||||
|
||||
def _get_url(forgeapi, path):
|
||||
path = path[1:] if path.startswith('/') else path
|
||||
return '%s/%s' % (forgeapi, path)
|
||||
|
||||
|
||||
def _forge_auth(forgeapi, username, password):
|
||||
url = _get_url(forgeapi, '/oauth/token')
|
||||
data = {
|
||||
'client_id': CLIENT_ID,
|
||||
'client_secret': CLIENT_SECRET,
|
||||
'username': username,
|
||||
'password': password,
|
||||
'grant_type': 'password',
|
||||
}
|
||||
headers = {
|
||||
'User-Agent': 'forge_upload-ansible-module/1.0',
|
||||
}
|
||||
response = requests.post(url, json=data, headers=headers)
|
||||
return response
|
||||
|
||||
|
||||
def _forge_upload(forgeapi, token, tarball):
|
||||
url = _get_url(forgeapi, '/v2/releases')
|
||||
data = {
|
||||
'file': open(tarball, 'rb').read(),
|
||||
}
|
||||
headers = {
|
||||
'User-Agent': 'forge_upload-ansible-module/1.0',
|
||||
'Authorization': 'Bearer %s' % token,
|
||||
}
|
||||
response = requests.post(url, files=data, headers=headers)
|
||||
return response
|
||||
|
||||
|
||||
def run_module():
|
||||
module_args = dict(
|
||||
username=dict(type='str', required=True),
|
||||
password=dict(type='str', required=True, no_log=True),
|
||||
tarball=dict(type='str', required=True),
|
||||
forgeapi=dict(type='str', default=FORGEAPI),
|
||||
)
|
||||
|
||||
result = dict(
|
||||
changed=False,
|
||||
)
|
||||
|
||||
module = AnsibleModule(
|
||||
argument_spec=module_args,
|
||||
supports_check_mode=True
|
||||
)
|
||||
|
||||
tarball = module.params['tarball']
|
||||
if os.path.exists(tarball) is False:
|
||||
module.fail_json(msg='Tarball %s does not exist' % tarball, **result)
|
||||
|
||||
resp = _forge_auth(module.params['forgeapi'],
|
||||
module.params['username'],
|
||||
module.params['password'])
|
||||
|
||||
if resp.status_code != 200:
|
||||
msg = 'Forge API auth failed with code: %d' % resp.status_code
|
||||
module.fail_json(msg=msg, **result)
|
||||
|
||||
if module.check_mode:
|
||||
return result
|
||||
|
||||
auth = resp.json()
|
||||
token = auth['access_token']
|
||||
|
||||
resp = _forge_upload(module.params['forgeapi'], token, tarball)
|
||||
|
||||
if resp.status_code == 409:
|
||||
msg = 'Module %s already exists on Forge' % tarball
|
||||
module.exit_json(msg=msg, **result)
|
||||
|
||||
if resp.status_code != 201:
|
||||
try:
|
||||
data = resp.json()
|
||||
errors = ','.join(data['errors'])
|
||||
except Exception:
|
||||
errors = 'unknown'
|
||||
msg = 'Forge API failed to upload tarball with code: %d errors: %s' % (
|
||||
resp.status_code, errors)
|
||||
module.fail_json(msg=msg, **result)
|
||||
|
||||
result['changed'] = True
|
||||
module.exit_json(msg='Successfully uploaded tarball %s' % tarball,
|
||||
**result)
|
||||
|
||||
|
||||
def main():
|
||||
run_module()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
28
roles/upload-forge/library/test_forge_upload.py
Normal file
28
roles/upload-forge/library/test_forge_upload.py
Normal file
@ -0,0 +1,28 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
# Copyright (c) 2019 Binero
|
||||
# Author: Tobias Urdin <tobias.urdin@binero.se>
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
|
||||
import testtools
|
||||
from .forge_upload import _get_url
|
||||
|
||||
|
||||
class TestForgeUpload(testtools.TestCase):
|
||||
def test_get_url(self):
|
||||
base_url = 'https://forgeapi.puppet.com'
|
||||
expected = 'https://forgeapi.puppet.com/test'
|
||||
self.assertEqual(_get_url(base_url, '/test'), expected)
|
||||
self.assertEqual(_get_url(base_url, 'test'), expected)
|
13
roles/upload-forge/tasks/main.yaml
Normal file
13
roles/upload-forge/tasks/main.yaml
Normal file
@ -0,0 +1,13 @@
|
||||
- name: Check required variables
|
||||
assert:
|
||||
that:
|
||||
- "forge_username is defined"
|
||||
- "forge_password is defined"
|
||||
- "forge_tarball is defined"
|
||||
|
||||
- name: Upload module to Forge
|
||||
forge_upload:
|
||||
username: "{{ forge_username }}"
|
||||
password: "{{ forge_password }}"
|
||||
tarball: "{{ forge_tarball }}"
|
||||
forgeapi: "{{ forge_url }}"
|
@ -1,22 +0,0 @@
|
||||
Upload puppet module to Puppet Forge
|
||||
|
||||
**Role Variables**
|
||||
|
||||
.. zuul:rolevar:: puppet_module_dir
|
||||
:default: {{ zuul.project.src_dir }}
|
||||
|
||||
The folder where the puppet module code is that it can
|
||||
switch folder to.
|
||||
|
||||
.. zuul:rolevar:: blacksmith_forge_url
|
||||
:default: https://forgeapi.puppetlabs.com
|
||||
|
||||
The URL to the Puppet Forge API.
|
||||
|
||||
.. zuul:rolevar:: blacksmith_forge_username
|
||||
|
||||
Username to use to log in to Puppet Forge.
|
||||
|
||||
.. zuul:rolevar:: blacksmith_forge_password
|
||||
|
||||
Password to use to log in to Puppet Forge.
|
@ -1,3 +0,0 @@
|
||||
---
|
||||
puppet_module_dir: "{{ zuul.project.src_dir }}"
|
||||
blacksmith_forge_url: "https://forgeapi.puppetlabs.com"
|
@ -1,52 +0,0 @@
|
||||
- name: Install ruby dependencies on RedHat/Suse based
|
||||
package:
|
||||
name:
|
||||
- ruby-devel
|
||||
- gcc-c++
|
||||
- make
|
||||
state: present
|
||||
become: yes
|
||||
when: ansible_os_family == "RedHat" or ansible_os_family == "Suse"
|
||||
|
||||
- name: Install ruby dependencies on Debian based
|
||||
package:
|
||||
name:
|
||||
- ruby-dev
|
||||
- g++
|
||||
- make
|
||||
state: present
|
||||
become: yes
|
||||
when: ansible_os_family == "Debian"
|
||||
|
||||
- name: Install required gems
|
||||
gem:
|
||||
name: "{{ item }}"
|
||||
user_install: no
|
||||
with_items:
|
||||
- rake
|
||||
- puppetlabs_spec_helper
|
||||
- puppet-blacksmith
|
||||
become: yes
|
||||
|
||||
# NOTE(tobias.urdin): The build task is needed because puppet-blacksmith
|
||||
# doesn't provide a build task so it fails, we don't need one anyway since
|
||||
# we have already built the module before this role is called.
|
||||
- name: Install new Rakefile
|
||||
copy:
|
||||
content: |
|
||||
namespace 'module' do
|
||||
task 'build' do
|
||||
end
|
||||
end
|
||||
|
||||
require 'puppet_blacksmith/rake_tasks'
|
||||
dest: "{{ puppet_module_dir }}/Rakefile"
|
||||
|
||||
- name: Publish puppet module
|
||||
command: "rake module:push"
|
||||
args:
|
||||
chdir: "{{ puppet_module_dir }}"
|
||||
environment:
|
||||
BLACKSMITH_FORGE_URL: "{{ blacksmith_forge_url }}"
|
||||
BLACKSMITH_FORGE_USERNAME: "{{ blacksmith_forge_username }}"
|
||||
BLACKSMITH_FORGE_PASSWORD: "{{ blacksmith_forge_password }}"
|
Loading…
Reference in New Issue
Block a user