Added standalone tool to work with vcloud director. finished vmware connector ready...
[osm/RO.git] / vmwarerecli.py
1 # -*- coding: utf-8 -*-
2 ##
3 # This file is standalone vmware vcloud director util
4 # All Rights Reserved.
5 #
6 # Licensed under the Apache License, Version 2.0 (the "License"); you may
7 # not use this file except in compliance with the License. You may obtain
8 # a copy of the License at
9 #
10 # http://www.apache.org/licenses/LICENSE-2.0
11 #
12 # Unless required by applicable law or agreed to in writing, software
13 # distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
14 # WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
15 # License for the specific language governing permissions and limitations
16 # under the License.
17 #
18 # For those usages not covered by the Apache License, Version 2.0 please
19 # contact with: mbayramov@vmware.com
20 ##
21
22 '''
23
24 Provide standalone application to work with vCloud director rest api.
25
26 mbayramov@vmware.com
27 '''
28 import os
29 import requests
30 import logging
31 import sys
32 import argparse
33 import traceback
34
35 from xml.etree import ElementTree as ET
36
37 from pyvcloud import Http
38 from pyvcloud.vcloudair import VCA
39 from pyvcloud.schema.vcd.v1_5.schemas.vcloud.networkType import *
40 from pyvcloud.schema.vcd.v1_5.schemas.vcloud import sessionType, organizationType, \
41 vAppType, organizationListType, vdcType, catalogType, queryRecordViewType, \
42 networkType, vcloudType, taskType, diskType, vmsType, vdcTemplateListType, mediaType
43 from xml.sax.saxutils import escape
44
45 import logging
46 import json
47 import vimconn
48 import time
49 import uuid
50 import httplib
51 import urllib3
52 import requests
53
54 from vimconn_vmware import vimconnector
55 from requests.packages.urllib3.exceptions import InsecureRequestWarning
56 from prettytable import PrettyTable
57 from xml.etree import ElementTree as XmlElementTree
58 from prettytable import PrettyTable
59
60 requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
61
62 __author__ = "Mustafa Bayramov"
63 __date__ = "$16-Sep-2016 11:09:29$"
64
65
66 def delete_network_action(vca=None, network_uuid=None):
67 """
68 Method leverages vCloud director and query network based on network uuid
69
70 Args:
71 vca - is active VCA connection.
72 network_uuid - is a network uuid
73
74 Returns:
75 The return XML respond
76 """
77
78 if vca is None or network_uuid is None:
79 return None
80
81 url_list = [vca.host, '/api/admin/network/', network_uuid]
82 vm_list_rest_call = ''.join(url_list)
83
84 if not (not vca.vcloud_session or not vca.vcloud_session.organization):
85 response = Http.get(url=vm_list_rest_call,
86 headers=vca.vcloud_session.get_vcloud_headers(),
87 verify=vca.verify,
88 logger=vca.logger)
89 if response.status_code == requests.codes.ok:
90 print response.content
91 return response.content
92
93 return None
94
95
96 def print_vapp(vapp_dict=None):
97 """ Method takes vapp_dict and print in tabular format
98
99 Args:
100 vapp_dict: container vapp object.
101
102 Returns:
103 The return nothing
104 """
105
106 # following key available to print
107
108 # {'status': 'POWERED_OFF', 'storageProfileName': '*', 'hardwareVersion': '7', 'vmToolsVersion': '0',
109 # 'memoryMB': '384',
110 # 'href': 'https://172.16.254.206/api/vAppTemplate/vm-129e22e8-08dc-4cb6-8358-25f635e65d3b',
111 # 'isBusy': 'false', 'isDeployed': 'false', 'isInMaintenanceMode': 'false', 'isVAppTemplate': 'true',
112 # 'networkName': 'nat', 'isDeleted': 'false', 'catalogName': 'Cirros',
113 # 'containerName': 'Cirros Template', # 'container': 'https://172.16.254.206/api/vAppTemplate/vappTemplate-b966453d-c361-4505-9e38-ccef45815e5d',
114 # 'name': 'Cirros', 'pvdcHighestSupportedHardwareVersion': '11', 'isPublished': 'false',
115 # 'numberOfCpus': '1', 'vdc': 'https://172.16.254.206/api/vdc/a5056f85-418c-4bfd-8041-adb0f48be9d9',
116 # 'guestOs': 'Other (32-bit)', 'isVdcEnabled': 'true'}
117
118 if vapp_dict is None:
119 return
120
121 vm_table = PrettyTable(['vapp uuid',
122 'vapp name',
123 'vdc uuid',
124 'network name',
125 'category name',
126 'storageProfileName',
127 'vcpu', 'memory', 'hw ver'])
128
129 for k in vapp_dict:
130 entry = []
131 entry.append(k)
132 entry.append(vapp_dict[k]['containerName'])
133 entry.append(vapp_dict[k]['vdc'].split('/')[-1:][0])
134 entry.append(vapp_dict[k]['networkName'])
135 entry.append(vapp_dict[k]['catalogName'])
136 entry.append(vapp_dict[k]['storageProfileName'])
137 entry.append(vapp_dict[k]['numberOfCpus'])
138 entry.append(vapp_dict[k]['memoryMB'])
139 entry.append(vapp_dict[k]['pvdcHighestSupportedHardwareVersion'])
140
141 vm_table.add_row(entry)
142
143 print vm_table
144
145
146 def print_org(org_dict=None):
147 """ Method takes vapp_dict and print in tabular format
148
149 Args:
150 org_dict: dictionary of organization where key is org uuid.
151
152 Returns:
153 The return nothing
154 """
155
156 if org_dict is None:
157 return
158
159 org_table = PrettyTable(['org uuid', 'name'])
160 for k in org_dict:
161 entry = [k, org_dict[k]]
162 org_table.add_row(entry)
163
164 print org_table
165
166
167 def print_vm_list(vm_dict=None):
168 """ Method takes vapp_dict and print in tabular format
169
170 Args:
171 org_dict: dictionary of organization where key is org uuid.
172
173 Returns:
174 The return nothing
175 """
176 if vm_dict is None:
177 return
178
179 vm_table = PrettyTable(
180 ['vm uuid', 'vm name', 'vapp uuid', 'vdc uuid', 'network name', 'is deployed', 'vcpu', 'memory', 'status'])
181
182 try:
183 for k in vm_dict:
184 entry = []
185 entry.append(k)
186 entry.append(vm_dict[k]['name'])
187 entry.append(vm_dict[k]['container'].split('/')[-1:][0][5:])
188 entry.append(vm_dict[k]['vdc'].split('/')[-1:][0])
189 entry.append(vm_dict[k]['networkName'])
190 entry.append(vm_dict[k]['isDeployed'])
191 entry.append(vm_dict[k]['numberOfCpus'])
192 entry.append(vm_dict[k]['memoryMB'])
193 entry.append(vm_dict[k]['status'])
194 vm_table.add_row(entry)
195 print vm_table
196 except KeyError:
197 logger.error("wrong key {}".format(KeyError.message))
198 pass
199
200
201 def print_org_details(org_dict=None):
202 """ Method takes vapp_dict and print in tabular format
203
204 Args:
205 org_dict: dictionary of organization where key is org uuid.
206
207 Returns:
208 The return nothing
209 """
210 if org_dict is None:
211 return
212 try:
213 network_dict = {}
214 catalogs_dict = {}
215 vdcs_dict = {}
216
217 if org_dict.has_key('networks'):
218 network_dict = org_dict['networks']
219
220 if org_dict.has_key('vdcs'):
221 vdcs_dict = org_dict['vdcs']
222
223 if org_dict.has_key('catalogs'):
224 catalogs_dict = org_dict['catalogs']
225
226 vdc_table = PrettyTable(['vdc uuid', 'vdc name'])
227 for k in vdcs_dict:
228 entry = [k, vdcs_dict[k]]
229 vdc_table.add_row(entry)
230
231 network_table = PrettyTable(['network uuid', 'network name'])
232 for k in network_dict:
233 entry = [k, network_dict[k]]
234 network_table.add_row(entry)
235
236 catalog_table = PrettyTable(['catalog uuid', 'catalog name'])
237 for k in catalogs_dict:
238 entry = [k, catalogs_dict[k]]
239 catalog_table.add_row(entry)
240
241 print vdc_table
242 print network_table
243 print catalog_table
244
245 except KeyError:
246 logger.error("wrong key {}".format(KeyError.message))
247 logger.logger.debug(traceback.format_exc())
248
249
250 def delete_actions(vim=None, action=None, namespace=None):
251 if action == 'network' or namespace.action == 'network':
252 logger.debug("Requesting delete for network {}".format(namespace.network_name))
253 network_uuid = namespace.network_name
254 # if request name based we need find UUID
255 # TODO optimize it or move to external function
256 if not namespace.uuid:
257 org_dict = vim.get_org_list()
258 for org in org_dict:
259 org_net = vim.get_org(org)['networks']
260 for network in org_net:
261 if org_net[network] == namespace.network_name:
262 network_uuid = network
263
264 vim.delete_network_action(network_uuid=network_uuid)
265
266
267 def list_actions(vim=None, action=None, namespace=None):
268 if action == 'vms' or namespace.action == 'vms':
269 vm_dict = vim.get_vm_list(vdc_name=namespace.vcdvdc)
270 print_vm_list(vm_dict=vm_dict)
271 elif action == 'vapps' or namespace.action == 'vapps':
272 vapp_dict = vim.get_vapp_list(vdc_name=namespace.vcdvdc)
273 print_vapp(vapp_dict=vapp_dict)
274 elif action == 'networks' or namespace.action == 'networks':
275 print "Requesting networks"
276 # var = OrgVdcNetworkType.get_status()
277 elif action == 'vdc' or namespace.action == 'vdc':
278 vm_dict = vim.get_vm_list(vdc_name=namespace.vcdvdc)
279 print_vm_list(vm_dict=vm_dict)
280 elif action == 'org' or namespace.action == 'org':
281 logger.debug("Listing avaliable orgs")
282 print_org(org_dict=vim.get_org_list())
283 else:
284 return None
285
286
287 def view_actions(vim=None, action=None, namespace=None):
288 # view org
289 if action == 'org' or namespace.action == 'org':
290 org_id = None
291 orgs = vim.get_org_list()
292 if namespace.uuid:
293 if namespace.org_name in orgs:
294 org_id = namespace.org_name
295 else:
296 # we need find UUID based on name provided
297 for org in orgs:
298 if orgs[org] == namespace.org_name:
299 org_id = org
300 break
301
302 logger.debug("Requesting view for orgs {}".format(org_id))
303 print_org_details(vim.get_org(org_uuid=org_id))
304
305 # view vapp action
306 if action == 'vapp' or namespace.action == 'vapp':
307 if namespace.vapp_name is not None and namespace.uuid == False:
308 logger.debug("Requesting vapp {} for vdc {}".format(namespace.vapp_name, namespace.vcdvdc))
309
310 vapp_dict = {}
311 # if request based on just name we need get UUID
312 if not namespace.uuid:
313 vappid = vim.get_vappid(vdc=namespace.vcdvdc, vapp_name=namespace.vapp_name)
314
315 vapp_dict = vim.get_vapp(vdc_name=namespace.vcdvdc, vapp_name=vappid, isuuid=True)
316 print_vapp(vapp_dict=vapp_dict)
317
318 # view network
319 if action == 'network' or namespace.action == 'network':
320 logger.debug("Requesting view for network {}".format(namespace.network_name))
321 network_uuid = namespace.network_name
322 # if request name based we need find UUID
323 # TODO optimize it or move to external function
324 if not namespace.uuid:
325 org_dict = vim.get_org_list()
326 for org in org_dict:
327 org_net = vim.get_org(org)['networks']
328 for network in org_net:
329 if org_net[network] == namespace.network_name:
330 network_uuid = network
331
332 print vim.get_vcd_network(network_uuid=network_uuid)
333
334
335 def create_actions(vim=None, action=None, namespace=None):
336 """Method gets provider vdc view from vcloud director
337
338 Args:
339 vim - is Cloud director vim connector
340 action - action for create ( network / vdc etc)
341
342 Returns:
343 The return xml content of respond or None
344 """
345 if action == 'network' or namespace.action == 'network':
346 logger.debug("Creating a network in vcloud director".format(namespace.network_name))
347 network_uuid = vim.create_network(namespace.network_name)
348 if network_uuid is not None:
349 print ("Crated new network {} and uuid: {}".format(namespace.network_name, network_uuid))
350 else:
351 print ("Failed create a new network {}".format(namespace.network_name))
352 elif action == 'vdc' or namespace.action == 'vdc':
353 logger.debug("Creating a new vdc in vcloud director.".format(namespace.vdc_name))
354 vdc_uuid = vim.create_vdc(namespace.vdc_name)
355 if vdc_uuid is not None:
356 print ("Crated new vdc {} and uuid: {}".format(namespace.vdc_name, vdc_uuid))
357 else:
358 print ("Failed create a new vdc {}".format(namespace.vdc_name))
359 else:
360 return None
361
362
363 def vmwarecli(command=None, action=None, namespace=None):
364 print namespace
365
366 urllib3.disable_warnings()
367 vim = vimconnector('0cd19677-7517-11e6-aa08-000c29db3077',
368 'test',
369 'a5056f85-418c-4bfd-8041-adb0f48be9d9',
370 namespace.vcdvdc,
371 'https://172.16.254.206',
372 'https://172.16.254.206',
373 'admin',
374 'qwerty123',
375 "DEBUG", config={'admin_username': 'Administrator', 'admin_password': 'qwerty123'})
376
377 vim.vca = vim.connect()
378 #
379 # "{'status': 'ACTIVE'}
380 # 2016-09-26 13:06:33,989 - mano.vim.vmware - DEBUG - Adding 4d2e9ec6-e3d8-4014-a1ab-8b622524bd9c to a list vcd id a5056f85-418c-4bfd-8041-adb0f48be9d9 network tefexternal
381 # Dict contains {'status': 'ACTIVE'}
382 # 2016-09-26 13:06:33,989 - mano.vim.vmware - DEBUG - Adding 93729eaa-4159-4d18-ac28-b000f91bd331 to a list vcd id a5056f85-418c-4bfd-8041-adb0f48be9d9 network default
383 # Dict contains {'status': 'ACTIVE'}
384
385 vim.get_network_list(filter_dict={'status': 'ACTIVE', 'type': 'bridge'})
386 # vim.get_network_list(filter_dict={'status' : 'ACTIVE'})
387
388 # print vim.get_vminstance('7e06889a-50c4-4b08-8877-c1ef001eb030')
389 # vim.get_network_name_by_id()
390
391 # exit()
392 # get_network_action(vca=vca, network_uuid="123")
393
394 # list
395 if command == 'list' or namespace.command == 'list':
396 logger.debug("Client requested list action")
397 # route request to list actions
398 list_actions(vim=vim, action=action, namespace=namespace)
399
400 # view action
401 if command == 'view' or namespace.command == 'view':
402 logger.debug("Client requested view action")
403 view_actions(vim=vim, action=action, namespace=namespace)
404
405 # delete action
406 if command == 'delete' or namespace.command == 'delete':
407 logger.debug("Client requested delete action")
408 delete_actions(vim=vim, action=action, namespace=namespace)
409
410 # create action
411 if command == 'create' or namespace.command == 'create':
412 logger.debug("Client requested create action")
413 create_actions(vim=vim, action=action, namespace=namespace)
414
415
416 # def get_vappid(vdc, vapp_name):
417 # refs = filter(lambda ref: ref.name == vapp_name and ref.type_ == 'application/vnd.vmware.vcloud.vApp+xml',vdc.ResourceEntities.ResourceEntity)
418 # if len(refs) == 1:
419 # return refs[0].href.split("vapp")[1][1:]
420 # return None
421
422 if __name__ == '__main__':
423 defaults = {'vcdvdc': 'default',
424 'vcduser': 'admin',
425 'vcdpassword': 'admin',
426 'vcdhost': 'https://localhost',
427 'vcdorg': 'default',
428 'debug': 'INFO'}
429
430 parser = argparse.ArgumentParser()
431 parser.add_argument('-u', '--vcduser', help='vcloud director username', type=str)
432 parser.add_argument('-p', '--vcdpassword', help='vcloud director password', type=str)
433 parser.add_argument('-c', '--vcdhost', help='vcloud director host', type=str)
434 parser.add_argument('-o', '--vcdorg', help='vcloud director org', type=str)
435 parser.add_argument('-v', '--vcdvdc', help='vcloud director vdc', type=str)
436 parser.add_argument('-d', '--debug', help='debug level', type=int)
437
438 parser_subparsers = parser.add_subparsers(help='commands', dest='command')
439 sub = parser_subparsers.add_parser('list', help='List objects (VMs, vApps, networks)')
440 sub_subparsers = sub.add_subparsers(dest='action')
441 view_vms = sub_subparsers.add_parser('vms', help='list - all vm deployed in vCloud director')
442 view_vapps = sub_subparsers.add_parser('vapps', help='list - all vapps deployed in vCloud director')
443 view_network = sub_subparsers.add_parser('networks', help='list - all networks deployed')
444 view_vdc = sub_subparsers.add_parser('vdc', help='list - list all vdc for organization accessible to you')
445 view_vdc = sub_subparsers.add_parser('org', help='list - list of organizations accessible to you.')
446
447 create_sub = parser_subparsers.add_parser('create')
448 create_sub_subparsers = create_sub.add_subparsers(dest='action')
449 create_vms = create_sub_subparsers.add_parser('vms')
450 create_vapp = create_sub_subparsers.add_parser('vapp')
451 create_vapp.add_argument('uuid')
452
453 # add network
454 create_network = create_sub_subparsers.add_parser('network')
455 create_network.add_argument('network_name', action='store', help='create a network for a vdc')
456
457 # add VDC
458 create_vdc = create_sub_subparsers.add_parser('vdc')
459 create_vdc.add_argument('vdc_name', action='store', help='create a new VDC for org')
460
461 delete_sub = parser_subparsers.add_parser('delete')
462 del_sub_subparsers = delete_sub.add_subparsers(dest='action')
463 del_vms = del_sub_subparsers.add_parser('vms')
464 del_vapp = del_sub_subparsers.add_parser('vapp')
465 del_vapp.add_argument('uuid', help='view vapp based on UUID')
466
467 # delete network
468 del_network = del_sub_subparsers.add_parser('network')
469 del_network.add_argument('network_name', action='store',
470 help='- delete network for vcloud director by provided name')
471 del_network.add_argument('-u', '--uuid', default=False, action='store_true',
472 help='delete network for vcloud director by provided uuid')
473
474 # delete vdc
475 del_vdc = del_sub_subparsers.add_parser('vdc')
476
477 view_sub = parser_subparsers.add_parser('view')
478 view_sub_subparsers = view_sub.add_subparsers(dest='action')
479
480 view_vms_parser = view_sub_subparsers.add_parser('vms')
481 view_vms_parser.add_argument('uuid', default=False, action='store_true',
482 help='- View VM for specific uuid in vcloud director')
483 view_vms_parser.add_argument('name', default=False, action='store_true',
484 help='- View VM for specific vapp name in vcloud director')
485
486 # view vapp
487 view_vapp_parser = view_sub_subparsers.add_parser('vapp')
488 view_vapp_parser.add_argument('vapp_name', action='store',
489 help='- view vapp for specific vapp name in vcloud director')
490 view_vapp_parser.add_argument('-u', '--uuid', default=False, action='store_true', help='view vapp based on uuid')
491
492 # view network
493 view_network = view_sub_subparsers.add_parser('network')
494 view_network.add_argument('network_name', action='store',
495 help='- view network for specific network name in vcloud director')
496 view_network.add_argument('-u', '--uuid', default=False, action='store_true', help='view network based on uuid')
497
498 # view VDC command and actions
499 view_vdc = view_sub_subparsers.add_parser('vdc')
500 view_vdc.add_argument('vdc_name', action='store',
501 help='- View VDC based and action based on provided vdc uuid')
502 view_vdc.add_argument('-u', '--uuid', default=False, action='store_true', help='view vdc based on uuid')
503
504 # view organization command and actions
505 view_org = view_sub_subparsers.add_parser('org')
506 view_org.add_argument('org_name', action='store',
507 help='- View VDC based and action based on provided vdc uuid')
508 view_org.add_argument('-u', '--uuid', default=False, action='store_true', help='view org based on uuid')
509
510 #
511 # view_org.add_argument('uuid', default=False, action='store',
512 # help='- View Organization and action based on provided uuid.')
513 # view_org.add_argument('name', default=False, action='store_true',
514 # help='- View Organization and action based on provided name')
515
516 namespace = parser.parse_args()
517 # put command_line args to mapping
518 command_line_args = {k: v for k, v in vars(namespace).items() if v}
519
520 d = defaults.copy()
521 d.update(os.environ)
522 d.update(command_line_args)
523
524 logger = logging.getLogger('mano.vim.vmware')
525 formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
526 ch = logging.StreamHandler()
527 ch.setLevel(str.upper(d['debug']))
528 ch.setFormatter(formatter)
529 logger.addHandler(ch)
530 logger.setLevel(getattr(logging, str.upper(d['debug'])))
531 logger.info(
532 "Connecting {} username: {} org: {} vdc: {} ".format(d['vcdhost'], d['vcduser'], d['vcdorg'], d['vcdvdc']))
533
534 logger.debug("command: \"{}\" actio: \"{}\"".format(d['command'], d['action']))
535 vmwarecli(namespace=namespace)
536