Add integration between pol and mysql charms
[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 import logging
25 import os
26 from progressbar import Percentage, Bar, ETA, FileTransferSpeed, ProgressBar
27 from pyvcloud.vcd.client import BasicLoginCredentials, Client
28 from pyvcloud.vcd.org import Org
29 import re
30 import requests
31 import sys
32 import time
33 from xml.etree import ElementTree as XmlElementTree
34
35 API_VERSION = '5.6'
36
37
38 class vCloudconfig(object):
39
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 = logging.getLogger('vmware_ovf_upload')
46 self.logger.setLevel(10)
47
48 def connect(self):
49 """ Method connect as normal user to vCloud director.
50
51 Returns:
52 The return vca object that letter can be used to connect to vCloud director as admin for VDC
53 """
54
55 try:
56 self.logger.debug("Logging in to a vcd {} as user {}".format(self.org,
57 self.user))
58 client = Client(self.url, verify_ssl_certs=False)
59 client.set_credentials(BasicLoginCredentials(self.user, self.org, self.password))
60 except Exception:
61 raise Exception("Can't connect to a vCloud director org: "
62 "{} as user: {}".format(self.org, self.user))
63
64 return client
65
66 def get_catalog_id_from_path(self, catalog_name=None, path=None, progress=False):
67 """
68 Args
69 catalog - catalog name to be created
70 path: - valid path to OVF file.
71 progress - boolean progress bar show progress bar.
72
73 Return: if image uploaded correct method will provide image catalog UUID.
74 """
75 if not path:
76 raise Exception("Image path can't be None.")
77
78 if not os.path.isfile(path):
79 raise Exception("Can't read file. File not found.")
80
81 if not os.access(path, os.R_OK):
82 raise Exception("Can't read file. Check file permission to read.")
83
84 self.logger.debug("get_catalog_id_from_path() client requesting {} ".format(path))
85
86 _, filename = os.path.split(path)
87 _, file_extension = os.path.splitext(path)
88 if file_extension != '.ovf':
89 self.logger.debug("Wrong file extension {} connector support only OVF container.".format(file_extension))
90 raise Exception("Wrong container. vCloud director supports only OVF.")
91
92 self.logger.debug("File name {} Catalog Name {} file path {} ".format(filename,
93 catalog_name,
94 path))
95 try:
96 client = self.connect()
97 if not client:
98 raise Exception("Failed to connect vCD")
99 org = Org(client, resource=client.get_org())
100 catalogs = org.list_catalogs()
101 except Exception as exp:
102 self.logger.debug("Failed get catalogs() with Exception {} ".format(exp))
103 raise Exception("Failed get catalogs() with Exception {} ".format(exp))
104
105 if len(catalogs) == 0:
106 self.logger.info("Creating a new catalog entry {} in vcloud director".format(catalog_name))
107 result = org.create_catalog(catalog_name, catalog_name)
108 if result is None:
109 raise Exception("Failed to create new catalog {} ".format(catalog_name))
110 result = self.upload_ovf(org=org, catalog_name=catalog_name, image_name=filename.split(".")[0],
111 media_file_name=path, description='medial_file_name', progress=progress)
112 if not result:
113 raise Exception("Failed to create vApp template for catalog {} ".format(catalog_name))
114 return self.get_catalogid(catalog_name, catalogs)
115 else:
116 for catalog in catalogs:
117 # search for existing catalog if we find same name we return ID
118 if catalog['name'] == catalog_name:
119 self.logger.debug("Found existing catalog entry for {} "
120 "catalog id {}".format(catalog_name,
121 self.get_catalogid(catalog_name, catalogs)))
122 return self.get_catalogid(catalog_name, catalogs)
123
124 # if we didn't find existing catalog we create a new one and upload image.
125 self.logger.debug("Creating new catalog entry {} - {}".format(catalog_name, catalog_name))
126 result = org.create_catalog(catalog_name, catalog_name)
127 if result is None:
128 raise Exception("Failed to create new catalog {} ".format(catalog_name))
129
130 result = self.upload_ovf(org=org, catalog_name=catalog_name, image_name=filename.split(".")[0],
131 media_file_name=path, description='medial_file_name', progress=progress)
132 if not result:
133 raise Exception("Failed create vApp template for catalog {} ".format(catalog_name))
134
135 def get_catalogid(self, catalog_name=None, catalogs=None):
136 """ Method check catalog and return catalog ID in UUID format.
137
138 Args
139 catalog_name: catalog name as string
140 catalogs: list of catalogs.
141
142 Return: catalogs uuid
143 """
144
145 for catalog in catalogs:
146 if catalog['name'] == catalog_name:
147 catalog_id = catalog['id']
148 return catalog_id
149 return None
150
151 def upload_ovf(self, org=None, catalog_name=None, image_name=None, media_file_name=None,
152 description='', progress=False, chunk_bytes=128 * 1024):
153 """
154 Uploads a OVF file to a vCloud catalog
155
156 org : organization object
157 catalog_name: (str): The name of the catalog to upload the media.
158 media_file_name: (str): The name of the local media file to upload.
159 return: (bool) True if the media file was successfully uploaded, false otherwise.
160 """
161 client = self.connect()
162 if not client:
163 raise Exception("Failed to connect vCD!")
164
165 os.path.isfile(media_file_name)
166 statinfo = os.stat(media_file_name)
167
168 # find a catalog entry where we upload OVF.
169 # create vApp Template and check the status if vCD able to read OVF it will respond with appropirate
170 # status change.
171 # if VCD can parse OVF we upload VMDK file
172 try:
173 for catalog in org.list_catalogs():
174 if catalog_name != catalog['name']:
175 continue
176 catalog_href = "{}/api/catalog/{}/action/upload".format(self.url, catalog['id'])
177 data = """
178 <UploadVAppTemplateParams name="{}" xmlns="http://www.vmware.com/vcloud/v1.5"
179 xmlns:ovf="http://schemas.dmtf.org/ovf/envelope/1">
180 <Description>{} vApp Template</Description></UploadVAppTemplateParams>
181 """.format(catalog_name, description)
182
183 if client:
184 headers = {'Accept': 'application/*+xml;version=' + API_VERSION,
185 'x-vcloud-authorization': client._session.headers['x-vcloud-authorization']}
186 headers['Content-Type'] = 'application/vnd.vmware.vcloud.uploadVAppTemplateParams+xml'
187
188 response = requests.post(url=catalog_href,
189 headers=headers,
190 data=data,
191 verify=False)
192 if response.status_code != 201:
193 self.logger.debug("Failed to create vApp template")
194 raise Exception("Failed to create vApp template")
195
196 if response.status_code == requests.codes.created:
197 catalogItem = XmlElementTree.fromstring(response.content)
198 entity = [child for child in catalogItem if
199 child.get("type") == "application/vnd.vmware.vcloud.vAppTemplate+xml"][0]
200 href = entity.get('href')
201 template = href
202
203 response = requests.get(url=href,
204 headers=headers,
205 verify=False)
206 if response.status_code == requests.codes.ok:
207 headers['Content-Type'] = 'Content-Type text/xml'
208 result = re.search('rel="upload:default"\shref="(.*?\/descriptor.ovf)"', response.content)
209 if result:
210 transfer_href = result.group(1)
211
212 response = requests.put(url=transfer_href, headers=headers,
213 data=open(media_file_name, 'rb'),
214 verify=False)
215
216 if response.status_code != requests.codes.ok:
217 self.logger.debug(
218 "Failed create vApp template for catalog name {} and image {}".format(
219 catalog_name,
220 media_file_name))
221 return False
222
223 # TODO fix this with aync block
224 time.sleep(5)
225
226 self.logger.debug("vApp template for catalog name {} and image {}".format(
227 catalog_name,
228 media_file_name))
229
230 # uploading VMDK file
231 # check status of OVF upload and upload remaining files.
232
233 response = requests.get(url=template,
234 headers=headers,
235 verify=False)
236
237 if response.status_code == requests.codes.ok:
238 result = re.search('rel="upload:default"\s*href="(.*?vmdk)"', response.content)
239 if result:
240 link_href = result.group(1)
241 # we skip ovf since it already uploaded.
242 if 'ovf' in link_href:
243 continue
244 # The OVF file and VMDK must be in a same directory
245 head, _ = os.path.split(media_file_name)
246 file_vmdk = head + '/' + link_href.split("/")[-1]
247 if not os.path.isfile(file_vmdk):
248 return False
249 statinfo = os.stat(file_vmdk)
250 if statinfo.st_size == 0:
251 return False
252 hrefvmdk = link_href
253 if progress:
254 widgets = ['Uploading file: ', Percentage(), ' ', Bar(), ' ', ETA(), ' ',
255 FileTransferSpeed()]
256 progress_bar = ProgressBar(widgets=widgets, maxval=statinfo.st_size).start()
257
258 bytes_transferred = 0
259 f = open(file_vmdk, 'rb')
260 while bytes_transferred < statinfo.st_size:
261 my_bytes = f.read(chunk_bytes)
262 if len(my_bytes) <= chunk_bytes:
263 headers['Content-Range'] = 'bytes %s-%s/%s' % (
264 bytes_transferred, len(my_bytes) - 1, statinfo.st_size)
265 headers['Content-Length'] = str(len(my_bytes))
266 response = requests.put(url=hrefvmdk,
267 headers=headers,
268 data=my_bytes,
269 verify=False)
270 if response.status_code == requests.codes.ok:
271 bytes_transferred += len(my_bytes)
272 if progress:
273 progress_bar.update(bytes_transferred)
274 else:
275 self.logger.debug(
276 'file upload failed with error: [%s] %s' % (response.status_code,
277 response.content))
278
279 f.close()
280 return False
281 f.close()
282 if progress:
283 progress_bar.finish()
284 time.sleep(60)
285 return True
286 else:
287 self.logger.debug("Failed retrieve vApp template for catalog name {} for OVF {}".
288 format(catalog_name, media_file_name))
289 return False
290 except Exception as exp:
291 self.logger.debug("Failed while uploading OVF to catalog {} for OVF file {} with Exception {}"
292 .format(catalog_name, media_file_name, exp))
293 raise Exception(
294 "Failed while uploading OVF to catalog {} for OVF file {} with Exception {}"
295 .format(catalog_name, media_file_name, exp))
296 self.logger.debug("Failed to retrieve catalog name {} for OVF file {}".format(catalog_name, media_file_name))
297 return False
298
299
300 if __name__ == "__main__":
301
302 print("This file is deprecated. Please use ovf_uplader_cli instead.")
303
304 # vmware vcloud director credentials
305 vcd_hostname = sys.argv[1]
306 vcd_username = sys.argv[2]
307 vcd_password = sys.argv[3]
308 orgname = sys.argv[4]
309 # OVF image path to be upload to vCD
310 ovf_file_path = sys.argv[5]
311
312 logging.basicConfig(filename='ovf_upload.log', level=logging.DEBUG)
313 logger = logging.getLogger(__name__)
314
315 obj = vCloudconfig(vcd_hostname, vcd_username, vcd_password, orgname, logger)
316
317 dirpath, filename = os.path.split(ovf_file_path)
318 filename_name, file_extension = os.path.splitext(filename)
319
320 # Get image name from cirros vnfd
321 cirros_yaml = '../descriptor-packages/vnfd/cirros_vnf/src/cirros_vnfd.yaml'
322 rh = open(cirros_yaml, 'r')
323 match = re.search("image:\s'(.*?)'\n", rh.read())
324 if match:
325 catalog = match.group(1)
326
327 if file_extension == '.ovf':
328 obj.get_catalog_id_from_path(catalog_name=catalog, path=ovf_file_path,
329 progress=True)