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…
x
Reference in New Issue
Block a user