1
0
mirror of https://github.com/vmware/vsphere-automation-sdk-python.git synced 2024-11-21 09:19:59 -05:00

Initial sample drop

This commit is contained in:
Tianhao He 2016-10-26 16:08:23 -07:00
parent ba97ea9f43
commit fb7b0f53cc
124 changed files with 12255 additions and 2 deletions

4
.gitignore vendored Normal file
View File

@ -0,0 +1,4 @@
*.py[cod]
__pycache__/
.DS_Store
.idea/*

11
.travis.yml Normal file
View File

@ -0,0 +1,11 @@
language: python
python:
- "2.7.13"
- "3.6"
# command to install dependencies
install:
- pip install -r requirements.txt
- pip install -r test-requirements.txt
- pip install pycodestyle
# command to run tests
script: pycodestyle samples/*

9
LICENSE Normal file
View File

@ -0,0 +1,9 @@
The MIT License
Copyright 2017 VMware Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

195
README.md
View File

@ -1,2 +1,193 @@
# vsphere-automation-sdk-python-samples
Python Samples for the vSphere Automation SDK
# VMware vSphere Automation SDK for Python
[![Build Status](https://travis-ci.com/tianhao64/vsphere-automation-sdk-python-samples.svg?token=v9mEJjcpDiQ9DrYbzyaQ&branch=master)](https://travis-ci.com/tianhao64/vsphere-automation-sdk-python-samples)
## Table of Contents
- [Abstract](#abstract)
- [Quick Start Guide](#quick-start-guide)
- [Installing the required Python Packages](#installing-the-required-python-packages)
- [Setting up a vSphere Test Environment](#setting-up-a-vsphere-test-environment)
- [Running the SDK Sample Setup Script](#running-the-sdk-sample-setup-script)
- [Running a complex sample](#running-a-complex-sample)
- [API Documentation](#api-documentation)
- [Submitting samples](#submitting-samples)
- [Required Information](#required-information)
- [Suggested Information](#suggested-information)
- [Contribution Process](#contribution-process)
- [Code Style](#code-style)
- [Resource Maintenance](#resource-maintenance)
- [Maintenance Ownership](#maintenance-ownership)
- [Filing Issues](#filing-issues)
- [Resolving Issues](#resolving-issues)
- [VMware Sample Exchange](#vmware-sample-exchange)
- [Repository Administrator Resources](#repository-administrator-resources)
- [Board Members](#board-members)
- [Approval of Additions](#approval-of-additions)
## Abstract
This document describes the vSphere Automation Python SDK samples that use the vSphere Automation
python client library. Additionally, some of the samples demonstrate the combined use of the
vSphere Automation and vSphere APIs. To support this combined use, the vSphere Automation Python SDK
samples require the vSphere Management SDK packages (pyVmomi) to be installed on the client.
The samples have been developed to work with python 2.7.x and 3.3+
## Supported vCenter Releases:
vCenter 6.0 and 6.5.
Certain APIs and samples that are introduced in 6.5 release, such as vCenter, Virtual Machine and Appliance Management. Please refer to the notes in each sample for detailed compatibility information.
## Quick Start Guide
This document will walk you through getting up and running with the Python SDK Samples.
Prior to running the samples you will need to setup a vCenter test environment and
install local Python packages, the following steps will take you through this process.
Before you can run the SDK samples we'll need to walk you through the following steps:
1. Installing the required Python packages
2. Installing SDK provided packages
3. Setting up a vSphere test environment
4. Running SDK Samples setup script
### Installing the required Python Packages
**Note:** The SDK requires Python v2.7+ (preferably v3.6) to run the setup/samples,
please make sure you have the appropriate version installed before continuing.
If you are on macOS/OSX/Linux, please note that the system installed version of
Python may be outdated and/or not be intended for development and we recommended you [install Python](http://docs.python-guide.org/en/latest/starting/installation/) yourself before installing the required packages. [Virtualenv](https://virtualenv.pypa.io/en/stable/) is also highly recommended.
The required packages are listed in the requirements.txt file and installed using "pip install"; For more details on how to install python packages using pip please refer to the [pip user guide](http://pip.readthedocs.io/en/latest/user_guide/).
```cmd
pip install -r requirements.txt
```
### Setting up a vSphere Test Environment
**NOTE:** The samples are intended to be run against a freshly installed **non-Production** vSphere setup as the scripts may make changes to the test environment and in some cases can destroy items when needed.
To run the samples a vSphere test environment is required with the following configuration
* 1 vCenter Server
* 2 ESX hosts
* 1 NFS Datastore with at least 3GB of free capacity
Please have the details of these available but do not have any configuration pre-created on vCenter server or ESXi Hosts, for example there should be no existing datacenters, clusters or attached hosts on the vCenter server.
### Running the SDK Sample Setup Script
Before executing the samples we'll need to setup the vSphere test environment using one of the sample scripts. Before we run the script we'll need to edit one of the files and provide IP addresses for the various machine instances.
First, from the command line change to the SDK ./bin folder.
```cmd
$ cd /path/to/vsphere-automation-sdk-python-samples/bin
```
Next, using a text editor open ../samples/vsphere/vcenter/setup/testbed.py and edit the following settings replace everything in < > brackets with your environment information. Leave the rest of the settings in this file at their default values.
```python
config["SERVER"] = "<vcenter_hostname_or_ip>"
config["USERNAME"] = "<vsphere_username>"
config["PASSWORD"] = "<vsphere_password>"
config["ESX_HOST1"] = "<ESX_host1_ipaddress>"
config["ESX_HOST2"] = "<ESX_host2_ipaddress>"
config["ESX_USER"] = "<esx_username>"
config["ESX_PASS"] = "<esx_password>"
config["USE_NFS"] = True
config["NFS_HOST"] = "<nfs_ipaddress>"
config["NFS_REMOTE_PATH"] = "/store1"
```
Save and close the file.
At this point, we're ready to run the setup script.
This script will perform the following:
* Create 2 test Datacenters
* Create a test Cluster
* Create Test Folders for VM Storage
* Attach the hosts
* Create a Distributed Switch
* Create a Distributed Portgroup
* Attach the NFS datastore (if Selected) to the hosts
* Copy the [Photon OS](https://vmware.github.io/photon/) ISO image downloaded from [VMware's bintray server](https://dl.bintray.com/vmware/photon) to the datastore
* Create directories to add sample ports
**Note:** The setup script may take several minutes to complete.
**To view the available command-line options:**
```cmd
$ ./run_sample.sh ../samples/vsphere/vcenter/setup/main.py -h
```
**To run the setup script:**
```cmd
$ ./run_sample.sh ../samples/vsphere/vcenter/setup/main.py -sv
```
After completion you will see from the output and also the vSphere Webclient that the environment has now been fully setup and is ready to easily run further samples.
### Running a complex sample
This SDK includes a sample script which can be used to perform a number of actions and give you an indication of how to perform multiple vCenter actions, this script is located in the /samples/vsphere/vcenter/setup/ directory, use the following instructions to run this sample:
**Run the vAPI vCenter sample suite:**
```cmd
$ ./run_sample.sh ../samples/vsphere/vcenter/setup/main.py -riv
```
## API Documentation
The API documentation can be found [here] (doc/client.zip)
## Submitting samples
### Required Information
The following information must be included in the README.md or in the sample docstring in case README already exists in same folder.
* Author Name
* This can include full name, email address or other identifiable piece of information that would allow interested parties to contact author with questions.
* Date
* Date the sample was originally written
* Minimal/High Level Description
* What does the sample do ?
* Any KNOWN limitations or dependencies
### Suggested Information
The following information should be included when possible. Inclusion of information provides valuable information to consumers of the resource.
* vSphere version against which the sample was developed/tested
* SDK version against which the sample was developed/tested
* Python version against which the sample was developed/tested
### Contribution Process
* Follow the [GitHub process](https://help.github.com/articles/fork-a-repo)
* Please use one branch per sample or change-set
* Please use one commit and pull request per sample
* Please post the sample output along with the pull request
* If you include a license with your sample, use the project license
### Code Style
Please conform to pep8 standards. Check your code by running the pep8 tool.
https://pypi.python.org/pypi/pep8
## Resource Maintenance
### Maintenance Ownership
Ownership of any and all submitted samples are maintained by the submitter.
### Filing Issues
Any bugs or other issues should be filed within GitHub by way of the repositorys Issue Tracker.
### Resolving Issues
Any community member can resolve issues within the repository, however only the board member can approve the update. Once approved, assuming the resolution involves a pull request, only a board member will be able to merge and close the request.
### VMware Sample Exchange
It is highly recommended to add any and all submitted samples to the VMware Sample Exchange: <https://code.vmware.com/samples>
Sample Exchange can be allowed to access your GitHub resources, by way of a linking process, where they can be indexed and searched by the community. There are VMware social media accounts which will advertise resources posted to the site and there's no additional accounts needed, as the VMware Sample Exchange uses MyVMware credentials.
## Repository Administrator Resources
### Board Members
Board members are volunteers from the SDK community and VMware staff members, board members are not held responsible for any issues which may occur from running of samples from this repository.
Members:
* Tianhao He (VMware)
* Steve Trefethen (VMware)
### Approval of Additions
Items added to the repository, including items from the Board members, require 2 votes from the board members before being added to the repository. The approving members will have ideally downloaded and tested the item. When two “Approved for Merge” comments are added from board members, the pull can then be committed to the repository.

11
bin/run_sample.bat Normal file
View File

@ -0,0 +1,11 @@
@echo off
setlocal ENABLEDELAYEDEXPANSION
:: Clear the command-prompt screen
cls
set SRCDIR=%cd%\..\
set LIBDIR=%cd%\..\lib
set PYTHONPATH=%PYTHONPATH%;%SRCDIR%
setlocal DisableDelayedExpansion
:: Run the sample
python %*
endlocal

13
bin/run_sample.sh Executable file
View File

@ -0,0 +1,13 @@
#!/bin/bash
SCRIPTDIR=`dirname $0`
cd $SCRIPTDIR
PATHDIR=`pwd`
PROJECT_ROOT=$PATHDIR/..
SRCDIR=$PROJECT_ROOT/
LIBDIR=$PROJECT_ROOT/lib
# add the src directory to the python path
export PYTHONPATH=$PYTHONPATH:$SRCDIR
# run the sample
python $@

BIN
doc/client.zip Normal file

Binary file not shown.

9
lib/README.md Normal file
View File

@ -0,0 +1,9 @@
# SDK libraries
For python developers, client libraries are supplied for testing and development purposes. All the supplied libraries are located under lib directory.
Name | Description
------------------------------------| -------------
vapi_runtime-\<version>.zip | vAPI runtime responsible for serialization/de-serialization of objects and wire protocol
vapi_common_client-\<version>.zip | vAPI common client code
vapi_client_bindings-\<version>.zip | client stubs for vSphere Automation APIs

Binary file not shown.

Binary file not shown.

BIN
lib/vapi_runtime-2.5.0.zip Normal file

Binary file not shown.

8
requirements.txt Normal file
View File

@ -0,0 +1,8 @@
pyOpenSSL >= 0.14
pyVmomi >= 6.5
lxml
suds ; python_version < '3'
suds-jurko ; python_version >= '3.0'
lib/vapi_runtime-2.5.0.zip
lib/vapi_common_client-2.5.0.zip
lib/vapi_client_bindings-2.5.0.zip

24
samples/__init__.py Normal file
View File

@ -0,0 +1,24 @@
"""
* *******************************************************
* Copyright VMware, Inc. 2016. All Rights Reserved.
* *******************************************************
*
* DISCLAIMER. THIS PROGRAM IS PROVIDED TO YOU "AS IS" WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, WHETHER ORAL OR WRITTEN,
* EXPRESS OR IMPLIED. THE AUTHOR SPECIFICALLY DISCLAIMS ANY IMPLIED
* WARRANTIES OR CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY,
* NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE.
"""
__author__ = 'VMware, Inc.'
__copyright__ = 'Copyright 2016 VMware, Inc. All rights reserved.'
# Required to distribute different parts of this
# package as multiple distribution
try:
import pkg_resources
pkg_resources.declare_namespace(__name__)
except ImportError:
from pkgutil import extend_path
__path__ = extend_path(__path__, __name__) # @ReservedAssignment

11
samples/vsphere/README.md Normal file
View File

@ -0,0 +1,11 @@
#Client Samples
The following table shows the sample sub-directories and their contents.
Directory | Description
----------------| -------------
common | Samples common helper classes and abstractions; This package does NOT contain any sample
contentlibrary | Samples for Content Library APIs
tagging | Samples for Tagging APIs
vcenter | Samples for managing vSphere infrastructure and virtual machines
sso | Samples for Platform Service Controller(PSC), SSO and Lookup Service APIs

View File

@ -0,0 +1,24 @@
"""
* *******************************************************
* Copyright VMware, Inc. 2016. All Rights Reserved.
* *******************************************************
*
* DISCLAIMER. THIS PROGRAM IS PROVIDED TO YOU "AS IS" WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, WHETHER ORAL OR WRITTEN,
* EXPRESS OR IMPLIED. THE AUTHOR SPECIFICALLY DISCLAIMS ANY IMPLIED
* WARRANTIES OR CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY,
* NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE.
"""
__author__ = 'VMware, Inc.'
__copyright__ = 'Copyright 2016 VMware, Inc. All rights reserved.'
# Required to distribute different parts of this
# package as multiple distribution
try:
import pkg_resources
pkg_resources.declare_namespace(__name__)
except ImportError:
from pkgutil import extend_path
__path__ = extend_path(__path__, __name__) # @ReservedAssignment

View File

@ -0,0 +1,10 @@
# Required to distribute different parts of this
# package as multiple distribution
try:
import pkg_resources
pkg_resources.declare_namespace(__name__)
except ImportError:
from pkgutil import extend_path
__path__ = extend_path(__path__, __name__) # @ReservedAssignment

View File

@ -0,0 +1,42 @@
"""
* *******************************************************
* Copyright (c) VMware, Inc. 2013. All Rights Reserved.
* *******************************************************
*
* DISCLAIMER. THIS PROGRAM IS PROVIDED TO YOU "AS IS" WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, WHETHER ORAL OR WRITTEN,
* EXPRESS OR IMPLIED. THE AUTHOR SPECIFICALLY DISCLAIMS ANY IMPLIED
* WARRANTIES OR CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY,
* NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE.
"""
__author__ = 'VMware, Inc.'
__copyright__ = 'Copyright 2013 VMware, Inc. All rights reserved.'
import uuid
import string
import random
def generate_random_uuid():
return str(uuid.uuid4())
def rand(value):
return value + generate_random_string(5)
def generate_random_string(length):
return ''.join(random.choice(string.ascii_uppercase) for _i in range(length))
def main():
print(generate_random_uuid())
print(generate_random_string(5))
print(rand('Simple VM-'))
# Start program
if __name__ == "__main__":
main()

View File

@ -0,0 +1,362 @@
"""
* *******************************************************
* Copyright (c) VMware, Inc. 2013. All Rights Reserved.
* *******************************************************
*
* DISCLAIMER. THIS PROGRAM IS PROVIDED TO YOU "AS IS" WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, WHETHER ORAL OR WRITTEN,
* EXPRESS OR IMPLIED. THE AUTHOR SPECIFICALLY DISCLAIMS ANY IMPLIED
* WARRANTIES OR CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY,
* NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE.
"""
__author__ = 'VMware, Inc.'
__copyright__ = 'Copyright 2013 VMware, Inc. All rights reserved.'
import os
from suds.client import Client
class LookupServiceHelper(object):
def __init__(self, wsdl_url, soap_url, skip_verification):
self.wsdl_url = wsdl_url
self.soap_url = soap_url
self.skip_verification = skip_verification
self.client = None
self.managedObjectReference = None
self.serviceRegistration = None
def connect(self):
if self.client is None:
# Suds library doesn't support passing unverified context to disable
# server certificate verification. Thus disable checking globally in
# order to skip verification. This is not recommended in production
# code. see https://www.python.org/dev/peps/pep-0476/
if self.skip_verification:
import ssl
try:
_create_unverified_https_context = \
ssl._create_unverified_context
except AttributeError:
# Legacy Python that doesn't verify HTTPS certificates by
# default
pass
else:
# Handle target environment that doesn't support HTTPS
# verification
ssl._create_default_https_context = \
_create_unverified_https_context
self.client = Client(url=self.wsdl_url, location=self.soap_url)
assert self.client is not None
self.client.set_options(service='LsService', port='LsPort')
self.managedObjectReference = self.client.factory.create(
'ns0:ManagedObjectReference')
self.managedObjectReference._type = 'LookupServiceInstance'
self.managedObjectReference.value = 'ServiceInstance'
lookupServiceContent = self.client.service.RetrieveServiceContent(
self.managedObjectReference)
self.serviceRegistration = lookupServiceContent.serviceRegistration
def find_sso_urls(self):
"""
Finds all the SSO service URLs.
In an MxN setup where there are more than one infrastructure node; This method returns more than one URL.
:rtype: list
:return: list of SSO Service endpoint URLs
"""
return self.__find_platform_service_urls(product='com.vmware.cis',
service='cs.identity',
endpoint='com.vmware.cis.cs.identity.sso',
protocol='wsTrust')
def find_sso_url(self):
"""
Finds the SSO service URL.
In an MxN setup where there are more than one infrastructure node; This method returns the first SSO service endpoint URL
as returned by the lookup service.
:rtype: :class:`str`
:return: SSO Service endpoint URL
"""
result = self.__find_platform_service_urls(product='com.vmware.cis',
service='cs.identity',
endpoint='com.vmware.cis.cs.identity.sso',
protocol='wsTrust')
return result[0]
def find_vapi_urls(self):
"""
Finds all the vAPI service endpoint URLs.
In an MxN setup where there are more than one management node; this method returns more than one URL.
:rtype: dictionary
:return: vapi service endpoint URLs in a dictionary where the key is the node_id and the value is the service URL
"""
return self.__find_service_urls(product='com.vmware.cis',
service='cs.vapi',
endpoint='com.vmware.vapi.endpoint',
protocol='vapi.json.https.public')
def find_vapi_url(self, node_id):
"""
Finds the vapi service endpoint URL of a management node
:type: :class:`str`
:param node_id: The UUID of the management node
:rtype: :class:`str`
:return: vapi service endpoint URL of a management node or, None if no vapi endpoint is found
"""
assert node_id is not None
result = self.__find_service_urls(product='com.vmware.cis',
service='cs.vapi',
endpoint='com.vmware.vapi.endpoint',
protocol='vapi.json.https.public')
assert result is not None
return result.get(node_id)
def find_vim_urls(self):
"""
Finds all the vim service endpoint URLs.
In an MxN setup where there are more than one management node; this method returns more than one URL.
:rtype: dictionary
:return: vim service endpoint URLs in a dictionary where the key is the node_id and the value is the service URL
"""
return self.__find_service_urls(product='com.vmware.cis',
service='vcenterserver',
endpoint='com.vmware.vim',
protocol='vmomi')
def find_vim_url(self, node_id):
"""
Finds the vim service endpoint URL of a management node
:type: :class:`str`
:param node_id: The UUID of the management node
:rtype: :class:`str`
:return: vim service endpoint URL of a management node or, None if no vim endpoint is found
"""
assert node_id is not None
result = self.__find_service_urls(product='com.vmware.cis',
service='vcenterserver',
endpoint='com.vmware.vim',
protocol='vmomi')
assert result is not None
return result.get(node_id)
def find_vim_pbm_urls(self):
"""
Finds all the spbm service endpoint URLs.
In an MxN setup where there are more than one management node; this method returns more than one URL.
:rtype: dictionary
:return: spbm service endpoint URLs in a dictionary where the key is the node_id and the value is the service URL
"""
return self.__find_service_urls(product='com.vmware.vim.sms',
service='sms',
endpoint='com.vmware.vim.pbm',
protocol='https')
def find_vim_pbm_url(self, node_id):
"""
Finds the spbm service endpoint URL of a management node
:type: :class:`str`
:param node_id: The UUID of the management node
:rtype: :class:`str`
:return: spbm service endpoint URL of a management node or, None if no spbm endpoint is found
"""
assert node_id is not None
result = self.__find_service_urls(product='com.vmware.vim.sms',
service='sms',
endpoint='com.vmware.vim.pbm',
protocol='https')
assert result is not None
return result.get(node_id)
def __find_service_urls(self, product, service, endpoint, protocol):
"""
Finds the endpoint URLs of a service running on management nodes.
Returns a dictionary where the key is the management node id.
"""
assert self.client is not None
assert self.serviceRegistration is not None
lookupServiceRegistrationFilter = self.__create_filter_spec(product,
service,
endpoint,
protocol)
result = self.client.service.List(self.serviceRegistration,
lookupServiceRegistrationFilter)
assert len(result) > 0
# Support for MxN
# return the results in a dictionary where key is NodeId and Value is Service URL
results_dict = {}
for lookupServiceRegistrationInfo in result:
lookupServiceRegistrationEndpoint = \
lookupServiceRegistrationInfo.serviceEndpoints[0]
assert lookupServiceRegistrationEndpoint is not None
results_dict[
lookupServiceRegistrationInfo.nodeId] = lookupServiceRegistrationEndpoint.url
return results_dict
def __find_platform_service_urls(self, product, service, endpoint,
protocol):
"""
Finds the endpoint URLs of a service running on PSCs (Platform Service Controller).
Returns a list of service URLs since there is no node id associated with the PSC.
"""
assert self.client is not None
assert self.serviceRegistration is not None
lookupServiceRegistrationFilter = self.__create_filter_spec(product,
service,
endpoint,
protocol)
result = self.client.service.List(self.serviceRegistration,
lookupServiceRegistrationFilter)
assert len(result) > 0
urls = []
for lookupServiceRegistrationInfo in result:
lookupServiceRegistrationEndpoint = \
lookupServiceRegistrationInfo.serviceEndpoints[0]
assert lookupServiceRegistrationEndpoint is not None
urls.append(lookupServiceRegistrationEndpoint.url)
return urls
def __create_filter_spec(self, product, service, endpoint, protocol):
assert self.client is not None
lookupServiceRegistrationServiceType = self.client.factory.create(
'ns0:LookupServiceRegistrationServiceType')
lookupServiceRegistrationServiceType.product = product
lookupServiceRegistrationServiceType.type = service
lookupServiceRegistrationEndpointType = self.client.factory.create(
'ns0:LookupServiceRegistrationEndpointType')
lookupServiceRegistrationEndpointType.type = endpoint
lookupServiceRegistrationEndpointType.protocol = protocol
lookupServiceRegistrationFilter = self.client.factory.create(
'ns0:LookupServiceRegistrationFilter')
lookupServiceRegistrationFilter.serviceType = lookupServiceRegistrationServiceType
lookupServiceRegistrationFilter.endpointType = lookupServiceRegistrationEndpointType
return lookupServiceRegistrationFilter
def find_mgmt_nodes(self):
"""
Finds all the management nodes
:rtype: dictionary
:return: management node instance name and node id (UUID) in a dictionary
"""
assert self.client is not None
assert self.serviceRegistration is not None
lookupServiceRegistrationServiceType = self.client.factory.create(
'ns0:LookupServiceRegistrationServiceType')
lookupServiceRegistrationServiceType.product = 'com.vmware.cis'
lookupServiceRegistrationServiceType.type = 'vcenterserver'
lookupServiceRegistrationEndpointType = self.client.factory.create(
'ns0:LookupServiceRegistrationEndpointType')
lookupServiceRegistrationEndpointType.type = 'com.vmware.vim'
lookupServiceRegistrationEndpointType.protocol = 'vmomi'
lookupServiceRegistrationFilter = self.client.factory.create(
'ns0:LookupServiceRegistrationFilter')
lookupServiceRegistrationFilter.serviceType = lookupServiceRegistrationServiceType
lookupServiceRegistrationFilter.endpointType = lookupServiceRegistrationEndpointType
result = self.client.service.List(self.serviceRegistration,
lookupServiceRegistrationFilter)
assert len(result) > 0
results_dict = {}
for lookupServiceRegistrationInfo in result:
for lookupServiceRegistrationAttribute in lookupServiceRegistrationInfo.serviceAttributes:
if lookupServiceRegistrationAttribute.key == 'com.vmware.vim.vcenter.instanceName':
results_dict[
lookupServiceRegistrationAttribute.value] = lookupServiceRegistrationInfo.nodeId
return results_dict
def get_mgmt_node_id(self, instance_name):
"""
Get the management node id from the instance name
:type: :class:`str`
:param instance_name: The instance name of the management node
:rtype: :class:`str`
:return: The UUID of the management node or, None is no management node is found by the given instance name
"""
result = self.find_mgmt_nodes()
assert result is not None
return result.get(instance_name)
def get_mgmt_node_instance_name(self, node_id):
result = self.find_mgmt_nodes()
assert result is not None
for k, v in result.items():
if v == node_id:
return k
def get_default_mgmt_node(self):
"""
Finds the instance name and UUID of the management node for M1xN or, when the PSC and
management services all reside on a single node (embedded).
"""
result = self.find_mgmt_nodes()
assert result is not None
if len(result) < 1:
raise Exception('No management node found')
if len(result) > 1:
raise MultipleManagementNodeException(
MultipleManagementNodeException.format(result))
return list(result.keys())[0], list(result.values())[
0] # python 3.x dict.keys() returns a view rather than a list
class MultipleManagementNodeException(Exception):
def __init__(self, message):
super(MultipleManagementNodeException, self).__init__(message)
@staticmethod
def format(nodes):
"""
Formats the multiple management node exception message
:type: :class:`dict`
:param nodes: The dictionary containing management nodes
:rtype: :class:`str`
:return: Formatted string output
"""
message = 'Multiple Management Node Found on server'
for k, v in nodes.items():
message = message + os.linesep + 'Node name: {0} uuid: {1}'.format(
k, v)
return message
def main():
lookup_service_helper = LookupServiceHelper(
wsdl_url='file:///path/to/lookupservice.wsdl',
soap_url='https://server_ip/lookupservice/sdk')
lookup_service_helper.connect()
print(lookup_service_helper.find_sso_url())
print(lookup_service_helper.find_vapi_urls())
print(lookup_service_helper.find_vim_urls())
print(lookup_service_helper.find_vim_pbm_urls())
print(lookup_service_helper.find_mgmt_nodes())
# Start program
if __name__ == "__main__":
main()

View File

@ -0,0 +1,62 @@
"""
* *******************************************************
* Copyright (c) VMware, Inc. 2013, 2016. All Rights Reserved.
* *******************************************************
*
* DISCLAIMER. THIS PROGRAM IS PROVIDED TO YOU "AS IS" WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, WHETHER ORAL OR WRITTEN,
* EXPRESS OR IMPLIED. THE AUTHOR SPECIFICALLY DISCLAIMS ANY IMPLIED
* WARRANTIES OR CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY,
* NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE.
"""
__author__ = 'VMware, Inc.'
__copyright__ = 'Copyright 2013, 2016 VMware, Inc. All rights reserved.'
from vmware.vapi.security.sso import create_saml_bearer_security_context
from samples.vsphere.common import sso
from samples.vsphere.common.lookup_service_helper import LookupServiceHelper
from samples.vsphere.common.ssl_helper import get_unverified_context
class PlatformServiceController(object):
"""
Manages services on the infrastructure node (e.g. lookup service, SSO etc.)
"""
def __init__(self, lswsdlurl, lssoapurl, ssousername, ssopassword,
skip_verification):
self.lswsdlurl = lswsdlurl
self.lssoapurl = lssoapurl
self.ssousername = ssousername
self.ssopassword = ssopassword
self.lookupservicehelper = None
self.stsurl = None
self.bearer_token = None # SAML bearer token
self.sec_ctx = None # Security context
self.skip_verification = skip_verification
def login(self):
"""
Finds the SSO URL from the lookup service and retrieves the SAML token from STS URL
"""
print('Connecting to lookup service url: {0}'.format(self.lssoapurl))
self.lookupservicehelper = LookupServiceHelper(wsdl_url=self.lswsdlurl,
soap_url=self.lssoapurl,
skip_verification=self.skip_verification)
self.lookupservicehelper.connect()
self.stsurl = self.lookupservicehelper.find_sso_url()
assert self.stsurl is not None
print('Retrieving a SAML bearer token from STS url : {0}'.format(
self.stsurl))
au = sso.SsoAuthenticator(self.stsurl)
context = None
if self.skip_verification:
context = get_unverified_context()
self.bearer_token = au.get_bearer_saml_assertion(
self.ssousername, self.ssopassword, delegatable=True,
ssl_context=context)
self.sec_ctx = create_saml_bearer_security_context(self.bearer_token)

View File

@ -0,0 +1,103 @@
"""
* *******************************************************
* Copyright VMware, Inc. 2013, 2016. All Rights Reserved.
* *******************************************************
*
* DISCLAIMER. THIS PROGRAM IS PROVIDED TO YOU "AS IS" WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, WHETHER ORAL OR WRITTEN,
* EXPRESS OR IMPLIED. THE AUTHOR SPECIFICALLY DISCLAIMS ANY IMPLIED
* WARRANTIES OR CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY,
* NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE.
"""
__author__ = 'VMware, Inc.'
__copyright__ = 'Copyright 2013, 2016 VMware, Inc. All rights reserved.'
import argparse
import traceback
from samples.vsphere.common.service_manager_factory import ServiceManagerFactory
class SampleBase(object):
def __init__(self, description):
if description is None:
raise Exception('Sample description cannot be empty')
self.description = description
# setup the argument parser
self.argparser = argparse.ArgumentParser(description=description)
self.argparser.add_argument('-s', '--server',
help='Hostname of vCenter Server')
self.argparser.add_argument('-u', '--username',
help='Username to login to the vCenter Server')
self.argparser.add_argument('-p', '--password',
help='Password to login to the vCenter Server')
self.argparser.add_argument('-c', '--cleardata', action='store_true',
help='Clears the sample data on server after running')
self.argparser.add_argument('-v', '--skipverification',
action='store_true',
help='Do not verify server certificate')
self.args = None
self.server = None
self.username = None
self.password = None
self.cleardata = False
self.skip_verification = False
def parse_args(self):
for name in dir(self):
attr = getattr(self, name)
if callable(attr) and name == '_options':
attr() # calling the method
self.args = self.argparser.parse_args() # parse all the sample arguments when they are all set
self.server = self.args.server
assert self.server is not None
print('server: {0}'.format(self.server))
self.username = self.args.username
assert self.username is not None
self.password = self.args.password
assert self.password is not None
self.cleardata = self.args.cleardata
self.skip_verification = self.args.skipverification
def before(self):
for name in dir(self):
attr = getattr(self, name)
if callable(attr) and name == '_setup':
attr() # calling the method
def run(self):
for name in dir(self):
attr = getattr(self, name)
if callable(attr) and name == '_execute':
try:
attr() # calling the method
except Exception as e:
# print the exception and move on to the cleanup stage if cleardata is set to True.
traceback.print_exc()
if bool(self.cleardata) is not True:
# re-throw the exception
raise Exception(e)
def after(self):
if bool(self.cleardata) is True:
for name in dir(self):
attr = getattr(self, name)
if callable(attr) and name == '_cleanup':
attr() # calling the method
def main(self):
self.parse_args()
self.before()
self.run()
self.after()
def get_service_manager(self):
return ServiceManagerFactory.get_service_manager(self.server,
self.username,
self.password,
self.skip_verification)

View File

@ -0,0 +1,53 @@
"""
* *******************************************************
* Copyright (c) VMware, Inc. 2016. All Rights Reserved.
* *******************************************************
*
* DISCLAIMER. THIS PROGRAM IS PROVIDED TO YOU "AS IS" WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, WHETHER ORAL OR WRITTEN,
* EXPRESS OR IMPLIED. THE AUTHOR SPECIFICALLY DISCLAIMS ANY IMPLIED
* WARRANTIES OR CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY,
* NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE.
"""
__author__ = 'VMware, Inc.'
__copyright__ = 'Copyright 2016 VMware, Inc. All rights reserved.'
import argparse
def build_arg_parser():
"""
Builds a standard argument parser with arguments for talking to vCenter
-s server
-u username
-p password
-c cleanup
-v skip_verification
"""
parser = argparse.ArgumentParser(
description='Standard Arguments for talking to vCenter')
parser.add_argument('-s', '--server',
action='store',
help='vSphere service IP to connect to')
parser.add_argument('-u', '--username',
action='store',
help='Username to use when connecting to vc')
parser.add_argument('-p', '--password',
action='store',
help='Password to use when connecting to vc')
parser.add_argument('-c', '--cleanup',
action='store_true',
help='Clean up after sample run. ')
parser.add_argument('-v', '--skipverification',
action='store_true',
help='Verify server certificate when connecting to vc.')
return parser

View File

@ -0,0 +1,169 @@
"""
* *******************************************************
* Copyright (c) VMware, Inc. 2016. All Rights Reserved.
* *******************************************************
*
* DISCLAIMER. THIS PROGRAM IS PROVIDED TO YOU "AS IS" WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, WHETHER ORAL OR WRITTEN,
* EXPRESS OR IMPLIED. THE AUTHOR SPECIFICALLY DISCLAIMS ANY IMPLIED
* WARRANTIES OR CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY,
* NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE.
"""
__author__ = 'VMware, Inc.'
__copyright__ = 'Copyright 2016 VMware, Inc. All rights reserved.'
from six.moves import cStringIO
from vmware.vapi.bindings.struct import PrettyPrinter
from samples.vsphere.common import sample_cli
from samples.vsphere.vcenter.setup import testbed
def pp(value):
""" Utility method used to print the data nicely. """
output = cStringIO()
PrettyPrinter(stream=output).pprint(value)
return output.getvalue()
def parse_cli_args():
"""
Parse the server IP and credential used by samples.
Use values from command line arguments if present, otherwise use values
from testbed.py
"""
# parse command line
parser = sample_cli.build_arg_parser()
args = parser.parse_args()
return process_cli_args(args)
def parse_cli_args_vm(vm_name):
"""
Parse the server IP, credential and vm name used by vcenter vm samples.
Use values from command line arguments if present, otherwise use values
from testbed.py
"""
# parse command line
parser = sample_cli.build_arg_parser()
parser.add_argument('-n', '--vm_name',
action='store',
help='Name of the testing vm')
args = parser.parse_args()
server, username, password, cleardata, skip_verification = \
process_cli_args(args)
if args.vm_name:
vm_name = args.vm_name
else:
print("Try to use vm name({}) specified in testbed.py".format(vm_name))
if not vm_name:
raise Exception("vm name is required")
print("vm name = {}".format(vm_name))
return server, username, password, cleardata, skip_verification, vm_name
def process_cli_args(args):
"""
Process server IP and credential args.
"""
if args.server:
server = args.server
else:
print("Using vcenter server specified in testbed.py")
server = testbed.config['SERVER']
if not server:
raise Exception("vcenter server is required")
print("vcenter server = {}".format(server))
if args.username:
username = args.username
else:
print("Using vc user specified in testbed.py")
username = testbed.config['USERNAME']
if not username:
raise Exception("vc username is required")
print("vc username = {}".format(username))
if args.password:
password = args.password
else:
print("Using vc password specified in testbed.py")
password = testbed.config['PASSWORD']
cleardata = args.cleanup
print("sample cleanup = {}".format(cleardata))
skip_verification = args.skipverification
print("skip server cert verification = {}".format(skip_verification))
return server, username, password, cleardata, skip_verification
class Context(object):
"""Class that holds common context for running vcenter samples."""
def __init__(self, testbed, service_instance, stub_config):
# Testbed configuration
self.testbed = testbed
# pyVmomi SOAP Service Instance
self.service_instance = service_instance
# vAPI stub configuration used to make other stubs
self.stub_config = stub_config
self.option = {}
@property
def testbed(self):
return self._testbed
@testbed.setter
def testbed(self, value):
self._testbed = value
@property
def service_instance(self):
return self._service_instance
@service_instance.setter
def service_instance(self, value):
self._service_instance = value
@property
def soap_stub(self):
return self._service_instance._stub
@soap_stub.setter
def soap_stub(self, value):
self._soap_stub = value
@property
def stub_config(self):
return self._stub_config
@stub_config.setter
def stub_config(self, value):
self._stub_config = value
@property
def option(self):
return self._option
@option.setter
def option(self, value):
self._option = value
def to_option_string(self):
s = ['=' * 79,
'Testbed Options:',
'=' * 79]
s += [' {}: {}'.format(k, self._option[k])
for k in sorted(self._option.keys())]
s += ['=' * 79]
return '\n'.join(s)

View File

@ -0,0 +1,66 @@
"""
* *******************************************************
* Copyright VMware, Inc. 2013, 2016. All Rights Reserved.
* *******************************************************
*
* DISCLAIMER. THIS PROGRAM IS PROVIDED TO YOU "AS IS" WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, WHETHER ORAL OR WRITTEN,
* EXPRESS OR IMPLIED. THE AUTHOR SPECIFICALLY DISCLAIMS ANY IMPLIED
* WARRANTIES OR CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY,
* NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE.
"""
__author__ = 'VMware, Inc.'
__copyright__ = 'Copyright 2013, 2016 VMware, Inc. All rights reserved.'
from pyVim.connect import SmartConnect, Disconnect
from samples.vsphere.common import vapiconnect
from samples.vsphere.common.ssl_helper import get_unverified_context
class ServiceManager(object):
"""
Manages Vim and vAPI services on a management node.
"""
def __init__(self, server, username, password, skip_verification):
self.server_url = server
self.username = username
self.password = password
self.skip_verification = skip_verification
self.vapi_url = None
self.vim_url = None
self.session = None
self.session_id = None
self.stub_config = None
self.si = None
self.content = None
self.vim_uuid = None
def connect(self):
# Connect to vAPI Endpoint on vCenter Server system
self.stub_config = vapiconnect.connect(host=self.server_url,
user=self.username,
pwd=self.password,
skip_verification=self.skip_verification)
# Connect to VIM API Endpoint on vCenter Server system
context = None
if self.skip_verification:
context = get_unverified_context()
self.si = SmartConnect(host=self.server_url,
user=self.username,
pwd=self.password,
sslContext=context)
assert self.si is not None
# Retrieve the service content
self.content = self.si.RetrieveContent()
assert self.content is not None
self.vim_uuid = self.content.about.instanceUuid
def disconnect(self):
print('disconnecting the session')
vapiconnect.logout(self.stub_config)
Disconnect(self.si)

View File

@ -0,0 +1,41 @@
"""
* *******************************************************
* Copyright (c) VMware, Inc. 2013, 2016. All Rights Reserved.
* *******************************************************
*
* DISCLAIMER. THIS PROGRAM IS PROVIDED TO YOU "AS IS" WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, WHETHER ORAL OR WRITTEN,
* EXPRESS OR IMPLIED. THE AUTHOR SPECIFICALLY DISCLAIMS ANY IMPLIED
* WARRANTIES OR CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY,
* NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE.
"""
__author__ = 'VMware, Inc.'
__copyright__ = 'Copyright 2013, 2016 VMware, Inc. All rights reserved.'
from samples.vsphere.common.service_manager import ServiceManager
class ServiceManagerFactory(object):
"""
Factory class for getting service manager for a management node.
"""
service_manager = None
@classmethod
def get_service_manager(cls, server, username, password, skip_verification):
cls.service_manager = ServiceManager(server,
username,
password,
skip_verification)
cls.service_manager.connect()
return cls.service_manager
@classmethod
def disconnect(cls):
if cls.service_manager:
cls.service_manager.disconnect()
import atexit
atexit.register(ServiceManagerFactory.disconnect)

View File

@ -0,0 +1,28 @@
"""
* *******************************************************
* Copyright (c) VMware, Inc. 2013, 2016. All Rights Reserved.
* *******************************************************
*
* DISCLAIMER. THIS PROGRAM IS PROVIDED TO YOU "AS IS" WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, WHETHER ORAL OR WRITTEN,
* EXPRESS OR IMPLIED. THE AUTHOR SPECIFICALLY DISCLAIMS ANY IMPLIED
* WARRANTIES OR CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY,
* NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE.
"""
__author__ = 'VMware, Inc.'
__copyright__ = 'Copyright 2016 VMware, Inc. All rights reserved.'
import ssl
def get_unverified_context():
"""
Get an unverified ssl context. Used to disable the server certificate
verification.
@return: unverified ssl context.
"""
context = None
if hasattr(ssl, '_create_unverified_context'):
context = ssl._create_unverified_context()
return context

View File

@ -0,0 +1,536 @@
"""
* *******************************************************
* Copyright VMware, Inc. 2013, 2016. All Rights Reserved.
* *******************************************************
*
* DISCLAIMER. THIS PROGRAM IS PROVIDED TO YOU "AS IS" WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, WHETHER ORAL OR WRITTEN,
* EXPRESS OR IMPLIED. THE AUTHOR SPECIFICALLY DISCLAIMS ANY IMPLIED
* WARRANTIES OR CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY,
* NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE.
"""
__author__ = 'VMware, Inc.'
__copyright__ = 'Copyright 2013, 2016 VMware, Inc. All rights reserved.'
# Standard library imports.
try:
import httplib
except ImportError:
import http.client as httplib
import base64
import cgi
import hashlib
import re
import sys
import time
from uuid import uuid4
try:
from StringIO import StringIO
except ImportError:
from io import StringIO
try:
from urlparse import urlparse
except ImportError:
from urllib.parse import urlparse
# Third-party imports.
from lxml import etree
def _extract_certificate(cert):
"""
Extract DER certificate/private key from DER/base64-ed DER/PEM string.
@type cert: C{str}
@param cert: Certificate/private key in one of three supported formats.
@rtype: C{str}
@return: Certificate/private key in DER (binary ASN.1) format.
"""
if not cert:
raise IOError('Empty certificate')
signature = cert[0]
# DER certificate is sequence. ASN.1 sequence is 0x30.
if signature == '\x30':
return cert
# PEM without preamble. Base64-encoded 0x30 is 0x4D.
if signature == '\x4D':
return base64.b64decode(cert)
# PEM with preamble. Starts with '-'.
if signature == '-':
return base64.b64decode(re.sub('-----[A-Z ]*-----', '', cert))
# Unknown format.
raise IOError('Invalid certificate file format')
class SoapException(Exception):
"""
Exception raised in case of STS request failure.
"""
def __init__(self, soap_msg, fault_code, fault_string):
"""
Initializer for SoapException.
@type soap_msg: C{str}
@param soap_msg: the soap fault XML returned by STS
@type fault_code: C{str}
@param fault_code: The fault code returned by STS.
@type fault_string: C{str}
@param fault_string: The fault string returned by STS.
"""
self._soap_msg = soap_msg
self._fault_code = fault_code
self._fault_string = fault_string
Exception.__init__(self)
def __str__(self):
"""
Returns the string representation of SoapException.
@rtype: C{str}
@return: string representation of SoapException
"""
return ("SoapException:\nfaultcode: %(_fault_code)s\n"
"faultstring: %(_fault_string)s\n"
"faultxml: %(_soap_msg)s" % self.__dict__)
class SSOHTTPSConnection(httplib.HTTPSConnection):
"""
An HTTPS class that verifies server's certificate on connect.
"""
def __init__(self, *args, **kwargs):
"""
Initializer. See httplib.HTTPSConnection for other arguments
than thumbprint and server_cert.
At least one of thumbprint, server_cert should be provided,
otherwise server certificate is not validated.
@type thumbprint: C(str)
@param thumbprint: Expected SHA-1 thumbprint of the server
certificate. May be None.
@type server_cert: C(str)
@param server_cert: File with expected server certificate.
May be None.
"""
self.server_thumbprint = kwargs.pop('thumbprint')
if self.server_thumbprint is not None:
self.server_thumbprint = re.sub(':', '',
self.server_thumbprint.lower())
server_cert_path = kwargs.pop('server_cert')
if server_cert_path is not None:
with open(server_cert_path, 'rb') as f:
server_cert = f.read()
self.server_cert = _extract_certificate(server_cert)
else:
self.server_cert = None
httplib.HTTPSConnection.__init__(self, *args, **kwargs)
def _check_cert(self, peerCert):
"""
Verify that peer certificate matches one we expect.
@type peerCert: C(str)
@param peerCert: Server certificate in DER format.
@rtype: boolean
@return: True if peerCert is acceptable. False otherwise.
"""
if self.server_cert is not None:
if peerCert != self.server_cert:
return False
if self.server_thumbprint is not None:
thumbprint = hashlib.sha1(peerCert).hexdigest().lower() # pylint: disable=E1101
if thumbprint != self.server_thumbprint:
return False
return True
def connect(self):
"""
Connect method: connects to the remote system, and upon
successful connection validates certificate.
Throws an exception when something is wrong. See
httplib.HTTPSConnection.connect() for details.
"""
httplib.HTTPSConnection.connect(self)
if not self._check_cert(self.sock.getpeercert(True)):
self.sock.close()
self.sock = None
raise IOError('Invalid certificate')
class SsoAuthenticator(object):
"""
A class to handle the transport layer communication between the client and
the STS service.
"""
def __init__(self,
sts_url,
sts_cert=None,
thumbprint=None
):
"""
Initializer for SsoAuthenticator.
@type sts_url: C{str}
@param sts_url: URL for the Security Token Service. Usually
obtained by querying Component Manager.
@type sts_cert: C{str}
@param sts_cert: The file with public key of the Security
Token Service. Usually obtained from
Component Manager and written to the file.
@type thumbprint: C{str}
@param thumbprint: The SHA-1 thumbprint of the certificate used
by the Security Token Service. It is same
thumbprint you can pass to pyVmomi SoapAdapter.
"""
self._sts_cert = sts_cert
self._sts_url = sts_url
self._sts_thumbprint = thumbprint
def perform_request(self,
soap_message,
public_key=None,
private_key=None,
ssl_context=None):
"""
Performs a Holder-of-Key SAML token request using the service user's
certificates or a bearer token request using the user credentials.
@type soap_message: C{str}
@param soap_message: Authentication SOAP request.
@type public_key: C{str}
@param public_key: File containing the public key for the service
user registered with SSO, in PEM format.
@type private_key: C{str}
@param private_key: File containing the private key for the service
user registered with SSO, in PEM format.
@type ssl_context: ssl.SSLContext
@param ssl_context: Context describing the various SSL options.
@rtype: C{str}
@return: Response received from the STS after the HoK request.
"""
parsed = urlparse(self._sts_url)
host = parsed.netloc # pylint: disable=E1101
import ssl
if ssl_context and hasattr(ssl, '_create_unverified_context'):
# Python 2.7.9 has stronger SSL certificate validation, so we need
# to pass in a context when dealing with self-signed certificates.
webservice = SSOHTTPSConnection(host=host,
key_file=private_key,
cert_file=public_key,
server_cert=self._sts_cert,
thumbprint=self._sts_thumbprint,
context=ssl_context)
else:
# Versions of Python before 2.7.9 don't support the context
# parameter, so if it wan't provided, don't pass it on.
webservice = SSOHTTPSConnection(host=host,
key_file=private_key,
cert_file=public_key,
server_cert=self._sts_cert,
thumbprint=self._sts_thumbprint)
webservice.putrequest("POST", parsed.path, skip_host=True) # pylint: disable=E1101
webservice.putheader("Host", host)
webservice.putheader("User-Agent", "VMware/pyVmomi")
webservice.putheader("Accept", "text/xml, multipart/related")
webservice.putheader("Content-type", "text/xml; charset=\"UTF-8\"")
webservice.putheader("Content-length", "%d" % len(soap_message))
webservice.putheader("Connection", "keep-alive")
webservice.putheader("SOAPAction",
"http://docs.oasis-open.org/ws-sx/ws-trust/200512/RST/Issue")
webservice.endheaders()
if sys.version_info[0] >= 3: # Python 3
webservice.send(bytes(soap_message, 'UTF-8'))
else:
webservice.send(soap_message)
saml_response = webservice.getresponse()
if saml_response.status != 200:
fault = saml_response.read()
# Best effort at figuring out a SOAP fault.
if saml_response.status == 500 and fault and 'faultcode' in fault:
fault_xml = etree.fromstring(fault)
parsed_fault = fault_xml.xpath("//text()")
if len(parsed_fault) == 2:
raise SoapException(fault, *parsed_fault)
raise Exception("Got response %s: %s\n%s" %
(saml_response.status, saml_response.msg, fault))
return saml_response.read()
def get_bearer_saml_assertion(self,
username,
password,
public_key=None,
private_key=None,
request_duration=60,
token_duration=600,
delegatable=False,
renewable=False,
ssl_context=None):
"""
Extracts the assertion from the Bearer Token received from the Security
Token Service.
@type username: C{str}
@param username: Username for the user for which bearer token
needs to be requested.
@type password: C{str}
@param password: Password for the user for which bearer token
needs to be requested.
@type public_key: C{str}
@param public_key: File containing the public key for the service
user registered with SSO, in PEM format.
@type private_key: C{str}
@param private_key: File containing the private key for the service
user registered with SSO, in PEM format.
@type request_duration: C{long}
@param request_duration: The duration for which the request is valid. If
the STS receives this request after this
duration, it is assumed to have expired. The
duration is in seconds and the default is 60s.
@type token_duration: C{long}
@param token_duration: The duration for which the SAML token is issued
for. The duration is specified in seconds and
the default is 600s.
@type delegatable: C{boolean}
@param delegatable: Whether the generated token is delegatable or not
The default value is False
@type ssl_context: ssl.SSLContext
@param ssl_context: Context describing the various SSL options.
@rtype: C{str}
@return: The SAML assertion.
"""
request = SecurityTokenRequest(username=username,
password=password,
public_key=public_key,
private_key=private_key,
request_duration=request_duration,
token_duration=token_duration)
soap_message = request.construct_bearer_token_request(
delegatable=delegatable, renewable=renewable)
bearer_token = self.perform_request(soap_message,
public_key,
private_key,
ssl_context)
if sys.version_info[0] >= 3:
return etree.tostring(
_extract_element(etree.fromstring(bearer_token),
'Assertion',
{'saml2': "urn:oasis:names:tc:SAML:2.0:assertion"}),
pretty_print=False).decode('utf-8')
else:
return etree.tostring(
_extract_element(etree.fromstring(bearer_token),
'Assertion',
{'saml2': "urn:oasis:names:tc:SAML:2.0:assertion"}),
pretty_print=False)
class SecurityTokenRequest(object):
"""
SecurityTokenRequest class handles the serialization of request to the STS
for a SAML token.
"""
# pylint: disable=R0902
def __init__(self,
username=None,
password=None,
public_key=None,
private_key=None,
request_duration=60,
token_duration=600):
"""
Initializer for the SecurityToken Request class.
@type username: C{str}
@param username: Username for the user for which bearer token
needs to be requested.
@type password: C{str}
@param password: Password for the user for which bearer token
needs to be requested.
@type public_key: C{str}
@param public_key: The file containing the public key of the
service account requesting the SAML token.
@type private_key: C{str}
@param private_key: The file containing the private key of the
service account requesting the SAML token.
@type request_duration: C{long}
@param request_duration: The duration for which the request is valid. If
the STS receives this request after this
duration, it is assumed to have expired. The
duration is specified in seconds and default is
60s.
@type token_duration: C{long}
@param token_duraiton: The duration for which the SAML token is issued
for. The duration is specified in seconds and
the default is 600s.
"""
self._timestamp_id = _generate_id()
self._signature_id = _generate_id()
self._request_id = _generate_id()
self._security_token_id = _generate_id()
current = time.time()
self._created = time.strftime(TIME_FORMAT,
time.gmtime(current))
self._expires = time.strftime(TIME_FORMAT,
time.gmtime(current + token_duration))
self._request_expires = time.strftime(TIME_FORMAT,
time.gmtime(current +
request_duration))
self._timestamp = TIMESTAMP_TEMPLATE % self.__dict__
self._username = cgi.escape(username) if username else username
self._password = cgi.escape(password) if password else password
self._public_key_file = public_key
self._private_key_file = private_key
self._act_as_token = None
self._renewable = str(False).lower()
self._delegatable = str(False).lower()
self._use_key = ''
self._private_key = None
self._binary_exchange = None
self._public_key = None
def construct_bearer_token_request(self, delegatable=False, renewable=False):
"""
Constructs the actual Bearer token SOAP request.
@type delegatable: C{boolean}
@param delegatable: Whether the generated token is delegatable or not
@type renewable: C{boolean}
@param renewable: Whether the generated token is renewable or not
The default value is False
@rtype: C{str}
@return: Bearer token SOAP request.
"""
self._key_type = "http://docs.oasis-open.org/ws-sx/ws-trust/200512/Bearer"
self._security_token = USERNAME_TOKEN_TEMPLATE % self.__dict__
self._delegatable = str(delegatable).lower()
self._renewable = str(renewable).lower()
return _canonicalize(REQUEST_TEMPLATE % self.__dict__)
def _generate_id():
"""
An internal helper method to generate UUIDs.
@rtype: C{str}
@return: UUID
"""
return "_%s" % uuid4()
def _canonicalize(xml_string):
"""
Given an xml string, canonicalize the string per
U{http://www.w3.org/2001/10/xml-exc-c14n#}
@type xml_string: C{str}
@param xml_string: The XML string that needs to be canonicalized.
@rtype: C{str}
@return: Canonicalized string.
"""
string = StringIO(xml_string)
parser = etree.XMLParser(remove_blank_text=True)
tree = etree.parse(string, parser=parser)
# io.StringIO only accepts Unicode input (i.e. u"multibyte string"), while StringIO.StringIO accepts either 8 bit input or unicode input.
if sys.version_info[0] >= 3:
from io import BytesIO
string = BytesIO()
tree.write_c14n(string, exclusive=True, with_comments=False)
return string.getvalue().decode('utf-8')
else:
string = StringIO()
tree.write_c14n(string, exclusive=True, with_comments=False)
return string.getvalue()
def _extract_element(xml, element_name, namespace):
"""
An internal method provided to extract an element from the given XML.
@type xml: C{str}
@param xml: The XML string from which the element will be extracted.
@type element_name: C{str}
@param element_name: The element that needs to be extracted from the XML.
@type namespace: dict
@param namespace: A dict containing the namespace of the element to be
extracted.
@rtype: etree element.
@return: The extracted element.
"""
assert(len(namespace) == 1)
result = xml.xpath("//%s:%s" % (list(namespace.keys())[0], element_name), # python 3.x dict.keys() returns a view
namespaces=namespace)
if result:
return result[0]
else:
raise KeyError('%s does not seem to be present in the XML.' %
element_name)
TIME_FORMAT = "%Y-%m-%dT%H:%M:%S.987Z"
# Template container for user's credentials when requesting a bearer token.
USERNAME_TOKEN_TEMPLATE = """\
<ns2:UsernameToken xmlns:ns2="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<ns2:Username>%(_username)s</ns2:Username>
<ns2:Password>%(_password)s</ns2:Password>
</ns2:UsernameToken>"""
# Template containing the anchor to the signature.
USE_KEY_TEMPLATE = """\
<UseKey Sig="%(_signature_id)s"/>"""
# The follwoing template is used to create a timestamp for the various messages.
# The timestamp is used to indicate the duration of the request itself.
TIMESTAMP_TEMPLATE = """\
<ns3:Timestamp xmlns:ns3="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" ns3:Id="%(_timestamp_id)s">
<ns3:Created>%(_created)s</ns3:Created><ns3:Expires>%(_request_expires)s</ns3:Expires></ns3:Timestamp>"""
# The following template is used to construct the token requests to the STS.
REQUEST_TEMPLATE = """\
<SOAP-ENV:Envelope xmlns:SOAP-ENV="http://schemas.xmlsoap.org/soap/envelope/">
<SOAP-ENV:Header>
<ns6:Security xmlns="http://docs.oasis-open.org/ws-sx/ws-trust/200512"
xmlns:ns2="http://www.w3.org/2005/08/addressing"
xmlns:ns3="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
xmlns:ns6="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
%(_timestamp)s
%(_security_token)s
</ns6:Security>
</SOAP-ENV:Header>
<SOAP-ENV:Body xmlns:wsu="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd" wsu:Id="%(_request_id)s">
<RequestSecurityToken xmlns="http://docs.oasis-open.org/ws-sx/ws-trust/200512"
xmlns:ns2="http://www.w3.org/2005/08/addressing"
xmlns:ns3="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-utility-1.0.xsd"
xmlns:ns6="http://docs.oasis-open.org/wss/2004/01/oasis-200401-wss-wssecurity-secext-1.0.xsd">
<TokenType>urn:oasis:names:tc:SAML:2.0:assertion</TokenType>
<RequestType>http://docs.oasis-open.org/ws-sx/ws-trust/200512/Issue</RequestType>
<Lifetime>
<ns3:Created>%(_created)s</ns3:Created>
<ns3:Expires>%(_expires)s</ns3:Expires>
</Lifetime>
<Renewing Allow="%(_renewable)s" OK="%(_renewable)s"/>
<Delegatable>%(_delegatable)s</Delegatable>
<KeyType>%(_key_type)s</KeyType>
<SignatureAlgorithm>http://www.w3.org/2001/04/xmldsig-more#rsa-sha256</SignatureAlgorithm>%(_use_key)s</RequestSecurityToken>
</SOAP-ENV:Body>
</SOAP-ENV:Envelope>"""

View File

@ -0,0 +1,95 @@
"""
* *******************************************************
* Copyright (c) VMware, Inc. 2016. All Rights Reserved.
* *******************************************************
*
* DISCLAIMER. THIS PROGRAM IS PROVIDED TO YOU "AS IS" WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, WHETHER ORAL OR WRITTEN,
* EXPRESS OR IMPLIED. THE AUTHOR SPECIFICALLY DISCLAIMS ANY IMPLIED
* WARRANTIES OR CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY,
* NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE.
"""
__author__ = 'VMware, Inc.'
__copyright__ = 'Copyright 2016 VMware, Inc. All rights reserved.'
import requests
from com.vmware.cis_client import Session
from vmware.vapi.lib.connect import get_requests_connector
from vmware.vapi.security.session import create_session_security_context
from vmware.vapi.security.user_password import \
create_user_password_security_context
from vmware.vapi.stdlib.client.factories import StubConfigurationFactory
def get_jsonrpc_endpoint_url(host):
# The URL for the stub requests are made against the /api HTTP endpoint
# of the vCenter system.
return "https://{}/api".format(host)
def connect(host, user, pwd, skip_verification=False, suppress_warning=True):
"""
Create an authenticated stub configuration object that can be used to issue
requests against vCenter.
Returns a stub_config that stores the session identifier that can be used
to issue authenticated requests against vCenter.
"""
host_url = get_jsonrpc_endpoint_url(host)
session = requests.Session()
if skip_verification:
session = create_unverified_session(session, suppress_warning)
connector = get_requests_connector(session=session, url=host_url)
stub_config = StubConfigurationFactory.new_std_configuration(connector)
return login(stub_config, user, pwd)
def login(stub_config, user, pwd):
"""
Create an authenticated session with vCenter.
Returns a stub_config that stores the session identifier that can be used
to issue authenticated requests against vCenter.
"""
# Pass user credentials (user/password) in the security context to
# authenticate.
user_password_security_context = create_user_password_security_context(user,
pwd)
stub_config.connector.set_security_context(user_password_security_context)
# Create the stub for the session service and login by creating a session.
session_svc = Session(stub_config)
session_id = session_svc.create()
# Successful authentication. Store the session identifier in the security
# context of the stub and use that for all subsequent remote requests
session_security_context = create_session_security_context(session_id)
stub_config.connector.set_security_context(session_security_context)
return stub_config
def logout(stub_config):
"""
Delete session with vCenter.
"""
if stub_config:
session_svc = Session(stub_config)
session_svc.delete()
def create_unverified_session(session, suppress_warning=True):
"""
Create a unverified session to disable the server certificate verification.
"""
session.verify = False
if suppress_warning:
# Suppress unverified https request warnings
from requests.packages.urllib3.exceptions import InsecureRequestWarning
requests.packages.urllib3.disable_warnings(InsecureRequestWarning)
return session

View File

@ -0,0 +1,10 @@
# Required to distribute different parts of this
# package as multiple distribution
try:
import pkg_resources
pkg_resources.declare_namespace(__name__)
except ImportError:
from pkgutil import extend_path
__path__ = extend_path(__path__, __name__) # @ReservedAssignment

View File

@ -0,0 +1,342 @@
"""
* *******************************************************
* Copyright (c) VMware, Inc. 2016. All Rights Reserved.
* *******************************************************
*
* DISCLAIMER. THIS PROGRAM IS PROVIDED TO YOU "AS IS" WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, WHETHER ORAL OR WRITTEN,
* EXPRESS OR IMPLIED. THE AUTHOR SPECIFICALLY DISCLAIMS ANY IMPLIED
* WARRANTIES OR CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY,
* NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE.
"""
__author__ = 'VMware, Inc.'
__copyright__ = 'Copyright 2016 VMware, Inc. All rights reserved.'
import pyVim.task
import requests
from pyVmomi import vim
from samples.vsphere.common.vim.inventory import get_datacenter_for_datastore
# TODO:
# verify=False in all cases. Expose this as a top level control
debug = False
(FILE, FOLDER) = range(2)
class FileArray(list):
def list(self, path=None):
children = FileArray()
for e in self:
children += e.list(path)
return children
def __repr__(self):
return '\n'.join([str(e) for e in self])
def _check_unique(self):
if len(self) == 0:
raise Exception('FileArray: No elements')
elif len(self) > 1:
raise Exception('FileArray: Maybe applied to only one element')
@property
def path(self):
self._check_unique()
return self[0].path
@property
def datastore_path(self):
self._check_unique()
return self[0].datastore_path
@property
def datastore_mo(self):
self._check_unique()
return self[0].datastore_mo
@property
def type(self):
self._check_unique()
return self[0].type
def list(self, path=None):
self._check_unique()
return self[0].list(path)
def put(self, path=None, src_url=None, src_file=None, src_path=None,
content=None):
self._check_unique()
return self[0].put(path, src_url, src_file, src_path, content)
def get(self, path=None):
self._check_unique()
return self[0].get(path)
def exists(self, path=None):
self._check_unique()
return self[0].exists(path)
def delete(self, path=None):
self._check_unique()
return self[0].delete(path)
def delete2(self, path=None):
self._check_unique()
return self[0].delete2(path)
def mkdir(self, path=None, parent=None):
self._check_unique()
return self[0].mkdir(path, parent)
class File(object):
"""
Utility class contains datastore related helper methods using vim API
and HTTP requests module.
"""
def __init__(self, parent=None, path=None, ftype=None):
self._file_manager = None
if isinstance(parent, vim.Datastore):
# Iteratively look for the Datacenter parent
self._datacenter_mo = get_datacenter_for_datastore(parent)
self._datastore_mo = parent
self._ftype = FOLDER
if path:
self._path = path
else:
self._path = ''
elif isinstance(parent, File):
self._datacenter_mo = parent._datacenter_mo
self._datastore_mo = parent.datastore_mo
self._ftype = ftype
if parent._path == '':
self._path = path
else:
self._path = '{}/{}'.format(parent._path, path)
else:
raise Exception(
"Invalid type '{}' for datastore_file".format(type(parent)))
def _get_file_manager(self):
if not self._file_manager:
soap_stub = self._datacenter_mo._stub
service_instance = vim.ServiceInstance('ServiceInstance', soap_stub)
self._file_manager = service_instance.content.fileManager
return self._file_manager
@property
def path(self):
return self._path
@path.setter
def path(self, value):
self._path = value
def get_datastore_path(self, path=None):
if not path:
return self.datastore_path
paths = [p for p in [self._path, path] if p]
return '[{}] {}'.format(self._datastore_mo.name, '/'.join(paths))
@property
def datastore_path(self):
if self._path != '':
return '[{}] {}'.format(self._datastore_mo.name, self._path)
else:
return '[{}]'.format(self._datastore_mo.name)
@property
def datastore_mo(self):
return self._datastore_mo
@datastore_mo.setter
def datastore_mo(self, value):
self._datastore_mo = value
@property
def type(self):
return self._ftype
@type.setter
def type(self, value):
self._ftype = value
def to_string(self):
s = ''
if self._ftype == FOLDER:
s += 'D '
else:
s += 'F '
s += self.datastore_path
return s
def __repr__(self):
return self.to_string()
def list(self, path=None):
match_pattern = None
dirname = None
if path is not None:
# Determine the dirname and the basename making sure only the
# basename is passed in the match_pattern
paths = path.split('/')
if len(paths) == 1:
dirname = paths[0]
else:
path = paths[-1]
dirname = '/'.join(paths[0:-1])
match_pattern = [path]
browser = self._datastore_mo.browser
search_spec = vim.host.DatastoreBrowser.SearchSpec(
query=[vim.host.DatastoreBrowser.FolderQuery(),
vim.host.DatastoreBrowser.Query()],
details=vim.host.DatastoreBrowser.FileInfo.Details(fileType=True),
matchPattern=match_pattern,
sortFoldersFirst=True)
if debug:
print("list: dirname='{}' search_spec='{}'".
format(dirname, search_spec))
task = browser.Search(dirname, search_spec)
pyVim.task.WaitForTask(task)
children = FileArray()
for f in task.info.result.file:
ftype = FILE
if isinstance(f, vim.host.DatastoreBrowser.FolderInfo):
ftype = FOLDER
if dirname:
children.append(
File(self, path='/'.join([dirname, f.path]), ftype=ftype))
else:
children.append(File(self, path=f.path, ftype=ftype))
return children
def _make_cookie(self, stub):
cookies = {}
for c in stub.cookie.split(';'):
e = c.strip().split('=')
if len(e) > 1:
cookies[e[0]] = e[1]
return cookies
def exists(self, path=None):
try:
return len(self.list(path)) > 0
except vim.fault.FileNotFound:
return False
def put(self, path=None, src_url=None, src_file=None, src_path=None,
content=None):
datacenter_name = self._datacenter_mo.name
datastore_name = self._datastore_mo.name
stub = self._datastore_mo._stub
cookie = self._make_cookie(stub)
f = None
if src_file is not None:
f = src_file
elif src_url is not None:
f = requests.get(src_url, stream=True)
elif src_path is not None:
f = open(src_file, 'wb')
elif content is None:
raise Exception('No input provided for put')
if f:
data = f
else:
data = content
paths = ['https://{0}/folder'.format(stub.host)]
if self._path:
paths.append(self._path)
if path:
paths.append(path)
url = '/'.join(paths)
if debug:
print("put: url is '{}'".format(url))
r = requests.put(url, params={'dcPath': datacenter_name,
'dsName': datastore_name},
cookies=cookie, verify=False, data=data)
if f:
f.close()
f = None
if r.status_code < 200 or r.status_code >= 300:
raise Exception('Put failed with status {}'.format(r.status_code),
r)
def get(self, path=None):
datacenter_name = self._datacenter_mo.name
datastore_name = self._datastore_mo.name
stub = self._datastore_mo._stub
cookie = self._make_cookie(stub)
paths = ['https://{0}/folder'.format(stub.host)]
if self._path:
paths.append(self._path)
if path:
paths.append(path)
url = '/'.join(paths)
if debug:
print("get: url is '{}'".format(url))
r = requests.get(url, params={'dcPath': datacenter_name,
'dsName': datastore_name},
cookies=cookie, verify=False, stream=True)
if r.status_code < 200 or r.status_code >= 300:
raise Exception('Get failed with status {}'.format(r.status_code),
r)
return r
def delete(self, path=None):
datacenter_name = self._datacenter_mo.name
datastore_name = self._datastore_mo.name
stub = self._datastore_mo._stub
cookie = self._make_cookie(stub)
paths = ['https://{0}/folder'.format(stub.host)]
if self._path:
paths.append(self._path)
if path:
paths.append(path)
url = '/'.join(paths)
if debug:
print("delete: url is '{}'".format(url))
r = requests.delete(url, params={'dcPath': datacenter_name,
'dsName': datastore_name},
cookies=cookie, verify=False)
if r.status_code < 200 or r.status_code >= 300:
raise Exception(
'Delete failed with status {}'.format(r.status_code), r)
def delete2(self, path=None):
datacenter_mo = self._datacenter_mo
file_manager = self._get_file_manager()
datastore_path = self.get_datastore_path(path)
if debug:
print("delete2: datastore_path is '{}'".format(datastore_path))
# TODO 'FileType' is not public?
# file_manager.Delete(self._datacenter_mo, datastore_path, 'File')
def mkdir(self, path=None, parent=False):
datacenter_mo = self._datacenter_mo
file_manager = self._get_file_manager()
datastore_path = self.get_datastore_path(path)
if debug:
print("mkdir: datastore_path is '{}'".format(datastore_path))
file_manager.MakeDirectory(datastore_path, self._datacenter_mo, parent)

View File

@ -0,0 +1,127 @@
"""
* *******************************************************
* Copyright (c) VMware, Inc. 2016. All Rights Reserved.
* *******************************************************
*
* DISCLAIMER. THIS PROGRAM IS PROVIDED TO YOU "AS IS" WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, WHETHER ORAL OR WRITTEN,
* EXPRESS OR IMPLIED. THE AUTHOR SPECIFICALLY DISCLAIMS ANY IMPLIED
* WARRANTIES OR CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY,
* NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE.
"""
__author__ = 'VMware, Inc.'
__copyright__ = 'Copyright 2016 VMware, Inc. All rights reserved.'
import re
from samples.vsphere.common.vim.inventory import get_datastore_mo
from samples.vsphere.common.vim import datastore_file
datastore_path_regex = re.compile('\[(.+)\]\s?(.*)')
def parse_datastore_path(datastore_path):
"""Extract datastore name from datastore path"""
m = datastore_path_regex.match(datastore_path)
if m:
(datastore_name, path) = m.groups()
return datastore_name, path
return None, None
def detect_directory(context, description, datacenter_name, datastore_path):
"""Find directory based on specific datacenter and datastore path"""
(datastore_name, path) = parse_datastore_path(datastore_path)
datastore_mo = get_datastore_mo(context.stub_config,
context.service_instance._stub,
datacenter_name,
datastore_name)
if not datastore_mo:
raise Exception("Could not find datastore '{}'".format(datastore_name))
dsfile = datastore_file.File(datastore_mo)
f = dsfile.list(datastore_path)
if len(f) == 0:
print("Failed to detect {} directory '{}'".format(description,
datastore_path))
return False
if f.type != datastore_file.FOLDER:
print("Path '{}' is not a directory".format(datastore_path))
return False
return True
def create_directory(context, description, datacenter_name, datastore_path):
"""Create directory in specific datacenter"""
(datastore_name, path) = parse_datastore_path(datastore_path)
datastore_mo = get_datastore_mo(context.stub_config,
context.service_instance._stub,
datacenter_name,
datastore_name)
if not datastore_mo:
raise Exception("Could not find datastore '{}'".format(datastore_name))
dsfile = datastore_file.File(datastore_mo)
if not dsfile.exists(datastore_path):
print("Creating {} directory '{}'".format(description, datastore_path))
dsfile.mkdir(path, parent=True)
else:
# TODO Need to check that this is actually a directory.
print("{} directory '{}' exists.".format(description, datastore_path))
def delete_directory(context, description, datacenter_name, datastore_path):
"""Delete directory from specific datacenter"""
(datastore_name, path) = parse_datastore_path(datastore_path)
datastore_mo = get_datastore_mo(context.stub_config,
context.service_instance._stub,
datacenter_name,
datastore_name)
if not datastore_mo:
return
dsfile = datastore_file.File(datastore_mo)
if dsfile.exists(datastore_path):
print("Deleting {} directory '{}'.".format(description, datastore_path))
dsfile.delete2(path)
def detect_file(context, description, datacenter_name, datastore_path):
"""Find specific file in specific datacenter"""
(datastore_name, path) = parse_datastore_path(datastore_path)
datastore_mo = get_datastore_mo(context.stub_config,
context.service_instance._stub,
datacenter_name,
datastore_name)
if not datastore_mo:
raise Exception("Could not find datastore '{}'".format(datastore_name))
dsfile = datastore_file.File(datastore_mo)
f = dsfile.list(datastore_path)
if len(f) == 0:
print("Failed to detect {} file '{}'".
format(description, datastore_path))
return False
if f.type != datastore_file.FILE:
print("Path '{}' is not a file".format(datastore_path))
return False
return True
def delete_file(stub_config, service_instance,
description, datacenter_name, datastore_path):
"""Delete a file from specific datacenter"""
(datastore_name, path) = parse_datastore_path(datastore_path)
datastore_mo = get_datastore_mo(stub_config,
service_instance._stub,
datacenter_name,
datastore_name)
if not datastore_mo:
return
dsfile = datastore_file.File(datastore_mo)
if dsfile.exists(datastore_path):
print("Deleting {} file '{}'.".format(description, datastore_path))
dsfile.delete(path)

View File

@ -0,0 +1,10 @@
# Required to distribute different parts of this
# package as multiple distribution
try:
import pkg_resources
pkg_resources.declare_namespace(__name__)
except ImportError:
from pkgutil import extend_path
__path__ = extend_path(__path__, __name__) # @ReservedAssignment

View File

@ -0,0 +1,76 @@
"""
* *******************************************************
* Copyright (c) VMware, Inc. 2013, 2016. All Rights Reserved.
* *******************************************************
*
* DISCLAIMER. THIS PROGRAM IS PROVIDED TO YOU "AS IS" WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, WHETHER ORAL OR WRITTEN,
* EXPRESS OR IMPLIED. THE AUTHOR SPECIFICALLY DISCLAIMS ANY IMPLIED
* WARRANTIES OR CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY,
* NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE.
"""
__author__ = 'VMware, Inc.'
__copyright__ = 'Copyright 2013, 2016 VMware, Inc. All rights reserved.'
from pyVmomi import vim
from samples.vsphere.common.sample_base import SampleBase
from samples.vsphere.common.vim.helpers.vim_utils import get_obj
class GetClusterByName(SampleBase):
"""
Retrieves the given cluster MOID from VC using container view
"""
def __init__(self):
SampleBase.__init__(self, self.__doc__)
self.cluster_name = None
self.mo_id = None
self.servicemanager = None
def _options(self):
self.argparser.add_argument('-clustername', '--clustername',
help='Name of the cluster to be queried')
def _setup(self):
if self.cluster_name is None:
self.cluster_name = self.args.clustername
assert self.cluster_name is not None
if self.servicemanager is None:
self.servicemanager = self.get_service_manager()
def _execute(self):
content = self.servicemanager.content
cluster_obj = get_obj(content, [vim.ClusterComputeResource],
self.cluster_name)
if cluster_obj is not None:
self.mo_id = cluster_obj._GetMoId()
print('Cluster MoId: {0}'.format(self.mo_id))
else:
print('Cluster: {0} not found'.format(self.cluster_name))
def _cleanup(self):
pass
def get_cluster_id(service_manager, cluster_name):
"""
Returns the cluster's MoId, or None if the cluster doesn't exist
"""
get_cluster_by_name = GetClusterByName()
get_cluster_by_name.servicemanager = service_manager
get_cluster_by_name.cluster_name = cluster_name
get_cluster_by_name.run()
return get_cluster_by_name.mo_id
def main():
get_cluster_by_name = GetClusterByName()
get_cluster_by_name.main()
# Start program
if __name__ == "__main__":
main()

View File

@ -0,0 +1,75 @@
"""
* *******************************************************
* Copyright (c) VMware, Inc. 2013, 2016. All Rights Reserved.
* *******************************************************
*
* DISCLAIMER. THIS PROGRAM IS PROVIDED TO YOU "AS IS" WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, WHETHER ORAL OR WRITTEN,
* EXPRESS OR IMPLIED. THE AUTHOR SPECIFICALLY DISCLAIMS ANY IMPLIED
* WARRANTIES OR CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY,
* NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE.
"""
__author__ = 'VMware, Inc.'
__copyright__ = 'Copyright 2013, 2016 VMware, Inc. All rights reserved.'
from pyVmomi import vim
from samples.vsphere.common.sample_base import SampleBase
from samples.vsphere.common.vim.helpers.vim_utils import get_obj
class GetDatastoreByName(SampleBase):
"""
Retrieves the given datastore MOID from VC using container view
"""
def __init__(self):
SampleBase.__init__(self, self.__doc__)
self.datastore_name = None
self.mo_id = None
self.servicemanager = None
def _options(self):
self.argparser.add_argument('-datastorename', '--datastorename',
help='Name of the datastore to be queried')
def _setup(self):
if self.datastore_name is None:
self.datastore_name = self.args.datastorename
assert self.datastore_name is not None
if self.servicemanager is None:
self.servicemanager = self.get_service_manager()
def _execute(self):
content = self.servicemanager.content
datastore_obj = get_obj(content, [vim.Datastore], self.datastore_name)
if datastore_obj is not None:
self.mo_id = datastore_obj._GetMoId()
print('Datastore MoId: {0}'.format(self.mo_id))
else:
print('Datastore: {0} not found'.format(self.datastore_name))
def _cleanup(self):
pass
def get_datastore_id(service_manager, datastore_name):
"""
returns the datastore's MoId, or None if the datastore doesn't exist
"""
get_datastore_by_name = GetDatastoreByName()
get_datastore_by_name.servicemanager = service_manager
get_datastore_by_name.datastore_name = datastore_name
get_datastore_by_name.run()
return get_datastore_by_name.mo_id
def main():
get_datastore_by_name = GetDatastoreByName()
get_datastore_by_name.main()
# Start program
if __name__ == "__main__":
main()

View File

@ -0,0 +1,159 @@
"""
* *******************************************************
* Copyright (c) VMware, Inc. 2013. All Rights Reserved.
* *******************************************************
*
* DISCLAIMER. THIS PROGRAM IS PROVIDED TO YOU "AS IS" WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, WHETHER ORAL OR WRITTEN,
* EXPRESS OR IMPLIED. THE AUTHOR SPECIFICALLY DISCLAIMS ANY IMPLIED
* WARRANTIES OR CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY,
* NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE.
"""
__author__ = 'VMware, Inc.'
__copyright__ = 'Copyright 2013 VMware, Inc. All rights reserved.'
from pyVmomi import vim, vmodl
_views = [] # list of container views
def get_obj(content, vimtype, name):
"""
Get the vsphere managed object associated with a given text name
"""
obj = None
container = content.viewManager.CreateContainerView(content.rootFolder,
vimtype, True)
_views.append(container)
for c in container.view:
if c.name == name:
obj = c
break
return obj
def get_obj_by_moId(content, vimtype, moid):
"""
Get the vsphere managed object by moid value
"""
obj = None
container = content.viewManager.CreateContainerView(content.rootFolder,
vimtype, True)
_views.append(container)
for c in container.view:
if c._GetMoId() == moid:
obj = c
break
return obj
def delete_object(content, mo):
"""
Deletes a vsphere managed object and waits for the deletion to complete
"""
print('Deleting {0}'.format(mo._GetMoId()))
try:
wait_for_tasks(content, [mo.Destroy()])
print('Deleted {0}'.format(mo._GetMoId()))
except Exception:
print('Unexpected error while deleting managed object {0}'.format(
mo._GetMoId()))
return False
return True
def poweron_vm(content, mo):
"""
Powers on a VM and wait for power on operation to complete
"""
if not isinstance(mo, vim.VirtualMachine):
return False
print('Powering on vm {0}'.format(mo._GetMoId()))
try:
wait_for_tasks(content, [mo.PowerOn()])
print('{0} powered on successfully'.format(mo._GetMoId()))
except Exception:
print('Unexpected error while powering on vm {0}'.format(mo._GetMoId()))
return False
return True
def poweroff_vm(content, mo):
"""
Powers on a VM and wait for power on operation to complete
"""
if not isinstance(mo, vim.VirtualMachine):
return False
print('Powering off vm {0}'.format(mo._GetMoId()))
try:
wait_for_tasks(content, [mo.PowerOff()])
print('{0} powered off successfully'.format(mo._GetMoId()))
except Exception:
print(
'Unexpected error while powering off vm {0}'.format(mo._GetMoId()))
return False
return True
def wait_for_tasks(content, tasks):
"""
Given the tasks, it returns after all the tasks are complete
"""
taskList = [str(task) for task in tasks]
# Create filter
objSpecs = [vmodl.query.PropertyCollector.ObjectSpec(obj=task) for task in
tasks]
propSpec = vmodl.query.PropertyCollector.PropertySpec(type=vim.Task,
pathSet=[], all=True)
filterSpec = vmodl.query.PropertyCollector.FilterSpec()
filterSpec.objectSet = objSpecs
filterSpec.propSet = [propSpec]
task_filter = content.propertyCollector.CreateFilter(filterSpec, True)
try:
version, state = None, None
# Loop looking for updates till the state moves to a completed state.
while len(taskList):
update = content.propertyCollector.WaitForUpdates(version)
for filterSet in update.filterSet:
for objSet in filterSet.objectSet:
task = objSet.obj
for change in objSet.changeSet:
if change.name == 'info':
state = change.val.state
elif change.name == 'info.state':
state = change.val
else:
continue
if not str(task) in taskList:
continue
if state == vim.TaskInfo.State.success:
# Remove task from taskList
taskList.remove(str(task))
elif state == vim.TaskInfo.State.error:
raise task.info.error
# Move to next version
version = update.version
finally:
if task_filter:
task_filter.Destroy()
def __destroy_container_views():
for view in _views:
try:
view.Destroy()
except vmodl.fault.ManagedObjectNotFound:
pass # silently bypass the exception if the objects are already deleted/not found on the server
import atexit
atexit.register(__destroy_container_views)

View File

@ -0,0 +1,42 @@
"""
* *******************************************************
* Copyright (c) VMware, Inc. 2016. All Rights Reserved.
* *******************************************************
*
* DISCLAIMER. THIS PROGRAM IS PROVIDED TO YOU "AS IS" WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, WHETHER ORAL OR WRITTEN,
* EXPRESS OR IMPLIED. THE AUTHOR SPECIFICALLY DISCLAIMS ANY IMPLIED
* WARRANTIES OR CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY,
* NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE.
"""
__author__ = 'VMware, Inc.'
__copyright__ = 'Copyright 2016 VMware, Inc. All rights reserved.'
__vcenter__ = 'since 6.0'
from pyVmomi import vim
from samples.vsphere.vcenter.helper.datastore_helper import get_datastore
def get_datastore_mo(stub_config, soap_stub,
datacenter_name, datastore_name):
"""
Return datastore managed object with specific datacenter and datastore name
"""
datastore = get_datastore(stub_config, datacenter_name, datastore_name)
if not datastore:
return None
datastore_mo = vim.Datastore(datastore, soap_stub)
return datastore_mo
# TODO Not the most efficient implementation. This can be done as a single
# property collector query but it's a little more complicated
def get_datacenter_for_datastore(datastore_mo):
datacenter_mo = datastore_mo.parent
while datacenter_mo is not None:
if isinstance(datacenter_mo, vim.Datacenter):
return datacenter_mo
datacenter_mo = datacenter_mo.parent
return None

View File

@ -0,0 +1,58 @@
"""
* *******************************************************
* Copyright (c) VMware, Inc. 2016. All Rights Reserved.
* *******************************************************
*
* DISCLAIMER. THIS PROGRAM IS PROVIDED TO YOU "AS IS" WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, WHETHER ORAL OR WRITTEN,
* EXPRESS OR IMPLIED. THE AUTHOR SPECIFICALLY DISCLAIMS ANY IMPLIED
* WARRANTIES OR CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY,
* NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE.
"""
__author__ = 'VMware, Inc.'
__copyright__ = 'Copyright 2016 VMware, Inc. All rights reserved.'
import pyVim.task
from pyVmomi import vim
from samples.vsphere.common.vim.inventory import get_datastore_mo
from samples.vsphere.common.vim import datastore_file
def create_vmdk(service_instance, datacenter_mo, datastore_path):
"""Create vmdk in specific datacenter"""
vdm = service_instance.content.virtualDiskManager
task = vdm.CreateVirtualDisk(
datastore_path, datacenter_mo,
vim.VirtualDiskManager.SeSparseVirtualDiskSpec(
diskType='seSparse', adapterType='lsiLogic',
capacityKb=1024 * 1024 * 4))
pyVim.task.WaitForTask(task)
print("Created VMDK '{}' in Datacenter '{}'".
format(datastore_path, datacenter_mo.name))
return task.info.result
def delete_vmdk(service_instance, datacenter_mo, datastore_path):
"""Delete vmdk from specific datastore"""
vdm = service_instance.content.virtualDiskManager
task = vdm.DeleteVirtualDisk(datastore_path, datacenter_mo)
pyVim.task.WaitForTask(task)
def detect_vmdk(stub_config, soap_stub, datacenter_name, datastore_name,
datastore_path):
"""Find vmdk in specific datastore"""
datastore_mo = get_datastore_mo(stub_config,
soap_stub,
datacenter_name,
datastore_name)
if not datastore_mo:
return False
dsfile = datastore_file.File(datastore_mo)
if dsfile.exists(datastore_path):
return True
else:
return False

View File

@ -0,0 +1,31 @@
This directory contains samples for Content Library APIs:
* CRUD operations on a content library - crud/library_crud.py
* Updating content of a content library item - contentupdate/content_update.py
* Workflow to deploy an OVF library item to a resource pool - ovfdeploy/deploy_ovf_template.py
* Workflows to import an OVF package into a content library, and download of an OVF template from a content library - ovfimport/ovf_import_export.py
* Basic workflow to publish and subscribe content libraries - publishsubscribe/library_publish_subscribe.py
* Workflow to capture a virtual machine into a content library - vmcapture/vm_template_capture.py
* Content library ISO item mount and unmount workflow - isomount/iso_mount.py
Running the samples
$ cd /path/to/vsphere-automation-sdk-python-samples/bin
$ ./run_sample.sh ../samples/vsphere/contentlibrary/<sample-dir>/<sample>.py --server <vCenter Server IP> --username <username> --password <password> <additional-sample-parameters>
The additional sample parameters are as follows (all parameters can be displayed for any sample using option --help)
* library_crud.py --datastorename <datastore-name>
* content_update.py --datastorename <datastore-name>
* deploy_ovf_template.py --clustername <cluster-name> --libitemname <ovf-item-name>
* ovf_import_export.py --datastorename <datastore-name>
* library_publish_subscribe.py --datastorename <datastore-name>
* vm_template_capture.py --datastorename <datastore-name> --vmname <vm-name>
* iso_mount.py --datastorename <datastore-name> --vmname <vm-name>
* Testbed Requirement:
- 1 vCenter Server
- 2 ESX hosts
- 1 datastore
- Some samples need a VM or an OVF library item created as mentioned above

View File

@ -0,0 +1,25 @@
"""
* *******************************************************
* Copyright VMware, Inc. 2016. All Rights Reserved.
* *******************************************************
*
* DISCLAIMER. THIS PROGRAM IS PROVIDED TO YOU "AS IS" WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, WHETHER ORAL OR WRITTEN,
* EXPRESS OR IMPLIED. THE AUTHOR SPECIFICALLY DISCLAIMS ANY IMPLIED
* WARRANTIES OR CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY,
* NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE.
"""
__author__ = 'VMware, Inc.'
__copyright__ = 'Copyright 2016 VMware, Inc. All rights reserved.'
# Required to distribute different parts of this
# package as multiple distribution
try:
import pkg_resources
pkg_resources.declare_namespace(__name__)
except ImportError:
from pkgutil import extend_path
__path__ = extend_path(__path__, __name__) # @ReservedAssignment

View File

@ -0,0 +1,25 @@
"""
* *******************************************************
* Copyright VMware, Inc. 2016. All Rights Reserved.
* *******************************************************
*
* DISCLAIMER. THIS PROGRAM IS PROVIDED TO YOU "AS IS" WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, WHETHER ORAL OR WRITTEN,
* EXPRESS OR IMPLIED. THE AUTHOR SPECIFICALLY DISCLAIMS ANY IMPLIED
* WARRANTIES OR CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY,
* NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE.
"""
__author__ = 'VMware, Inc.'
__copyright__ = 'Copyright 2016 VMware, Inc. All rights reserved.'
# Required to distribute different parts of this
# package as multiple distribution
try:
import pkg_resources
pkg_resources.declare_namespace(__name__)
except ImportError:
from pkgutil import extend_path
__path__ = extend_path(__path__, __name__) # @ReservedAssignment

View File

@ -0,0 +1,175 @@
#!/usr/bin/env python
"""
* DISCLAIMER. THIS PROGRAM IS PROVIDED TO YOU "AS IS" WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, WHETHER ORAL OR WRITTEN,
* EXPRESS OR IMPLIED. THE AUTHOR SPECIFICALLY DISCLAIMS ANY IMPLIED
* WARRANTIES OR CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY,
* NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE.
"""
__author__ = 'VMware, Inc.'
__copyright__ = 'Copyright 2016 VMware, Inc. All rights reserved.'
__vcenter_version__ = '6.0+'
try:
import urllib2
except ImportError:
import urllib.request as urllib2
from com.vmware.content.library.item_client import UpdateSessionModel
from samples.vsphere.common.id_generator import generate_random_uuid
from samples.vsphere.common.sample_base import SampleBase
from samples.vsphere.contentlibrary.lib.cls_api_client import ClsApiClient
from samples.vsphere.contentlibrary.lib.cls_api_helper import ClsApiHelper
class ContentUpdate(SampleBase):
"""
Demonstrates the workflow of updating a content library item.
Note: the workflow needs an existing datastore (of type vmfs) with available storage.
"""
ISO_FILE_1 = 'test.iso'
ISO_FILE_2 = 'test-2.iso'
ISO_ITEM_NAME = 'test'
def __init__(self):
SampleBase.__init__(self, self.__doc__)
self.servicemanager = None
self.client = None
self.helper = None
self.datastore_name = None
self.lib_name = "demo-lib"
self.local_library = None
def _options(self):
self.argparser.add_argument('-datastorename', '--datastorename',
help='The name of the datastore where '
'the library will be created.')
def _setup(self):
self.datastore_name = self.args.datastorename
assert self.datastore_name is not None
self.servicemanager = self.get_service_manager()
self.client = ClsApiClient(self.servicemanager)
self.helper = ClsApiHelper(self.client, self.skip_verification)
def _execute(self):
storage_backings = self.helper.create_storage_backings(self.servicemanager,
self.datastore_name)
library_id = self.helper.create_local_library(storage_backings, self.lib_name)
self.local_library = self.client.local_library_service.get(library_id)
self.delete_and_upload_scenario(library_id)
self.replace_scenario(library_id)
def replace_scenario(self, library_id):
"""
:param library_id: the Iso item will be created, and then replaced in this library
:return: None
Content update scenario 2:
Update ISO library item by creating an update session for the
item, then adding the new ISO file using the same session file
name into the update session, which will replace the existing
ISO file upon session complete.
"""
iso_item_id = self.helper.create_library_item(library_id=library_id,
item_name=self.ISO_ITEM_NAME,
item_description='Sample iso file',
item_type='iso')
print('ISO Library item version (on creation) {0}:'.format(
self.get_item_version(iso_item_id)))
iso_files_map = self.helper.get_iso_file_map(item_filename=self.ISO_FILE_1,
disk_filename=self.ISO_FILE_1)
self.helper.upload_files(library_item_id=iso_item_id, files_map=iso_files_map)
original_version = self.get_item_version(iso_item_id)
print('ISO Library item version (on original content upload) {0}:'.format(
original_version))
session_id = self.client.upload_service.create(
create_spec=UpdateSessionModel(library_item_id=iso_item_id),
client_token=generate_random_uuid())
# Use the same item filename (update endpoint, as it's a replace scenario)
iso_files_map = self.helper.get_iso_file_map(item_filename=self.ISO_FILE_1,
disk_filename=self.ISO_FILE_2)
self.helper.upload_files_in_session(iso_files_map, session_id)
self.client.upload_service.complete(session_id)
self.client.upload_service.delete(session_id)
updated_version = self.get_item_version(iso_item_id)
print('ISO Library item version (after content update): {0}'.format(
updated_version))
assert updated_version > original_version, 'content update should increase the version'
def delete_and_upload_scenario(self, library_id):
"""
:param library_id: the OVF item will be created and updated in this library
:return: None
Content update scenario 1:
Update OVF library item by creating an update session for the
OVF item, removing all existing files in the session, then
adding all new files into the same update session, and completing
the session to finish the content update.
"""
# Create a new library item in the content library for uploading the files
ovf_item_id = self.helper.create_library_item(library_id=library_id,
item_name='demo-ovf-item',
item_description='Sample simple VM template',
item_type='ovf')
assert ovf_item_id is not None
print('Library item created id: {0}'.format(ovf_item_id))
print('OVF Library item version (at creation) {0}:'.format(
self.get_item_version(ovf_item_id)))
# Upload a VM template to the CL
ovf_files_map = self.helper.get_ovf_files_map(ClsApiHelper.SIMPLE_OVF_RELATIVE_DIR)
self.helper.upload_files(library_item_id=ovf_item_id, files_map=ovf_files_map)
print('Uploaded ovf and vmdk files to library item {0}'.format(ovf_item_id))
original_version = self.get_item_version(ovf_item_id)
print('OVF Library item version (on original content upload): {0}'.format(
original_version))
# Create a new session and perform content update
session_id = self.client.upload_service.create(
create_spec=UpdateSessionModel(library_item_id=ovf_item_id),
client_token=generate_random_uuid())
existing_files = self.client.upload_file_service.list(session_id)
for file in existing_files:
print('deleting {0}'.format(file.name))
self.client.upload_file_service.remove(session_id, file.name)
ovf_files_map = self.helper.get_ovf_files_map(
ovf_location=ClsApiHelper.PLAIN_OVF_RELATIVE_DIR)
self.helper.upload_files_in_session(ovf_files_map, session_id)
self.client.upload_service.complete(session_id)
self.client.upload_service.delete(session_id)
updated_version = self.get_item_version(ovf_item_id)
print('OVF Library item version (after content update): {0}'.format(
updated_version))
assert updated_version > original_version, 'content update should increase the version'
def get_item_version(self, item_id):
ovf_item_model = self.client.library_item_service.get(item_id)
pre_update_version = ovf_item_model.content_version
return pre_update_version
def _cleanup(self):
if self.local_library:
self.client.local_library_service.delete(library_id=self.local_library.id)
print('Deleted Library Id: {0}'.format(self.local_library.id))
def main():
content_update_sample = ContentUpdate()
content_update_sample.main()
if __name__ == '__main__':
main()

View File

@ -0,0 +1,25 @@
"""
* *******************************************************
* Copyright VMware, Inc. 2016. All Rights Reserved.
* *******************************************************
*
* DISCLAIMER. THIS PROGRAM IS PROVIDED TO YOU "AS IS" WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, WHETHER ORAL OR WRITTEN,
* EXPRESS OR IMPLIED. THE AUTHOR SPECIFICALLY DISCLAIMS ANY IMPLIED
* WARRANTIES OR CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY,
* NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE.
"""
__author__ = 'VMware, Inc.'
__copyright__ = 'Copyright 2016 VMware, Inc. All rights reserved.'
# Required to distribute different parts of this
# package as multiple distribution
try:
import pkg_resources
pkg_resources.declare_namespace(__name__)
except ImportError:
from pkgutil import extend_path
__path__ = extend_path(__path__, __name__) # @ReservedAssignment

View File

@ -0,0 +1,112 @@
#!/usr/bin/env python
"""
* *******************************************************
* Copyright VMware, Inc. 2016. All Rights Reserved.
* *******************************************************
*
* DISCLAIMER. THIS PROGRAM IS PROVIDED TO YOU "AS IS" WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, WHETHER ORAL OR WRITTEN,
* EXPRESS OR IMPLIED. THE AUTHOR SPECIFICALLY DISCLAIMS ANY IMPLIED
* WARRANTIES OR CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY,
* NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE.
"""
__author__ = 'VMware, Inc.'
__copyright__ = 'Copyright 2016 VMware, Inc. All rights reserved.'
__vcenter_version__ = '6.0+'
from com.vmware.content.library_client import StorageBacking
from com.vmware.content_client import LibraryModel
from samples.vsphere.common.id_generator import generate_random_uuid
from samples.vsphere.common.sample_base import SampleBase
from samples.vsphere.common.vim.helpers.get_datastore_by_name import get_datastore_id
from samples.vsphere.contentlibrary.lib.cls_api_client import ClsApiClient
class LibraryCrud(SampleBase):
"""
Demonstrates the basic operations of a content library. The sample also
demonstrates the interoperability of the VIM and vAPI.
Note: the workflow needs an existing VC DS with available storage.
"""
def __init__(self):
SampleBase.__init__(self, self.__doc__)
self.servicemanager = None
self.client = None
self.datastore_name = None
self.lib_name = "demo-local-lib"
self.local_library = None
def _options(self):
self.argparser.add_argument('-datastorename',
'--datastorename',
help='The name of the datastore.')
def _setup(self):
if not self.datastore_name:
self.datastore_name = self.args.datastorename
assert self.datastore_name is not None
if not self.servicemanager:
self.servicemanager = self.get_service_manager()
self.client = ClsApiClient(self.servicemanager)
def _execute(self):
# List of visible content libraries
visible_cls = self.client.local_library_service.list()
if len(visible_cls) > 0:
for visible_cl in visible_cls:
get_visible_cl = self.client.local_library_service.get(visible_cl)
print('Visible content library: {0} with id: {1}'.format(get_visible_cl.name, visible_cl))
# Find the datastore by the given datastore name using property collector
self.datastore_id = get_datastore_id(service_manager=self.servicemanager, datastore_name=self.datastore_name)
assert self.datastore_id is not None
print('DataStore: {0} ID: {1}'.format(self.datastore_name, self.datastore_id))
# Build the storage backing for the library to be created
storage_backings = []
storage_backing = StorageBacking(type=StorageBacking.Type.DATASTORE, datastore_id=self.datastore_id)
storage_backings.append(storage_backing)
# Build the specification for the library to be created
create_spec = LibraryModel()
create_spec.name = self.lib_name
create_spec.description = "Local library backed by VC datastore"
create_spec.type = create_spec.LibraryType.LOCAL
create_spec.storage_backings = storage_backings
# Create a local content library backed the VC datastore using vAPIs
library_id = self.client.local_library_service.create(create_spec=create_spec,
client_token=generate_random_uuid())
print('Local library created: ID: {0}'.format(library_id))
# Retrieve the local content library
self.local_library = self.client.local_library_service.get(library_id)
print('Retrieved library: ID: {0}'.format(self.local_library.id))
# Update the local content library
update_spec = LibraryModel()
update_spec.description = "new description"
self.client.local_library_service.update(library_id, update_spec)
print('Updated library description')
def _cleanup(self):
if self.local_library:
self.client.local_library_service.delete(library_id=self.local_library.id)
print('Deleted Library Id: {0}'.format(self.local_library.id))
def main():
sample = LibraryCrud()
sample.main()
if __name__ == '__main__':
main()

View File

@ -0,0 +1,25 @@
"""
* *******************************************************
* Copyright VMware, Inc. 2016. All Rights Reserved.
* *******************************************************
*
* DISCLAIMER. THIS PROGRAM IS PROVIDED TO YOU "AS IS" WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, WHETHER ORAL OR WRITTEN,
* EXPRESS OR IMPLIED. THE AUTHOR SPECIFICALLY DISCLAIMS ANY IMPLIED
* WARRANTIES OR CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY,
* NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE.
"""
__author__ = 'VMware, Inc.'
__copyright__ = 'Copyright 2016 VMware, Inc. All rights reserved.'
# Required to distribute different parts of this
# package as multiple distribution
try:
import pkg_resources
pkg_resources.declare_namespace(__name__)
except ImportError:
from pkgutil import extend_path
__path__ = extend_path(__path__, __name__) # @ReservedAssignment

View File

@ -0,0 +1,105 @@
#!/usr/bin/env python
"""
* *******************************************************
* Copyright VMware, Inc. 2016. All Rights Reserved.
* *******************************************************
*
* DISCLAIMER. THIS PROGRAM IS PROVIDED TO YOU "AS IS" WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, WHETHER ORAL OR WRITTEN,
* EXPRESS OR IMPLIED. THE AUTHOR SPECIFICALLY DISCLAIMS ANY IMPLIED
* WARRANTIES OR CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY,
* NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE.
"""
__author__ = 'VMware, Inc.'
__copyright__ = 'Copyright 2016 VMware, Inc. All rights reserved.'
__vcenter_version__ = '6.5+'
from samples.vsphere.common.sample_base import SampleBase
from samples.vsphere.contentlibrary.lib.cls_api_client import ClsApiClient
from samples.vsphere.contentlibrary.lib.cls_api_helper import ClsApiHelper
from samples.vsphere.vcenter.helper.vm_helper import get_vm
class IsoMount(SampleBase):
"""
Demonstrates the content library ISO item mount and
unmount workflow via the mount and unmount APIs from the
ISO service.
"""
ISO_FILENAME = 'test.iso'
def __init__(self):
SampleBase.__init__(self, self.__doc__)
self.servicemanager = None
self.client = None
self.datastore_name = None
self.lib_name = "iso-demo-lib"
self.local_library = None
self.iso_item_name = "iso-demo-lib-item"
self.vm_name = None
def _options(self):
self.argparser.add_argument('-datastorename',
'--datastorename',
help='The name of a datastore (of type vmfs) that is'
' acceassible to the vm specified with --vmname.')
self.argparser.add_argument('-vmname',
'--vmname',
help='The name of the vm where iso will be mounted. '
'The vm needs to be already created on the vCenter')
def _setup(self):
self.datastore_name = self.args.datastorename
assert self.datastore_name is not None
self.vm_name = self.args.vmname
assert self.vm_name is not None
self.servicemanager = self.get_service_manager()
self.client = ClsApiClient(self.servicemanager)
self.helper = ClsApiHelper(self.client, self.skip_verification)
def _execute(self):
storage_backings = self.helper.create_storage_backings(
self.servicemanager, self.datastore_name)
library_id = self.helper.create_local_library(storage_backings,
self.lib_name)
self.local_library = self.client.local_library_service.get(library_id)
library_item_id = self.helper.create_iso_library_item(library_id,
self.iso_item_name,
self.ISO_FILENAME)
vm_id = get_vm(self.servicemanager.stub_config, self.vm_name)
assert vm_id is not None
# Mount the iso item as a CDROM device
device_id = self.client.iso_service.mount(library_item_id, vm_id)
assert device_id is not None
print('Mounted library item {0} on vm {1} at device {2}'.
format(self.iso_item_name, self.vm_name, device_id))
# Unmount the CDROM
self.client.iso_service.unmount(vm_id, device_id)
print('Unmounted library item {0} from vm {1} mounted at device {2}'.
format(self.iso_item_name, self.vm_name, device_id))
def _cleanup(self):
if self.local_library:
self.client.local_library_service.delete(
library_id=self.local_library.id)
print('Deleted Library Id: {0}'.format(self.local_library.id))
def main():
iso_mount_sample = IsoMount()
iso_mount_sample.main()
if __name__ == '__main__':
main()

View File

@ -0,0 +1,25 @@
"""
* *******************************************************
* Copyright VMware, Inc. 2016. All Rights Reserved.
* *******************************************************
*
* DISCLAIMER. THIS PROGRAM IS PROVIDED TO YOU "AS IS" WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, WHETHER ORAL OR WRITTEN,
* EXPRESS OR IMPLIED. THE AUTHOR SPECIFICALLY DISCLAIMS ANY IMPLIED
* WARRANTIES OR CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY,
* NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE.
"""
__author__ = 'VMware, Inc.'
__copyright__ = 'Copyright 2016 VMware, Inc. All rights reserved.'
# Required to distribute different parts of this
# package as multiple distribution
try:
import pkg_resources
pkg_resources.declare_namespace(__name__)
except ImportError:
from pkgutil import extend_path
__path__ = extend_path(__path__, __name__) # @ReservedAssignment

View File

@ -0,0 +1,77 @@
"""
* *******************************************************
* Copyright VMware, Inc. 2016. All Rights Reserved.
* *******************************************************
*
* DISCLAIMER. THIS PROGRAM IS PROVIDED TO YOU "AS IS" WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, WHETHER ORAL OR WRITTEN,
* EXPRESS OR IMPLIED. THE AUTHOR SPECIFICALLY DISCLAIMS ANY IMPLIED
* WARRANTIES OR CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY,
* NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE.
"""
__author__ = 'VMware, Inc.'
__copyright__ = 'Copyright 2016 VMware, Inc. All rights reserved.'
__vcenter_version__ = '6.0+'
from com.vmware.content_client import (Library,
LocalLibrary,
SubscribedLibrary)
from com.vmware.content.library_client import Item, SubscribedItem
from com.vmware.content.library.item_client import DownloadSession
from com.vmware.content.library.item_client import UpdateSession
from com.vmware.content.library.item.downloadsession_client import File as DownloadSessionFile
from com.vmware.content.library.item.updatesession_client import File as UpdateSessionFile
from com.vmware.vcenter_client import VM
from com.vmware.vcenter.iso_client import Image
from com.vmware.vcenter.ovf_client import LibraryItem
class ClsApiClient(object):
"""
This is a simplified wrapper around the Content Library APIs.
It is used to access services exposed by Content Library Service.
"""
def __init__(self, service_manager):
# Client for all the services on a management node.
self.service_manager = service_manager
# Returns the service which provides support for generic functionality
# which can be applied equally to all types of libraries
self.library_service = Library(self.service_manager.stub_config)
# Returns the service for managing local libraries
self.local_library_service = LocalLibrary(self.service_manager.stub_config)
# Returns the service for managing subscribed libraries
self.subscribed_library_service = SubscribedLibrary(self.service_manager.stub_config)
# Returns the service for managing library items
self.library_item_service = Item(self.service_manager.stub_config)
# Returns the service for managing sessions to update or delete content
self.upload_service = UpdateSession(self.service_manager.stub_config)
# Returns the service for managing files within an update session
self.upload_file_service = UpdateSessionFile(self.service_manager.stub_config)
# Returns the service for managing sessions to download content
self.download_service = DownloadSession(self.service_manager.stub_config)
# Returns the service for managing files within a download session
self.download_file_service = DownloadSessionFile(self.service_manager.stub_config)
# Returns the service for deploying virtual machines from OVF library items
self.ovf_lib_item_service = LibraryItem(self.service_manager.stub_config)
# Returns the service for mount and unmount of an iso file on a VM
self.iso_service = Image(self.service_manager.stub_config)
# Returns the service for managing subscribed library items
self.subscribed_item_service = SubscribedItem(self.service_manager.stub_config)
# Creates the service that communicates with virtual machines
self.vm_service = VM(self.service_manager.stub_config)
# TODO: Add the other CLS services, eg. storage, config, type

View File

@ -0,0 +1,250 @@
"""
* *******************************************************
* Copyright VMware, Inc. 2016. All Rights Reserved.
* *******************************************************
*
* DISCLAIMER. THIS PROGRAM IS PROVIDED TO YOU "AS IS" WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, WHETHER ORAL OR WRITTEN,
* EXPRESS OR IMPLIED. THE AUTHOR SPECIFICALLY DISCLAIMS ANY IMPLIED
* WARRANTIES OR CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY,
* NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE.
"""
__author__ = 'VMware, Inc.'
__copyright__ = 'Copyright 2016 VMware, Inc. All rights reserved.'
__vcenter_version__ = '6.0+'
import os
import ssl
import time
try:
import urllib2
except ImportError:
import urllib.request as urllib2
from com.vmware.content_client import LibraryModel
from com.vmware.content.library_client import (ItemModel,
StorageBacking)
from com.vmware.content.library.item_client import (DownloadSessionModel,
UpdateSessionModel)
from com.vmware.content.library.item.downloadsession_client import File as DownloadSessionFile
from com.vmware.content.library.item.updatesession_client import File as UpdateSessionFile
from samples.vsphere.common.id_generator import generate_random_uuid
from samples.vsphere.common.vim.helpers.get_datastore_by_name import get_datastore_id
class ClsApiHelper(object):
"""
Helper class to perform commonly used operations using Content Library API.
"""
ISO_FILE_RELATIVE_DIR = '../resources/isoImages/'
PLAIN_OVF_RELATIVE_DIR = '../resources/plainVmTemplate'
SIMPLE_OVF_RELATIVE_DIR = '../resources/simpleVmTemplate'
def __init__(self, cls_api_client, skip_verification):
self.client = cls_api_client
self.skip_verification = skip_verification
def get_ovf_files_map(self, ovf_location):
"""
Get OVF template file paths to be used during uploads
Note: This method returns OVF template paths for the template included
in the SDK resources directory
"""
ovf_files_map = {}
ovf_dir = os.path.abspath(os.path.join(os.path.dirname(os.path.realpath(__file__)),
ovf_location))
for file_name in os.listdir(ovf_dir):
if file_name.endswith('.ovf') or file_name.endswith('.vmdk'):
ovf_files_map[file_name] = os.path.join(ovf_dir, file_name)
return ovf_files_map
def create_local_library(self, storage_backings, lib_name):
"""
:param storage_backings: Storage for the library
:param lib_name: Name of the library
:return: id of the created library
"""
create_spec = LibraryModel()
create_spec.name = lib_name
create_spec.description = "Local library backed by VC datastore"
create_spec.type = LibraryModel.LibraryType.LOCAL
create_spec.storage_backings = storage_backings
# Create a local content library backed the VC datastore
library_id = self.client.local_library_service.create(create_spec=create_spec,
client_token=generate_random_uuid())
print('Local library created, ID: {0}'.format(library_id))
return library_id
def create_storage_backings(self, service_manager, datastore_name):
"""
:param service_manager:
:param datastore_name: name of the datastore providing storage
:return: the storage backing array
"""
# Find the datastore by the given datastore name
datastore_id = get_datastore_id(service_manager=service_manager,
datastore_name=datastore_name)
assert datastore_id is not None
# If provided datastore is not of type vmfs, substitute the type
# StorageBacking.Type.DATASTORE with StorageBacking.Type.OTHER
# Build the specification for the library to be created
storage_backings = [StorageBacking(type=StorageBacking.Type.DATASTORE,
datastore_id=datastore_id)]
return storage_backings
def create_iso_library_item(self, library_id, iso_item_name, iso_filename):
"""
:param library_id: item will be created on this library
:param iso_item_name: name of the iso item to be created
:param iso_filename: name of the iso file to be uploaded
:return: id of the item created
"""
# Create a new library item in the content library for uploading the files
library_item_id = self.create_library_item(library_id=library_id,
item_name=iso_item_name,
item_description='Sample iso file',
item_type='iso')
assert library_item_id is not None
print('Library item created id: {0}'.format(library_item_id))
# Upload an iso file to above library item, use the filename as the item_filename
iso_files_map = self.get_iso_file_map(item_filename=iso_filename, disk_filename=iso_filename)
self.upload_files(library_item_id=library_item_id, files_map=iso_files_map)
print('Uploaded iso file to library item {0}'.format(library_item_id))
return library_item_id
def get_iso_file_map(self, item_filename, disk_filename):
iso_files_map = {}
iso_file_path = os.path.abspath(os.path.join(os.path.dirname(os.path.realpath(__file__)),
self.ISO_FILE_RELATIVE_DIR + disk_filename))
iso_files_map[item_filename] = iso_file_path
return iso_files_map
def get_libraryitem_spec(self, client_token, name, description, library_id, library_item_type):
"""
Create library item spec
"""
lib_item_spec = ItemModel()
lib_item_spec.name = name
lib_item_spec.description = description
lib_item_spec.library_id = library_id
lib_item_spec.type = library_item_type
return lib_item_spec
def create_library_item(self, library_id, item_name, item_description, item_type):
"""
Create a library item in the specified library
"""
lib_item_spec = self.get_libraryitem_spec(client_token=generate_random_uuid(),
name=item_name,
description=item_description,
library_id=library_id,
library_item_type=item_type)
# Create a library item
return self.client.library_item_service.create(create_spec=lib_item_spec,
client_token=generate_random_uuid())
def upload_files(self, library_item_id, files_map):
"""
Upload a VM template to the published CL
"""
# Create a new upload session for uploading the files
session_id = self.client.upload_service.create(
create_spec=UpdateSessionModel(library_item_id=library_item_id),
client_token=generate_random_uuid())
self.upload_files_in_session(files_map, session_id)
self.client.upload_service.complete(session_id)
self.client.upload_service.delete(session_id)
def upload_files_in_session(self, files_map, session_id):
for f_name, f_path in files_map.items():
file_spec = self.client.upload_file_service.AddSpec(name=f_name,
source_type=UpdateSessionFile.SourceType.PUSH,
size=os.path.getsize(f_path))
file_info = self.client.upload_file_service.add(session_id, file_spec)
# Upload the file content to the file upload URL
with open(f_path, 'rb') as local_file:
request = urllib2.Request(file_info.upload_endpoint.uri, local_file)
request.add_header('Cache-Control', 'no-cache')
request.add_header('Content-Length', '{0}'.format(os.path.getsize(f_path)))
request.add_header('Content-Type', 'text/ovf')
if self.skip_verification and hasattr(ssl, '_create_unverified_context'):
# Python 2.7.9 has stronger SSL certificate validation,
# so we need to pass in a context when dealing with
# self-signed certificates.
context = ssl._create_unverified_context()
urllib2.urlopen(request, context=context)
else:
# Don't pass context parameter since versions of Python
# before 2.7.9 don't support it.
urllib2.urlopen(request)
def download_files(self, library_item_id, directory):
"""
Download files from a library item
Args:
library_item_id: id for the library item to download files from
directory: location on the client machine to download the files into
"""
downloaded_files_map = {}
# create a new download session for downloading the session files
session_id = self.client.download_service.create(create_spec=DownloadSessionModel(
library_item_id=library_item_id),
client_token=generate_random_uuid())
file_infos = self.client.download_file_service.list(session_id)
for file_info in file_infos:
self.client.download_file_service.prepare(session_id, file_info.name)
download_info = self.wait_for_prepare(session_id, file_info.name)
if self.skip_verification and hasattr(ssl, '_create_unverified_context'):
# Python 2.7.9 has stronger SSL certificate validation,
# so we need to pass in a context when dealing with self-signed
# certificates.
context = ssl._create_unverified_context()
response = urllib2.urlopen(
url=download_info.download_endpoint.uri,
context=context)
else:
# Don't pass context parameter since versions of Python
# before 2.7.9 don't support it.
response = urllib2.urlopen(download_info.download_endpoint.uri)
file_path = os.path.join(directory, file_info.name)
with open(file_path, 'wb') as local_file:
local_file.write(response.read())
downloaded_files_map[file_info.name] = file_path
self.client.download_service.delete(session_id)
return downloaded_files_map
def wait_for_prepare(self, session_id, file_name,
status_list=(DownloadSessionFile.PrepareStatus.PREPARED,),
timeout=30, sleep_interval=1):
"""
Waits for a file to reach a status in the status list (default: prepared)
This method will either timeout or return the result of
downloadSessionFile.get(session_id, file_name)
"""
start_time = time.time()
while (time.time() - start_time) < timeout:
file_info = self.client.download_file_service.get(session_id, file_name)
if file_info.status in status_list:
return file_info
else:
time.sleep(sleep_interval)
raise Exception(
'timed out after waiting {0} seconds for file {1} to reach a terminal state'.format(
timeout, file_name))

View File

@ -0,0 +1,131 @@
"""
* *******************************************************
* Copyright VMware, Inc. 2016. All Rights Reserved.
* *******************************************************
*
* DISCLAIMER. THIS PROGRAM IS PROVIDED TO YOU "AS IS" WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, WHETHER ORAL OR WRITTEN,
* EXPRESS OR IMPLIED. THE AUTHOR SPECIFICALLY DISCLAIMS ANY IMPLIED
* WARRANTIES OR CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY,
* NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE.
"""
__author__ = 'VMware, Inc.'
__copyright__ = 'Copyright 2016 VMware, Inc. All rights reserved.'
__vcenter_version__ = '6.0+'
import time
class ClsSyncHelper:
"""
Helper class to wait for the subscribed libraries and items to be
synchronized completely with the publisher.
"""
wait_interval_sec = 1
start_time = None
sync_timeout_sec = None
def __init__(self, cls_api_client, sync_timeout_sec):
self.client = cls_api_client
self.sync_timeout_sec = sync_timeout_sec
def verify_library_sync(self, pub_lib_id, sub_lib):
"""
Wait until the subscribed library and its items are synchronized with
the published library.
"""
self.start_time = time.time()
if not self.verify_same_items(pub_lib_id, sub_lib.id):
return False
sub_item_ids = self.client.library_item_service.list(sub_lib.id)
for sub_item_id in sub_item_ids:
if not self.verify_item_sync(sub_item_id):
return False
if not self.verify_library_last_sync_time(sub_lib):
return False
return True
def verify_item_sync(self, sub_item_id):
"""
Wait until the subscribed item is synchronized with the published item.
"""
self.start_time = time.time()
is_synced = False
pub_item_id = self.client.library_item_service.get(
sub_item_id).source_id
pub_item = self.client.library_item_service.get(pub_item_id)
while self.not_timed_out():
sub_item = self.client.library_item_service.get(sub_item_id)
# Verify if the subscribed item is the latest
if (sub_item.metadata_version == pub_item.metadata_version and
sub_item.content_version == pub_item.content_version):
is_synced = True
break
time.sleep(self.wait_interval_sec)
return is_synced
def verify_same_items(self, pub_lib_id, sub_lib_id):
"""
Wait until the subscribed library has the same source item IDs as the
published library.
"""
is_synced = False
pub_item_ids = self.client.library_item_service.list(pub_lib_id)
while self.not_timed_out():
sub_item_ids = self.client.library_item_service.list(sub_lib_id)
if self.has_same_items(pub_item_ids, sub_item_ids):
is_synced = True
break
time.sleep(self.wait_interval_sec)
return is_synced
def verify_library_last_sync_time(self, sub_lib):
"""
Wait until the subscribed library's last sync time is populated.
"""
is_synced = False
while self.not_timed_out():
# Get the subscribed library's updated information from server.
refreshed_sub_lib = self.client.subscribed_library_service.get(
sub_lib.id)
if refreshed_sub_lib.last_sync_time is not None:
if (sub_lib.last_sync_time is None or
refreshed_sub_lib.last_sync_time > sub_lib.last_sync_time):
is_synced = True
break
time.sleep(self.wait_interval_sec)
return is_synced
def has_same_items(self, pub_item_ids, sub_item_ids):
"""
Check if the subscribed library contains the same items as the
published library. The item versions are not checked.
"""
if len(pub_item_ids) != len(sub_item_ids):
return False
synced_item_ids = []
for sub_item_id in sub_item_ids:
source_id = self.client.library_item_service.get(
sub_item_id).source_id
if source_id not in synced_item_ids and source_id in pub_item_ids:
synced_item_ids.append(sub_item_id)
return len(pub_item_ids) == len(synced_item_ids)
def not_timed_out(self):
"""
Check if sync is not timed out yet.
"""
elasped_time = time.time() - self.start_time
return elasped_time < self.sync_timeout_sec

View File

@ -0,0 +1,25 @@
"""
* *******************************************************
* Copyright VMware, Inc. 2016. All Rights Reserved.
* *******************************************************
*
* DISCLAIMER. THIS PROGRAM IS PROVIDED TO YOU "AS IS" WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, WHETHER ORAL OR WRITTEN,
* EXPRESS OR IMPLIED. THE AUTHOR SPECIFICALLY DISCLAIMS ANY IMPLIED
* WARRANTIES OR CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY,
* NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE.
"""
__author__ = 'VMware, Inc.'
__copyright__ = 'Copyright 2016 VMware, Inc. All rights reserved.'
# Required to distribute different parts of this
# package as multiple distribution
try:
import pkg_resources
pkg_resources.declare_namespace(__name__)
except ImportError:
from pkgutil import extend_path
__path__ = extend_path(__path__, __name__) # @ReservedAssignment

View File

@ -0,0 +1,157 @@
#!/usr/bin/env python
"""
* *******************************************************
* Copyright VMware, Inc. 2016. All Rights Reserved.
* *******************************************************
*
* DISCLAIMER. THIS PROGRAM IS PROVIDED TO YOU "AS IS" WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, WHETHER ORAL OR WRITTEN,
* EXPRESS OR IMPLIED. THE AUTHOR SPECIFICALLY DISCLAIMS ANY IMPLIED
* WARRANTIES OR CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY,
* NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE.
"""
__author__ = 'VMware, Inc.'
__copyright__ = 'Copyright 2016 VMware, Inc. All rights reserved.'
__vcenter_version__ = '6.0+'
try:
import urllib2
except ImportError:
import urllib.request as urllib2
from com.vmware.content.library_client import Item
from com.vmware.vcenter.ovf_client import LibraryItem
from pyVmomi import vim
from samples.vsphere.common.id_generator import generate_random_uuid
from samples.vsphere.common.sample_base import SampleBase
from samples.vsphere.common.vim.helpers.vim_utils import (
get_obj, get_obj_by_moId, poweron_vm, poweroff_vm, delete_object)
from samples.vsphere.contentlibrary.lib.cls_api_client import ClsApiClient
from samples.vsphere.contentlibrary.lib.cls_api_helper import ClsApiHelper
class DeployOvfTemplate(SampleBase):
"""
Demonstrates the workflow to deploy an OVF library item to a resource pool.
Note: the sample needs an existing library item with an OVF template
and an existing cluster with resources for deploying the VM.
"""
def __init__(self):
SampleBase.__init__(self, self.__doc__)
self.servicemanager = None
self.client = None
self.helper = None
self.cluster_name = None
self.lib_item_name = None
self.vm_obj = None
self.vm_name = None
def _options(self):
self.argparser.add_argument('-clustername',
'--clustername',
help='The name of the cluster to be used.')
self.argparser.add_argument('-libitemname',
'--libitemname',
help='The name of the library item to deploy.'
'The library item should contain an OVF package.')
def _setup(self):
self.cluster_name = self.args.clustername
assert self.cluster_name is not None
self.lib_item_name = self.args.libitemname
assert self.lib_item_name is not None
self.servicemanager = self.get_service_manager()
self.client = ClsApiClient(self.servicemanager)
self.helper = ClsApiHelper(self.client, self.skip_verification)
# Default VM name
self.vm_name = 'vm-' + str(generate_random_uuid())
def _execute(self):
# Find the cluster's resource pool moid
cluster_obj = get_obj(self.servicemanager.content,
[vim.ClusterComputeResource], self.cluster_name)
assert cluster_obj is not None
print("Cluster Moref: {0}".format(cluster_obj))
deployment_target = LibraryItem.DeploymentTarget(
resource_pool_id=cluster_obj.resourcePool._GetMoId())
# Find lib item id from given item name
find_spec = Item.FindSpec()
find_spec.name = self.lib_item_name
item_ids = self.client.library_item_service.find(find_spec)
assert (item_ids is not None and len(item_ids) > 0), ('No items found with name: {0}'
.format(self.lib_item_name))
lib_item_id = item_ids[0]
ovf_summary = self.client.ovf_lib_item_service.filter(ovf_library_item_id=lib_item_id,
target=deployment_target)
print('Found an OVF template :{0} to deploy.'.format(ovf_summary.name))
# Deploy the ovf template
self.deploy_ovf_template(lib_item_id, ovf_summary, deployment_target)
def deploy_ovf_template(self, lib_item_id, ovf_summary, deployment_target):
# Build the deployment spec
deployment_spec = LibraryItem.ResourcePoolDeploymentSpec(
name=self.vm_name,
annotation=ovf_summary.annotation,
accept_all_eula=True,
network_mappings=None,
storage_mappings=None,
storage_provisioning=None,
storage_profile_id=None,
locale=None,
flags=None,
additional_parameters=None,
default_datastore_id=None)
# Deploy the ovf template
result = self.client.ovf_lib_item_service.deploy(lib_item_id,
deployment_target,
deployment_spec,
client_token=generate_random_uuid())
# The type and ID of the target deployment is available in the deployment result.
if result.succeeded:
print('Deployment successful. Result resource: {0}, ID: {1}'
.format(result.resource_id.type, result.resource_id.id))
self.vm_id = result.resource_id.id
error = result.error
if error is not None:
for warning in error.warnings:
print('OVF warning: {}'.format(warning.message))
# Power on the VM and wait for the power on operation to be completed
self.vm_obj = get_obj_by_moId(self.servicemanager.content,
[vim.VirtualMachine], self.vm_id)
assert self.vm_obj is not None
poweron_vm(self.servicemanager.content, self.vm_obj)
else:
print('Deployment failed.')
for error in result.error.errors:
print('OVF error: {}'.format(error.message))
def _cleanup(self):
if self.vm_obj is not None:
# Power off the VM and wait for the power off operation to complete
poweroff_vm(self.servicemanager.content, self.vm_obj)
# Delete the VM
delete_object(self.servicemanager.content, self.vm_obj)
def main():
deploy_ovf_sample = DeployOvfTemplate()
deploy_ovf_sample.main()
if __name__ == '__main__':
main()

View File

@ -0,0 +1,25 @@
"""
* *******************************************************
* Copyright VMware, Inc. 2016. All Rights Reserved.
* *******************************************************
*
* DISCLAIMER. THIS PROGRAM IS PROVIDED TO YOU "AS IS" WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, WHETHER ORAL OR WRITTEN,
* EXPRESS OR IMPLIED. THE AUTHOR SPECIFICALLY DISCLAIMS ANY IMPLIED
* WARRANTIES OR CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY,
* NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE.
"""
__author__ = 'VMware, Inc.'
__copyright__ = 'Copyright 2016 VMware, Inc. All rights reserved.'
# Required to distribute different parts of this
# package as multiple distribution
try:
import pkg_resources
pkg_resources.declare_namespace(__name__)
except ImportError:
from pkgutil import extend_path
__path__ = extend_path(__path__, __name__) # @ReservedAssignment

View File

@ -0,0 +1,125 @@
#!/usr/bin/env python
"""
* *******************************************************
* Copyright VMware, Inc. 2016. All Rights Reserved.
* *******************************************************
*
* DISCLAIMER. THIS PROGRAM IS PROVIDED TO YOU "AS IS" WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, WHETHER ORAL OR WRITTEN,
* EXPRESS OR IMPLIED. THE AUTHOR SPECIFICALLY DISCLAIMS ANY IMPLIED
* WARRANTIES OR CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY,
* NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE.
"""
__author__ = 'VMware, Inc.'
__copyright__ = 'Copyright 2016 VMware, Inc. All rights reserved.'
__vcenter_version__ = '6.0+'
import tempfile
try:
import urllib2
except ImportError:
import urllib.request as urllib2
from com.vmware.content_client import LibraryModel
from com.vmware.content.library_client import StorageBacking
from samples.vsphere.common.id_generator import generate_random_uuid
from samples.vsphere.common.sample_base import SampleBase
from samples.vsphere.contentlibrary.lib.cls_api_client import ClsApiClient
from samples.vsphere.contentlibrary.lib.cls_api_helper import ClsApiHelper
from samples.vsphere.common.vim.helpers.get_datastore_by_name import get_datastore_id
class OvfImportExport(SampleBase):
"""
Demonstrates the workflow to import an OVF package into the content library,
as well as download of an OVF template from the content library.
Note: the workflow needs an existing VC DS with available storage.
"""
def __init__(self):
SampleBase.__init__(self, self.__doc__)
self.servicemanager = None
self.client = None
self.helper = None
self.datastore_name = None
self.lib_name = "demo-lib"
self.local_library = None
self.lib_item_name = "simpleVmTemplate"
self.library_item = None
def _options(self):
self.argparser.add_argument('-datastorename',
'--datastorename',
help='The name of the datastore.')
def _setup(self):
self.datastore_name = self.args.datastorename
assert self.datastore_name is not None
if not self.servicemanager:
self.servicemanager = self.get_service_manager()
self.client = ClsApiClient(self.servicemanager)
self.helper = ClsApiHelper(self.client, self.skip_verification)
def _execute(self):
# Find the datastore by the given datastore name using property collector
self.datastore_id = get_datastore_id(service_manager=self.servicemanager, datastore_name=self.datastore_name)
assert self.datastore_id is not None
print('DataStore: {0} ID: {1}'.format(self.datastore_name, self.datastore_id))
# Build the storage backing for the library to be created
storage_backings = []
storage_backing = StorageBacking(type=StorageBacking.Type.DATASTORE, datastore_id=self.datastore_id)
storage_backings.append(storage_backing)
# Build the specification for the library to be created
create_spec = LibraryModel()
create_spec.name = self.lib_name
create_spec.description = "Local library backed by VC datastore"
create_spec.type = create_spec.LibraryType.LOCAL
create_spec.storage_backings = storage_backings
# Create a local content library backed the VC datastore using vAPIs
library_id = self.client.local_library_service.create(create_spec=create_spec,
client_token=generate_random_uuid())
print('Local library created: ID: {0}'.format(library_id))
self.local_library = self.client.local_library_service.get(library_id)
# Create a new library item in the content library for uploading the files
self.library_item_id = self.helper.create_library_item(library_id=self.local_library.id,
item_name=self.lib_item_name,
item_description='Sample simple VM template',
item_type='ovf')
assert self.library_item_id is not None
assert self.client.library_item_service.get(self.library_item_id) is not None
print('Library item created id: {0}'.format(self.library_item_id))
# Upload a VM template to the CL
ovf_files_map = self.helper.get_ovf_files_map(ClsApiHelper.SIMPLE_OVF_RELATIVE_DIR)
self.helper.upload_files(library_item_id=self.library_item_id, files_map=ovf_files_map)
print('Uploaded ovf and vmdk files to library item {0}'.format(self.library_item_id))
# Download the library item from the CL
temp_dir = tempfile.mkdtemp(prefix='simpleVmTemplate-')
print('Downloading library item {0} to directory {1}'.format(self.library_item_id, temp_dir))
downloaded_files_map = self.helper.download_files(library_item_id=self.library_item_id, directory=temp_dir)
assert len(downloaded_files_map) == len(ovf_files_map)
def _cleanup(self):
if self.local_library:
self.client.local_library_service.delete(library_id=self.local_library.id)
print('Deleted Library Id: {0}'.format(self.local_library.id))
def main():
sample = OvfImportExport()
sample.main()
if __name__ == '__main__':
main()

View File

@ -0,0 +1,25 @@
"""
* *******************************************************
* Copyright VMware, Inc. 2016. All Rights Reserved.
* *******************************************************
*
* DISCLAIMER. THIS PROGRAM IS PROVIDED TO YOU "AS IS" WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, WHETHER ORAL OR WRITTEN,
* EXPRESS OR IMPLIED. THE AUTHOR SPECIFICALLY DISCLAIMS ANY IMPLIED
* WARRANTIES OR CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY,
* NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE.
"""
__author__ = 'VMware, Inc.'
__copyright__ = 'Copyright 2016 VMware, Inc. All rights reserved.'
# Required to distribute different parts of this
# package as multiple distribution
try:
import pkg_resources
pkg_resources.declare_namespace(__name__)
except ImportError:
from pkgutil import extend_path
__path__ = extend_path(__path__, __name__) # @ReservedAssignment

View File

@ -0,0 +1,201 @@
#!/usr/bin/env python
"""
* *******************************************************
* Copyright VMware, Inc. 2016. All Rights Reserved.
* *******************************************************
*
* DISCLAIMER. THIS PROGRAM IS PROVIDED TO YOU "AS IS" WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, WHETHER ORAL OR WRITTEN,
* EXPRESS OR IMPLIED. THE AUTHOR SPECIFICALLY DISCLAIMS ANY IMPLIED
* WARRANTIES OR CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY,
* NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE.
"""
__author__ = 'VMware, Inc.'
__copyright__ = 'Copyright 2016 VMware, Inc. All rights reserved.'
__vcenter_version__ = '6.0+'
try:
import urllib2
except ImportError:
import urllib.request as urllib2
from com.vmware.content_client import LibraryModel
from com.vmware.content.library_client import (ItemModel, PublishInfo,
StorageBacking, SubscriptionInfo)
from samples.vsphere.common.id_generator import generate_random_uuid
from samples.vsphere.common.sample_base import SampleBase
from samples.vsphere.contentlibrary.lib.cls_api_client import ClsApiClient
from samples.vsphere.contentlibrary.lib.cls_api_helper import ClsApiHelper
from samples.vsphere.contentlibrary.lib.cls_sync_helper import ClsSyncHelper
class LibraryPublishSubscribe(SampleBase):
"""
Demonstrates the basic sync workflow to publish and subscribe content libraries.
Note: the workflow needs an existing VC datastore with available storage.
"""
VCSP_USERNAME = 'vcsp'
DEMO_PASSWORD = 'Password!23'
SYNC_TIMEOUT_SEC = 60
DEMO_FILENAME = 'test.iso'
def __init__(self):
SampleBase.__init__(self, self.__doc__)
self.servicemanager = None
self.client = None
self.helper = None
self.datastore_name = None
self.pub_lib_name = "demo-publib"
self.sub_lib_name = "demo-sublib"
self.pub_lib_id = None
self.sub_lib_id = None
def _options(self):
self.argparser.add_argument('-datastorename',
'--datastorename',
help='The name of the datastore.')
def _setup(self):
self.datastore_name = self.args.datastorename
assert self.datastore_name is not None
self.servicemanager = self.get_service_manager()
self.client = ClsApiClient(self.servicemanager)
self.helper = ClsApiHelper(self.client, self.skip_verification)
def _execute(self):
storage_backings = self.helper.create_storage_backings(
self.servicemanager,
self.datastore_name)
# Create a published library backed the VC datastore using vAPIs
self.pub_lib_id = self.create_published_library(storage_backings)
assert self.pub_lib_id is not None
print('Published library created: ID: {0}'.format(self.pub_lib_id))
pub_lib = self.client.local_library_service.get(self.pub_lib_id)
pub_lib_url = pub_lib.publish_info.publish_url
assert pub_lib_url is not None
print('Publish URL : {0}'.format(pub_lib_url))
# Create a library item in the published library
pub_lib_item_id = self.helper.create_iso_library_item(self.pub_lib_id,
'item_1',
self.DEMO_FILENAME)
assert self.client.library_item_service.get(pub_lib_item_id) is not None
# Create the subscribed library
sub_lib, sub_spec = self.create_subcribed_library(storage_backings,
pub_lib_url)
assert self.sub_lib_id is not None
print('Subscribed library created: ID: {0}'.format(self.sub_lib_id))
# It is not mandatory to verify sync, it is just for demonstrating the sample workflow.
assert (ClsSyncHelper(self.client, self.SYNC_TIMEOUT_SEC).
verify_library_sync(self.pub_lib_id, sub_lib))
sub_lib = self.client.subscribed_library_service.get(self.sub_lib_id)
print('Subscribed library synced : {0}'.format(sub_lib.last_sync_time))
sub_item_ids = self.client.library_item_service.list(self.sub_lib_id)
assert len(sub_item_ids) == 1, 'Subscribed library must have one item'
# Add another item to the published library
self.helper.create_iso_library_item(self.pub_lib_id, 'item_2',
self.DEMO_FILENAME)
# Manually synchronize the subscribed library to get the latest changes immediately.
self.client.subscribed_library_service.sync(self.sub_lib_id)
# It is not mandatory to verify sync, it is just for demonstrating the sample workflow.
assert (ClsSyncHelper(self.client, self.SYNC_TIMEOUT_SEC).
verify_library_sync(self.pub_lib_id, sub_lib))
sub_lib = self.client.subscribed_library_service.get(self.sub_lib_id)
print('Subscribed library synced : {0}'.format(sub_lib.last_sync_time))
# List the subscribed items.
sub_item_ids = self.client.library_item_service.list(self.sub_lib_id)
assert len(sub_item_ids) == 2, 'Subscribed library must have two items'
for sub_item_id in sub_item_ids:
sub_item = self.client.library_item_service.get(sub_item_id)
print('Subscribed item : {0}'.format(sub_item.name))
# Change the subscribed library to be on-demand
sub_spec.subscription_info.on_demand = True
self.client.subscribed_library_service.update(self.sub_lib_id, sub_spec)
# Evict the cached content of the first subscribed library item
self.client.subscribed_item_service.evict(sub_item_id)
sub_item = self.client.library_item_service.get(sub_item_id)
print('Subscribed item evicted : {0}'.format(sub_item.name))
assert not sub_item.cached, 'Subscribed item must not be cached'
# Force synchronize the subscribed library item to fetch and cache the content
self.client.subscribed_item_service.sync(sub_item_id, True)
# It is not mandatory to verify sync, it is just for demonstrating the sample workflow.
assert (ClsSyncHelper(self.client, self.SYNC_TIMEOUT_SEC).
verify_item_sync(sub_item_id))
sub_item = self.client.library_item_service.get(sub_item_id)
print('Subscribed item force sync : {0}'.format(sub_item.name))
assert sub_item.cached, 'Subscribed item must be cached'
def create_published_library(self, storage_backings):
# Build the authenticated publish info.
# Note: The username will be 'vcsp'.
pub_info = PublishInfo()
pub_info.published = True
pub_info.authentication_method = PublishInfo.AuthenticationMethod.BASIC
pub_info.password = self.DEMO_PASSWORD
# Build the specification for the published library to be created
pub_spec = LibraryModel()
pub_spec.name = self.pub_lib_name
pub_spec.description = "Published library backed by VC datastore"
pub_spec.publish_info = pub_info
pub_spec.type = pub_spec.LibraryType.LOCAL
pub_spec.storage_backings = storage_backings
pub_lib_id = self.client.local_library_service.create(
create_spec=pub_spec, client_token=generate_random_uuid())
return pub_lib_id
def create_subcribed_library(self, storage_backings, pub_lib_url):
# Build the subscription information using the publish URL of the published
# library. The username must be 'vcsp'.
sub_info = SubscriptionInfo()
sub_info.authentication_method = SubscriptionInfo.AuthenticationMethod.BASIC
sub_info.user_name = self.VCSP_USERNAME
sub_info.password = self.DEMO_PASSWORD
sub_info.on_demand = False
sub_info.automatic_sync_enabled = True
sub_info.subscription_url = pub_lib_url
# Build the specification for the subscribed library
sub_spec = LibraryModel()
sub_spec.name = self.sub_lib_name
sub_spec.type = sub_spec.LibraryType.SUBSCRIBED
sub_spec.subscription_info = sub_info
sub_spec.storage_backings = storage_backings
self.sub_lib_id = self.client.subscribed_library_service.create(
create_spec=sub_spec, client_token=generate_random_uuid())
sub_lib = self.client.subscribed_library_service.get(self.sub_lib_id)
return sub_lib, sub_spec
def _cleanup(self):
if self.sub_lib_id:
self.client.subscribed_library_service.delete(self.sub_lib_id)
print('Deleted subscribed library Id: {0}'.format(self.sub_lib_id))
if self.pub_lib_id:
self.client.local_library_service.delete(self.pub_lib_id)
print('Deleted published library Id : {0}'.format(self.pub_lib_id))
def main():
sample = LibraryPublishSubscribe()
sample.main()
if __name__ == '__main__':
main()

View File

@ -0,0 +1,115 @@
<?xml version='1.0' encoding='UTF-8'?>
<Envelope xmlns="http://schemas.dmtf.org/ovf/envelope/1" xmlns:vssd="http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_VirtualSystemSettingData" xmlns:vmw="http://www.vmware.com/schema/ovf" xmlns:ovf="http://schemas.dmtf.org/ovf/envelope/1" xmlns:rasd="http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_ResourceAllocationSettingData">
<References>
<File ovf:id="file1" ovf:href="plain-vm.vmdk"/>
</References>
<DiskSection>
<Info>List of the virtual disks</Info>
<Disk ovf:capacityAllocationUnits="byte" ovf:fileRef="file1" ovf:diskId="vmdisk1" ovf:capacity="52428800" ovf:format="http://www.vmware.com/interfaces/specifications/vmdk.html#streamOptimized"/>
</DiskSection>
<NetworkSection>
<Info>The list of logical networks</Info>
<Network ovf:name="VM Network">
<Description>The VM Network network</Description>
</Network>
</NetworkSection>
<VirtualSystem ovf:id="Plain-VM">
<Info>A Virtual system</Info>
<Name>Plain-VM</Name>
<OperatingSystemSection ovf:id="101" vmw:osType="otherLinux64Guest">
<Info>The operating system installed</Info>
<Description>Other Linux (64-bit)</Description>
</OperatingSystemSection>
<VirtualHardwareSection>
<Info>Virtual hardware requirements</Info>
<System>
<vssd:ElementName>Virtual Hardware Family</vssd:ElementName>
<vssd:InstanceID>0</vssd:InstanceID>
<vssd:VirtualSystemType>vmx-11</vssd:VirtualSystemType>
</System>
<Item>
<rasd:AllocationUnits>hertz * 10^6</rasd:AllocationUnits>
<rasd:Description>Number of Virtual CPUs</rasd:Description>
<rasd:ElementName>1 virtual CPU(s)</rasd:ElementName>
<rasd:InstanceID>1</rasd:InstanceID>
<rasd:ResourceType>3</rasd:ResourceType>
<rasd:VirtualQuantity>1</rasd:VirtualQuantity>
<vmw:CoresPerSocket ovf:required="false">1</vmw:CoresPerSocket>
</Item>
<Item>
<rasd:AllocationUnits>byte * 2^20</rasd:AllocationUnits>
<rasd:Description>Memory Size</rasd:Description>
<rasd:ElementName>100MB of memory</rasd:ElementName>
<rasd:InstanceID>2</rasd:InstanceID>
<rasd:ResourceType>4</rasd:ResourceType>
<rasd:VirtualQuantity>100</rasd:VirtualQuantity>
</Item>
<Item>
<rasd:Address>0</rasd:Address>
<rasd:Description>SCSI Controller</rasd:Description>
<rasd:ElementName>SCSI Controller 1</rasd:ElementName>
<rasd:InstanceID>3</rasd:InstanceID>
<rasd:ResourceSubType>lsilogic</rasd:ResourceSubType>
<rasd:ResourceType>6</rasd:ResourceType>
<vmw:Config ovf:required="false" vmw:value="16" vmw:key="slotInfo.pciSlotNumber"/>
</Item>
<Item>
<rasd:Address>1</rasd:Address>
<rasd:Description>IDE Controller</rasd:Description>
<rasd:ElementName>IDE Controller 1</rasd:ElementName>
<rasd:InstanceID>4</rasd:InstanceID>
<rasd:ResourceType>5</rasd:ResourceType>
</Item>
<Item>
<rasd:AddressOnParent>0</rasd:AddressOnParent>
<rasd:ElementName>Hard Disk 1</rasd:ElementName>
<rasd:HostResource>ovf:/disk/vmdisk1</rasd:HostResource>
<rasd:InstanceID>5</rasd:InstanceID>
<rasd:Parent>3</rasd:Parent>
<rasd:ResourceType>17</rasd:ResourceType>
</Item>
<Item>
<rasd:AddressOnParent>0</rasd:AddressOnParent>
<rasd:AutomaticAllocation>true</rasd:AutomaticAllocation>
<rasd:ElementName>CD/DVD Drive 1</rasd:ElementName>
<rasd:InstanceID>6</rasd:InstanceID>
<rasd:Parent>4</rasd:Parent>
<rasd:ResourceSubType>vmware.cdrom.remoteatapi</rasd:ResourceSubType>
<rasd:ResourceType>15</rasd:ResourceType>
</Item>
<Item>
<rasd:AddressOnParent>0</rasd:AddressOnParent>
<rasd:AutomaticAllocation>false</rasd:AutomaticAllocation>
<rasd:Description>Floppy Drive</rasd:Description>
<rasd:ElementName>Floppy Drive 1</rasd:ElementName>
<rasd:InstanceID>7</rasd:InstanceID>
<rasd:ResourceSubType>vmware.floppy.remotedevice</rasd:ResourceSubType>
<rasd:ResourceType>14</rasd:ResourceType>
</Item>
<Item>
<rasd:AddressOnParent>0</rasd:AddressOnParent>
<rasd:AutomaticAllocation>true</rasd:AutomaticAllocation>
<rasd:Connection>VM Network</rasd:Connection>
<rasd:ElementName>Network adapter 1</rasd:ElementName>
<rasd:InstanceID>8</rasd:InstanceID>
<rasd:ResourceSubType>E1000</rasd:ResourceSubType>
<rasd:ResourceType>10</rasd:ResourceType>
<vmw:Config ovf:required="false" vmw:value="true" vmw:key="connectable.allowGuestControl"/>
<vmw:Config ovf:required="false" vmw:value="true" vmw:key="wakeOnLanEnabled"/>
<vmw:Config ovf:required="false" vmw:value="32" vmw:key="slotInfo.pciSlotNumber"/>
</Item>
<Item ovf:required="false">
<rasd:ElementName>Video card</rasd:ElementName>
<rasd:InstanceID>9</rasd:InstanceID>
<rasd:ResourceType>24</rasd:ResourceType>
<vmw:Config ovf:required="false" vmw:value="262144" vmw:key="graphicsMemorySizeInKB"/>
<vmw:Config ovf:required="false" vmw:value="1" vmw:key="numDisplays"/>
<vmw:Config ovf:required="false" vmw:value="automatic" vmw:key="use3dRenderer"/>
<vmw:Config ovf:required="false" vmw:value="4096" vmw:key="videoRamSizeInKB"/>
<vmw:Config ovf:required="false" vmw:value="false" vmw:key="enableMPTSupport"/>
<vmw:Config ovf:required="false" vmw:value="false" vmw:key="enable3DSupport"/>
<vmw:Config ovf:required="false" vmw:value="false" vmw:key="useAutoDetect"/>
</Item>
</VirtualHardwareSection>
</VirtualSystem>
</Envelope>

View File

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="UTF-8"?><Envelope xmlns="http://schemas.dmtf.org/ovf/envelope/1" xmlns:vssd="http://schemas.dmtf.org/wbem/wscim/1/cim-schema/2/CIM_VirtualSystemSettingData" xmlns:ovf="http://schemas.dmtf.org/ovf/envelope/1">
<References/>
<VirtualSystem ovf:id="moref:VirtualMachine:vm-28:a7296408-184e-4b11-a4ce-d55a878fd325">
<Info>A Virtual system</Info>
<Name>vmBV8ly</Name>
<AnnotationSection>
<Info>A human-readable annotation</Info>
<Annotation/>
</AnnotationSection>
<VirtualHardwareSection ovf:transport="com.vmware.guestInfo">
<Info>Virtual hardware requirements</Info>
<System>
<vssd:ElementName>Virtual Hardware Family</vssd:ElementName>
<vssd:InstanceID>System</vssd:InstanceID>
</System>
</VirtualHardwareSection>
</VirtualSystem>
</Envelope>

View File

@ -0,0 +1,25 @@
"""
* *******************************************************
* Copyright VMware, Inc. 2016. All Rights Reserved.
* *******************************************************
*
* DISCLAIMER. THIS PROGRAM IS PROVIDED TO YOU "AS IS" WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, WHETHER ORAL OR WRITTEN,
* EXPRESS OR IMPLIED. THE AUTHOR SPECIFICALLY DISCLAIMS ANY IMPLIED
* WARRANTIES OR CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY,
* NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE.
"""
__author__ = 'VMware, Inc.'
__copyright__ = 'Copyright 2016 VMware, Inc. All rights reserved.'
# Required to distribute different parts of this
# package as multiple distribution
try:
import pkg_resources
pkg_resources.declare_namespace(__name__)
except ImportError:
from pkgutil import extend_path
__path__ = extend_path(__path__, __name__) # @ReservedAssignment

View File

@ -0,0 +1,128 @@
#!/usr/bin/env python
"""
* *******************************************************
* Copyright VMware, Inc. 2013, 2016. All Rights Reserved.
* *******************************************************
*
* DISCLAIMER. THIS PROGRAM IS PROVIDED TO YOU "AS IS" WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, WHETHER ORAL OR WRITTEN,
* EXPRESS OR IMPLIED. THE AUTHOR SPECIFICALLY DISCLAIMS ANY IMPLIED
* WARRANTIES OR CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY,
* NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE.
"""
__author__ = 'VMware, Inc.'
__copyright__ = 'Copyright 2016 VMware, Inc. All rights reserved.'
__vcenter_version__ = '6.0+'
try:
import urllib2
except ImportError:
import urllib.request as urllib2
from com.vmware.vcenter.ovf_client import LibraryItem
from samples.vsphere.common.id_generator import generate_random_uuid
from samples.vsphere.common.sample_base import SampleBase
from samples.vsphere.contentlibrary.lib.cls_api_client import ClsApiClient
from samples.vsphere.contentlibrary.lib.cls_api_helper import ClsApiHelper
from samples.vsphere.vcenter.helper.vm_helper import get_vm
class CaptureVMTemplateToContentLibrary(SampleBase):
"""
Demonstrates the workflow to capture a virtual machine into a content library.
Note: The sample needs an existing virtual machine to capture.
"""
def __init__(self):
SampleBase.__init__(self, self.__doc__)
self.servicemanager = None
self.datastore_name = None
self.datastore_id = None
self.cl_name = "LocalLibraryToCapture"
self.vm_name = None
self.vm_template_name = 'CapturedOvf'
self.vm_template_description = 'Captured OVF description'
self.deployable_resource_type = 'VirtualMachine' # Substitute 'VirtualApp' for vApp
self.content_library = None
self.library_item_id = None
def _options(self):
self.argparser.add_argument('-datastorename', '--datastorename',
help='The name of the datastore for'
' content library backing (of type vmfs)')
self.argparser.add_argument('-vmname', '--vmname',
help='Name of the VM to be captured')
def _setup(self):
self.datastore_name = self.args.datastorename
assert self.datastore_name is not None
self.vm_name = self.args.vmname
assert self.vm_name is not None
if self.servicemanager is None:
self.servicemanager = self.get_service_manager()
self.client = ClsApiClient(self.servicemanager)
self.helper = ClsApiHelper(self.client, self.skip_verification)
def _execute(self):
storage_backings = self.helper.create_storage_backings(
self.servicemanager,
self.datastore_name)
print('Creating Content Library')
# Create a content library
library_id = self.helper.create_local_library(storage_backings,
self.cl_name)
self.content_library = self.client.local_library_service.get(library_id)
vm_id = get_vm(self.servicemanager.stub_config, self.vm_name)
assert vm_id is not None
param = self.create_capture_param(self.content_library,
self.vm_template_name,
self.vm_template_description)
self.library_item_id = self.capture_source_vm(vm_id, param)
assert self.library_item_id is not None
assert self.client.library_item_service.get(self.library_item_id) is not None
print('The VM id : {0} is captured as vm template library item id : {1}'.format
(vm_id, self.library_item_id))
def capture_source_vm(self, vm_id, param):
source = LibraryItem.DeployableIdentity(self.deployable_resource_type,
vm_id)
result = self.client.ovf_lib_item_service.create(source,
param["target"],
param["spec"],
client_token=generate_random_uuid())
return result.ovf_library_item_id
def create_capture_param(self, library, name, description):
spec = LibraryItem.CreateSpec(name=name,
description=description)
target = LibraryItem.CreateTarget(library_id=library.id,
library_item_id=None)
return {"target": target, "spec": spec}
def _cleanup(self):
# delete the local library.
if self.content_library is not None:
self.client.local_library_service.delete(
library_id=self.content_library.id)
print('Deleted Library Id: {0}'.format
(self.content_library.id))
def main():
vm_template_capture = CaptureVMTemplateToContentLibrary()
vm_template_capture.main()
# Start program
if __name__ == '__main__':
main()

View File

@ -0,0 +1,14 @@
This directory contains samples for Platform Service Controller, SSO and Lookup Service APIs:
The vSphere Automation SDK for Python samples use the vCenter Lookup Service
to obtain the URLs for other vSphere Automation services (SSO, vAPI, VIM, SPBM, etc.).
The SDK contains the Lookup Service WSDL files. The samples use the python SUDS client
for accessing the lookup service. The Lookup Service WSDL files are located in wsdl/ directory.
Running the samples
```cmd
$ cd /path/to/vsphere-automation-sdk-python-samples/bin
$ ./run_sample.sh ../samples/vsphere/sso/external_psc_sso_workflow.py --lsurl https://<server>/lookupservice/sdk -u 'administrator@vsphere.local' -p 'Admin!23' -v
```
* Testbed Requirement:
- 1 vCenter Server

View File

@ -0,0 +1,25 @@
"""
* *******************************************************
* Copyright VMware, Inc. 2016. All Rights Reserved.
* *******************************************************
*
* DISCLAIMER. THIS PROGRAM IS PROVIDED TO YOU "AS IS" WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, WHETHER ORAL OR WRITTEN,
* EXPRESS OR IMPLIED. THE AUTHOR SPECIFICALLY DISCLAIMS ANY IMPLIED
* WARRANTIES OR CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY,
* NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE.
"""
__author__ = 'VMware, Inc.'
__copyright__ = 'Copyright 2016 VMware, Inc. All rights reserved.'
# Required to distribute different parts of this
# package as multiple distribution
try:
import pkg_resources
pkg_resources.declare_namespace(__name__)
except ImportError:
from pkgutil import extend_path
__path__ = extend_path(__path__, __name__) # @ReservedAssignment

View File

@ -0,0 +1,119 @@
#!/usr/bin/env python
"""
* *******************************************************
* Copyright (c) VMware, Inc. 2017. All Rights Reserved.
* *******************************************************
*
* DISCLAIMER. THIS PROGRAM IS PROVIDED TO YOU "AS IS" WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, WHETHER ORAL OR WRITTEN,
* EXPRESS OR IMPLIED. THE AUTHOR SPECIFICALLY DISCLAIMS ANY IMPLIED
* WARRANTIES OR CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY,
* NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE.
"""
__author__ = 'VMware, Inc.'
__copyright__ = 'Copyright 2017 VMware, Inc. All rights reserved.'
__vcenter_version__ = '6.0+'
from pprint import pprint
import requests
from com.vmware.cis_client import Session
from com.vmware.vcenter_client import Datacenter
from vmware.vapi.lib.connect import get_requests_connector
from vmware.vapi.security.session import create_session_security_context
from vmware.vapi.security.sso import create_saml_bearer_security_context
from vmware.vapi.stdlib.client.factories import StubConfigurationFactory
from samples.vsphere.common.ssl_helper import get_unverified_context
from samples.vsphere.common.vapiconnect import create_unverified_session
from samples.vsphere.common.sample_util import parse_cli_args
from samples.vsphere.common import sso
class EmbeddedPscSsoWorkflow(object):
"""
Demonstrates how to Login to vCenter vAPI service with
embedded Platform Services Controller.
"""
def __init__(self):
self.server = None
self.username = None
self.password = None
self.session = None
self.session_id = None
self.skip_verification = False
def setup(self):
self.server, self.username, self.password, _, self.skip_verification = \
parse_cli_args()
def run(self):
print('\n\n#### Example: Login to vCenter server with '
'embedded Platform Services Controller')
# Since the platform services controller is embedded, the sso server
# is the same as the vCenter server.
ssoUrl = 'https://{}/sts/STSService'.format(self.server)
print('\nStep 1: Connect to the Single Sign-On URL and '
'retrieve the SAML bearer token.')
authenticator = sso.SsoAuthenticator(ssoUrl)
context = None
if self.skip_verification:
context = get_unverified_context()
bearer_token = authenticator.get_bearer_saml_assertion(
self.username,
self.password,
delegatable=True,
ssl_context=context)
# Creating SAML Bearer Security Context
sec_ctx = create_saml_bearer_security_context(bearer_token)
print('\nStep 2. Login to vAPI services using the SAML bearer token.')
# The URL for the stub requests are made against the /api HTTP endpoint
# of the vCenter system.
vapi_url = 'https://{}/api'.format(self.server)
# Create an authenticated stub configuration object that can be used to
# issue requests against vCenter.
session = requests.Session()
if self.skip_verification:
session = create_unverified_session(session)
connector = get_requests_connector(session=session, url=vapi_url)
connector.set_security_context(sec_ctx)
stub_config = StubConfigurationFactory.new_std_configuration(
connector)
self.session = Session(stub_config)
# Login to VAPI endpoint and get the session_id
self.session_id = self.session.create()
# Update the VAPI connection with session_id
session_sec_ctx = create_session_security_context(self.session_id)
connector.set_security_context(session_sec_ctx)
print('\nStep 3: List available datacenters using the vAPI services')
datacenter_svc = Datacenter(stub_config)
pprint(datacenter_svc.list())
self.session.delete()
print('VAPI session disconnected successfully...')
def main():
embedded_psc_sso_workflow = EmbeddedPscSsoWorkflow()
embedded_psc_sso_workflow.setup()
embedded_psc_sso_workflow.run()
# Start program
if __name__ == '__main__':
main()

View File

@ -0,0 +1,190 @@
#!/usr/bin/env python
"""
* *******************************************************
* Copyright (c) VMware, Inc. 2017. All Rights Reserved.
* *******************************************************
*
* DISCLAIMER. THIS PROGRAM IS PROVIDED TO YOU "AS IS" WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, WHETHER ORAL OR WRITTEN,
* EXPRESS OR IMPLIED. THE AUTHOR SPECIFICALLY DISCLAIMS ANY IMPLIED
* WARRANTIES OR CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY,
* NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE.
"""
__author__ = 'VMware, Inc.'
__copyright__ = 'Copyright 2017 VMware, Inc. All rights reserved.'
__vcenter_version__ = '6.0+'
import os
import argparse
import requests
from pprint import pprint
from six.moves.urllib import request, parse
from com.vmware.cis_client import Session
from com.vmware.vcenter_client import Datacenter
from vmware.vapi.lib.connect import get_requests_connector
from vmware.vapi.security.session import create_session_security_context
from vmware.vapi.security.sso import create_saml_bearer_security_context
from vmware.vapi.stdlib.client.factories import StubConfigurationFactory
from samples.vsphere.common import sso
from samples.vsphere.common.lookup_service_helper import LookupServiceHelper
from samples.vsphere.common.ssl_helper import get_unverified_context
from samples.vsphere.common.vapiconnect import create_unverified_session
class ExternalPscSsoWorkflow(object):
"""
Demonstrates how to Login to vCenter vAPI service with
external Platform Services Controller.
"""
def __init__(self):
self.lswsdl = None
self.lsurl = None
self.mgmtinstancename = None
self.username = None
self.password = None
self.session = None
self.session_id = None
self.args = None
self.argparser = None
self.mgmtinstancename = None
self.skip_verification = False
def options(self):
self.argparser = argparse.ArgumentParser(description=self.__doc__)
# setup the argument parser
self.argparser.add_argument('-w', '--lswsdl',
help='Path to the Lookup Service WSDL. '
'By default, lookupservice.wsdl in '
'../wsdl will be used if the parameter'
' is absent')
self.argparser.add_argument('-s', '--lsurl', help='Lookup service URL')
self.argparser.add_argument('-m', '--mgmtinstancename',
help='Instance name of the vCenter Server '
'management node. '
'When only one node is registered, '
'it is selected by default; otherwise,'
' omit the parameter to get a list of '
'available nodes.')
self.argparser.add_argument('-u', '--username', help='SSO user name')
self.argparser.add_argument('-p', '--password',
help='SSO user password')
self.argparser.add_argument('-v', '--skipverification',
action='store_true',
help='Do not verify server certificate')
self.args = self.argparser.parse_args()
def setup(self):
self.lswsdl = self.args.lswsdl
if not self.lswsdl:
self.lswsdl = os.path.join(
os.path.dirname(os.path.abspath(__file__)),
'wsdl',
'lookupservice.wsdl')
assert self.lswsdl is not None
print('lswsdl: {0}'.format(self.lswsdl))
self.lsurl = self.args.lsurl
assert self.lsurl is not None
print('lsurl: {0}'.format(self.lsurl))
self.username = self.args.username
assert self.username is not None
self.password = self.args.password
assert self.password is not None
self.mgmtinstancename = self.args.mgmtinstancename
self.skip_verification = self.args.skipverification
def run(self):
print('\n\n#### Example: Login to vCenter server with '
'external Platform Services Controller')
print('\nStep 1: Connect to the lookup service on the '
'Platform Services Controller node: {0}'.format(self.lsurl))
# Convert wsdl path to url
self.lswsdl = parse.urljoin('file:', request.pathname2url(self.lswsdl))
lookupservicehelper = LookupServiceHelper(wsdl_url=self.lswsdl,
soap_url=self.lsurl,
skip_verification=self.skip_verification)
lookupservicehelper.connect()
if self.mgmtinstancename is None:
self.mgmtinstancename, self.mgmtnodeid = lookupservicehelper.get_default_mgmt_node()
elif self.mgmtnodeid is None:
self.mgmtnodeid = lookupservicehelper.get_mgmt_node_id(
self.mgmtinstancename)
assert self.mgmtnodeid is not None
print('\nStep 2: Discover the Single Sign-On service URL'
' from lookup service.')
sso_url = lookupservicehelper.find_sso_url()
print('Sso URL: {0}'.format(sso_url))
print('\nStep 3: Connect to the Single Sign-On URL and '
'retrieve the SAML bearer token.')
authenticator = sso.SsoAuthenticator(sso_url)
context = None
if self.skip_verification:
context = get_unverified_context()
bearer_token = authenticator.get_bearer_saml_assertion(
self.username,
self.password,
delegatable=True,
ssl_context=context)
# Creating SAML Bearer Security Context
sec_ctx = create_saml_bearer_security_context(bearer_token)
print('\nStep 4. Discover the vAPI service URL from lookup service.')
vapi_url = lookupservicehelper.find_vapi_url(self.mgmtnodeid)
print('vAPI URL: {0}'.format(vapi_url))
print('\nStep 5. Login to vAPI service using the SAML bearer token.')
# Create an authenticated stub configuration object that can be used to
# issue requests against vCenter.
session = requests.Session()
if self.skip_verification:
session = create_unverified_session(session)
connector = get_requests_connector(session=session, url=vapi_url)
connector.set_security_context(sec_ctx)
stub_config = StubConfigurationFactory.new_std_configuration(
connector)
self.session = Session(stub_config)
# Login to VAPI endpoint and get the session_id
self.session_id = self.session.create()
# Update the VAPI connection with session_id
session_sec_ctx = create_session_security_context(self.session_id)
connector.set_security_context(session_sec_ctx)
print('\nStep 6: List available datacenters using the vAPI service')
datacenter_svc = Datacenter(stub_config)
pprint(datacenter_svc.list())
self.session.delete()
print('VAPI session disconnected successfully...')
def main():
external_psc_sso_workflow = ExternalPscSsoWorkflow()
external_psc_sso_workflow.options()
external_psc_sso_workflow.setup()
external_psc_sso_workflow.run()
# Start program
if __name__ == '__main__':
main()

View File

@ -0,0 +1,922 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!--
Copyright 2005-2015 VMware, Inc. All rights reserved.
-->
<definitions targetNamespace="urn:lookup"
xmlns="http://schemas.xmlsoap.org/wsdl/"
xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:lookup="urn:lookup"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
>
<types>
<schema
targetNamespace="urn:lookup"
xmlns="http://www.w3.org/2001/XMLSchema"
xmlns:mime="http://schemas.xmlsoap.org/wsdl/mime/"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:wsdl="http://schemas.xmlsoap.org/wsdl/"
xmlns:lookup="urn:lookup"
xmlns:xsd="http://www.w3.org/2001/XMLSchema"
elementFormDefault="qualified"
>
<complexType name="DynamicArray">
<sequence>
<element name="val" type="xsd:anyType" maxOccurs="unbounded" />
</sequence>
</complexType>
<complexType name="DynamicData">
<sequence>
</sequence>
</complexType>
<complexType name="DynamicProperty">
<sequence>
<element name="name" type="xsd:string" />
<element name="val" type="xsd:anyType" />
</sequence>
</complexType>
<complexType name="ArrayOfDynamicProperty">
<sequence>
<element name="DynamicProperty" type="lookup:DynamicProperty" minOccurs="0" maxOccurs="unbounded" />
</sequence>
</complexType>
<complexType name="KeyAnyValue">
<complexContent>
<extension base="lookup:DynamicData">
<sequence>
<element name="key" type="xsd:string" />
<element name="value" type="xsd:anyType" />
</sequence>
</extension>
</complexContent>
</complexType>
<complexType name="ArrayOfKeyAnyValue">
<sequence>
<element name="KeyAnyValue" type="lookup:KeyAnyValue" minOccurs="0" maxOccurs="unbounded" />
</sequence>
</complexType>
<complexType name="LocalizableMessage">
<complexContent>
<extension base="lookup:DynamicData">
<sequence>
<element name="key" type="xsd:string" />
<element name="arg" type="lookup:KeyAnyValue" minOccurs="0" maxOccurs="unbounded" />
<element name="message" type="xsd:string" minOccurs="0" />
</sequence>
</extension>
</complexContent>
</complexType>
<complexType name="ArrayOfLocalizableMessage">
<sequence>
<element name="LocalizableMessage" type="lookup:LocalizableMessage" minOccurs="0" maxOccurs="unbounded" />
</sequence>
</complexType>
<complexType name="LocalizedMethodFault">
<complexContent>
<extension base="lookup:DynamicData">
<sequence>
<element name="fault" type="lookup:MethodFault" />
<element name="localizedMessage" type="xsd:string" minOccurs="0" />
</sequence>
</extension>
</complexContent>
</complexType>
<complexType name="MethodFault">
<sequence>
<element name="faultCause" type="lookup:LocalizedMethodFault" minOccurs="0" />
<element name="faultMessage" type="lookup:LocalizableMessage" minOccurs="0" maxOccurs="unbounded" />
</sequence>
</complexType>
<element name="MethodFaultFault" type="lookup:MethodFault"/>
<complexType name="RuntimeFault">
<complexContent>
<extension base="lookup:MethodFault">
<sequence>
</sequence>
</extension>
</complexContent>
</complexType>
<element name="RuntimeFaultFault" type="lookup:RuntimeFault"/>
<complexType name="HostCommunication">
<complexContent>
<extension base="lookup:RuntimeFault">
<sequence>
</sequence>
</extension>
</complexContent>
</complexType>
<element name="HostCommunicationFault" type="lookup:HostCommunication"/>
<complexType name="HostNotConnected">
<complexContent>
<extension base="lookup:HostCommunication">
<sequence>
</sequence>
</extension>
</complexContent>
</complexType>
<element name="HostNotConnectedFault" type="lookup:HostNotConnected"/>
<complexType name="HostNotReachable">
<complexContent>
<extension base="lookup:HostCommunication">
<sequence>
</sequence>
</extension>
</complexContent>
</complexType>
<element name="HostNotReachableFault" type="lookup:HostNotReachable"/>
<complexType name="InvalidArgument">
<complexContent>
<extension base="lookup:RuntimeFault">
<sequence>
<element name="invalidProperty" type="xsd:string" minOccurs="0" />
</sequence>
</extension>
</complexContent>
</complexType>
<element name="InvalidArgumentFault" type="lookup:InvalidArgument"/>
<complexType name="InvalidRequest">
<complexContent>
<extension base="lookup:RuntimeFault">
<sequence>
</sequence>
</extension>
</complexContent>
</complexType>
<element name="InvalidRequestFault" type="lookup:InvalidRequest"/>
<complexType name="InvalidType">
<complexContent>
<extension base="lookup:InvalidRequest">
<sequence>
<element name="argument" type="xsd:string" minOccurs="0" />
</sequence>
</extension>
</complexContent>
</complexType>
<element name="InvalidTypeFault" type="lookup:InvalidType"/>
<complexType name="ManagedObjectNotFound">
<complexContent>
<extension base="lookup:RuntimeFault">
<sequence>
<element name="obj" type="lookup:ManagedObjectReference" />
</sequence>
</extension>
</complexContent>
</complexType>
<element name="ManagedObjectNotFoundFault" type="lookup:ManagedObjectNotFound"/>
<complexType name="MethodNotFound">
<complexContent>
<extension base="lookup:InvalidRequest">
<sequence>
<element name="receiver" type="lookup:ManagedObjectReference" />
<element name="method" type="xsd:string" />
</sequence>
</extension>
</complexContent>
</complexType>
<element name="MethodNotFoundFault" type="lookup:MethodNotFound"/>
<complexType name="NotEnoughLicenses">
<complexContent>
<extension base="lookup:RuntimeFault">
<sequence>
</sequence>
</extension>
</complexContent>
</complexType>
<element name="NotEnoughLicensesFault" type="lookup:NotEnoughLicenses"/>
<complexType name="NotImplemented">
<complexContent>
<extension base="lookup:RuntimeFault">
<sequence>
</sequence>
</extension>
</complexContent>
</complexType>
<element name="NotImplementedFault" type="lookup:NotImplemented"/>
<complexType name="NotSupported">
<complexContent>
<extension base="lookup:RuntimeFault">
<sequence>
</sequence>
</extension>
</complexContent>
</complexType>
<element name="NotSupportedFault" type="lookup:NotSupported"/>
<complexType name="RequestCanceled">
<complexContent>
<extension base="lookup:RuntimeFault">
<sequence>
</sequence>
</extension>
</complexContent>
</complexType>
<element name="RequestCanceledFault" type="lookup:RequestCanceled"/>
<complexType name="SecurityError">
<complexContent>
<extension base="lookup:RuntimeFault">
<sequence>
</sequence>
</extension>
</complexContent>
</complexType>
<element name="SecurityErrorFault" type="lookup:SecurityError"/>
<complexType name="SystemError">
<complexContent>
<extension base="lookup:RuntimeFault">
<sequence>
<element name="reason" type="xsd:string" />
</sequence>
</extension>
</complexContent>
</complexType>
<element name="SystemErrorFault" type="lookup:SystemError"/>
<complexType name="UnexpectedFault">
<complexContent>
<extension base="lookup:RuntimeFault">
<sequence>
<element name="faultName" type="xsd:string" />
<element name="fault" type="lookup:LocalizedMethodFault" minOccurs="0" />
</sequence>
</extension>
</complexContent>
</complexType>
<element name="UnexpectedFaultFault" type="lookup:UnexpectedFault"/>
<complexType name="RetrieveHaBackupConfigurationRequestType">
<sequence>
<element name="_this" type="lookup:ManagedObjectReference" />
</sequence>
</complexType>
<element name="RetrieveHaBackupConfiguration" type="lookup:RetrieveHaBackupConfigurationRequestType" />
<element name="RetrieveHaBackupConfigurationResponse">
<complexType>
<sequence>
<element name="returnval" type="lookup:LookupHaBackupNodeConfiguration" />
</sequence>
</complexType>
</element>
<complexType name="LookupHaBackupNodeConfiguration">
<complexContent>
<extension base="lookup:DynamicData">
<sequence>
<element name="dbType" type="xsd:string" />
<element name="dbJdbcUrl" type="xsd:string" />
<element name="dbUser" type="xsd:string" />
<element name="dbPass" type="xsd:string" />
</sequence>
</extension>
</complexContent>
</complexType>
<complexType name="SetLocaleRequestType">
<sequence>
<element name="_this" type="lookup:ManagedObjectReference" />
<element name="locale" type="xsd:string" />
</sequence>
</complexType>
<element name="SetLocale" type="lookup:SetLocaleRequestType" />
<element name="SetLocaleResponse">
<complexType>
<sequence>
<element name="returnval" type="xsd:string" />
</sequence>
</complexType>
</element>
<complexType name="GetLocaleRequestType">
<sequence>
<element name="_this" type="lookup:ManagedObjectReference" />
</sequence>
</complexType>
<element name="GetLocale" type="lookup:GetLocaleRequestType" />
<element name="GetLocaleResponse">
<complexType>
<sequence>
<element name="returnval" type="xsd:string" />
</sequence>
</complexType>
</element>
<complexType name="LookupServiceContent">
<complexContent>
<extension base="lookup:DynamicData">
<sequence>
<element name="lookupService" type="lookup:ManagedObjectReference" />
<element name="serviceRegistration" type="lookup:ManagedObjectReference" minOccurs="0" />
<element name="deploymentInformationService" type="lookup:ManagedObjectReference" />
<element name="l10n" type="lookup:ManagedObjectReference" />
</sequence>
</extension>
</complexContent>
</complexType>
<simpleType name="LookupServiceEndpointEndpointProtocol">
<restriction base="xsd:string">
<enumeration value="vmomi" />
<enumeration value="wsTrust" />
<enumeration value="rest" />
<enumeration value="http" />
<enumeration value="unknown" />
</restriction>
</simpleType>
<complexType name="RetrieveServiceContentRequestType">
<sequence>
<element name="_this" type="lookup:ManagedObjectReference" />
</sequence>
</complexType>
<element name="RetrieveServiceContent" type="lookup:RetrieveServiceContentRequestType" />
<element name="RetrieveServiceContentResponse">
<complexType>
<sequence>
<element name="returnval" type="lookup:LookupServiceContent" />
</sequence>
</complexType>
</element>
<complexType name="LookupServiceRegistrationMutableServiceInfo">
<complexContent>
<extension base="lookup:DynamicData">
<sequence>
<element name="serviceVersion" type="xsd:string" />
<element name="vendorNameResourceKey" type="xsd:string" minOccurs="0" />
<element name="vendorNameDefault" type="xsd:string" minOccurs="0" />
<element name="vendorProductInfoResourceKey" type="xsd:string" minOccurs="0" />
<element name="vendorProductInfoDefault" type="xsd:string" minOccurs="0" />
<element name="serviceEndpoints" type="lookup:LookupServiceRegistrationEndpoint" minOccurs="0" maxOccurs="unbounded" />
<element name="serviceAttributes" type="lookup:LookupServiceRegistrationAttribute" minOccurs="0" maxOccurs="unbounded" />
<element name="serviceNameResourceKey" type="xsd:string" minOccurs="0" />
<element name="serviceNameDefault" type="xsd:string" minOccurs="0" />
<element name="serviceDescriptionResourceKey" type="xsd:string" minOccurs="0" />
<element name="serviceDescriptionDefault" type="xsd:string" minOccurs="0" />
</sequence>
</extension>
</complexContent>
</complexType>
<complexType name="LookupServiceRegistrationCommonServiceInfo">
<complexContent>
<extension base="lookup:LookupServiceRegistrationMutableServiceInfo">
<sequence>
<element name="ownerId" type="xsd:string" />
<element name="serviceType" type="lookup:LookupServiceRegistrationServiceType" />
<element name="nodeId" type="xsd:string" minOccurs="0" />
</sequence>
</extension>
</complexContent>
</complexType>
<complexType name="LookupServiceRegistrationCreateSpec">
<complexContent>
<extension base="lookup:LookupServiceRegistrationCommonServiceInfo">
<sequence>
</sequence>
</extension>
</complexContent>
</complexType>
<complexType name="LookupServiceRegistrationSetSpec">
<complexContent>
<extension base="lookup:LookupServiceRegistrationMutableServiceInfo">
<sequence>
</sequence>
</extension>
</complexContent>
</complexType>
<complexType name="LookupServiceRegistrationInfo">
<complexContent>
<extension base="lookup:LookupServiceRegistrationCommonServiceInfo">
<sequence>
<element name="serviceId" type="xsd:string" />
<element name="siteId" type="xsd:string" />
</sequence>
</extension>
</complexContent>
</complexType>
<complexType name="ArrayOfLookupServiceRegistrationInfo">
<sequence>
<element name="LookupServiceRegistrationInfo" type="lookup:LookupServiceRegistrationInfo" minOccurs="0" maxOccurs="unbounded" />
</sequence>
</complexType>
<complexType name="LookupServiceRegistrationServiceType">
<complexContent>
<extension base="lookup:DynamicData">
<sequence>
<element name="product" type="xsd:string" />
<element name="type" type="xsd:string" />
</sequence>
</extension>
</complexContent>
</complexType>
<complexType name="LookupServiceRegistrationEndpoint">
<complexContent>
<extension base="lookup:DynamicData">
<sequence>
<element name="url" type="xsd:anyURI" />
<element name="endpointType" type="lookup:LookupServiceRegistrationEndpointType" />
<element name="sslTrust" type="xsd:string" minOccurs="0" maxOccurs="unbounded" />
<element name="endpointAttributes" type="lookup:LookupServiceRegistrationAttribute" minOccurs="0" maxOccurs="unbounded" />
</sequence>
</extension>
</complexContent>
</complexType>
<complexType name="ArrayOfLookupServiceRegistrationEndpoint">
<sequence>
<element name="LookupServiceRegistrationEndpoint" type="lookup:LookupServiceRegistrationEndpoint" minOccurs="0" maxOccurs="unbounded" />
</sequence>
</complexType>
<complexType name="LookupServiceRegistrationEndpointType">
<complexContent>
<extension base="lookup:DynamicData">
<sequence>
<element name="protocol" type="xsd:string" minOccurs="0" />
<element name="type" type="xsd:string" minOccurs="0" />
</sequence>
</extension>
</complexContent>
</complexType>
<complexType name="LookupServiceRegistrationAttribute">
<complexContent>
<extension base="lookup:DynamicData">
<sequence>
<element name="key" type="xsd:string" />
<element name="value" type="xsd:string" />
</sequence>
</extension>
</complexContent>
</complexType>
<complexType name="ArrayOfLookupServiceRegistrationAttribute">
<sequence>
<element name="LookupServiceRegistrationAttribute" type="lookup:LookupServiceRegistrationAttribute" minOccurs="0" maxOccurs="unbounded" />
</sequence>
</complexType>
<complexType name="LookupServiceRegistrationFilter">
<complexContent>
<extension base="lookup:DynamicData">
<sequence>
<element name="siteId" type="xsd:string" minOccurs="0" />
<element name="nodeId" type="xsd:string" minOccurs="0" />
<element name="serviceType" type="lookup:LookupServiceRegistrationServiceType" minOccurs="0" />
<element name="endpointType" type="lookup:LookupServiceRegistrationEndpointType" minOccurs="0" />
</sequence>
</extension>
</complexContent>
</complexType>
<complexType name="CreateRequestType">
<sequence>
<element name="_this" type="lookup:ManagedObjectReference" />
<element name="serviceId" type="xsd:string" />
<element name="createSpec" type="lookup:LookupServiceRegistrationCreateSpec" />
</sequence>
</complexType>
<element name="Create" type="lookup:CreateRequestType" />
<element name="CreateResponse">
<complexType />
</element>
<complexType name="DeleteRequestType">
<sequence>
<element name="_this" type="lookup:ManagedObjectReference" />
<element name="serviceId" type="xsd:string" />
</sequence>
</complexType>
<element name="Delete" type="lookup:DeleteRequestType" />
<element name="DeleteResponse">
<complexType />
</element>
<complexType name="SetRequestType">
<sequence>
<element name="_this" type="lookup:ManagedObjectReference" />
<element name="serviceId" type="xsd:string" />
<element name="serviceSpec" type="lookup:LookupServiceRegistrationSetSpec" />
</sequence>
</complexType>
<element name="Set" type="lookup:SetRequestType" />
<element name="SetResponse">
<complexType />
</element>
<complexType name="GetRequestType">
<sequence>
<element name="_this" type="lookup:ManagedObjectReference" />
<element name="serviceId" type="xsd:string" />
</sequence>
</complexType>
<element name="Get" type="lookup:GetRequestType" />
<element name="GetResponse">
<complexType>
<sequence>
<element name="returnval" type="lookup:LookupServiceRegistrationInfo" />
</sequence>
</complexType>
</element>
<complexType name="ListRequestType">
<sequence>
<element name="_this" type="lookup:ManagedObjectReference" />
<element name="filterCriteria" type="lookup:LookupServiceRegistrationFilter" minOccurs="0" />
</sequence>
</complexType>
<element name="List" type="lookup:ListRequestType" />
<element name="ListResponse">
<complexType>
<sequence>
<element name="returnval" type="lookup:LookupServiceRegistrationInfo" minOccurs="0" maxOccurs="unbounded" />
</sequence>
</complexType>
</element>
<complexType name="GetSiteIdRequestType">
<sequence>
<element name="_this" type="lookup:ManagedObjectReference" />
</sequence>
</complexType>
<element name="GetSiteId" type="lookup:GetSiteIdRequestType" />
<element name="GetSiteIdResponse">
<complexType>
<sequence>
<element name="returnval" type="xsd:string" />
</sequence>
</complexType>
</element>
<complexType name="LookupFaultEntryExistsFault">
<complexContent>
<extension base="lookup:LookupFaultServiceFault">
<sequence>
<element name="name" type="xsd:string" />
</sequence>
</extension>
</complexContent>
</complexType>
<element name="LookupFaultEntryExistsFaultFault" type="lookup:LookupFaultEntryExistsFault"/>
<complexType name="LookupFaultEntryNotFoundFault">
<complexContent>
<extension base="lookup:LookupFaultServiceFault">
<sequence>
<element name="name" type="xsd:string" />
</sequence>
</extension>
</complexContent>
</complexType>
<element name="LookupFaultEntryNotFoundFaultFault" type="lookup:LookupFaultEntryNotFoundFault"/>
<complexType name="LookupFaultServiceFault">
<complexContent>
<extension base="lookup:MethodFault">
<sequence>
<element name="errorMessage" type="xsd:string" minOccurs="0" />
</sequence>
</extension>
</complexContent>
</complexType>
<element name="LookupFaultServiceFaultFault" type="lookup:LookupFaultServiceFault"/>
<complexType name="LookupFaultUnsupportedSiteFault">
<complexContent>
<extension base="lookup:LookupFaultServiceFault">
<sequence>
<element name="operatingSite" type="xsd:string" />
<element name="requestedSite" type="xsd:string" />
</sequence>
</extension>
</complexContent>
</complexType>
<element name="LookupFaultUnsupportedSiteFaultFault" type="lookup:LookupFaultUnsupportedSiteFault"/>
<complexType name="ManagedObjectReference">
<simpleContent>
<extension base="xsd:string">
<attribute name="type" type="xsd:string"/>
</extension>
</simpleContent>
</complexType>
<complexType name="ArrayOfString">
<sequence>
<element name="string" type="xsd:string" minOccurs="0" maxOccurs="unbounded" />
</sequence>
</complexType>
<complexType name="ArrayOfAnyType">
<sequence>
<element name="anyType" type="xsd:anyType" minOccurs="0" maxOccurs="unbounded" />
</sequence>
</complexType>
<element name="versionURI" type="xsd:string" />
</schema>
</types>
<message name="MethodFaultFaultMsg">
<part name="fault" element="lookup:MethodFaultFault" />
</message>
<message name="RuntimeFaultFaultMsg">
<part name="fault" element="lookup:RuntimeFaultFault" />
</message>
<message name="HostCommunicationFaultMsg">
<part name="fault" element="lookup:HostCommunicationFault" />
</message>
<message name="HostNotConnectedFaultMsg">
<part name="fault" element="lookup:HostNotConnectedFault" />
</message>
<message name="HostNotReachableFaultMsg">
<part name="fault" element="lookup:HostNotReachableFault" />
</message>
<message name="InvalidArgumentFaultMsg">
<part name="fault" element="lookup:InvalidArgumentFault" />
</message>
<message name="InvalidRequestFaultMsg">
<part name="fault" element="lookup:InvalidRequestFault" />
</message>
<message name="InvalidTypeFaultMsg">
<part name="fault" element="lookup:InvalidTypeFault" />
</message>
<message name="ManagedObjectNotFoundFaultMsg">
<part name="fault" element="lookup:ManagedObjectNotFoundFault" />
</message>
<message name="MethodNotFoundFaultMsg">
<part name="fault" element="lookup:MethodNotFoundFault" />
</message>
<message name="NotEnoughLicensesFaultMsg">
<part name="fault" element="lookup:NotEnoughLicensesFault" />
</message>
<message name="NotImplementedFaultMsg">
<part name="fault" element="lookup:NotImplementedFault" />
</message>
<message name="NotSupportedFaultMsg">
<part name="fault" element="lookup:NotSupportedFault" />
</message>
<message name="RequestCanceledFaultMsg">
<part name="fault" element="lookup:RequestCanceledFault" />
</message>
<message name="SecurityErrorFaultMsg">
<part name="fault" element="lookup:SecurityErrorFault" />
</message>
<message name="SystemErrorFaultMsg">
<part name="fault" element="lookup:SystemErrorFault" />
</message>
<message name="UnexpectedFaultFaultMsg">
<part name="fault" element="lookup:UnexpectedFaultFault" />
</message>
<message name="RetrieveHaBackupConfigurationRequestMsg">
<part name="parameters" element="lookup:RetrieveHaBackupConfiguration" />
</message>
<message name="RetrieveHaBackupConfigurationResponseMsg">
<part name="parameters" element="lookup:RetrieveHaBackupConfigurationResponse" />
</message>
<message name="SetLocaleRequestMsg">
<part name="parameters" element="lookup:SetLocale" />
</message>
<message name="SetLocaleResponseMsg">
<part name="parameters" element="lookup:SetLocaleResponse" />
</message>
<message name="GetLocaleRequestMsg">
<part name="parameters" element="lookup:GetLocale" />
</message>
<message name="GetLocaleResponseMsg">
<part name="parameters" element="lookup:GetLocaleResponse" />
</message>
<message name="RetrieveServiceContentRequestMsg">
<part name="parameters" element="lookup:RetrieveServiceContent" />
</message>
<message name="RetrieveServiceContentResponseMsg">
<part name="parameters" element="lookup:RetrieveServiceContentResponse" />
</message>
<message name="CreateRequestMsg">
<part name="parameters" element="lookup:Create" />
</message>
<message name="CreateResponseMsg">
<part name="parameters" element="lookup:CreateResponse" />
</message>
<message name="DeleteRequestMsg">
<part name="parameters" element="lookup:Delete" />
</message>
<message name="DeleteResponseMsg">
<part name="parameters" element="lookup:DeleteResponse" />
</message>
<message name="SetRequestMsg">
<part name="parameters" element="lookup:Set" />
</message>
<message name="SetResponseMsg">
<part name="parameters" element="lookup:SetResponse" />
</message>
<message name="GetRequestMsg">
<part name="parameters" element="lookup:Get" />
</message>
<message name="GetResponseMsg">
<part name="parameters" element="lookup:GetResponse" />
</message>
<message name="ListRequestMsg">
<part name="parameters" element="lookup:List" />
</message>
<message name="ListResponseMsg">
<part name="parameters" element="lookup:ListResponse" />
</message>
<message name="GetSiteIdRequestMsg">
<part name="parameters" element="lookup:GetSiteId" />
</message>
<message name="GetSiteIdResponseMsg">
<part name="parameters" element="lookup:GetSiteIdResponse" />
</message>
<message name="LookupFaultEntryExistsFaultFaultMsg">
<part name="fault" element="lookup:LookupFaultEntryExistsFaultFault" />
</message>
<message name="LookupFaultEntryNotFoundFaultFaultMsg">
<part name="fault" element="lookup:LookupFaultEntryNotFoundFaultFault" />
</message>
<message name="LookupFaultServiceFaultFaultMsg">
<part name="fault" element="lookup:LookupFaultServiceFaultFault" />
</message>
<message name="LookupFaultUnsupportedSiteFaultFaultMsg">
<part name="fault" element="lookup:LookupFaultUnsupportedSiteFaultFault" />
</message>
<portType name="LsPortType">
<operation name="RetrieveHaBackupConfiguration">
<input message="lookup:RetrieveHaBackupConfigurationRequestMsg" />
<output message="lookup:RetrieveHaBackupConfigurationResponseMsg" />
<fault name="RuntimeFault" message="lookup:RuntimeFaultFaultMsg"/>
</operation>
<operation name="SetLocale">
<input message="lookup:SetLocaleRequestMsg" />
<output message="lookup:SetLocaleResponseMsg" />
<fault name="RuntimeFault" message="lookup:RuntimeFaultFaultMsg"/>
</operation>
<operation name="GetLocale">
<input message="lookup:GetLocaleRequestMsg" />
<output message="lookup:GetLocaleResponseMsg" />
<fault name="RuntimeFault" message="lookup:RuntimeFaultFaultMsg"/>
</operation>
<operation name="RetrieveServiceContent">
<input message="lookup:RetrieveServiceContentRequestMsg" />
<output message="lookup:RetrieveServiceContentResponseMsg" />
<fault name="RuntimeFault" message="lookup:RuntimeFaultFaultMsg"/>
</operation>
<operation name="Create">
<input message="lookup:CreateRequestMsg" />
<output message="lookup:CreateResponseMsg" />
<fault name="LookupFaultEntryExistsFaultFault" message="lookup:LookupFaultEntryExistsFaultFaultMsg"/>
<fault name="InvalidArgumentFault" message="lookup:InvalidArgumentFaultMsg"/>
<fault name="SecurityErrorFault" message="lookup:SecurityErrorFaultMsg"/>
<fault name="RuntimeFault" message="lookup:RuntimeFaultFaultMsg"/>
</operation>
<operation name="Delete">
<input message="lookup:DeleteRequestMsg" />
<output message="lookup:DeleteResponseMsg" />
<fault name="LookupFaultEntryNotFoundFaultFault" message="lookup:LookupFaultEntryNotFoundFaultFaultMsg"/>
<fault name="SecurityErrorFault" message="lookup:SecurityErrorFaultMsg"/>
<fault name="RuntimeFault" message="lookup:RuntimeFaultFaultMsg"/>
</operation>
<operation name="Set">
<input message="lookup:SetRequestMsg" />
<output message="lookup:SetResponseMsg" />
<fault name="LookupFaultEntryNotFoundFaultFault" message="lookup:LookupFaultEntryNotFoundFaultFaultMsg"/>
<fault name="InvalidArgumentFault" message="lookup:InvalidArgumentFaultMsg"/>
<fault name="SecurityErrorFault" message="lookup:SecurityErrorFaultMsg"/>
<fault name="RuntimeFault" message="lookup:RuntimeFaultFaultMsg"/>
</operation>
<operation name="Get">
<input message="lookup:GetRequestMsg" />
<output message="lookup:GetResponseMsg" />
<fault name="LookupFaultEntryNotFoundFaultFault" message="lookup:LookupFaultEntryNotFoundFaultFaultMsg"/>
<fault name="RuntimeFault" message="lookup:RuntimeFaultFaultMsg"/>
</operation>
<operation name="List">
<input message="lookup:ListRequestMsg" />
<output message="lookup:ListResponseMsg" />
<fault name="RuntimeFault" message="lookup:RuntimeFaultFaultMsg"/>
</operation>
<operation name="GetSiteId">
<input message="lookup:GetSiteIdRequestMsg" />
<output message="lookup:GetSiteIdResponseMsg" />
<fault name="RuntimeFault" message="lookup:RuntimeFaultFaultMsg"/>
</operation>
</portType>
<binding name="LsBinding" type="lookup:LsPortType">
<soap:binding style="document" transport="http://schemas.xmlsoap.org/soap/http" />
<operation name="RetrieveHaBackupConfiguration">
<soap:operation soapAction="urn:lookup/2.0" style="document" />
<input>
<soap:body use="literal" />
</input>
<output>
<soap:body use="literal" />
</output>
<fault name="RuntimeFault">
<soap:fault name="RuntimeFault" use="literal" />
</fault>
</operation>
<operation name="SetLocale">
<soap:operation soapAction="urn:lookup/2.0" style="document" />
<input>
<soap:body use="literal" />
</input>
<output>
<soap:body use="literal" />
</output>
<fault name="RuntimeFault">
<soap:fault name="RuntimeFault" use="literal" />
</fault>
</operation>
<operation name="GetLocale">
<soap:operation soapAction="urn:lookup/2.0" style="document" />
<input>
<soap:body use="literal" />
</input>
<output>
<soap:body use="literal" />
</output>
<fault name="RuntimeFault">
<soap:fault name="RuntimeFault" use="literal" />
</fault>
</operation>
<operation name="RetrieveServiceContent">
<soap:operation soapAction="urn:lookup/2.0" style="document" />
<input>
<soap:body use="literal" />
</input>
<output>
<soap:body use="literal" />
</output>
<fault name="RuntimeFault">
<soap:fault name="RuntimeFault" use="literal" />
</fault>
</operation>
<operation name="Create">
<soap:operation soapAction="urn:lookup/2.0" style="document" />
<input>
<soap:body use="literal" />
</input>
<output>
<soap:body use="literal" />
</output>
<fault name="LookupFaultEntryExistsFaultFault">
<soap:fault name="LookupFaultEntryExistsFaultFault" use="literal" />
</fault>
<fault name="InvalidArgumentFault">
<soap:fault name="InvalidArgumentFault" use="literal" />
</fault>
<fault name="SecurityErrorFault">
<soap:fault name="SecurityErrorFault" use="literal" />
</fault>
<fault name="RuntimeFault">
<soap:fault name="RuntimeFault" use="literal" />
</fault>
</operation>
<operation name="Delete">
<soap:operation soapAction="urn:lookup/2.0" style="document" />
<input>
<soap:body use="literal" />
</input>
<output>
<soap:body use="literal" />
</output>
<fault name="LookupFaultEntryNotFoundFaultFault">
<soap:fault name="LookupFaultEntryNotFoundFaultFault" use="literal" />
</fault>
<fault name="SecurityErrorFault">
<soap:fault name="SecurityErrorFault" use="literal" />
</fault>
<fault name="RuntimeFault">
<soap:fault name="RuntimeFault" use="literal" />
</fault>
</operation>
<operation name="Set">
<soap:operation soapAction="urn:lookup/2.0" style="document" />
<input>
<soap:body use="literal" />
</input>
<output>
<soap:body use="literal" />
</output>
<fault name="LookupFaultEntryNotFoundFaultFault">
<soap:fault name="LookupFaultEntryNotFoundFaultFault" use="literal" />
</fault>
<fault name="InvalidArgumentFault">
<soap:fault name="InvalidArgumentFault" use="literal" />
</fault>
<fault name="SecurityErrorFault">
<soap:fault name="SecurityErrorFault" use="literal" />
</fault>
<fault name="RuntimeFault">
<soap:fault name="RuntimeFault" use="literal" />
</fault>
</operation>
<operation name="Get">
<soap:operation soapAction="urn:lookup/2.0" style="document" />
<input>
<soap:body use="literal" />
</input>
<output>
<soap:body use="literal" />
</output>
<fault name="LookupFaultEntryNotFoundFaultFault">
<soap:fault name="LookupFaultEntryNotFoundFaultFault" use="literal" />
</fault>
<fault name="RuntimeFault">
<soap:fault name="RuntimeFault" use="literal" />
</fault>
</operation>
<operation name="List">
<soap:operation soapAction="urn:lookup/2.0" style="document" />
<input>
<soap:body use="literal" />
</input>
<output>
<soap:body use="literal" />
</output>
<fault name="RuntimeFault">
<soap:fault name="RuntimeFault" use="literal" />
</fault>
</operation>
<operation name="GetSiteId">
<soap:operation soapAction="urn:lookup/2.0" style="document" />
<input>
<soap:body use="literal" />
</input>
<output>
<soap:body use="literal" />
</output>
<fault name="RuntimeFault">
<soap:fault name="RuntimeFault" use="literal" />
</fault>
</operation>
</binding>
</definitions>

View File

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8" ?>
<!--
Copyright 2005-2015 VMware, Inc. All rights reserved.
-->
<definitions targetNamespace="urn:lookupService"
xmlns="http://schemas.xmlsoap.org/wsdl/"
xmlns:soap="http://schemas.xmlsoap.org/wsdl/soap/"
xmlns:interface="urn:lookup"
>
<import location="lookup.wsdl" namespace="urn:lookup" />
<service name="LsService">
<port binding="interface:LsBinding" name="LsPort">
<soap:address location="https://{IPADDR}/lookupservice/sdk" />
</port>
</service>
</definitions>

View File

@ -0,0 +1,11 @@
This directory contains samples for Tagging APIs:
Running the samples
$ cd /path/to/vsphere-automation-sdk-python-samples/bin
$ ./run_sample.sh ../samples/vsphere/tagging/tagging_workflow.py --server <vCenter Server IP> --username <username> --password <password> --clustername <clustername> --categoryname <categoryname> --categorydesc <categorydesc> --tagname <tagname> -tagdesc <tagdesc> -v
* Testbed Requirement:
- 1 vCenter Server
- 1 cluster

View File

@ -0,0 +1,25 @@
"""
* *******************************************************
* Copyright VMware, Inc. 2016. All Rights Reserved.
* *******************************************************
*
* DISCLAIMER. THIS PROGRAM IS PROVIDED TO YOU "AS IS" WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, WHETHER ORAL OR WRITTEN,
* EXPRESS OR IMPLIED. THE AUTHOR SPECIFICALLY DISCLAIMS ANY IMPLIED
* WARRANTIES OR CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY,
* NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE.
"""
__author__ = 'VMware, Inc.'
__copyright__ = 'Copyright 2016 VMware, Inc. All rights reserved.'
# Required to distribute different parts of this
# package as multiple distribution
try:
import pkg_resources
pkg_resources.declare_namespace(__name__)
except ImportError:
from pkgutil import extend_path
__path__ = extend_path(__path__, __name__) # @ReservedAssignment

View File

@ -0,0 +1,211 @@
#!/usr/bin/env python
"""
* *******************************************************
* Copyright (c) VMware, Inc. 2014, 2016. All Rights Reserved.
* *******************************************************
*
* DISCLAIMER. THIS PROGRAM IS PROVIDED TO YOU "AS IS" WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, WHETHER ORAL OR WRITTEN,
* EXPRESS OR IMPLIED. THE AUTHOR SPECIFICALLY DISCLAIMS ANY IMPLIED
* WARRANTIES OR CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY,
* NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE.
"""
__author__ = 'VMware, Inc.'
__copyright__ = 'Copyright 2014, 2016 VMware, Inc. All rights reserved.'
__vcenter_version__ = '6.0+'
import time
from com.vmware.cis.tagging_client import (
Category, CategoryModel, Tag, TagAssociation)
from com.vmware.vapi.std_client import DynamicID
from samples.vsphere.common.sample_base import SampleBase
from samples.vsphere.common.vim.helpers.get_cluster_by_name import get_cluster_id
class TaggingWorkflow(SampleBase):
"""
Demonstrates tagging CRUD operations
Step 1: Create a Tag category.
Step 2: Create a Tag under the category.
Step 3: Retrieve the managed object id of an existing cluster from its name.
Step 4: Assign the tag to the cluster.
Additional steps when clearData flag is set to TRUE:
Step 5: Detach the tag from the cluster.
Step 6: Delete the tag.
Step 7: Delete the tag category.
Note: the sample needs an existing cluster
"""
def __init__(self):
SampleBase.__init__(self, self.__doc__)
self.servicemanager = None
self.category_svc = None
self.tag_svc = None
self.tag_association = None
self.category_name = None
self.category_desc = None
self.tag_name = None
self.tag_desc = None
self.cluster_name = None
self.cluster_moid = None
self.category_id = None
self.tag_id = None
self.tag_attached = False
self.dynamic_id = None
def _options(self):
self.argparser.add_argument('-clustername', '--clustername', help='Name of the cluster to be tagged')
self.argparser.add_argument('-categoryname', '--categoryname', help='Name of the Category to be created')
self.argparser.add_argument('-categorydesc', '--categorydesc', help='Description of the Category to be created')
self.argparser.add_argument('-tagname', '--tagname', help='Name of the tag to be created')
self.argparser.add_argument('-tagdesc', '--tagdesc', help='Description of the tag to be created')
def _setup(self):
if self.cluster_name is None: # for testing
self.cluster_name = self.args.clustername
assert self.cluster_name is not None
print('Cluster Name: {0}'.format(self.cluster_name))
if self.category_name is None:
self.category_name = self.args.categoryname
assert self.category_name is not None
print('Category Name: {0}'.format(self.category_name))
if self.category_desc is None:
self.category_desc = self.args.categorydesc
assert self.category_desc is not None
print('Category Description: {0}'.format(self.category_desc))
if self.tag_name is None:
self.tag_name = self.args.tagname
assert self.tag_name is not None
print('Tag Name: {0}'.format(self.tag_name))
if self.tag_desc is None:
self.tag_desc = self.args.tagdesc
assert self.tag_desc is not None
print('Tag Description: {0}'.format(self.tag_desc))
if self.servicemanager is None:
self.servicemanager = self.get_service_manager()
self.category_svc = Category(self.servicemanager.stub_config)
self.tag_svc = Tag(self.servicemanager.stub_config)
self.tag_association = TagAssociation(self.servicemanager.stub_config)
def _execute(self):
print('List all the existing categories user has access to...')
categories = self.category_svc.list()
if len(categories) > 0:
for category in categories:
print('Found Category: {0}'.format(category))
else:
print('No Tag Category Found...')
print('List all the existing tags user has access to...')
tags = self.tag_svc.list()
if len(tags) > 0:
for tag in tags:
print('Found Tag: {0}'.format(tag))
else:
print('No Tag Found...')
print('creating a new tag category...')
self.category_id = self.create_tag_category(self.category_name, self.category_desc, CategoryModel.Cardinality.MULTIPLE)
assert self.category_id is not None
print('Tag category created; Id: {0}'.format(self.category_id))
print("creating a new Tag...")
self.tag_id = self.create_tag(self.tag_name, self.tag_desc, self.category_id)
assert self.tag_id is not None
print('Tag created; Id: {0}'.format(self.tag_id))
print('updating the tag...')
date_time = time.strftime('%d/%m/%Y %H:%M:%S')
self.update_tag(self.tag_id, 'Server Tag updated at ' + date_time)
print('Tag updated; Id: {0}'.format(self.tag_id))
print('finding the cluster {0}'.format(self.cluster_name))
self.cluster_moid = get_cluster_id(service_manager=self.servicemanager, cluster_name=self.cluster_name)
assert self.cluster_moid is not None
print('Found cluster:{0} mo_id:{1}'.format('vAPISDKCluster', self.cluster_moid))
print('Tagging the cluster {0}...'.format(self.cluster_name))
self.dynamic_id = DynamicID(type='ClusterComputeResource', id=self.cluster_moid)
self.tag_association.attach(tag_id=self.tag_id, object_id=self.dynamic_id)
for tag_id in self.tag_association.list_attached_tags(self.dynamic_id):
if tag_id == self.tag_id:
self.tag_attached = True
break
assert self.tag_attached
print('Tagged cluster: {0}'.format(self.cluster_moid))
def _cleanup(self):
try:
if self.tag_attached:
self.tag_association.detach(self.tag_id, self.dynamic_id)
print('Removed tag from cluster: {0}'.format(self.cluster_moid))
if self.tag_id is not None:
self.delete_tag(self.tag_id)
print('Tag deleted; Id: {0}'.format(self.tag_id))
if self.category_id is not None:
self.delete_tag_category(self.category_id)
print('Tag category deleted; Id: {0}'.format(self.category_id))
except Exception as e:
raise Exception(e)
def create_tag_category(self, name, description, cardinality):
"""create a category. User who invokes this needs create category privilege."""
create_spec = self.category_svc.CreateSpec()
create_spec.name = name
create_spec.description = description
create_spec.cardinality = cardinality
associableTypes = set()
create_spec.associable_types = associableTypes
return self.category_svc.create(create_spec)
def delete_tag_category(self, category_id):
"""Deletes an existing tag category; User who invokes this API needs
delete privilege on the tag category.
"""
self.category_svc.delete(category_id)
def create_tag(self, name, description, category_id):
"""Creates a Tag"""
create_spec = self.tag_svc.CreateSpec()
create_spec.name = name
create_spec.description = description
create_spec.category_id = category_id
return self.tag_svc.create(create_spec)
def update_tag(self, tag_id, description):
"""Update the description of an existing tag.
User who invokes this API needs edit privilege on the tag.
"""
update_spec = self.tag_svc.UpdateSpec()
update_spec.setDescription = description
self.tag_svc.update(tag_id, update_spec)
def delete_tag(self, tag_id):
"""Delete an existing tag.
User who invokes this API needs delete privilege on the tag."""
self.tag_svc.delete(tag_id)
def main():
tagging_workflow = TaggingWorkflow()
tagging_workflow.main()
# Start program
if __name__ == '__main__':
main()

View File

@ -0,0 +1,15 @@
This directory contains samples for the vSphere infrastructure and virtual machine APIs. You have two options to run samples inside this package:
* Run all samples under vcenter folder using main.py in samples.vsphere.vcenter.setup package. Please see the [README](../../../README.md#running-a-complex-sample) for more details.
* Run an individual sample in an existing environment. You can either pass the environment parameters through command line arguments or specify them in testbed.py in the setup package.
For example, to run the create_default_vm sample in the vsphere.samples.vcenter.vm.create package:
* with the testbed settings specified in testbed.py in a Linux machine:
$ ./run_sample.sh ../samples/vsphere/vcenter/vm/create/create_default_vm.py -v
* Or specify the credentials using command line parameters:
$ ./run_sample.sh ../samples/vsphere/vcenter/vm/create/create_default_vm.py -s \<server> -u \<username> -p \<password> -v

View File

@ -0,0 +1,24 @@
"""
* *******************************************************
* Copyright VMware, Inc. 2016. All Rights Reserved.
* *******************************************************
*
* DISCLAIMER. THIS PROGRAM IS PROVIDED TO YOU "AS IS" WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, WHETHER ORAL OR WRITTEN,
* EXPRESS OR IMPLIED. THE AUTHOR SPECIFICALLY DISCLAIMS ANY IMPLIED
* WARRANTIES OR CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY,
* NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE.
"""
__author__ = 'VMware, Inc.'
__copyright__ = 'Copyright 2016 VMware, Inc. All rights reserved.'
# Required to distribute different parts of this
# package as multiple distribution
try:
import pkg_resources
pkg_resources.declare_namespace(__name__)
except ImportError:
from pkgutil import extend_path
__path__ = extend_path(__path__, __name__) # @ReservedAssignment

View File

@ -0,0 +1,24 @@
"""
* *******************************************************
* Copyright VMware, Inc. 2016. All Rights Reserved.
* *******************************************************
*
* DISCLAIMER. THIS PROGRAM IS PROVIDED TO YOU "AS IS" WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, WHETHER ORAL OR WRITTEN,
* EXPRESS OR IMPLIED. THE AUTHOR SPECIFICALLY DISCLAIMS ANY IMPLIED
* WARRANTIES OR CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY,
* NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE.
"""
__author__ = 'VMware, Inc.'
__copyright__ = 'Copyright 2016 VMware, Inc. All rights reserved.'
# Required to distribute different parts of this
# package as multiple distribution
try:
import pkg_resources
pkg_resources.declare_namespace(__name__)
except ImportError:
from pkgutil import extend_path
__path__ = extend_path(__path__, __name__) # @ReservedAssignment

View File

@ -0,0 +1,45 @@
"""
* *******************************************************
* Copyright (c) VMware, Inc. 2016. All Rights Reserved.
* *******************************************************
*
* DISCLAIMER. THIS PROGRAM IS PROVIDED TO YOU "AS IS" WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, WHETHER ORAL OR WRITTEN,
* EXPRESS OR IMPLIED. THE AUTHOR SPECIFICALLY DISCLAIMS ANY IMPLIED
* WARRANTIES OR CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY,
* NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE.
"""
__author__ = 'VMware, Inc.'
__copyright__ = 'Copyright 2016 VMware, Inc. All rights reserved.'
__vcenter_version__ = '6.5+'
from com.vmware.vcenter_client import Cluster
from samples.vsphere.vcenter.helper import datacenter_helper
def get_cluster(stub_config, datacenter_name, cluster_name):
"""
Returns the identifier of a cluster
Note: The method assumes only one cluster and datacenter
with the mentioned name.
"""
datacenter = datacenter_helper.get_datacenter(stub_config, datacenter_name)
if not datacenter:
print("Datacenter '{}' not found".format(datacenter_name))
return None
filter_spec = Cluster.FilterSpec(names=set([cluster_name]),
datacenters=set([datacenter]))
cluster_svc = Cluster(stub_config)
cluster_summaries = cluster_svc.list(filter_spec)
if len(cluster_summaries) > 0:
cluster = cluster_summaries[0].cluster
print("Detected cluster '{}' as {}".format(cluster_name, cluster))
return cluster
else:
print("Cluster '{}' not found".format(cluster_name))
return None

View File

@ -0,0 +1,34 @@
"""
* *******************************************************
* Copyright (c) VMware, Inc. 2016. All Rights Reserved.
* *******************************************************
*
* DISCLAIMER. THIS PROGRAM IS PROVIDED TO YOU "AS IS" WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, WHETHER ORAL OR WRITTEN,
* EXPRESS OR IMPLIED. THE AUTHOR SPECIFICALLY DISCLAIMS ANY IMPLIED
* WARRANTIES OR CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY,
* NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE.
"""
__author__ = 'VMware, Inc.'
__copyright__ = 'Copyright 2016 VMware, Inc. All rights reserved.'
__vcenter_version__ = '6.5+'
from com.vmware.vcenter_client import Datacenter
def get_datacenter(stub_config, datacenter_name):
"""
Returns the identifier of a datacenter
Note: The method assumes only one datacenter with the mentioned name.
"""
filter_spec = Datacenter.FilterSpec(names=set([datacenter_name]))
datacenter_svc = Datacenter(stub_config)
datacenter_summaries = datacenter_svc.list(filter_spec)
if len(datacenter_summaries) > 0:
datacenter = datacenter_summaries[0].datacenter
return datacenter
else:
return None

View File

@ -0,0 +1,42 @@
"""
* *******************************************************
* Copyright (c) VMware, Inc. 2016. All Rights Reserved.
* *******************************************************
*
* DISCLAIMER. THIS PROGRAM IS PROVIDED TO YOU "AS IS" WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, WHETHER ORAL OR WRITTEN,
* EXPRESS OR IMPLIED. THE AUTHOR SPECIFICALLY DISCLAIMS ANY IMPLIED
* WARRANTIES OR CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY,
* NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE.
"""
__author__ = 'VMware, Inc.'
__copyright__ = 'Copyright 2016 VMware, Inc. All rights reserved.'
__vcenter_version__ = '6.5+'
from com.vmware.vcenter_client import Datastore
from samples.vsphere.vcenter.helper import datacenter_helper
def get_datastore(stub_config, datacenter_name, datastore_name):
"""
Returns the identifier of a datastore
Note: The method assumes that there is only one datastore and datacenter
with the mentioned names.
"""
datacenter = datacenter_helper.get_datacenter(stub_config, datacenter_name)
if not datacenter:
print("Datacenter '{}' not found".format(datacenter_name))
return None
filter_spec = Datastore.FilterSpec(names=set([datastore_name]),
datacenters=set([datacenter]))
datastore_svc = Datastore(stub_config)
datastore_summaries = datastore_svc.list(filter_spec)
if len(datastore_summaries) > 0:
datastore = datastore_summaries[0].datastore
return datastore
else:
return None

View File

@ -0,0 +1,45 @@
"""
* *******************************************************
* Copyright (c) VMware, Inc. 2016. All Rights Reserved.
* *******************************************************
*
* DISCLAIMER. THIS PROGRAM IS PROVIDED TO YOU "AS IS" WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, WHETHER ORAL OR WRITTEN,
* EXPRESS OR IMPLIED. THE AUTHOR SPECIFICALLY DISCLAIMS ANY IMPLIED
* WARRANTIES OR CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY,
* NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE.
"""
__author__ = 'VMware, Inc.'
__copyright__ = 'Copyright 2016 VMware, Inc. All rights reserved.'
__vcenter_version__ = '6.5+'
from com.vmware.vcenter_client import Folder
from samples.vsphere.vcenter.helper import datacenter_helper
def get_folder(stub_config, datacenter_name, folder_name):
"""
Returns the identifier of a folder
Note: The method assumes that there is only one folder and datacenter
with the mentioned names.
"""
datacenter = datacenter_helper.get_datacenter(stub_config, datacenter_name)
if not datacenter:
print("Datacenter '{}' not found".format(datacenter_name))
return None
filter_spec = Folder.FilterSpec(type=Folder.Type.VIRTUAL_MACHINE,
names=set([folder_name]),
datacenters=set([datacenter]))
folder_svc = Folder(stub_config)
folder_summaries = folder_svc.list(filter_spec)
if len(folder_summaries) > 0:
folder = folder_summaries[0].folder
print("Detected folder '{}' as {}".format(folder_name, folder))
return folder
else:
print("Folder '{}' not found".format(folder_name))
return None

View File

@ -0,0 +1,81 @@
"""
* *******************************************************
* Copyright (c) VMware, Inc. 2016. All Rights Reserved.
* *******************************************************
*
* DISCLAIMER. THIS PROGRAM IS PROVIDED TO YOU "AS IS" WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, WHETHER ORAL OR WRITTEN,
* EXPRESS OR IMPLIED. THE AUTHOR SPECIFICALLY DISCLAIMS ANY IMPLIED
* WARRANTIES OR CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY,
* NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE.
"""
__author__ = 'VMware, Inc.'
__copyright__ = 'Copyright 2016 VMware, Inc. All rights reserved.'
__vcenter_version__ = '6.5+'
from com.vmware.vcenter_client import Network
from samples.vsphere.vcenter.helper import datacenter_helper
def get_standard_network_backing(stub_config,
std_porggroup_name,
datacenter_name):
"""
Gets a standard portgroup network backing for a given Datacenter
Note: The method assumes that there is only one standard portgroup
and datacenter with the mentioned names.
"""
datacenter = datacenter_helper.get_datacenter(stub_config, datacenter_name)
if not datacenter:
print("Datacenter '{}' not found".format(datacenter_name))
return None
network_svc = Network(stub_config)
filter = Network.FilterSpec(datacenters=set([datacenter]),
names=set([std_porggroup_name]),
types=set([Network.Type.STANDARD_PORTGROUP]))
network_summaries = network_svc.list(filter=filter)
network = None
if len(network_summaries) > 0:
network = network_summaries[0].network
print("Selecting Standard Portgroup Network '{}' ({})".
format(std_porggroup_name, network))
return network
else:
print("Standard Portgroup Network not found in Datacenter '{}'".
format(datacenter_name))
return None
def get_distributed_network_backing(stub_config,
dv_portgroup_name,
datacenter_name):
"""
Gets a distributed portgroup network backing for a given Datacenter
Note: The method assumes that there is only one distributed portgroup
and datacenter with the mentioned names.
"""
datacenter = datacenter_helper.get_datacenter(stub_config, datacenter_name)
if not datacenter:
print("Datacenter '{}' not found".format(datacenter_name))
return None
network_svc = Network(stub_config)
filter = Network.FilterSpec(datacenters=set([datacenter]),
names=set([dv_portgroup_name]),
types=set([Network.Type.DISTRIBUTED_PORTGROUP]))
network_summaries = network_svc.list(filter=filter)
network = None
if len(network_summaries) > 0:
network = network_summaries[0].network
print("Selecting Distributed Portgroup Network '{}' ({})".
format(dv_portgroup_name, network))
return network
else:
print("Distributed Portgroup Network not found in Datacenter '{}'".
format(datacenter_name))
return None

View File

@ -0,0 +1,42 @@
"""
* *******************************************************
* Copyright (c) VMware, Inc. 2016. All Rights Reserved.
* *******************************************************
*
* DISCLAIMER. THIS PROGRAM IS PROVIDED TO YOU "AS IS" WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, WHETHER ORAL OR WRITTEN,
* EXPRESS OR IMPLIED. THE AUTHOR SPECIFICALLY DISCLAIMS ANY IMPLIED
* WARRANTIES OR CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY,
* NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE.
"""
__author__ = 'VMware, Inc.'
__copyright__ = 'Copyright 2016 VMware, Inc. All rights reserved.'
__vcenter_version__ = '6.5+'
from com.vmware.vcenter_client import ResourcePool
from samples.vsphere.vcenter.helper import datacenter_helper
def get_resource_pool(stub_config, datacenter_name):
"""
Returns the identifier of the first resourcepool in the datacenter
"""
datacenter = datacenter_helper.get_datacenter(stub_config, datacenter_name)
if not datacenter:
print("Datacenter '{}' not found".format(datacenter_name))
return None
filter_spec = ResourcePool.FilterSpec(datacenters=set([datacenter]))
resource_pool_svc = ResourcePool(stub_config)
resource_pool_summaries = resource_pool_svc.list(filter_spec)
if len(resource_pool_summaries) > 0:
resource_pool = resource_pool_summaries[0].resource_pool
print("Selecting ResourcePool '{}'".format(resource_pool))
return resource_pool
else:
print("ResourcePool not found in Datacenter '{}'".
format(datacenter_name))
return None

View File

@ -0,0 +1,48 @@
"""
* *******************************************************
* Copyright (c) VMware, Inc. 2016. All Rights Reserved.
* *******************************************************
*
* DISCLAIMER. THIS PROGRAM IS PROVIDED TO YOU "AS IS" WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, WHETHER ORAL OR WRITTEN,
* EXPRESS OR IMPLIED. THE AUTHOR SPECIFICALLY DISCLAIMS ANY IMPLIED
* WARRANTIES OR CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY,
* NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE.
"""
__author__ = 'VMware, Inc.'
__copyright__ = 'Copyright 2016 VMware, Inc. All rights reserved.'
__vcenter_version__ = '6.5+'
from com.vmware.vcenter_client import VM
def get_vm(stub_config, vm_name):
"""
Return the identifier of a vm
Note: The method assumes that there is only one vm with the mentioned name.
"""
vm_svc = VM(stub_config)
names = set([vm_name])
vms = vm_svc.list(VM.FilterSpec(names=names))
if len(vms) == 0:
print("VM with name ({}) not found".format(vm_name))
return None
vm = vms[0].vm
print("Found VM '{}' ({})".format(vm_name, vm))
return vm
def get_vms(stub_config, vm_names):
"""Return identifiers of a list of vms"""
vm_svc = VM(stub_config)
vms = vm_svc.list(VM.FilterSpec(names=vm_names))
if len(vms) == 0:
print('No vm found')
return None
print("Found VMs '{}' ({})".format(vm_names, vms))
return vms

View File

@ -0,0 +1,51 @@
"""
* *******************************************************
* Copyright (c) VMware, Inc. 2016. All Rights Reserved.
* *******************************************************
*
* DISCLAIMER. THIS PROGRAM IS PROVIDED TO YOU "AS IS" WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, WHETHER ORAL OR WRITTEN,
* EXPRESS OR IMPLIED. THE AUTHOR SPECIFICALLY DISCLAIMS ANY IMPLIED
* WARRANTIES OR CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY,
* NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE.
"""
__author__ = 'VMware, Inc.'
__copyright__ = 'Copyright 2016 VMware, Inc. All rights reserved.'
__vcenter_version__ = '6.5+'
from com.vmware.vcenter_client import VM
from samples.vsphere.vcenter.helper import datastore_helper
from samples.vsphere.vcenter.helper import folder_helper
from samples.vsphere.vcenter.helper import resource_pool_helper
def get_placement_spec_for_resource_pool(stub_config,
datacenter_name,
vm_folder_name,
datastore_name):
"""
Returns a VM placement spec for a resourcepool. Ensures that the
vm folder and datastore are all in the same datacenter which is specified.
"""
resource_pool = resource_pool_helper.get_resource_pool(stub_config,
datacenter_name)
folder = folder_helper.get_folder(stub_config,
datacenter_name,
vm_folder_name)
datastore = datastore_helper.get_datastore(stub_config,
datacenter_name,
datastore_name)
# Create the vm placement spec with the datastore, resource pool and vm
# folder
placement_spec = VM.PlacementSpec(folder=folder,
resource_pool=resource_pool,
datastore=datastore)
print("get_placement_spec_for_resource_pool: Result is '{}'".
format(placement_spec))
return placement_spec

View File

@ -0,0 +1,2 @@
This directory contains sample scripts to setup the testbed required to run
the vCenter APIs samples. Refer see [README](../../../../README.md#running-the-sdk-sample-setup-script) for more details.

View File

@ -0,0 +1,24 @@
"""
* *******************************************************
* Copyright VMware, Inc. 2016. All Rights Reserved.
* *******************************************************
*
* DISCLAIMER. THIS PROGRAM IS PROVIDED TO YOU "AS IS" WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, WHETHER ORAL OR WRITTEN,
* EXPRESS OR IMPLIED. THE AUTHOR SPECIFICALLY DISCLAIMS ANY IMPLIED
* WARRANTIES OR CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY,
* NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE.
"""
__author__ = 'VMware, Inc.'
__copyright__ = 'Copyright 2016 VMware, Inc. All rights reserved.'
# Required to distribute different parts of this
# package as multiple distribution
try:
import pkg_resources
pkg_resources.declare_namespace(__name__)
except ImportError:
from pkgutil import extend_path
__path__ = extend_path(__path__, __name__) # @ReservedAssignment

View File

@ -0,0 +1,91 @@
"""
* *******************************************************
* Copyright (c) VMware, Inc. 2016. All Rights Reserved.
* *******************************************************
*
* DISCLAIMER. THIS PROGRAM IS PROVIDED TO YOU "AS IS" WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, WHETHER ORAL OR WRITTEN,
* EXPRESS OR IMPLIED. THE AUTHOR SPECIFICALLY DISCLAIMS ANY IMPLIED
* WARRANTIES OR CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY,
* NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE.
"""
__author__ = 'VMware, Inc.'
__copyright__ = 'Copyright 2016 VMware, Inc. All rights reserved.'
from samples.vsphere.common.vim.file import (detect_directory,
create_directory,
delete_directory)
def setup(context):
"""Setup directories used by vcenter samples."""
create_directory(context, 'Disk',
context.testbed.config['DISK_DATACENTER_NAME'],
context.testbed.config['DISK_DATASTORE_ROOT_PATH'])
create_directory(context, 'CDROM ISO',
context.testbed.config['ISO_DATACENTER_NAME'],
context.testbed.config['ISO_DATASTORE_ROOT_PATH'])
create_directory(context, 'Serial Port',
context.testbed.config['SERIAL_PORT_DATACENTER_NAME'],
context.testbed.config['SERIAL_PORT_DATASTORE_ROOT_PATH'])
create_directory(context, 'Parallel Port',
context.testbed.config['PARALLEL_PORT_DATACENTER_NAME'],
context.testbed.config[
'PARALLEL_PORT_DATASTORE_ROOT_PATH'])
create_directory(context, 'Floppy',
context.testbed.config['FLOPPY_DATACENTER_NAME'],
context.testbed.config['FLOPPY_DATASTORE_ROOT_PATH'])
def cleanup(context):
"""Cleanup directories after running vcenter samples"""
delete_directory(context, 'Disk',
context.testbed.config['DISK_DATACENTER_NAME'],
context.testbed.config['DISK_DATASTORE_ROOT_PATH'])
if context.option['DO_TESTBED_ISO_CLEANUP']:
delete_directory(context, 'CDROM ISO',
context.testbed.config['ISO_DATACENTER_NAME'],
context.testbed.config['ISO_DATASTORE_ROOT_PATH'])
delete_directory(context, 'Serial Port',
context.testbed.config['SERIAL_PORT_DATACENTER_NAME'],
context.testbed.config['SERIAL_PORT_DATASTORE_ROOT_PATH'])
delete_directory(context, 'Parallel Port',
context.testbed.config['PARALLEL_PORT_DATACENTER_NAME'],
context.testbed.config[
'PARALLEL_PORT_DATASTORE_ROOT_PATH'])
delete_directory(context, 'Floppy',
context.testbed.config['FLOPPY_DATACENTER_NAME'],
context.testbed.config['FLOPPY_DATASTORE_ROOT_PATH'])
# Remove the top level Sample_Backends directory in the Datastore
if context.option['DO_TESTBED_ISO_CLEANUP']:
delete_directory(context, 'Backends',
context.testbed.config['BACKENDS_DATACENTER_NAME'],
context.testbed.config['BACKENDS_DATASTORE_ROOT_PATH'])
def validate(context):
"""Validate if all required directories exist to run vcenter samples"""
return (
detect_directory(context, 'Disk',
context.testbed.config['DISK_DATACENTER_NAME'],
context.testbed.config['DISK_DATASTORE_ROOT_PATH']) and
detect_directory(context, 'CDROM ISO',
context.testbed.config['ISO_DATACENTER_NAME'],
context.testbed.config['ISO_DATASTORE_ROOT_PATH']) and
detect_directory(context, 'Serial Port',
context.testbed.config['SERIAL_PORT_DATACENTER_NAME'],
context.testbed.config[
'SERIAL_PORT_DATASTORE_ROOT_PATH']) and
detect_directory(context, 'Parallel Port',
context.testbed.config[
'PARALLEL_PORT_DATACENTER_NAME'],
context.testbed.config[
'PARALLEL_PORT_DATASTORE_ROOT_PATH']) and
detect_directory(context, 'Floppy',
context.testbed.config['FLOPPY_DATACENTER_NAME'],
context.testbed.config['FLOPPY_DATASTORE_ROOT_PATH']))

View File

@ -0,0 +1,147 @@
"""
* *******************************************************
* Copyright (c) VMware, Inc. 2016. All Rights Reserved.
* *******************************************************
*
* DISCLAIMER. THIS PROGRAM IS PROVIDED TO YOU "AS IS" WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, WHETHER ORAL OR WRITTEN,
* EXPRESS OR IMPLIED. THE AUTHOR SPECIFICALLY DISCLAIMS ANY IMPLIED
* WARRANTIES OR CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY,
* NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE.
"""
__author__ = 'VMware, Inc.'
__copyright__ = 'Copyright 2016 VMware, Inc. All rights reserved.'
import pyVim.task
from com.vmware.vcenter_client import Cluster
from pyVmomi import vim
from samples.vsphere.vcenter.helper import cluster_helper
def detect_cluster(context):
"""Find the cluster to run the vcenter samples"""
cluster1_name = context.testbed.config['CLUSTER1_NAME']
datacenter_name = context.testbed.config['VM_DATACENTER_NAME']
cluster = cluster_helper.get_cluster(context.stub_config, datacenter_name,
cluster1_name)
if cluster:
context.testbed.entities['CLUSTER_IDS'] = {}
context.testbed.entities['CLUSTER_IDS'][cluster1_name] = cluster
return True
else:
return False
def cleanup_cluster(context):
"""Delete cluster after vcenter sample run"""
cluster1_name = context.testbed.config['CLUSTER1_NAME']
names = set([cluster1_name])
cluster_svc = Cluster(context.stub_config)
cluster_summaries = cluster_svc.list(Cluster.FilterSpec(names=names))
print("Found '{}' Clusters matching names {}".
format(len(cluster_summaries), ", ".join(["'{}'".
format(n) for n in names])))
if len(cluster_summaries) < 1:
return
# Delete the cluster using the managed object
cluster = cluster_summaries[0].cluster
cluster_mo = vim.ClusterComputeResource(cluster, context.soap_stub)
print("Deleting Cluster '{}' ({})".format(cluster, cluster1_name))
task = cluster_mo.Destroy()
pyVim.task.WaitForTask(task)
def setup_cluster_vapi1(context):
"""Create a cluster from the Datacenter managed object."""
cluster1_name = context.testbed.config['CLUSTER1_NAME']
# Get the host folder for the Datacenter2 using the save identifier
datacenter_name = context.testbed.config['DATACENTER2_NAME']
datacenter = context.testbed.entities['DATACENTER_IDS'][datacenter_name]
# Create a managed object from the datacenter identifier
datacenter_mo = vim.Datacenter(datacenter, context.soap_stub)
# Using pyvmomi to get the host folder on which to create the cluster
folder_mo = datacenter_mo.hostFolder
cluster_mo = folder_mo.CreateClusterEx(cluster1_name,
vim.cluster.ConfigSpecEx())
print("Created Cluster '{}' ({})".format(cluster_mo._moId, cluster1_name))
context.testbed.entities['CLUSTER_IDS'] = {
cluster1_name: cluster_mo._moId
}
def setup_cluster_vapi2(context):
"""Create a cluster from the Folder managed object"""
cluster1_name = context.testbed.config['CLUSTER1_NAME']
# Get the host folder for the Datacenter2 using the folder query
datacenter_name = context.testbed.config['DATACENTER2_NAME']
datacenter = context.testbed.entities['DATACENTER_IDS'][datacenter_name]
folder_svc = Folder(context.stub_config)
folder_summaries = folder_svc.list(
Folder.FilterSpec(type=Folder.Type.HOST, datacenters=set([datacenter])))
folder = folder_summaries[0].folder
# Create a managed object from the folder identifier
folder_mo = vim.Folder(folder, context.soap_stub)
cluster_mo = folder_mo.CreateClusterEx(cluster1_name,
vim.cluster.ConfigSpecEx())
print("Created Cluster '{}' ({})".format(cluster_mo._moId, cluster1_name))
context.testbed.entities['CLUSTER_IDS'] = {
cluster1_name: cluster_mo._moId
}
def setup_cluster_vim(context):
"""Create a cluster using only the VIM API"""
cluster1_name = context.testbed.config['CLUSTER1_NAME']
# Get the host folder for the Datacenter2 using the save identifier
datacenter_name = context.testbed.config['DATACENTER2_NAME']
for entity in context.service_instance.content.rootFolder.childEntity:
if isinstance(entity,
vim.Datacenter) and entity.name == datacenter_name:
folder_mo = entity.hostFolder
cluster_mo = folder_mo.CreateClusterEx(cluster1_name,
vim.cluster.ConfigSpecEx())
print("Created Cluster '{}' ({})".format(cluster_mo._moId,
cluster1_name))
context.testbed.entities['CLUSTER_IDS'] = {
cluster1_name: cluster_mo._moId
}
break
def setup_cluster(context):
setup_cluster_vim(context)
def setup(context):
setup_cluster(context)
def cleanup(context):
cleanup_cluster(context)
def validate(context):
return detect_cluster(context)

View File

@ -0,0 +1,116 @@
"""
* *******************************************************
* Copyright (c) VMware, Inc. 2016. All Rights Reserved.
* *******************************************************
*
* DISCLAIMER. THIS PROGRAM IS PROVIDED TO YOU "AS IS" WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, WHETHER ORAL OR WRITTEN,
* EXPRESS OR IMPLIED. THE AUTHOR SPECIFICALLY DISCLAIMS ANY IMPLIED
* WARRANTIES OR CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY,
* NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE.
"""
__author__ = 'VMware, Inc.'
__copyright__ = 'Copyright 2016 VMware, Inc. All rights reserved.'
from com.vmware.vcenter_client import (Datacenter, Folder)
def folder_list_datacenter_folder(context):
folder_svc = Folder(context.stub_config)
return folder_svc.list(Folder.FilterSpec(type=Folder.Type.DATACENTER))
def detect_datacenter(context, datacenter_name):
"""Find the datacenter with the given name"""
datacenter_svc = Datacenter(context.stub_config)
names = set([datacenter_name])
datacenter_summaries = datacenter_svc.list(
Datacenter.FilterSpec(names=names))
if len(datacenter_summaries) > 0:
datacenter = datacenter_summaries[0].datacenter
print("Detected Datacenter '{}' as {}".
format(datacenter_name, datacenter))
context.testbed.entities['DATACENTER_IDS'][datacenter_name] = datacenter
return True
else:
print("Datacenter '{}' missing".format(datacenter_name))
return False
def detect_datacenters(context):
"""Find datacenters to run the vcenter samples"""
context.testbed.entities['DATACENTER_IDS'] = {}
# Look for the two datacenters
datacenter1_name = context.testbed.config['DATACENTER1_NAME']
datacenter2_name = context.testbed.config['DATACENTER2_NAME']
return (detect_datacenter(context, datacenter1_name) and
detect_datacenter(context, datacenter2_name))
def cleanup_datacenters(context):
"""Cleanup datacenters after sample run"""
datacenter_svc = Datacenter(context.stub_config)
# Look for the two datacenters
datacenter1_name = context.testbed.config['DATACENTER1_NAME']
datacenter2_name = context.testbed.config['DATACENTER2_NAME']
names = set([datacenter1_name, datacenter2_name])
datacenter_summaries = datacenter_svc.list(
Datacenter.FilterSpec(names=names))
print("Found {} Datacenters matching names {}".
format(len(datacenter_summaries), ", ".
join(["'{}'".format(n) for n in names])))
for datacenter_summary in datacenter_summaries:
datacenter = datacenter_summary.datacenter
print("Deleting Datacenter '{}' ({})".
format(datacenter, datacenter_summary.name))
datacenter_svc.delete(datacenter, force=True)
def setup_datacenters(context):
"""Create datacenters for running vcenter samples"""
# Find a Folder in which to put the Datacenters
folder_summaries = folder_list_datacenter_folder(context)
folder = folder_summaries[0].folder
print("Creating datacenters in Folder '{}' ({})".
format(folder, folder_summaries[0].name))
datacenter_svc = Datacenter(context.stub_config)
# Create first datacenter
datacenter1_name = context.testbed.config['DATACENTER1_NAME']
datacenter1 = datacenter_svc.create(
Datacenter.CreateSpec(name=datacenter1_name, folder=folder)
)
print("Created Datacenter '{}' ({})".format(datacenter1, datacenter1_name))
# Create second datacenter
datacenter2_name = context.testbed.config['DATACENTER2_NAME']
datacenter2 = datacenter_svc.create(
Datacenter.CreateSpec(name=datacenter2_name, folder=folder)
)
print("Created Datacenter '{}' ({})".format(datacenter2, datacenter2_name))
# Save datacenter name to identifier mappings for later use
context.testbed.entities['DATACENTER_IDS'] = {
datacenter1_name: datacenter1,
datacenter2_name: datacenter2
}
def cleanup(context):
cleanup_datacenters(context)
def setup(context):
setup_datacenters(context)
def validate(context):
return detect_datacenters(context)

View File

@ -0,0 +1,261 @@
"""
* *******************************************************
* Copyright (c) VMware, Inc. 2016. All Rights Reserved.
* *******************************************************
*
* DISCLAIMER. THIS PROGRAM IS PROVIDED TO YOU "AS IS" WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, WHETHER ORAL OR WRITTEN,
* EXPRESS OR IMPLIED. THE AUTHOR SPECIFICALLY DISCLAIMS ANY IMPLIED
* WARRANTIES OR CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY,
* NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE.
"""
__author__ = 'VMware, Inc.'
__copyright__ = 'Copyright 2016 VMware, Inc. All rights reserved.'
import pyVim.task
from com.vmware.vcenter_client import Host
from pyVmomi import vim
def detect_nfs_datastore_on_host(context, host_name):
"""Find NFS datastore on host"""
names = set([host_name])
datastore_name = context.testbed.config['NFS_DATASTORE_NAME']
# Use vAPI find the Host managed identities
host_svc = Host(context.stub_config)
host_summaries = host_svc.list(Host.FilterSpec(names=names))
for host_summary in host_summaries:
# Convert the host identifier into a ManagedObject
host = host_summary.host
host_mo = vim.HostSystem(host, context.soap_stub)
for datastore_mo in host_mo.datastore:
if (datastore_mo.name == datastore_name and
datastore_mo.summary.type == 'NFS'):
datastore = datastore_mo._moId
print("Detected NFS Volume '{}' as {} on Host '{}' ({})".
format(datastore_name, datastore, host_name, host))
context.testbed.entities['HOST_NFS_DATASTORE_IDS'][host_name] \
= datastore
return True
print("NFS Volume '{}' missing on Host '{}'".
format(datastore_name, host_name))
return False
def detect_nfs_datastore(context):
"""Find NFS datastore used to run vcenter samples"""
context.testbed.entities['HOST_NFS_DATASTORE_IDS'] = {}
host1_name = context.testbed.config['ESX_HOST1']
host2_name = context.testbed.config['ESX_HOST2']
return (detect_nfs_datastore_on_host(context, host1_name) and
detect_nfs_datastore_on_host(context, host2_name))
def cleanup_nfs_datastore(context):
"""Cleanup NFS datastore after running vcenter samples"""
# Remove NFS datastore from each Host
host1_name = context.testbed.config['ESX_HOST1']
host2_name = context.testbed.config['ESX_HOST2']
names = set([host1_name, host2_name])
datastore_name = context.testbed.config['NFS_DATASTORE_NAME']
# Use vAPI find the Host managed identities
host_svc = Host(context.stub_config)
host_summaries = host_svc.list(Host.FilterSpec(names=names))
for host_summary in host_summaries:
# Convert the host identifier into a ManagedObject
host = host_summary.host
host_mo = vim.HostSystem(host, context.soap_stub)
for datastore_mo in host_mo.datastore:
if datastore_mo.name == datastore_name:
datastore_system = host_mo.configManager.datastoreSystem
datastore_system.RemoveDatastore(datastore_mo)
print("Removed NFS Volume '{}' ({}) from Host '{}' ({})".
format(datastore_name, datastore_mo._moId,
host_mo.name, host_mo._moId))
# Remote NFS Datastore at the vCenter level
# TODO Do we need to do this?
def setup_nfs_datastore(context):
"""Setup NFS datastore for running vcenter samples"""
host1_name = context.testbed.config['ESX_HOST1']
nfs_datastore1 = setup_nfs_datastore_on_host(context, host1_name)
host2_name = context.testbed.config['ESX_HOST2']
nfs_datastore2 = setup_nfs_datastore_on_host(context, host2_name)
context.testbed.entities['HOST_NFS_DATASTORE_IDS'] = {
host1_name: nfs_datastore1,
host2_name: nfs_datastore2
}
def setup_nfs_datastore_on_host(context, host_name):
"""Mount the NFS volume on one ESX hosts using the VIM API."""
nfs_host = context.testbed.config['NFS_HOST']
remote_path = context.testbed.config['NFS_REMOTE_PATH']
local_path = context.testbed.config['NFS_DATASTORE_NAME']
host = context.testbed.entities['HOST_IDS'][host_name]
host_mo = vim.HostSystem(host, context.soap_stub)
datastore_system = host_mo.configManager.datastoreSystem
try:
datastore_mo = datastore_system.CreateNasDatastore(
vim.host.NasVolume.Specification(remoteHost=nfs_host,
remotePath=remote_path,
localPath=local_path,
accessMode=vim.host.MountInfo.AccessMode.readWrite,
type=vim.host.FileSystemVolume.FileSystemType.NFS))
print("Added NFS Volume '{}' ({}) to Host '{}' ({})".
format(local_path, datastore_mo._moId, host_name, host))
return datastore_mo._moId
except vim.fault.AlreadyExists as e:
print("NFS Volume '{}' already exists on Host '{}' ({})".
format(local_path, host_name, host))
for datastore_mo in host_mo.datastore:
info = datastore_mo.info
if (isinstance(info, vim.host.NasDatastoreInfo) and
info.nas.remoteHost == nfs_host and
info.nas.remotePath == remote_path):
if info.name == local_path:
print("Found NFS Volume '{}' ({}) on Host '{}' ({})".
format(local_path, datastore_mo._moId,
host_name, host_mo._moId))
return datastore_mo._moId
else:
print("Found NFS remote host '{}' and path '{}' on Host '{}' ({}) as '{}'".
format(nfs_host, remote_path, host_name,
host_mo._moId, info.name))
print("Renaming NFS Volume '{}' ({}) to '{}'".
format(info.name, datastore_mo._moId, local_path))
task = datastore_mo.Rename(local_path)
pyVim.task.WaitForTask(task)
# TODO Find the datastore identifier for the NFS volume and return it
return None
def detect_vmfs_datastore(context, host_name, datastore_name):
"""Find VMFS datastore given host and datastore names"""
names = set([host_name])
# Use vAPI find the Host managed identities
host_svc = Host(context.stub_config)
host_summaries = host_svc.list(Host.FilterSpec(names=names))
for host_summary in host_summaries:
# Convert the host identifier into a ManagedObject
host = host_summary.host
host_mo = vim.HostSystem(host, context.soap_stub)
for datastore_mo in host_mo.datastore:
if (datastore_mo.name == datastore_name and
datastore_mo.summary.type == 'VMFS'):
datastore = datastore_mo._moId
print("Detected VMFS Volume '{}' as {} on Host '{}' ({})".
format(datastore_name, datastore, host_name, host))
context.testbed.entities['HOST_VMFS_DATASTORE_IDS'][host_name] \
= datastore
return True
print("VMFS Volume '{}' missing on Host '{}'".
format(datastore_name, host_name))
return False
def detect_vmfs_datastores(context):
"""Find VMFS datastore used to run vcenter samples"""
context.testbed.entities['HOST_VMFS_DATASTORE_IDS'] = {}
host1_name = context.testbed.config['ESX_HOST1']
host1_vmfs_volume = context.testbed.config['ESX_HOST1_VMFS_DATASTORE']
host2_name = context.testbed.config['ESX_HOST2']
host2_vmfs_volume = context.testbed.config['ESX_HOST2_VMFS_DATASTORE']
# From each host, look for the VMFS Volume
return (detect_vmfs_datastore(context, host1_name, host1_vmfs_volume) and
detect_vmfs_datastore(context, host2_name, host2_vmfs_volume))
def setup_vmfs_datastore(context, host_name, datastore_name):
"""Find VMFS datastore given host and datastore names"""
context.testbed.entities['HOST_VMFS_DATASTORE_IDS'] = {}
names = set([host_name])
# Use vAPI find the Host managed identities
host_svc = Host(context.stub_config)
host_summaries = host_svc.list(Host.FilterSpec(names=names))
host_summary = host_summaries[0]
# Convert the host identifier into a ManagedObject
host = host_summary.host
host_mo = vim.HostSystem(host, context.soap_stub)
vmfs_datastores = dict([(datastore_mo.name, datastore_mo)
for datastore_mo in host_mo.datastore
if datastore_mo.summary.type == 'VMFS'])
# The VMFS volume exists. No need to do anything
if datastore_name in vmfs_datastores:
datastore = vmfs_datastores[datastore_name]._moId
print("Detected VMFS Volume '{}' as {} on Host '{}' ({})".
format(datastore_name, datastore, host_name, host))
context.testbed.entities['HOST_VMFS_DATASTORE_IDS'][host_name] \
= datastore
return True
# Rename a VMFS datastore
if len(vmfs_datastores) > 0:
datastore_mo = list(vmfs_datastores.values())[0]
datastore = datastore_mo._moId
print("Renaming VMFS Volume '{}' ({}) on Host '{}' ({}) to '{}'".
format(datastore_mo.name, datastore,
host_name, host, datastore_name))
task = datastore_mo.Rename(datastore_name)
pyVim.task.WaitForTask(task)
return True
return False
def setup_vmfs_datastores(context):
"""Setup VMFS datastore used to run vcenter samples"""
host1_name = context.testbed.config['ESX_HOST1']
host1_vmfs_volume = context.testbed.config['ESX_HOST1_VMFS_DATASTORE']
host2_name = context.testbed.config['ESX_HOST2']
host2_vmfs_volume = context.testbed.config['ESX_HOST2_VMFS_DATASTORE']
# From each host, look for the VMFS Volume
setup_vmfs_datastore(context, host1_name, host1_vmfs_volume)
setup_vmfs_datastore(context, host2_name, host2_vmfs_volume)
def setup(context):
setup_nfs_datastore(context)
setup_vmfs_datastores(context)
def cleanup(context):
cleanup_nfs_datastore(context)
def validate(context):
return (
detect_nfs_datastore(context) and
detect_vmfs_datastores(context))

View File

@ -0,0 +1,74 @@
"""
* *******************************************************
* Copyright (c) VMware, Inc. 2016. All Rights Reserved.
* *******************************************************
*
* DISCLAIMER. THIS PROGRAM IS PROVIDED TO YOU "AS IS" WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, WHETHER ORAL OR WRITTEN,
* EXPRESS OR IMPLIED. THE AUTHOR SPECIFICALLY DISCLAIMS ANY IMPLIED
* WARRANTIES OR CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY,
* NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE.
"""
__author__ = 'VMware, Inc.'
__copyright__ = 'Copyright 2016 VMware, Inc. All rights reserved.'
from samples.vsphere.common.vim.file import (detect_file, delete_file,
parse_datastore_path)
from samples.vsphere.common.vim.inventory import get_datastore_mo
from samples.vsphere.common.vim import datastore_file
def setup_floppy_image(context):
"""Copy floppy image used to run vcenter samples"""
floppy_src_url = context.testbed.config['FLOPPY_SRC_URL']
datacenter_name = context.testbed.config['FLOPPY_DATACENTER_NAME']
datastore_path = context.testbed.config['FLOPPY_DATASTORE_PATH']
(datastore_name, path) = parse_datastore_path(datastore_path)
datastore_mo = get_datastore_mo(context.stub_config,
context.service_instance._stub,
datacenter_name,
datastore_name)
if not datastore_mo:
raise Exception("Could not find datastore '{}'".format(datastore_name))
# See if the Floppy image exists. Copy it into the system if it does not
# exist
dsfile = datastore_file.File(datastore_mo)
if not dsfile.exists(datastore_path):
print("Putting Floppy file from '{}' at '{}'".
format(floppy_src_url, datastore_path))
dsfile.put(path=path, src_url=floppy_src_url)
def cleanup_floppy_image(context):
"""Delete floppy image after running samples"""
datacenter_name = context.testbed.config['FLOPPY_DATACENTER_NAME']
datastore_path = context.testbed.config['FLOPPY_DATASTORE_PATH']
delete_file(context.stub_config,
context.service_instance,
'Floppy Image',
datacenter_name,
datastore_path)
def detect_floppy_image(context):
"""Find the floppy image used to run vcenter samples"""
datacenter_name = context.testbed.config['FLOPPY_DATACENTER_NAME']
datastore_path = context.testbed.config['FLOPPY_DATASTORE_PATH']
return detect_file(context, 'Floppy Image', datacenter_name, datastore_path)
def setup(context):
setup_floppy_image(context)
def cleanup(context):
cleanup_floppy_image(context)
def validate(context):
return detect_floppy_image(context)

View File

@ -0,0 +1,124 @@
"""
* *******************************************************
* Copyright (c) VMware, Inc. 2016. All Rights Reserved.
* *******************************************************
*
* DISCLAIMER. THIS PROGRAM IS PROVIDED TO YOU "AS IS" WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, WHETHER ORAL OR WRITTEN,
* EXPRESS OR IMPLIED. THE AUTHOR SPECIFICALLY DISCLAIMS ANY IMPLIED
* WARRANTIES OR CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY,
* NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE.
"""
__author__ = 'VMware, Inc.'
__copyright__ = 'Copyright 2016 VMware, Inc. All rights reserved.'
import pyVim.task
from com.vmware.vcenter_client import (Folder)
from pyVmomi import vim
from samples.vsphere.vcenter.helper import datacenter_helper
def detect_vm_folder(context, datacenter_name, folder_name):
"""Find vm folder based on datacenter and folder name"""
datacenter = datacenter_helper.get_datacenter(context.stub_config,
datacenter_name)
if not datacenter:
print("Datacenter '{}' not found".format(datacenter_name))
return None
folder_svc = Folder(context.stub_config)
folder_summaries = folder_svc.list(
Folder.FilterSpec(type=Folder.Type.VIRTUAL_MACHINE,
names=set([folder_name]),
datacenters=set([datacenter])))
if len(folder_summaries) > 0:
folder = folder_summaries[0].folder
print("Detected VM Folder '{}' as {}".format(folder_name, folder))
context.testbed.entities['VM_FOLDER_IDS'][folder_name] = folder
return True
else:
print("VM Folder '{}' missing in Datacenter {}".
format(folder_name, datacenter_name))
return False
def detect_vm_folders(context):
"""Find vm folder used to run vcenter samples"""
context.testbed.entities['VM_FOLDER_IDS'] = {}
folder1_name = context.testbed.config['VM_FOLDER1_NAME']
datacenter1_name = context.testbed.config['DATACENTER1_NAME']
folder2_name = context.testbed.config['VM_FOLDER2_NAME']
datacenter2_name = context.testbed.config['DATACENTER2_NAME']
return (detect_vm_folder(context, datacenter1_name, folder1_name) and
detect_vm_folder(context, datacenter2_name, folder2_name))
def delete_vm_folder(context, datacenter_name, folder_name):
"""Delete vm folder from given datacenter"""
for datacenter_mo in context.service_instance.content.rootFolder\
.childEntity:
if (isinstance(datacenter_mo, vim.Datacenter) and
datacenter_mo.name == datacenter_name):
for folder_mo in datacenter_mo.vmFolder.childEntity:
if folder_mo.name == folder_name:
print("Deleting Folder '{}' ({})' in Datacenter '{}' ({})".
format(folder_name, folder_mo._moId,
datacenter_name, datacenter_mo._moId))
task = folder_mo.Destroy()
pyVim.task.WaitForTask(task)
def create_vm_folder(context, datacenter_name, folder_name):
"""Create vm folder in given datacenter"""
datacenter = context.testbed.entities['DATACENTER_IDS'][datacenter_name]
datacenter_mo = vim.Datacenter(datacenter, context.soap_stub)
folder_mo = datacenter_mo.vmFolder.CreateFolder(folder_name)
print("Created Folder '{}' ({}) in Datacenter '{}' ({})".
format(folder_name, folder_mo._moId, datacenter_name, datacenter))
return folder_mo._moId
def cleanup_vm_folders(context):
"""Delete vm folder after sample run"""
folder1_name = context.testbed.config['VM_FOLDER1_NAME']
datacenter1_name = context.testbed.config['DATACENTER1_NAME']
delete_vm_folder(context, datacenter1_name, folder1_name)
folder2_name = context.testbed.config['VM_FOLDER2_NAME']
datacenter2_name = context.testbed.config['DATACENTER2_NAME']
delete_vm_folder(context, datacenter2_name, folder2_name)
def setup_vm_folders(context):
"""Setup vm folder used to run vcenter samples"""
folder1_name = context.testbed.config['VM_FOLDER1_NAME']
datacenter1_name = context.testbed.config['DATACENTER1_NAME']
folder1 = create_vm_folder(context, datacenter1_name, folder1_name)
folder2_name = context.testbed.config['VM_FOLDER2_NAME']
datacenter2_name = context.testbed.config['DATACENTER2_NAME']
folder2 = create_vm_folder(context, datacenter2_name, folder2_name)
context.testbed.entities['VM_FOLDER_IDS'] = {
folder1_name: folder1,
folder2_name: folder2,
}
def setup(context):
setup_vm_folders(context)
def cleanup(context):
cleanup_vm_folders(context)
def validate(context):
return detect_vm_folders(context)

View File

@ -0,0 +1,213 @@
"""
* *******************************************************
* Copyright (c) VMware, Inc. 2016. All Rights Reserved.
* *******************************************************
*
* DISCLAIMER. THIS PROGRAM IS PROVIDED TO YOU "AS IS" WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, WHETHER ORAL OR WRITTEN,
* EXPRESS OR IMPLIED. THE AUTHOR SPECIFICALLY DISCLAIMS ANY IMPLIED
* WARRANTIES OR CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY,
* NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE.
"""
__author__ = 'VMware, Inc.'
__copyright__ = 'Copyright 2016 VMware, Inc. All rights reserved.'
import pyVim.task
from com.vmware.vcenter_client import (Folder, Host)
from pyVmomi import vim
def detect_host(context, host_name):
"""Find host based on host name"""
host_svc = Host(context.stub_config)
names = set([host_name])
host_summaries = host_svc.list(Host.FilterSpec(names=names))
if len(host_summaries) > 0:
host = host_summaries[0].host
print("Detected Host '{}' as {}".format(host_name, host))
context.testbed.entities['HOST_IDS'][host_name] = host
return True
else:
print("Host '{}' missing".format(host_name))
return False
def detect_hosts(context):
"""Find host used to run vcenter samples"""
context.testbed.entities['HOST_IDS'] = {}
host1_name = context.testbed.config['ESX_HOST1']
host2_name = context.testbed.config['ESX_HOST2']
return (detect_host(context, host1_name) and
detect_host(context, host2_name))
def cleanup_hosts(context):
"""Delete hosts after sample run"""
host_svc = Host(context.stub_config)
host1_name = context.testbed.config['ESX_HOST1']
host2_name = context.testbed.config['ESX_HOST2']
names = set([host1_name, host2_name])
host_summaries = host_svc.list(Host.FilterSpec(names=names))
print('Found {} Hosts matching names {}'.
format(len(host_summaries), ', '.
join(["'{}'".format(n) for n in names])))
for host_summary in host_summaries:
host = host_summary.host
print("Deleting Host '{}' ({})".format(host_summary.name, host))
host_svc.delete(host)
def create_host_vapi(context, host_name, datacenter_name):
"""
Adds a single Host to the vCenter inventory under the named Datacenter
using vAPI.
"""
host_svc = Host(context.stub_config)
user = context.testbed.config['ESX_USER']
pwd = context.testbed.config['ESX_PASS']
# Get the host folder for the Datacenter1 using the folder query
datacenter = context.testbed.entities['DATACENTER_IDS'][datacenter_name]
folder_svc = Folder(context.stub_config)
folder_summaries = folder_svc.list(
Folder.FilterSpec(type=Folder.Type.HOST, datacenters=set([datacenter])))
folder = folder_summaries[0].folder
create_spec = Host.CreateSpec(
hostname=host_name,
user_name=user,
password=pwd,
folder=folder,
thumbprint_verification=Host.CreateSpec.ThumbprintVerification.NONE)
host = host_svc.create(create_spec)
print("Created Host '{}' ({})".format(host, host_name))
return host
def create_host_vim(context, host_name, datacenter_name):
"""
Adds a single Host to the vCenter inventory under the named Datacenter
using the VIM API.
"""
user = context.testbed.config['ESX_USER']
pwd = context.testbed.config['ESX_PASS']
# Get the host folder for the Datacenter1 using the folder query
datacenter = context.testbed.entities['DATACENTER_IDS'][datacenter_name]
for entity in context.service_instance.content.rootFolder.childEntity:
if isinstance(entity, vim.Datacenter) and\
entity.name == datacenter_name:
datacenter_mo = entity
folder_mo = datacenter_mo.hostFolder
connect_spec = vim.host.ConnectSpec(hostName=host_name,
userName=user,
password=pwd,
force=False)
print("Creating Host ({})".format(host_name))
task = folder_mo.AddStandaloneHost(connect_spec,
vim.ComputeResource.ConfigSpec(),
True)
pyVim.task.WaitForTask(task)
# Get host from task result
host_mo = task.info.result.host[0]
print("Created Host '{}' ({})".format(host_mo._moId, host_name))
return host_mo._moId
def move_host_into_cluster_vim(context, host_name, cluster_name):
"""Use vim api to move host to another cluster"""
TIMEOUT = 30 # sec
host = context.testbed.entities['HOST_IDS'][host_name]
host_mo = vim.HostSystem(host, context.soap_stub)
# Move the host into the cluster
if not host_mo.runtime.inMaintenanceMode:
task = host_mo.EnterMaintenanceMode(TIMEOUT)
pyVim.task.WaitForTask(task)
print("Host '{}' ({}) in maintenance mode".format(host, host_name))
cluster = context.testbed.entities['CLUSTER_IDS'][cluster_name]
cluster_mo = vim.ClusterComputeResource(cluster, context.soap_stub)
task = cluster_mo.MoveInto([host_mo])
pyVim.task.WaitForTask(task)
print("Host '{}' ({}) moved into Cluster {} ({})".
format(host, host_name, cluster, cluster_name))
task = host_mo.ExitMaintenanceMode(TIMEOUT)
pyVim.task.WaitForTask(task)
print("Host '{}' ({}) out of maintenance mode".format(host, host_name))
def setup_hosts_vapi(context):
"""Use vsphere automation API to setup host for sample run"""
# Create Host1 as a standalone host in Datacenter1
host1_name = context.testbed.config['ESX_HOST1']
datacenter1_name = context.testbed.config['DATACENTER1_NAME']
host1 = create_host_vapi(context, host1_name, datacenter1_name)
# Create Host2 in a Cluster2
host2_name = context.testbed.config['ESX_HOST2']
datacenter2_name = context.testbed.config['DATACENTER2_NAME']
host2 = create_host_vapi(context, host2_name, datacenter2_name)
context.testbed.entities['HOST_IDS'] = {
host1_name: host1,
host2_name: host2
}
# Move Host2 into Cluster2
cluster_name = context.testbed.config['CLUSTER1_NAME']
move_host_into_cluster_vim(context, host2_name, cluster_name)
def setup_hosts_vim(context):
"""Use vim API to setup host for sample run"""
# Create Host1 as a standalone host in Datacenter1
host1_name = context.testbed.config['ESX_HOST1']
datacenter1_name = context.testbed.config['DATACENTER1_NAME']
host1 = create_host_vim(context, host1_name, datacenter1_name)
# Create Host2 in a Cluster2
host2_name = context.testbed.config['ESX_HOST2']
datacenter2_name = context.testbed.config['DATACENTER2_NAME']
host2 = create_host_vim(context, host2_name, datacenter2_name)
context.testbed.entities['HOST_IDS'] = {
host1_name: host1,
host2_name: host2
}
# Move Host2 into Cluster2
cluster_name = context.testbed.config['CLUSTER1_NAME']
move_host_into_cluster_vim(context, host2_name, cluster_name)
def setup_hosts(context):
setup_hosts_vapi(context)
def setup(context):
setup_hosts(context)
def cleanup(context):
cleanup_hosts(context)
def validate(context):
return detect_hosts(context)

View File

@ -0,0 +1,72 @@
"""
* *******************************************************
* Copyright (c) VMware, Inc. 2016. All Rights Reserved.
* *******************************************************
*
* DISCLAIMER. THIS PROGRAM IS PROVIDED TO YOU "AS IS" WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, WHETHER ORAL OR WRITTEN,
* EXPRESS OR IMPLIED. THE AUTHOR SPECIFICALLY DISCLAIMS ANY IMPLIED
* WARRANTIES OR CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY,
* NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE.
"""
__author__ = 'VMware, Inc.'
__copyright__ = 'Copyright 2016 VMware, Inc. All rights reserved.'
from samples.vsphere.common.vim.file import (detect_file, delete_file,
parse_datastore_path)
from samples.vsphere.common.vim.inventory import get_datastore_mo
from samples.vsphere.common.vim import datastore_file
def setup_iso_image(context):
"""Copy iso image used to run vcenter samples"""
iso_src_url = context.testbed.config['ISO_SRC_URL']
datacenter_name = context.testbed.config['ISO_DATACENTER_NAME']
datastore_path = context.testbed.config['ISO_DATASTORE_PATH']
(datastore_name, path) = parse_datastore_path(datastore_path)
datastore_mo = get_datastore_mo(context.stub_config,
context.service_instance._stub,
datacenter_name,
datastore_name)
if not datastore_mo:
raise Exception("Could not find datastore '{}'".format(datastore_name))
# See if the ISO image exists. Copy it into the system if it does not exist
dsfile = datastore_file.File(datastore_mo)
if not dsfile.exists(datastore_path):
print("Putting ISO image file from '{}' at '{}'".
format(iso_src_url, datastore_path))
dsfile.put(path=path, src_url=iso_src_url)
def cleanup_iso_image(context):
"""Cleanup iso image after sample run"""
datacenter_name = context.testbed.config['ISO_DATACENTER_NAME']
datastore_path = context.testbed.config['ISO_DATASTORE_PATH']
delete_file(context.stub_config,
context.service_instance,
"ISO Image",
datacenter_name,
datastore_path)
def detect_iso_image(context):
"""Find iso image used to run vcenter samples"""
datacenter_name = context.testbed.config['ISO_DATACENTER_NAME']
datastore_path = context.testbed.config['ISO_DATASTORE_PATH']
return detect_file(context, "ISO Image", datacenter_name, datastore_path)
def setup(context):
setup_iso_image(context)
def cleanup(context):
cleanup_iso_image(context)
def validate(context):
return detect_iso_image(context)

View File

@ -0,0 +1,123 @@
#!/usr/bin/env python
"""
* *******************************************************
* Copyright (c) VMware, Inc. 2016. All Rights Reserved.
* *******************************************************
*
* DISCLAIMER. THIS PROGRAM IS PROVIDED TO YOU "AS IS" WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, WHETHER ORAL OR WRITTEN,
* EXPRESS OR IMPLIED. THE AUTHOR SPECIFICALLY DISCLAIMS ANY IMPLIED
* WARRANTIES OR CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY,
* NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE.
"""
"""
Script that runs through all the setup and samples.
"""
__author__ = 'VMware, Inc.'
__copyright__ = 'Copyright 2016 VMware, Inc. All rights reserved.'
import pyVim.connect
from samples.vsphere.common import sample_util
from samples.vsphere.common import vapiconnect
from samples.vsphere.vcenter.setup import testbed
from samples.vsphere.vcenter.setup.setup_cli import build_arg_parser
from samples.vsphere.vcenter.setup.testbed_setup import cleanup as testbed_cleanup
from samples.vsphere.vcenter.setup.testbed_setup import setup as testbed_setup
from samples.vsphere.vcenter.setup.testbed_setup import validate as testbed_validate
from samples.vsphere.vcenter.vm.main import cleanup as sample_cleanup
from samples.vsphere.vcenter.vm.main import run as sample_run
from samples.vsphere.common.ssl_helper import get_unverified_context
# Parse command line params for setup script
args = build_arg_parser().parse_args()
_testbed = testbed.get()
# If VC/ESX/NFS Server IPs are passed as arguments,
# then override testbed.py values
if (args.vcenterserver):
_testbed.config['SERVER'] = args.vcenterserver
if (args.esxhost1):
_testbed.config['ESX_HOST1'] = args.esxhost1
if (args.esxhost2):
_testbed.config['ESX_HOST2'] = args.esxhost2
if (args.nfsserver):
_testbed.config['NFS_HOST'] = args.nfsserver
print(_testbed.to_config_string())
# Connect to VIM API Endpoint on vCenter system
context = None
if args.skipverification:
context = get_unverified_context()
service_instance = pyVim.connect.SmartConnect(host=_testbed.config['SERVER'],
user=_testbed.config['USERNAME'],
pwd=_testbed.config['PASSWORD'],
sslContext=context)
# Connect to vAPI Endpoint on vCenter system
stub_config = vapiconnect.connect(host=_testbed.config['SERVER'],
user=_testbed.config['USERNAME'],
pwd=_testbed.config['PASSWORD'],
skip_verification=args.skipverification)
context = sample_util.Context(_testbed, service_instance, stub_config)
context.option['DO_TESTBED_SETUP'] = args.testbed_setup
context.option['DO_TESTBED_VALIDATE'] = args.testbed_validate
context.option['DO_TESTBED_CLEANUP'] = args.testbed_cleanup
context.option['DO_TESTBED_ISO_CLEANUP'] = args.iso_cleanup
context.option['DO_SAMPLES_SETUP'] = args.samples_setup
context.option['DO_SAMPLES'] = args.samples
context.option['DO_SAMPLES_INCREMENTAL'] = args.samples_incremental
context.option['DO_SAMPLES_CLEANUP'] = args.samples_cleanup
context.option['SKIP_VERIFICATION'] = args.skipverification
print(context.to_option_string())
###############################################################################
# Testbed Setup
###############################################################################
# Setup testbed
if context.option['DO_TESTBED_SETUP']:
# Clean up in case of past failures
sample_cleanup(context)
testbed_cleanup(context)
testbed_setup(context)
# Validate testbed
if (context.option['DO_TESTBED_SETUP'] or
context.option['DO_TESTBED_VALIDATE'] or
context.option['DO_SAMPLES_SETUP'] or
context.option['DO_SAMPLES']):
if not testbed_validate(context):
exit(0)
print(context.testbed.to_entities_string())
###############################################################################
# Sample Run and Cleanup
###############################################################################
# Run Sample
if context.option['DO_SAMPLES']:
sample_run(context)
# Cleanup after sample run
if context.option['DO_SAMPLES_CLEANUP']:
sample_cleanup(context)
###############################################################################
# Testbed Cleanup
###############################################################################
# Teardown testbed.
if context.option['DO_TESTBED_CLEANUP']:
sample_cleanup(context)
testbed_cleanup(context)

View File

@ -0,0 +1,282 @@
"""
* *******************************************************
* Copyright (c) VMware, Inc. 2016. All Rights Reserved.
* *******************************************************
*
* DISCLAIMER. THIS PROGRAM IS PROVIDED TO YOU "AS IS" WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, WHETHER ORAL OR WRITTEN,
* EXPRESS OR IMPLIED. THE AUTHOR SPECIFICALLY DISCLAIMS ANY IMPLIED
* WARRANTIES OR CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY,
* NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE.
"""
__author__ = 'VMware, Inc.'
__copyright__ = 'Copyright 2016 VMware, Inc. All rights reserved.'
import pyVim.task
from com.vmware.vcenter_client import Host
from pyVmomi import vim
def detect_vdswitches(context):
"""Find distributed virtual switch used to run vcenter samples"""
context.testbed.entities['DISTRIBUTED_SWITCH_IDS'] = {}
context.testbed.entities['DISTRIBUTED_PORTGROUP_IDS'] = {}
datacenter_name = context.testbed.config['DATACENTER2_NAME']
vdswitch_name = context.testbed.config['VDSWITCH1_NAME']
vdswitch_mo = find_vdswitch(context, datacenter_name, vdswitch_name)
if vdswitch_mo:
vdswitch = vdswitch_mo._moId
print("Detected Distributed Switch '{}' as {}".
format(vdswitch_name, vdswitch))
context.testbed.entities['DISTRIBUTED_SWITCH_IDS'][
vdswitch_name] = vdswitch
vdportgroup_name = context.testbed.config['VDPORTGROUP1_NAME']
vdportgroup_mo = find_vdportgroup(context, datacenter_name,
vdswitch_name, vdportgroup_name)
if vdportgroup_mo:
vdportgroup = vdportgroup_mo._moId
print("Detected Distributed Portgroup '{}' as {}".
format(vdportgroup_name, vdportgroup))
context.testbed.entities['DISTRIBUTED_PORTGROUP_IDS'][
vdportgroup_name] = vdportgroup
else:
print("Distributed Portgroup '{}' missing".format(vdportgroup_name))
return False
else:
print("Distributed Switch '{}' missing".format(vdswitch_name))
return False
return True
def cleanup_vdswitch(context):
"""Cleanup Distributed Switch after sampel run"""
datacenter_name = context.testbed.config['DATACENTER2_NAME']
vdswitch_name = context.testbed.config['VDSWITCH1_NAME']
vdswitch_mo = find_vdswitch(context, datacenter_name, vdswitch_name)
if vdswitch_mo:
vdportgroup_name = context.testbed.config['VDPORTGROUP1_NAME']
vdportgroup_mo = find_vdportgroup(context, datacenter_name,
vdswitch_name, vdportgroup_name)
if vdportgroup_mo:
print("Deleting Distributed Portgroup '{}' ({})".
format(vdportgroup_name, vdportgroup_mo._moId))
task = vdportgroup_mo.Destroy()
pyVim.task.WaitForTask(task)
host_name = context.testbed.config['ESX_HOST2']
remove_host_from_vdswitch(context, vdswitch_mo, host_name)
print("Deleting Distributed Switch '{}' ({})".
format(vdswitch_name, vdswitch_mo._moId))
task = vdswitch_mo.Destroy()
pyVim.task.WaitForTask(task)
def find_vdswitch(context, datacenter_name, vdswitch_name):
""" Retrieve an existing Distributed Switch"""
# TODO Ugly deep nesting.
for datacenter_mo in context.service_instance.content.rootFolder \
.childEntity:
if (isinstance(datacenter_mo, vim.Datacenter) and
datacenter_mo.name == datacenter_name):
for vdswitch_mo in datacenter_mo.networkFolder.childEntity:
if (isinstance(vdswitch_mo, vim.DistributedVirtualSwitch) and
vdswitch_mo.summary.name == vdswitch_name):
print("Found VDSwitch '{}' ({}) in Datacenter '{}' ({})".
format(vdswitch_name, vdswitch_mo._moId,
datacenter_name, datacenter_mo._moId))
return vdswitch_mo
return None
def find_vdportgroup(context, datacenter_name, vdswitch_name, vdportgroup_name):
"""
Find existing Distributed Switch portgroup based on datacenter,
vds name and portgroup name
"""
vdswitch_mo = find_vdswitch(context, datacenter_name, vdswitch_name)
for vdportgroup_mo in vdswitch_mo.portgroup:
if vdportgroup_mo.name == vdportgroup_name:
print(
"Found Distributed Portgroup '{}' ({}) on Distributed Switch '{}' ({})".
format(vdportgroup_name, vdportgroup_mo._moId,
vdswitch_name, vdswitch_mo._moId))
return vdportgroup_mo
return None
def create_vdswitch(context, datacenter_name, vdswitch_name):
"""Create Distributed Switch in given datacenter"""
datacenter = context.testbed.entities['DATACENTER_IDS'][datacenter_name]
datacenter_mo = vim.Datacenter(datacenter, context.soap_stub)
spec = vim.DistributedVirtualSwitch.CreateSpec()
spec.configSpec = vim.DistributedVirtualSwitch.ConfigSpec(
name=vdswitch_name)
task = datacenter_mo.networkFolder.CreateDistributedVirtualSwitch(spec)
pyVim.task.WaitForTask(task)
vdswitch_mo = task.info.result
print("Created Distributed Switch '{}' ({})".
format(vdswitch_name, vdswitch_mo._moId))
return vdswitch_mo._moId
def create_vdportgroup(context, vdswitch_name, vdportgroup_name):
"""Create Distributed Switch portgroup"""
vdportgroup_type = "earlyBinding"
vdswitch = context.testbed.entities['DISTRIBUTED_SWITCH_IDS'][vdswitch_name]
vdswitch_mo = vim.DistributedVirtualSwitch(vdswitch, context.soap_stub)
vdportgroup_spec = vim.dvs.DistributedVirtualPortgroup.ConfigSpec(
name=vdportgroup_name, type=vdportgroup_type)
vdportgroup_specs = [vdportgroup_spec]
task = vdswitch_mo.AddPortgroups(vdportgroup_specs)
pyVim.task.WaitForTask(task)
# The AddPortgroup operation doesn't return any information about the
# created portgroup, so look it up.
vdportgroup = None
for vdportgroup_mo in vdswitch_mo.portgroup:
if vdportgroup_mo.name == vdportgroup_name:
vdportgroup = vdportgroup_mo._moId
print(
"Created Distributed Portgroup '{}' ({}) on Distributed Switch '{}' ({})".
format(vdportgroup_name, vdportgroup, vdswitch_name, vdswitch))
return vdportgroup
def add_host_to_vdswitch(context, vdswitch_name, host_name, pnic_names=None):
"""Add host to Distributed Switch"""
host = context.testbed.entities['HOST_IDS'][host_name]
host_mo = vim.HostSystem(host, context.soap_stub)
vdswitch = context.testbed.entities['DISTRIBUTED_SWITCH_IDS'][vdswitch_name]
vdswitch_mo = vim.DistributedVirtualSwitch(vdswitch, context.soap_stub)
pnic_specs = []
if pnic_names:
for pnic in pnic_names:
pnic_specs.append(vim.dvs.HostMember.PnicSpec(pnicDevice=pnic))
dvs_member_config = vim.dvs.HostMember.ConfigSpec(
operation="add",
host=host_mo,
backing=vim.dvs.HostMember.PnicBacking(pnicSpec=pnic_specs))
dvs_config = vim.DistributedVirtualSwitch.ConfigSpec(
configVersion=vdswitch_mo.config.configVersion,
host=[dvs_member_config])
task = vdswitch_mo.Reconfigure(dvs_config)
pyVim.task.WaitForTask(task)
print("Added Host '{}' ({}) to Distributed Switch '{}' ({})".
format(host_name, host, vdswitch_name, vdswitch))
def remove_host_from_vdswitch(context, vdswitch_mo, host_name):
"""Remove host from Distributed Switch"""
for host_member in vdswitch_mo.config.host:
if host_member.config.host.name == host_name:
dvs_member_config = vim.dvs.HostMember.ConfigSpec(
operation="remove",
host=host_member.config.host)
dvs_config = vim.DistributedVirtualSwitch.ConfigSpec(
configVersion=vdswitch_mo.config.configVersion,
host=[dvs_member_config])
task = vdswitch_mo.Reconfigure(dvs_config)
pyVim.task.WaitForTask(task)
print("Removed Host '{}' ({}) from Distributed Switch '{}' ({})".
format(host_name, host_member.config.host._moId,
vdswitch_mo.summary.name, vdswitch_mo._moId))
def setup_vdswitch(context):
"""Setup Distributed Switch used to run vcenter samples"""
# Add a Distributed Switch
datacenter_name = context.testbed.config['DATACENTER2_NAME']
vdswitch1_name = context.testbed.config['VDSWITCH1_NAME']
vdswitch1 = create_vdswitch(context, datacenter_name, vdswitch1_name)
context.testbed.entities['DISTRIBUTED_SWITCH_IDS'] = {
vdswitch1_name: vdswitch1
}
# Add a Distributed Portgroup
vdportgroup1_name = context.testbed.config['VDPORTGROUP1_NAME']
vdportgroup1 = create_vdportgroup(context, vdswitch1_name,
vdportgroup1_name)
context.testbed.entities['DISTRIBUTED_PORTGROUP_IDS'] = {
vdportgroup1_name: vdportgroup1
}
# Add a Host into the Distributed Switch
host2_name = context.testbed.config['ESX_HOST2']
add_host_to_vdswitch(context, vdswitch1_name, host2_name)
# @TODO: Add Host Uplink
def detect_stdportgroup(context, host_name, network_name):
"""Find Distributed Switch based on host and network name"""
# Ensure the standard switch is available on the host
names = set([host_name])
# Use vAPI find the Host managed identities
host_svc = Host(context.stub_config)
host_summaries = host_svc.list(Host.FilterSpec(names=names))
for host_summary in host_summaries:
# Convert the host identifier into a ManagedObject
host = host_summary.host
host_mo = vim.HostSystem(host, context.soap_stub)
for network_mo in host_mo.network:
if (type(network_mo) == vim.Network and
network_mo.name == network_name):
network = network_mo._moId
print(
"Detected Standard Portgroup '{}' as {} on Host '{}' ({})".
format(network_name, network, host_name, host))
context.testbed.entities['HOST_STANDARD_SWITCH_IDS'][
host_name] = network
return True
print("Standard Portgroup '{}' missing on Host '{}'".
format(network_name, host_name))
return False
def detect_stdportgroups(context):
"""Find Distributed Switch used to run vcenter samples"""
context.testbed.entities['HOST_STANDARD_SWITCH_IDS'] = {}
network_name = context.testbed.config['STDPORTGROUP_NAME']
host1_name = context.testbed.config['ESX_HOST1']
host2_name = context.testbed.config['ESX_HOST2']
return (detect_stdportgroup(context, host1_name, network_name) and
detect_stdportgroup(context, host2_name, network_name))
def setup(context):
setup_vdswitch(context)
def cleanup(context):
cleanup_vdswitch(context)
def validate(context):
return (
detect_vdswitches(context) and
detect_stdportgroups(context))

View File

@ -0,0 +1,106 @@
"""
* *******************************************************
* Copyright (c) VMware, Inc. 2016. All Rights Reserved.
* *******************************************************
*
* DISCLAIMER. THIS PROGRAM IS PROVIDED TO YOU "AS IS" WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, WHETHER ORAL OR WRITTEN,
* EXPRESS OR IMPLIED. THE AUTHOR SPECIFICALLY DISCLAIMS ANY IMPLIED
* WARRANTIES OR CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY,
* NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE.
"""
"""
This module implements simple helper functions for python samples
"""
__author__ = 'VMware, Inc.'
__copyright__ = 'Copyright 2016 VMware, Inc. All rights reserved.'
import argparse
def build_arg_parser():
"""
Builds a standard argument parser with arguments for executing sample
setup script
-s, --testbed_setup
-t, --testbed_validate
-c, --testbed_cleanup
-o, --iso_cleanup
-e, --samples_setup
-r, --samples
-i, --samples_incremental
-l, --samples_cleanup
-v, --skipverification
-server, --vcenterserver
-e1, --esxhost1
-e2, --esxhost2
-n, --nfsserver
"""
parser = argparse.ArgumentParser(
description='Arguments for running sample setup script')
parser.add_argument('-s', '--testbed_setup',
action='store_true',
help='Build the testbed. Will run cleanup before '
'trying to build in case there is '
'an intermediate failure')
parser.add_argument('-t', '--testbed_validate',
action='store_true',
help='Validate if the testbed is ready for the samples')
parser.add_argument('-c', '--testbed_cleanup',
action='store_true',
help='Tear down the testbed')
parser.add_argument('-o', '--iso_cleanup',
action='store_true',
help='Delete iso during cleanup. ')
parser.add_argument('-e', '--samples_setup',
action='store_true',
help='Run sample setup. ')
parser.add_argument('-r', '--samples',
action='store_true',
help='Run samples. ')
parser.add_argument('-i', '--samples_incremental',
action='store_true',
help='Runs samples that incrementally updates the VM '
'configuration. ')
parser.add_argument('-l', '--samples_cleanup',
action='store_true',
help='Clean up after sample run. ')
parser.add_argument('-v', '--skipverification',
action='store_true',
help='Verify server certificate when connecting to '
'vcenter. ')
parser.add_argument('-server', '--vcenterserver',
action='store',
help='Vcenter server IP to prepare the testbed to run the samples.'
'If not passed as argument, update testbed.py file')
parser.add_argument('-e1', '--esxhost1',
action='store',
help='ESX HOST 1 IP to prepare the testbed to run the samples.'
'If not passed as argument, update testbed.py file')
parser.add_argument('-e2', '--esxhost2',
action='store',
help='ESX HOST 2 IP to prepare the testbed to run the samples.'
'If not passed as argument, update testbed.py file')
parser.add_argument('-n', '--nfsserver',
action='store',
help='NFS Server IP to setup datastore for samples run.'
'If not passed as argument, update testbed.py file')
return parser

View File

@ -0,0 +1,140 @@
"""
* *******************************************************
* Copyright (c) VMware, Inc. 2016. All Rights Reserved.
* *******************************************************
*
* DISCLAIMER. THIS PROGRAM IS PROVIDED TO YOU "AS IS" WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, WHETHER ORAL OR WRITTEN,
* EXPRESS OR IMPLIED. THE AUTHOR SPECIFICALLY DISCLAIMS ANY IMPLIED
* WARRANTIES OR CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY,
* NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE.
"""
__author__ = 'VMware, Inc.'
__copyright__ = 'Copyright 2016 VMware, Inc. All rights reserved.'
config = {}
config["SERVER"] = ""
config["USERNAME"] = "administrator@vsphere.local"
config["PASSWORD"] = "Admin!23"
config["ESX_HOST1"] = ""
config["ESX_HOST2"] = ""
config["ESX_USER"] = "root"
config["ESX_PASS"] = ""
config["USE_NFS"] = True
config["NFS_HOST"] = ""
config["NFS_REMOTE_PATH"] = "/store1"
config["NFS_DATASTORE_NAME"] = "Shared_NFS_Volume"
config["ESX_HOST1_VMFS_DATASTORE"] = "Local_VMFS_Volume_on_Host1"
config["ESX_HOST2_VMFS_DATASTORE"] = "Local_VMFS_Volume_on_Host2"
config["DATACENTER1_NAME"] = "Sample_DC_1"
config["DATACENTER2_NAME"] = "Sample_DC_2"
config["VM_FOLDER1_NAME"] = "Sample_VM_Folder_1"
config["VM_FOLDER2_NAME"] = "Sample_VM_Folder_2"
config["CLUSTER1_NAME"] = "Cluster1"
config["VDSWITCH1_NAME"] = "DSwitch1"
config["VDPORTGROUP1_NAME"] = "Static_Portgroup_on_DSwitch_1"
config["STDPORTGROUP_NAME"] = "VM Network"
# The main datacenter and datastore that will be used for the VM tests
config["VM_DATACENTER_NAME"] = config["DATACENTER2_NAME"]
config["VM_DATASTORE_NAME"] = config["NFS_DATASTORE_NAME"]
# GestOS should be one of the enumeration values in com.vmware.vcenter.vm.GuestOS
config["VM_GUESTOS"] = "WINDOWS_9_64"
config["VM_NAME_DEFAULT"] = "Sample_Default_VM_for_Simple_Testbed"
config["VM_NAME_BASIC"] = "Sample_Basic_VM_for_Simple_Testbed"
config["VM_NAME_EXHAUSTIVE"] = "Sample_Exhaustive_VM_for_Simple_Testbed"
config["BACKENDS_DATACENTER_NAME"] = config["VM_DATACENTER_NAME"]
# Root datastore path where VM backend files not will be created for the
# samples
config["BACKENDS_DATASTORE_ROOT_PATH"] = "[{}] Sample_Backends".format(config["VM_DATASTORE_NAME"])
config["DISK_DATACENTER_NAME"] = config["VM_DATACENTER_NAME"]
config["DISK_DATASTORE_ROOT_PATH"] = config["BACKENDS_DATASTORE_ROOT_PATH"] + "/disk"
config["ISO_SRC_URL"] = "https://dl.bintray.com/vmware/photon/iso/1.0TP2/x86_64/photon-minimal-1.0TP2.iso"
config["ISO_DATACENTER_NAME"] = config["VM_DATACENTER_NAME"]
config["ISO_DATASTORE_ROOT_PATH"] = config["BACKENDS_DATASTORE_ROOT_PATH"] + "/iso"
config["ISO_DATASTORE_PATH"] = config["ISO_DATASTORE_ROOT_PATH"] + "/photonOS.iso"
config["SERIAL_PORT_DATACENTER_NAME"] = config["VM_DATACENTER_NAME"]
config["SERIAL_PORT_DATASTORE_ROOT_PATH"] = config["BACKENDS_DATASTORE_ROOT_PATH"] + "/serial"
config["SERIAL_PORT_DATASTORE_PATH"] = config["SERIAL_PORT_DATASTORE_ROOT_PATH"] + "/serial.log"
config["SERIAL_PORT_NETWORK_SERVER_LOCATION"] = "tcp://localhost:16000"
config["SERIAL_PORT_NETWORK_CLIENT_LOCATION"] = "tcp://www.vmware.com:80"
config["SERIAL_PORT_NETWORK_PROXY"] = None
config["PARALLEL_PORT_DATACENTER_NAME"] = config["VM_DATACENTER_NAME"]
config["PARALLEL_PORT_DATASTORE_ROOT_PATH"] = config["BACKENDS_DATASTORE_ROOT_PATH"] + "/parallel"
config["PARALLEL_PORT_DATASTORE_PATH"] = config["PARALLEL_PORT_DATASTORE_ROOT_PATH"] + "/parallel.log"
config["FLOPPY_SRC_URL"] = "http://www.ibiblio.org/pub/micro/pc-stuff/freedos/files/distributions/1.0/fdboot.img"
config["FLOPPY_DATACENTER_NAME"] = config["VM_DATACENTER_NAME"]
config["FLOPPY_DATASTORE_ROOT_PATH"] = config["BACKENDS_DATASTORE_ROOT_PATH"] + "/floppy"
config["FLOPPY_DATASTORE_PATH"] = config["FLOPPY_DATASTORE_ROOT_PATH"] + "/fdboot.img"
class Testbed(object):
def __init__(self):
self.config = {}
self.entities = {}
@property
def config(self):
return self._config
@config.setter
def config(self, value):
"""setting"""
self._config = value
@property
def entities(self):
return self._entities
@entities.setter
def entities(self, value):
"""setting"""
self._entities = value
def to_config_string(self):
s = ["=" * 79,
"Testbed Configuration:",
"=" * 79]
s += [" {}: {}".format(k, self.config[k])
for k in sorted(self.config.keys())]
s += ["=" * 79]
return "\n".join(s)
def to_entities_string(self):
s = ["=" * 79,
"Testbed Entities:",
"=" * 79]
s += [" {}: {}".format(k, self.entities[k])
for k in sorted(self.entities.keys())]
s += ["=" * 79]
return "\n".join(s)
def __str__(self):
return "\n".join(self.to_config_string(),
self.to_entities_string())
_testbed = Testbed()
_testbed.config.update(config)
def get():
return _testbed

View File

@ -0,0 +1,110 @@
"""
* *******************************************************
* Copyright (c) VMware, Inc. 2016. All Rights Reserved.
* *******************************************************
*
* DISCLAIMER. THIS PROGRAM IS PROVIDED TO YOU "AS IS" WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, WHETHER ORAL OR WRITTEN,
* EXPRESS OR IMPLIED. THE AUTHOR SPECIFICALLY DISCLAIMS ANY IMPLIED
* WARRANTIES OR CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY,
* NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE.
"""
__author__ = 'VMware, Inc.'
__copyright__ = 'Copyright 2016 VMware, Inc. All rights reserved.'
import samples.vsphere.vcenter.setup.backend_directory as backend_directory
import samples.vsphere.vcenter.setup.cluster as cluster
import samples.vsphere.vcenter.setup.datacenter as datacenter
import samples.vsphere.vcenter.setup.datastore as datastore
import samples.vsphere.vcenter.setup.floppy_image as floppy_image
import samples.vsphere.vcenter.setup.folder as folder
import samples.vsphere.vcenter.setup.host as host
import samples.vsphere.vcenter.setup.iso_image as iso_image
import samples.vsphere.vcenter.setup.network as network
"""
Setup Simple Testbed: Which provides the prerequisites for using the VM API
Inputs:
* IP address or hostname of vCenter
* IP address of 2 hosts
* (IP address,server path) of a NFS Server
* Assumes that all resources will be created off the root folders
within each datacenter. No need to recursively traverse across
different folders looking for the entities.
* Two Datacenters
* "Sample_DC_1"
* "Sample_DC_2"
* One Cluster
* "Sample_Cluster"
* 2 host environment
* 1 host in Sample Cluster in Sample_DC_1
* One network adapter per Host
* Name of Host will be the IP address
* 3 Datastores, any constraints?
* Shared NFS Datastore
* "Shared_NFS_Volume"
* 2 Local VMFS Datastore (name the datastores based on the host)
* "Local_VMFS_Datastore_on_<host_ip>"
* 1 Standard Portgroups (verify)
* "VM Network" (the default created per host)
* 1 Distributed Switch ("DSwitch 1")
* 1 non-uplink DvPortgroups
* static ("Static Portgroup on DSwitch 1")
* 2 created VM Folder, one in each Datacenter
* "Sample VM Folder 1"
* "Sample VM Folder 2"
* Put an ISO image on a Datastore
* Put a Floppy image on a Datastore
"""
def setup(context):
print('Setup Testbed Start')
datacenter.setup(context)
folder.setup(context)
cluster.setup(context)
host.setup(context)
datastore.setup(context)
network.setup(context)
backend_directory.setup(context)
iso_image.setup(context)
floppy_image.setup(context)
print('Setup Testbed Complete\n')
def cleanup(context):
print('Cleanup Testbed Start')
floppy_image.cleanup(context)
if context.option['DO_TESTBED_ISO_CLEANUP']:
iso_image.cleanup(context)
backend_directory.cleanup(context)
network.cleanup(context)
datastore.cleanup(context)
host.cleanup(context)
cluster.cleanup(context)
folder.cleanup(context)
datacenter.cleanup(context)
print('Cleanup Testbed Complete\n')
def validate(context):
print('Validating and Detecting Resources in Testbed')
r = (datacenter.validate(context) and
folder.validate(context) and
cluster.validate(context) and
host.validate(context) and
datastore.validate(context) and
network.validate(context) and
backend_directory.validate(context) and
iso_image.validate(context) and
floppy_image.validate(context)
)
if r:
print('==> Testbed validated')
return True
else:
print('==> Testbed has errors')
return False

View File

@ -0,0 +1,23 @@
This directory contains samples for vCenter virtual machine APIs:
1. Virtual machine Create, Read and Delete operations:
* Create a virtual machine with system provided defaults - create/create_default_vm.py
* Create a basic virtual machine - create/create_basic_vm.py
* Create a exhaustive virtual machine - create/create_exhaustive_vm.py
2. Virtual machine power lifecycle (requires an existing virtual machine):
* Manage virtual machine power state - power.py
3. Update virtual machine hardware settings (requires an existing virtual machine):
* Configure virtual SATA adapters of a virtual machine - hardware/adapter/sata.py
* Configure virtual SCSI adapters of a virtual machine - hardware/adapter/scsi.py
* Configure the booting settings for virtual machine - hardware/boot.py
* Configure the boot devices used by a virtual machine - hardware/boot_device.py
* Configure CD-ROM devices for a virtual machine - hardware/cdrom.py
* Configure CPU settings for a virtual machine - hardware/cpu.py
* Configure disk settings for a virtual machine - hardware/disk.py
* Configure virtual ethernet adapters of a virtual machine - hardware/ethernet.py
* Configure Floppy settings for a virtual machine - hardware/floppy.py
* Configure Memory settings of a virtual machine - hardware/memory.py
* Configure Parallel ports for a virtual machine - hardware/parallel.py
* Configure Serial ports for a virtual machine - hardware/serial.py

View File

@ -0,0 +1,23 @@
"""
* *******************************************************
* Copyright VMware, Inc. 2016. All Rights Reserved.
* *******************************************************
*
* DISCLAIMER. THIS PROGRAM IS PROVIDED TO YOU "AS IS" WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, WHETHER ORAL OR WRITTEN,
* EXPRESS OR IMPLIED. THE AUTHOR SPECIFICALLY DISCLAIMS ANY IMPLIED
* WARRANTIES OR CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY,
* NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE.
"""
__author__ = 'VMware, Inc.'
__copyright__ = 'Copyright 2016 VMware, Inc. All rights reserved.'
# Required to distribute different parts of this
# package as multiple distribution
try:
import pkg_resources
pkg_resources.declare_namespace(__name__)
except ImportError:
from pkgutil import extend_path
__path__ = extend_path(__path__, __name__) # @ReservedAssignment

View File

@ -0,0 +1,24 @@
"""
* *******************************************************
* Copyright VMware, Inc. 2016. All Rights Reserved.
* *******************************************************
*
* DISCLAIMER. THIS PROGRAM IS PROVIDED TO YOU "AS IS" WITHOUT
* WARRANTIES OR CONDITIONS OF ANY KIND, WHETHER ORAL OR WRITTEN,
* EXPRESS OR IMPLIED. THE AUTHOR SPECIFICALLY DISCLAIMS ANY IMPLIED
* WARRANTIES OR CONDITIONS OF MERCHANTABILITY, SATISFACTORY QUALITY,
* NON-INFRINGEMENT AND FITNESS FOR A PARTICULAR PURPOSE.
"""
__author__ = 'VMware, Inc.'
__copyright__ = 'Copyright 2016 VMware, Inc. All rights reserved.'
# Required to distribute different parts of this
# package as multiple distribution
try:
import pkg_resources
pkg_resources.declare_namespace(__name__)
except ImportError:
from pkgutil import extend_path
__path__ = extend_path(__path__, __name__) # @ReservedAssignment

Some files were not shown because too many files have changed in this diff Show More