2015-06-17 14:53:17 +02:00
#!/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
2015-06-17 15:42:18 +02:00
author : Dag Wieers ( @dagwieers ) < dag @wieers.com >
2015-06-17 14:53:17 +02:00
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 :
2015-06-19 17:04:25 +02:00
- " This module ought to be run from a system that can access vCenter directly and has the file to transfer.
It can be the normal remote target or you can change it either by using C ( transport : local ) or using C ( delegate_to ) . "
2015-06-17 14:53:17 +02:00
- 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 ( " / " )
2015-06-29 17:08:48 +02:00
# Due to a software bug in vSphere, it fails to handle ampersand in datacenter names
# The solution is to do what vSphere does (when browsing) and double-encode ampersands, maybe others ?
datacenter = datacenter . replace ( ' & ' , ' % 26 ' )
2015-06-17 14:53:17 +02:00
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 )
2015-06-19 13:30:29 +02:00
auth = base64 . encodestring ( ' %s : %s ' % ( login , password ) ) . rstrip ( )
2015-06-17 14:53:17 +02:00
headers = {
" Content-Type " : " application/octet-stream " ,
" Content-Length " : str ( len ( data ) ) ,
" 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 )
2015-06-30 20:45:53 +02:00
# Import module snippets
from ansible . module_utils . basic import *
2015-06-17 14:53:17 +02:00
main ( )