kolla-ansible/ansible/library/bslurp.py

216 lines
6.0 KiB
Python

#!/usr/bin/env python
# Copyright 2015 Sam Yaple
#
# 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.
# This module has been relicensed from the source below:
# https://github.com/SamYaple/yaodu/blob/master/ansible/library/bslurp
import base64
import hashlib
import os
import traceback
import zlib
from ansible.module_utils.basic import AnsibleModule
DOCUMENTATION = '''
---
module: bslurp
short_description: Slurps a file from a remote node
description:
- Used for fetching a binary blob containing the file, then push that file
to other hosts.
options:
src:
description:
- File to fetch. When dest is used, src is expected to be a str with data
required: True
type: str
compress:
description:
- Compress file with zlib
default: True
type: bool
dest:
description:
- Where to write out binary blob
required: False
type: str
mode:
description:
- Destination file permissions
default: '0644'
type: str
sha1:
description:
- sha1 hash of the underlying data
default: None
type: bool
sha256:
description:
- sha256 hash of the underlying data
default: None
type: bool
author: Sam Yaple
'''
EXAMPLES = '''
Distribute a file from single to many hosts:
- hosts: web_servers
tasks:
- name: Pull in web config
bslurp: src="/path/to/file"
register: file_data
run_once: True
- name: Push if changed
bslurp:
src: "{{ file_data.content }}"
dest: "{{ file_data.source }}"
mode: "{{ file_data.mode }}"
sha1: "{{ file_data.sha1 }}"
Distribute multiple files from single to many hosts:
- hosts: web_servers
tasks:
- name: Pull in web config
bslurp: src="{{ item }}"
with_items:
- "/path/to/file1"
- "/path/to/file2"
- "/path/to/file3"
register: file_data
run_once: True
- name: Push if changed
bslurp:
src: "{{ item.content }}"
dest: "{{ item.source }}"
mode: "{{ item.mode }}"
sha1: "{{ item.sha1 }}"
with_items: file_data.results
Distribute a file to many hosts without compression; Change
permissions on dest:
- hosts: web_servers
tasks:
- name: Pull in web config
bslurp: src="/path/to/file"
register: file_data
run_once: True
- name: Push if changed
bslurp:
src: "{{ file_data.content }}"
dest: "/new/path/to/file"
mode: "0777"
compress: False
sha1: "{{ file_data.sha1 }}"
'''
def copy_from_host(module):
compress = module.params.get('compress')
src = module.params.get('src')
if not os.path.exists(src):
module.fail_json(msg="file not found: {}".format(src))
if not os.access(src, os.R_OK):
module.fail_json(msg="file is not readable: {}".format(src))
mode = oct(os.stat(src).st_mode & 0o777)
with open(src, 'rb') as f:
raw_data = f.read()
sha1 = hashlib.sha1(raw_data).hexdigest()
sha256 = hashlib.sha256(raw_data).hexdigest()
data = zlib.compress(raw_data) if compress else raw_data
module.exit_json(content=base64.b64encode(data), sha1=sha1, sha256=sha256,
mode=mode, source=src)
def copy_to_host(module):
compress = module.params.get('compress')
dest = module.params.get('dest')
mode = int(module.params.get('mode'), 0)
sha1 = module.params.get('sha1')
sha256 = module.params.get('sha256')
src = module.params.get('src')
data = base64.b64decode(src)
raw_data = zlib.decompress(data) if compress else data
if sha256:
if os.path.exists(dest):
if os.access(dest, os.R_OK):
with open(dest, 'rb') as f:
if hashlib.sha256(f.read()).hexdigest() == sha256:
module.exit_json(changed=False)
else:
module.exit_json(failed=True, changed=False,
msg='file is not accessible: {}'.format(dest))
if sha256 != hashlib.sha256(raw_data).hexdigest():
module.exit_json(failed=True, changed=False,
msg='sha256 sum does not match data')
elif sha1:
if os.path.exists(dest):
if os.access(dest, os.R_OK):
with open(dest, 'rb') as f:
if hashlib.sha1(f.read()).hexdigest() == sha1:
module.exit_json(changed=False)
else:
module.exit_json(failed=True, changed=False,
msg='file is not accessible: {}'.format(dest))
if sha1 != hashlib.sha1(raw_data).hexdigest():
module.exit_json(failed=True, changed=False,
msg='sha1 sum does not match data')
with os.fdopen(os.open(dest, os.O_WRONLY | os.O_CREAT, mode), 'wb') as f:
f.write(raw_data)
module.exit_json(changed=True)
def main():
argument_spec = dict(
compress=dict(default=True, type='bool'),
dest=dict(type='str'),
mode=dict(default='0644', type='str'),
sha1=dict(default=None, type='str'),
sha256=dict(default=None, type='str'),
src=dict(required=True, type='str')
)
module = AnsibleModule(argument_spec)
dest = module.params.get('dest')
try:
if dest:
copy_to_host(module)
else:
copy_from_host(module)
except Exception:
module.exit_json(failed=True, changed=True,
msg=repr(traceback.format_exc()))
if __name__ == '__main__':
main()