1 # -*- coding: utf-8 -*-
4 # Copyright 2016-2017 VMware Inc.
5 # This file is part of ETSI OSM
8 # Licensed under the Apache License, Version 2.0 (the "License"); you may
9 # not use this file except in compliance with the License. You may obtain
10 # a copy of the License at
12 # http://www.apache.org/licenses/LICENSE-2.0
14 # Unless required by applicable law or agreed to in writing, software
15 # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
16 # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
17 # License for the specific language governing permissions and limitations
20 # For those usages not covered by the Apache License, Version 2.0 please
21 # contact: osslegalrouting@vmware.com
25 from pyvcloud
.vcloudair
import VCA
26 from pyvcloud
import Http
27 from xml
.etree
import ElementTree
as XmlElementTree
28 from pyvcloud
.schema
.vcd
.v1_5
.schemas
.vcloud
import mediaType
36 STANDALONE
= 'standalone'
39 class vCloudconfig(object):
40 def __init__(self
, host
=None, user
=None, password
=None,orgname
=None, logger
=None):
43 self
.password
= password
48 """ Method connect as normal user to vCloud director.
51 The return vca object that letter can be used to connect to vCloud director as admin for VDC
55 self
.logger
.debug("Logging in to a vca {} as {} to datacenter {}.".format(self
.org
,
58 vca
= VCA(host
=self
.url
,
60 service_type
=STANDALONE
,
65 result
= vca
.login(password
=self
.password
, org
=self
.org
)
67 raise vimconn
.vimconnConnectionException("Can't connect to a vCloud director as: {}".format(self
.user
))
68 result
= vca
.login(token
=vca
.token
, org
=self
.org
, org_url
=vca
.vcloud_session
.org_url
)
71 "Successfully logged to a vcloud direct org: {} as user: {}".format(self
.org
, self
.user
))
74 raise vimconn
.vimconnConnectionException("Can't connect to a vCloud director org: "
75 "{} as user: {}".format(self
.org
, self
.user
))
79 def upload_ovf(self
, catalog_name
=None, image_name
=None, media_file_name
=None,
80 description
='', progress
=False, chunk_bytes
=128 * 1024):
82 Uploads a OVF file to a vCloud catalog
84 catalog_name: (str): The name of the catalog to upload the media.
85 media_file_name: (str): The name of the local media file to upload.
86 return: (bool) True if the media file was successfully uploaded, false otherwise.
90 # Creating new catalog in vCD
91 task
= vca
.create_catalog(catalog_name
, catalog_name
)
92 result
= vca
.block_until_completed(task
)
96 os
.path
.isfile(media_file_name
)
97 statinfo
= os
.stat(media_file_name
)
100 # find a catalog entry where we upload OVF.
101 # create vApp Template and check the status if vCD able to read OVF it will respond with appropirate
103 # if VCD can parse OVF we upload VMDK file
105 for catalog
in vca
.get_catalogs():
106 if catalog_name
!= catalog
.name
:
108 link
= filter(lambda link
: link
.get_type() == "application/vnd.vmware.vcloud.media+xml" and
109 link
.get_rel() == 'add', catalog
.get_Link())
110 assert len(link
) == 1
112 <UploadVAppTemplateParams name="{}" xmlns="http://www.vmware.com/vcloud/v1.5" xmlns:ovf="http://schemas.dmtf.org/ovf/envelope/1"><Description>{} vApp Template</Description></UploadVAppTemplateParams>
113 """.format(catalog_name
, catalog_name
)
114 headers
= vca
.vcloud_session
.get_vcloud_headers()
115 headers
['Content-Type'] = 'application/vnd.vmware.vcloud.uploadVAppTemplateParams+xml'
116 response
= Http
.post(link
[0].get_href(), headers
=headers
, data
=data
, verify
=vca
.verify
, logger
=self
.logger
)
117 if response
.status_code
== requests
.codes
.created
:
118 catalogItem
= XmlElementTree
.fromstring(response
.content
)
119 entity
= [child
for child
in catalogItem
if
120 child
.get("type") == "application/vnd.vmware.vcloud.vAppTemplate+xml"][0]
121 href
= entity
.get('href')
123 response
= Http
.get(href
, headers
=vca
.vcloud_session
.get_vcloud_headers(),
124 verify
=vca
.verify
, logger
=self
.logger
)
126 if response
.status_code
== requests
.codes
.ok
:
127 media
= mediaType
.parseString(response
.content
, True)
128 link
= filter(lambda link
: link
.get_rel() == 'upload:default',
129 media
.get_Files().get_File()[0].get_Link())[0]
130 headers
= vca
.vcloud_session
.get_vcloud_headers()
131 headers
['Content-Type'] = 'Content-Type text/xml'
132 response
= Http
.put(link
.get_href(),
133 data
=open(media_file_name
, 'rb'),
135 verify
=vca
.verify
, logger
=self
.logger
)
136 if response
.status_code
!= requests
.codes
.ok
:
138 "Failed create vApp template for catalog name {} and image {}".format(catalog_name
,
142 # TODO fix this with aync block
145 self
.logger
.debug("vApp template for catalog name {} and image {}".format(catalog_name
, media_file_name
))
147 # uploading VMDK file
148 # check status of OVF upload and upload remaining files.
149 response
= Http
.get(template
,
150 headers
=vca
.vcloud_session
.get_vcloud_headers(),
154 if response
.status_code
== requests
.codes
.ok
:
155 media
= mediaType
.parseString(response
.content
, True)
156 number_of_files
= len(media
.get_Files().get_File())
157 for index
in xrange(0, number_of_files
):
158 links_list
= filter(lambda link
: link
.get_rel() == 'upload:default',
159 media
.get_Files().get_File()[index
].get_Link())
160 for link
in links_list
:
161 # we skip ovf since it already uploaded.
162 if 'ovf' in link
.get_href():
164 # The OVF file and VMDK must be in a same directory
165 head
, tail
= os
.path
.split(media_file_name
)
166 file_vmdk
= head
+ '/' + link
.get_href().split("/")[-1]
167 if not os
.path
.isfile(file_vmdk
):
169 statinfo
= os
.stat(file_vmdk
)
170 if statinfo
.st_size
== 0:
172 hrefvmdk
= link
.get_href()
175 print("Uploading file: {}".format(file_vmdk
))
177 widgets
= ['Uploading file: ', Percentage(), ' ', Bar(), ' ', ETA(), ' ',
179 progress_bar
= ProgressBar(widgets
=widgets
, maxval
=statinfo
.st_size
).start()
181 bytes_transferred
= 0
182 f
= open(file_vmdk
, 'rb')
183 while bytes_transferred
< statinfo
.st_size
:
184 my_bytes
= f
.read(chunk_bytes
)
185 if len(my_bytes
) <= chunk_bytes
:
186 headers
= vca
.vcloud_session
.get_vcloud_headers()
187 headers
['Content-Range'] = 'bytes %s-%s/%s' % (
188 bytes_transferred
, len(my_bytes
) - 1, statinfo
.st_size
)
189 headers
['Content-Length'] = str(len(my_bytes
))
190 response
= Http
.put(hrefvmdk
,
196 if response
.status_code
== requests
.codes
.ok
:
197 bytes_transferred
+= len(my_bytes
)
199 progress_bar
.update(bytes_transferred
)
202 'file upload failed with error: [%s] %s' % (response
.status_code
,
209 progress_bar
.finish()
211 self
.logger
.debug("OVF image sucessfully uploaded to the VMware vCloud Director")
214 self
.logger
.debug("Failed retrieve vApp template for catalog name {} for OVF {}".
215 format(catalog_name
, media_file_name
))
217 except Exception as exp
:
218 self
.logger
.debug("Failed while uploading OVF to catalog {} for OVF file {} with Exception {}"
219 .format(catalog_name
,media_file_name
, exp
))
220 raise Exception("Failed while uploading OVF to catalog {} for OVF file {} with Exception {}" \
221 .format(catalog_name
,media_file_name
, exp
))
224 if __name__
== "__main__":
226 # vmware vcloud director credentials
227 vcd_hostname
= sys
.argv
[1]
228 vcd_username
= sys
.argv
[2]
229 vcd_password
= sys
.argv
[3]
230 orgname
= sys
.argv
[4]
231 # OVF image path to be upload to vCD
232 ovf_file_path
= sys
.argv
[5]
234 # changing virtual system type in ovf file
235 fh
= open(ovf_file_path
,'r')
237 content
= content
.replace('<vssd:VirtualSystemType>vmx-7','<vssd:VirtualSystemType>vmx-07')
239 fh1
= open(ovf_file_path
,'w')
244 logging
.basicConfig(filename
='ovf_upload.log',level
=logging
.DEBUG
)
245 logger
= logging
.getLogger(__name__
)
247 obj
= vCloudconfig(vcd_hostname
, vcd_username
, vcd_password
, orgname
, logger
)
249 dirpath
, filename
= os
.path
.split(ovf_file_path
)
250 filename_name
, file_extension
= os
.path
.splitext(filename
)
252 # Get image name from cirros vnfd
253 cirros_yaml
= '../descriptor-packages/vnfd/cirros_vnf/src/cirros_vnfd.yaml'
254 rh
= open(cirros_yaml
,'r')
255 match
= re
.search("image:\s'(.*?)'\n",rh
.read())
256 if match
: catalog
= match
.group(1)
259 if file_extension
== '.ovf':
260 result
= obj
.upload_ovf(catalog_name
=catalog
, image_name
='linux',
261 media_file_name
=ovf_file_path
,
262 description
='', progress
=False,
263 chunk_bytes
=128 * 1024)