Merge "Add releasefive build"
[osm/devops.git] / tools / vmware_ovf_upload.py
1 # -*- coding: utf-8 -*-
2
3 ##
4 # Copyright 2016-2017 VMware Inc.
5 # This file is part of ETSI OSM
6 # All Rights Reserved.
7 #
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
11 #
12 # http://www.apache.org/licenses/LICENSE-2.0
13 #
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
18 # under the License.
19 #
20 # For those usages not covered by the Apache License, Version 2.0 please
21 # contact: osslegalrouting@vmware.com
22 ##
23
24
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
29 import sys,os
30 import logging
31 import requests
32 import time
33 import re
34
35
36 STANDALONE = 'standalone'
37 VCAVERSION = '5.9'
38
39 class vCloudconfig(object):
40 def __init__(self, host=None, user=None, password=None,orgname=None, logger=None):
41 self.url = host
42 self.user = user
43 self.password = password
44 self.org = orgname
45 self.logger = logger
46
47 def connect(self):
48 """ Method connect as normal user to vCloud director.
49
50 Returns:
51 The return vca object that letter can be used to connect to vCloud director as admin for VDC
52 """
53
54 try:
55 self.logger.debug("Logging in to a vca {} as {} to datacenter {}.".format(self.org,
56 self.user,
57 self.org))
58 vca = VCA(host=self.url,
59 username=self.user,
60 service_type=STANDALONE,
61 version=VCAVERSION,
62 verify=False,
63 log=False)
64
65 result = vca.login(password=self.password, org=self.org)
66 if not result:
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)
69 if result is True:
70 self.logger.info(
71 "Successfully logged to a vcloud direct org: {} as user: {}".format(self.org, self.user))
72
73 except:
74 raise vimconn.vimconnConnectionException("Can't connect to a vCloud director org: "
75 "{} as user: {}".format(self.org, self.user))
76
77 return vca
78
79 def upload_ovf(self, catalog_name=None, image_name=None, media_file_name=None,
80 description='', progress=False, chunk_bytes=128 * 1024):
81 """
82 Uploads a OVF file to a vCloud catalog
83
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.
87 """
88 vca = self.connect()
89
90 # Creating new catalog in vCD
91 task = vca.create_catalog(catalog_name, catalog_name)
92 result = vca.block_until_completed(task)
93 if not result:
94 return False
95
96 os.path.isfile(media_file_name)
97 statinfo = os.stat(media_file_name)
98
99
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
102 # status change.
103 # if VCD can parse OVF we upload VMDK file
104 try:
105 for catalog in vca.get_catalogs():
106 if catalog_name != catalog.name:
107 continue
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
111 data = """
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')
122 template = href
123 response = Http.get(href, headers=vca.vcloud_session.get_vcloud_headers(),
124 verify=vca.verify, logger=self.logger)
125
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'),
134 headers=headers,
135 verify=vca.verify, logger=self.logger)
136 if response.status_code != requests.codes.ok:
137 self.logger.debug(
138 "Failed create vApp template for catalog name {} and image {}".format(catalog_name,
139 media_file_name))
140 return False
141
142 # TODO fix this with aync block
143 time.sleep(5)
144
145 self.logger.debug("vApp template for catalog name {} and image {}".format(catalog_name, media_file_name))
146
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(),
151 verify=vca.verify,
152 logger=self.logger)
153
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():
163 continue
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):
168 return False
169 statinfo = os.stat(file_vmdk)
170 if statinfo.st_size == 0:
171 return False
172 hrefvmdk = link.get_href()
173
174 if progress:
175 print("Uploading file: {}".format(file_vmdk))
176 if progress:
177 widgets = ['Uploading file: ', Percentage(), ' ', Bar(), ' ', ETA(), ' ',
178 FileTransferSpeed()]
179 progress_bar = ProgressBar(widgets=widgets, maxval=statinfo.st_size).start()
180
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,
191 headers=headers,
192 data=my_bytes,
193 verify=vca.verify,
194 logger=None)
195
196 if response.status_code == requests.codes.ok:
197 bytes_transferred += len(my_bytes)
198 if progress:
199 progress_bar.update(bytes_transferred)
200 else:
201 self.logger.debug(
202 'file upload failed with error: [%s] %s' % (response.status_code,
203 response.content))
204
205 f.close()
206 return False
207 f.close()
208 if progress:
209 progress_bar.finish()
210 time.sleep(15)
211 self.logger.debug("OVF image sucessfully uploaded to the VMware vCloud Director")
212 return True
213 else:
214 self.logger.debug("Failed retrieve vApp template for catalog name {} for OVF {}".
215 format(catalog_name, media_file_name))
216 return False
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))
222
223
224 if __name__ == "__main__":
225
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]
233
234 # changing virtual system type in ovf file
235 fh = open(ovf_file_path,'r')
236 content = fh.read()
237 content = content.replace('<vssd:VirtualSystemType>vmx-7','<vssd:VirtualSystemType>vmx-07')
238 fh.close()
239 fh1 = open(ovf_file_path,'w')
240 fh1.write(content)
241 fh1.close()
242
243
244 logging.basicConfig(filename='ovf_upload.log',level=logging.DEBUG)
245 logger = logging.getLogger(__name__)
246
247 obj = vCloudconfig(vcd_hostname, vcd_username, vcd_password, orgname, logger)
248
249 dirpath, filename = os.path.split(ovf_file_path)
250 filename_name, file_extension = os.path.splitext(filename)
251
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)
257
258
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)
264