fixed issue with hardcoded credential, added capability to indicate from shell or...
[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 #TODO move to main vim
67 def delete_network_action(vca=None, network_uuid=None):
68 """
69 Method leverages vCloud director and query network based on network uuid
70
71 Args:
72 vca - is active VCA connection.
73 network_uuid - is a network uuid
74
75 Returns:
76 The return XML respond
77 """
78
79 if vca is None or network_uuid is None:
80 return None
81
82 url_list = [vca.host, '/api/admin/network/', network_uuid]
83 vm_list_rest_call = ''.join(url_list)
84
85 if not (not vca.vcloud_session or not vca.vcloud_session.organization):
86 response = Http.get(url=vm_list_rest_call,
87 headers=vca.vcloud_session.get_vcloud_headers(),
88 verify=vca.verify,
89 logger=vca.logger)
90 if response.status_code == requests.codes.ok:
91 print response.content
92 return response.content
93
94 return None
95
96
97 def print_vapp(vapp_dict=None):
98 """ Method takes vapp_dict and print in tabular format
99
100 Args:
101 vapp_dict: container vapp object.
102
103 Returns:
104 The return nothing
105 """
106
107 # following key available to print
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 for k in vapp_dict:
129 entry = []
130 entry.append(k)
131 entry.append(vapp_dict[k]['containerName'])
132 entry.append(vapp_dict[k]['vdc'].split('/')[-1:][0])
133 entry.append(vapp_dict[k]['networkName'])
134 entry.append(vapp_dict[k]['catalogName'])
135 entry.append(vapp_dict[k]['storageProfileName'])
136 entry.append(vapp_dict[k]['numberOfCpus'])
137 entry.append(vapp_dict[k]['memoryMB'])
138 entry.append(vapp_dict[k]['pvdcHighestSupportedHardwareVersion'])
139
140 vm_table.add_row(entry)
141
142 print vm_table
143
144
145 def print_org(org_dict=None):
146 """ Method takes vapp_dict and print in tabular format
147
148 Args:
149 org_dict: dictionary of organization where key is org uuid.
150
151 Returns:
152 The return nothing
153 """
154
155 if org_dict is None:
156 return
157
158 org_table = PrettyTable(['org uuid', 'name'])
159 for k in org_dict:
160 entry = [k, org_dict[k]]
161 org_table.add_row(entry)
162
163 print org_table
164
165
166 def print_vm_list(vm_dict=None):
167 """ Method takes vapp_dict and print in tabular format
168
169 Args:
170 org_dict: dictionary of organization where key is org uuid.
171
172 Returns:
173 The return nothing
174 """
175 if vm_dict is None:
176 return
177
178 vm_table = PrettyTable(
179 ['vm uuid', 'vm name', 'vapp uuid', 'vdc uuid', 'network name', 'is deployed', 'vcpu', 'memory', 'status'])
180
181 try:
182 for k in vm_dict:
183 entry = []
184 entry.append(k)
185 entry.append(vm_dict[k]['name'])
186 entry.append(vm_dict[k]['container'].split('/')[-1:][0][5:])
187 entry.append(vm_dict[k]['vdc'].split('/')[-1:][0])
188 entry.append(vm_dict[k]['networkName'])
189 entry.append(vm_dict[k]['isDeployed'])
190 entry.append(vm_dict[k]['numberOfCpus'])
191 entry.append(vm_dict[k]['memoryMB'])
192 entry.append(vm_dict[k]['status'])
193 vm_table.add_row(entry)
194 print vm_table
195 except KeyError:
196 logger.error("wrong key {}".format(KeyError.message))
197 pass
198
199
200 def print_org_details(org_dict=None):
201 """ Method takes vapp_dict and print in tabular format
202
203 Args:
204 org_dict: dictionary of organization where key is org uuid.
205
206 Returns:
207 The return nothing
208 """
209 if org_dict is None:
210 return
211 try:
212 network_dict = {}
213 catalogs_dict = {}
214 vdcs_dict = {}
215
216 if org_dict.has_key('networks'):
217 network_dict = org_dict['networks']
218
219 if org_dict.has_key('vdcs'):
220 vdcs_dict = org_dict['vdcs']
221
222 if org_dict.has_key('catalogs'):
223 catalogs_dict = org_dict['catalogs']
224
225 vdc_table = PrettyTable(['vdc uuid', 'vdc name'])
226 for k in vdcs_dict:
227 entry = [k, vdcs_dict[k]]
228 vdc_table.add_row(entry)
229
230 network_table = PrettyTable(['network uuid', 'network name'])
231 for k in network_dict:
232 entry = [k, network_dict[k]]
233 network_table.add_row(entry)
234
235 catalog_table = PrettyTable(['catalog uuid', 'catalog name'])
236 for k in catalogs_dict:
237 entry = [k, catalogs_dict[k]]
238 catalog_table.add_row(entry)
239
240 print vdc_table
241 print network_table
242 print catalog_table
243
244 except KeyError:
245 logger.error("wrong key {}".format(KeyError.message))
246 logger.logger.debug(traceback.format_exc())
247
248
249 def delete_actions(vim=None, action=None, namespace=None):
250 if action == 'network' or namespace.action == 'network':
251 logger.debug("Requesting delete for network {}".format(namespace.network_name))
252 network_uuid = namespace.network_name
253 # if request name based we need find UUID
254 # TODO optimize it or move to external function
255 if not namespace.uuid:
256 org_dict = vim.get_org_list()
257 for org in org_dict:
258 org_net = vim.get_org(org)['networks']
259 for network in org_net:
260 if org_net[network] == namespace.network_name:
261 network_uuid = network
262
263 vim.delete_network_action(network_uuid=network_uuid)
264
265
266 def list_actions(vim=None, action=None, namespace=None):
267 if action == 'vms' or namespace.action == 'vms':
268 vm_dict = vim.get_vm_list(vdc_name=namespace.vcdvdc)
269 print_vm_list(vm_dict=vm_dict)
270 elif action == 'vapps' or namespace.action == 'vapps':
271 vapp_dict = vim.get_vapp_list(vdc_name=namespace.vcdvdc)
272 print_vapp(vapp_dict=vapp_dict)
273 elif action == 'networks' or namespace.action == 'networks':
274 print "Requesting networks"
275 # var = OrgVdcNetworkType.get_status()
276 elif action == 'vdc' or namespace.action == 'vdc':
277 vm_dict = vim.get_vm_list(vdc_name=namespace.vcdvdc)
278 print_vm_list(vm_dict=vm_dict)
279 elif action == 'org' or namespace.action == 'org':
280 logger.debug("Listing avaliable orgs")
281 print_org(org_dict=vim.get_org_list())
282 else:
283 return None
284
285
286 def view_actions(vim=None, action=None, namespace=None):
287 # view org
288 if action == 'org' or namespace.action == 'org':
289 org_id = None
290 orgs = vim.get_org_list()
291 if namespace.uuid:
292 if namespace.org_name in orgs:
293 org_id = namespace.org_name
294 else:
295 # we need find UUID based on name provided
296 for org in orgs:
297 if orgs[org] == namespace.org_name:
298 org_id = org
299 break
300
301 logger.debug("Requesting view for orgs {}".format(org_id))
302 print_org_details(vim.get_org(org_uuid=org_id))
303
304 # view vapp action
305 if action == 'vapp' or namespace.action == 'vapp':
306 if namespace.vapp_name is not None and namespace.uuid == False:
307 logger.debug("Requesting vapp {} for vdc {}".format(namespace.vapp_name, namespace.vcdvdc))
308
309 vapp_dict = {}
310 # if request based on just name we need get UUID
311 if not namespace.uuid:
312 vappid = vim.get_vappid(vdc=namespace.vcdvdc, vapp_name=namespace.vapp_name)
313
314 vapp_dict = vim.get_vapp(vdc_name=namespace.vcdvdc, vapp_name=vappid, isuuid=True)
315 print_vapp(vapp_dict=vapp_dict)
316
317 # view network
318 if action == 'network' or namespace.action == 'network':
319 logger.debug("Requesting view for network {}".format(namespace.network_name))
320 network_uuid = namespace.network_name
321 # if request name based we need find UUID
322 # TODO optimize it or move to external function
323 if not namespace.uuid:
324 org_dict = vim.get_org_list()
325 for org in org_dict:
326 org_net = vim.get_org(org)['networks']
327 for network in org_net:
328 if org_net[network] == namespace.network_name:
329 network_uuid = network
330
331 print vim.get_vcd_network(network_uuid=network_uuid)
332
333
334 def create_actions(vim=None, action=None, namespace=None):
335 """Method gets provider vdc view from vcloud director
336
337 Args:
338 vim - is Cloud director vim connector
339 action - action for create ( network / vdc etc)
340
341 Returns:
342 The return xml content of respond or None
343 """
344 if action == 'network' or namespace.action == 'network':
345 logger.debug("Creating a network in vcloud director".format(namespace.network_name))
346 network_uuid = vim.create_network(namespace.network_name)
347 if network_uuid is not None:
348 print ("Crated new network {} and uuid: {}".format(namespace.network_name, network_uuid))
349 else:
350 print ("Failed create a new network {}".format(namespace.network_name))
351 elif action == 'vdc' or namespace.action == 'vdc':
352 logger.debug("Creating a new vdc in vcloud director.".format(namespace.vdc_name))
353 vdc_uuid = vim.create_vdc(namespace.vdc_name)
354 if vdc_uuid is not None:
355 print ("Crated new vdc {} and uuid: {}".format(namespace.vdc_name, vdc_uuid))
356 else:
357 print ("Failed create a new vdc {}".format(namespace.vdc_name))
358 else:
359 return None
360
361
362 def vmwarecli(command=None, action=None, namespace=None):
363
364 logger.debug("Namespace {}".format(namespace))
365 urllib3.disable_warnings()
366
367 if namespace.vcdpassword is None:
368 vcdpasword = input("vcd password ")
369 else:
370 vcdpasword = namespace.vcdpassword
371 vim = vimconnector(uuid=None,
372 name=namespace.org_name,
373 tenant_id=None,
374 tenant_name=namespace.vcdvdc,
375 url=namespace.vcdhost,
376 url_admin=namespace.vcdhost,
377 user=namespace.vcduser,
378 passwd=namespace.vcdpassword,
379 log_level="DEBUG",
380 config={'admin_username': namespace.vcdamdin, 'admin_password': namespace.vcdadminpassword})
381 vim.vca = vim.connect()
382
383 # list
384 if command == 'list' or namespace.command == 'list':
385 logger.debug("Client requested list action")
386 # route request to list actions
387 list_actions(vim=vim, action=action, namespace=namespace)
388
389 # view action
390 if command == 'view' or namespace.command == 'view':
391 logger.debug("Client requested view action")
392 view_actions(vim=vim, action=action, namespace=namespace)
393
394 # delete action
395 if command == 'delete' or namespace.command == 'delete':
396 logger.debug("Client requested delete action")
397 delete_actions(vim=vim, action=action, namespace=namespace)
398
399 # create action
400 if command == 'create' or namespace.command == 'create':
401 logger.debug("Client requested create action")
402 create_actions(vim=vim, action=action, namespace=namespace)
403
404
405 if __name__ == '__main__':
406 defaults = {'vcdvdc': 'default',
407 'vcduser': 'admin',
408 'vcdpassword': 'admin',
409 'vcdhost': 'https://localhost',
410 'vcdorg': 'default',
411 'debug': 'INFO'}
412
413 parser = argparse.ArgumentParser()
414 parser.add_argument('-u', '--vcduser', help='vcloud director username', type=str)
415 parser.add_argument('-p', '--vcdpassword', help='vcloud director password', type=str)
416 parser.add_argument('-U', '--vcdamdin', help='vcloud director password', type=str)
417 parser.add_argument('-P', '--vcdadminpassword', help='vcloud director password', type=str)
418 parser.add_argument('-c', '--vcdhost', help='vcloud director host', type=str)
419 parser.add_argument('-o', '--vcdorg', help='vcloud director org', type=str)
420 parser.add_argument('-v', '--vcdvdc', help='vcloud director vdc', type=str)
421 parser.add_argument('-d', '--debug', help='debug level', type=int)
422
423 parser_subparsers = parser.add_subparsers(help='commands', dest='command')
424 sub = parser_subparsers.add_parser('list', help='List objects (VMs, vApps, networks)')
425 sub_subparsers = sub.add_subparsers(dest='action')
426 view_vms = sub_subparsers.add_parser('vms', help='list - all vm deployed in vCloud director')
427 view_vapps = sub_subparsers.add_parser('vapps', help='list - all vapps deployed in vCloud director')
428 view_network = sub_subparsers.add_parser('networks', help='list - all networks deployed')
429 view_vdc = sub_subparsers.add_parser('vdc', help='list - list all vdc for organization accessible to you')
430 view_vdc = sub_subparsers.add_parser('org', help='list - list of organizations accessible to you.')
431
432 create_sub = parser_subparsers.add_parser('create')
433 create_sub_subparsers = create_sub.add_subparsers(dest='action')
434 create_vms = create_sub_subparsers.add_parser('vms')
435 create_vapp = create_sub_subparsers.add_parser('vapp')
436 create_vapp.add_argument('uuid')
437
438 # add network
439 create_network = create_sub_subparsers.add_parser('network')
440 create_network.add_argument('network_name', action='store', help='create a network for a vdc')
441
442 # add VDC
443 create_vdc = create_sub_subparsers.add_parser('vdc')
444 create_vdc.add_argument('vdc_name', action='store', help='create a new VDC for org')
445
446 delete_sub = parser_subparsers.add_parser('delete')
447 del_sub_subparsers = delete_sub.add_subparsers(dest='action')
448 del_vms = del_sub_subparsers.add_parser('vms')
449 del_vapp = del_sub_subparsers.add_parser('vapp')
450 del_vapp.add_argument('uuid', help='view vapp based on UUID')
451
452 # delete network
453 del_network = del_sub_subparsers.add_parser('network')
454 del_network.add_argument('network_name', action='store',
455 help='- delete network for vcloud director by provided name')
456 del_network.add_argument('-u', '--uuid', default=False, action='store_true',
457 help='delete network for vcloud director by provided uuid')
458
459 # delete vdc
460 del_vdc = del_sub_subparsers.add_parser('vdc')
461
462 view_sub = parser_subparsers.add_parser('view')
463 view_sub_subparsers = view_sub.add_subparsers(dest='action')
464
465 view_vms_parser = view_sub_subparsers.add_parser('vms')
466 view_vms_parser.add_argument('uuid', default=False, action='store_true',
467 help='- View VM for specific uuid in vcloud director')
468 view_vms_parser.add_argument('name', default=False, action='store_true',
469 help='- View VM for specific vapp name in vcloud director')
470
471 # view vapp
472 view_vapp_parser = view_sub_subparsers.add_parser('vapp')
473 view_vapp_parser.add_argument('vapp_name', action='store',
474 help='- view vapp for specific vapp name in vcloud director')
475 view_vapp_parser.add_argument('-u', '--uuid', default=False, action='store_true', help='view vapp based on uuid')
476
477 # view network
478 view_network = view_sub_subparsers.add_parser('network')
479 view_network.add_argument('network_name', action='store',
480 help='- view network for specific network name in vcloud director')
481 view_network.add_argument('-u', '--uuid', default=False, action='store_true', help='view network based on uuid')
482
483 # view VDC command and actions
484 view_vdc = view_sub_subparsers.add_parser('vdc')
485 view_vdc.add_argument('vdc_name', action='store',
486 help='- View VDC based and action based on provided vdc uuid')
487 view_vdc.add_argument('-u', '--uuid', default=False, action='store_true', help='view vdc based on uuid')
488
489 # view organization command and actions
490 view_org = view_sub_subparsers.add_parser('org')
491 view_org.add_argument('org_name', action='store',
492 help='- View VDC based and action based on provided vdc uuid')
493 view_org.add_argument('-u', '--uuid', default=False, action='store_true', help='view org based on uuid')
494
495 #
496 # view_org.add_argument('uuid', default=False, action='store',
497 # help='- View Organization and action based on provided uuid.')
498 # view_org.add_argument('name', default=False, action='store_true',
499 # help='- View Organization and action based on provided name')
500
501 namespace = parser.parse_args()
502 # put command_line args to mapping
503 command_line_args = {k: v for k, v in vars(namespace).items() if v}
504
505 d = defaults.copy()
506 d.update(os.environ)
507 d.update(command_line_args)
508
509 logger = logging.getLogger('mano.vim.vmware')
510 formatter = logging.Formatter('%(asctime)s - %(name)s - %(levelname)s - %(message)s')
511 ch = logging.StreamHandler()
512 ch.setLevel(str.upper(d['debug']))
513 ch.setFormatter(formatter)
514 logger.addHandler(ch)
515 logger.setLevel(getattr(logging, str.upper(d['debug'])))
516 logger.info(
517 "Connecting {} username: {} org: {} vdc: {} ".format(d['vcdhost'], d['vcduser'], d['vcdorg'], d['vcdvdc']))
518
519 logger.debug("command: \"{}\" actio: \"{}\"".format(d['command'], d['action']))
520
521 # main entry point.
522 vmwarecli(namespace=namespace)
523