New module to copy (push) files to a vCenter datastore
This commit is contained in:
parent
7108b77c17
commit
330e66327a
1 changed files with 152 additions and 0 deletions
152
cloud/vmware/vsphere_copy
Normal file
152
cloud/vmware/vsphere_copy
Normal file
|
@ -0,0 +1,152 @@
|
|||
#!/usr/bin/python
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
# Copyright 2015 Dag Wieers <dag@wieers.com>
|
||||
#
|
||||
# This file is part of Ansible
|
||||
#
|
||||
# Ansible is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU General Public License as published by
|
||||
# the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# Ansible is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with Ansible. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
DOCUMENTATION = '''
|
||||
---
|
||||
module: vsphere_copy
|
||||
short_description: Copy a file to a vCenter datastore
|
||||
description: Upload files to a vCenter datastore
|
||||
version_added: 2.0
|
||||
author: Dag Wieers <dag@wieers.com>
|
||||
options:
|
||||
host:
|
||||
description:
|
||||
- The vCenter server on which the datastore is available.
|
||||
required: true
|
||||
login:
|
||||
description:
|
||||
- The login name to authenticate on the vCenter server.
|
||||
required: true
|
||||
password:
|
||||
description:
|
||||
- The password to authenticate on the vCenter server.
|
||||
required: true
|
||||
src:
|
||||
description:
|
||||
- The file to push to vCenter
|
||||
required: true
|
||||
datacenter:
|
||||
description:
|
||||
- The datacenter on the vCenter server that holds the datastore.
|
||||
required: true
|
||||
datastore:
|
||||
description:
|
||||
- The datastore on the vCenter server to push files to.
|
||||
required: true
|
||||
path:
|
||||
description:
|
||||
- The file to push to the datastore on the vCenter server.
|
||||
required: true
|
||||
notes:
|
||||
- This module ought to be run from a system that can access vCenter directly.
|
||||
Either by using C(transport: local), or using C(delegate_to).
|
||||
- Tested on vSphere 5.5
|
||||
'''
|
||||
|
||||
EXAMPLES = '''
|
||||
- vsphere_copy: host=vhost login=vuser password=vpass src=/some/local/file datacenter='DC1 Someplace' datastore=datastore1 path=some/remote/file
|
||||
transport: local
|
||||
- vsphere_copy: host=vhost login=vuser password=vpass src=/other/local/file datacenter='DC2 Someplace' datastore=datastore2 path=other/remote/file
|
||||
delegate_to: other_system
|
||||
'''
|
||||
|
||||
import atexit
|
||||
import base64
|
||||
import httplib
|
||||
import urllib
|
||||
import mmap
|
||||
import errno
|
||||
import socket
|
||||
|
||||
def vmware_path(datastore, datacenter, path):
|
||||
''' Constructs a URL path that VSphere accepts reliably '''
|
||||
path = "/folder/%s" % path.lstrip("/")
|
||||
if not path.startswith("/"):
|
||||
path = "/" + path
|
||||
params = dict( dsName = datastore )
|
||||
if datacenter:
|
||||
params["dcPath"] = datacenter
|
||||
params = urllib.urlencode(params)
|
||||
return "%s?%s" % (path, params)
|
||||
|
||||
def main():
|
||||
|
||||
module = AnsibleModule(
|
||||
argument_spec = dict(
|
||||
host = dict(required=True, aliases=[ 'hostname' ]),
|
||||
login = dict(required=True, aliases=[ 'username' ]),
|
||||
password = dict(required=True),
|
||||
src = dict(required=True, aliases=[ 'name' ]),
|
||||
datacenter = dict(required=True),
|
||||
datastore = dict(required=True),
|
||||
dest = dict(required=True, aliases=[ 'path' ]),
|
||||
),
|
||||
# Implementing check-mode using HEAD is impossible, since size/date is not 100% reliable
|
||||
supports_check_mode = False,
|
||||
)
|
||||
|
||||
host = module.params.get('host')
|
||||
login = module.params.get('login')
|
||||
password = module.params.get('password')
|
||||
src = module.params.get('src')
|
||||
datacenter = module.params.get('datacenter')
|
||||
datastore = module.params.get('datastore')
|
||||
dest = module.params.get('dest')
|
||||
|
||||
fd = open(src, "rb")
|
||||
atexit.register(fd.close)
|
||||
|
||||
data = mmap.mmap(fd.fileno(), 0, access=mmap.ACCESS_READ)
|
||||
atexit.register(data.close)
|
||||
|
||||
conn = httplib.HTTPSConnection(host)
|
||||
atexit.register(conn.close)
|
||||
|
||||
remote_path = vmware_path(datastore, datacenter, dest)
|
||||
auth = base64.encodestring('%s:%s' % (login, password))
|
||||
headers = {
|
||||
"Content-Type": "application/octet-stream",
|
||||
"Content-Length": str(len(data)),
|
||||
"Accept": "text/plain",
|
||||
"Authorization": "Basic %s" % auth,
|
||||
}
|
||||
|
||||
# URL is only used in JSON output (helps troubleshooting)
|
||||
url = 'https://%s%s' % (host, remote_path)
|
||||
|
||||
try:
|
||||
conn.request("PUT", remote_path, body=data, headers=headers)
|
||||
except socket.error, e:
|
||||
if isinstance(e.args, tuple) and e[0] == errno.ECONNRESET:
|
||||
# VSphere resets connection if the file is in use and cannot be replaced
|
||||
module.fail_json(msg='Failed to upload, image probably in use', status=e[0], reason=str(e), url=url)
|
||||
else:
|
||||
module.fail_json(msg=str(e), status=e[0], reason=str(e), url=url)
|
||||
|
||||
resp = conn.getresponse()
|
||||
|
||||
if resp.status in range(200, 300):
|
||||
module.exit_json(changed=True, status=resp.status, reason=resp.reason, url=url)
|
||||
else:
|
||||
module.fail_json(msg='Failed to upload', status=resp.status, reason=resp.reason, length=resp.length, version=resp.version, headers=resp.getheaders(), chunked=resp.chunked, url=url)
|
||||
|
||||
# this is magic, see lib/ansible/module_common.py
|
||||
#<<INCLUDE_ANSIBLE_MODULE_COMMON>>
|
||||
main()
|
Loading…
Reference in a new issue