mirror of
https://github.com/vmware/vsphere-automation-sdk-python.git
synced 2024-11-26 19:29:58 -05:00
Initial sample drop
This commit is contained in:
parent
ba97ea9f43
commit
0b4d32c287
146
README.md
146
README.md
@ -1,2 +1,144 @@
|
|||||||
# vsphere-automation-sdk-python-samples
|
# VMware vSphere Automation SDK for Python
|
||||||
Python Samples for the vSphere Automation SDK
|
## Table of Contents
|
||||||
|
* [Abstract](#abstract)
|
||||||
|
* [Table of Contents](https://github.com/vmware/vsphere-automation-sdk-java-samples#table-of-contents)
|
||||||
|
* [Getting Started](https://github.com/vmware/vsphere-automation-sdk-java-samples#getting-started)
|
||||||
|
* [Downloading the Repository for Local Access](https://github.com/vmware/vsphere-automation-sdk-java-samples#downloading-the-repository-for-local-access)
|
||||||
|
* [Prerequisites](https://github.com/vmware/vsphere-automation-sdk-java-samples#prerequisites)
|
||||||
|
* [Building the Samples](https://github.com/vmware/vsphere-automation-sdk-java-samples#building-the-samples)
|
||||||
|
* [Running the Samples](https://github.com/vmware/vsphere-automation-sdk-java-samples#running-the-samples)
|
||||||
|
* [Submitting Samples](https://github.com/vmware/vsphere-automation-sdk-java-samples#submitting-samples)
|
||||||
|
* [Required Information](https://github.com/vmware/vsphere-automation-sdk-java-samples#required-information)
|
||||||
|
* [Suggested Information](https://github.com/vmware/vsphere-automation-sdk-java-samples#suggested-information)
|
||||||
|
* [Resource Maintenance](https://github.com/vmware/vsphere-automation-sdk-java-samples#resource-maintenance)
|
||||||
|
* [Maintenance Ownership](https://github.com/vmware/vsphere-automation-sdk-java-samples#maintenance-ownership)
|
||||||
|
* [Filing issues](https://github.com/vmware/vsphere-automation-sdk-java-samples#filing-isssues)
|
||||||
|
* [Resolving issues](https://github.com/vmware/vsphere-automation-sdk-java-samples#resolving-issues)
|
||||||
|
* [Additional Resources](https://github.com/vmware/vsphere-automation-sdk-java-samples#additional-resources)
|
||||||
|
* [Discussions](https://github.com/vmware/vsphere-automation-sdk-java-samples#discussions)
|
||||||
|
* [VMware Sample Exchange](https://github.com/vmware/vsphere-automation-sdk-java-samples#vmware-sample-exchange)
|
||||||
|
* [LICENSE AGREEMENT](https://github.com/vmware/vsphere-automation-sdk-java-samples#license-agreement)
|
||||||
|
|
||||||
|
## Abstract
|
||||||
|
This document for the vSphere Automation SDK for java describes -
|
||||||
|
1. How to build the java samples in this repository.
|
||||||
|
2. How to run the samples in this repository
|
||||||
|
3. The procedure for contributing new samples.
|
||||||
|
|
||||||
|
## Getting Started
|
||||||
|
### Downloading the Repository for Local Access
|
||||||
|
1. Load the GitHub repository page: <https://github.com/vmware/vsphere-automation-sdk-java-samples>
|
||||||
|
2. Click on the green “Clone or Download” button and then click “Download ZIP”
|
||||||
|
3. Once downloaded, extract the zip file to the location of your choosing
|
||||||
|
4. At this point, you now have a local copy of the repository
|
||||||
|
|
||||||
|
### Prerequisites
|
||||||
|
#### Required:
|
||||||
|
The below items need to be installed for building and running the samples:
|
||||||
|
* Maven 3
|
||||||
|
* JDK 8
|
||||||
|
* vCenter Server 6.5
|
||||||
|
|
||||||
|
### Building the Samples
|
||||||
|
In the root directory of your folder after cloning the repository, run the below maven commands -
|
||||||
|
|
||||||
|
`mvn initialize`
|
||||||
|
|
||||||
|
`mvn clean install`
|
||||||
|
|
||||||
|
### Running the Samples
|
||||||
|
When running the samples, parameters can be provided either on the command line, in a configuration file (using the --config-file parameter), or a combination of both. The parameter values specified on the command line will override those specified in the configuration file. When using a configuration file, each required parameter for the sample must be specified either in the configuration file or as a command line parameter. Each parameter specified in the configuration file should be in the "key=value" format. For example:
|
||||||
|
|
||||||
|
`vmname=TestVM`
|
||||||
|
|
||||||
|
`cluster=Cluster1`
|
||||||
|
|
||||||
|
Use a command like the following to display usage information for a particular sample.
|
||||||
|
```` bash
|
||||||
|
$java -cp target/samples-6.5.0-jar-with-dependencies.jar vmware.samples.tagging.workflow.TaggingWorkflow
|
||||||
|
|
||||||
|
java -cp target/samples-6.5.0-jar-with-dependencies.jar packagename.SampleClassName [--config-file <CONFIGURATION FILE>]
|
||||||
|
--server <SERVER> --username <USERNAME> --password <PASSWORD> --cluster <CLUSTER> [--truststorepath <ABSOLUTE PATH OF JAVA TRUSTSTORE FILE>]
|
||||||
|
[--truststorepassword <JAVA TRUSTSTORE PASSWORD>] [--cleardata] [--skip-server-verification]
|
||||||
|
|
||||||
|
Sample Options:
|
||||||
|
--config-file <CONFIGURATION FILE> OPTIONAL: Absolute path to the configuration file containing the sample options.
|
||||||
|
NOTE: Parameters can be specified either in the configuration file or on the command
|
||||||
|
line. Command line parameters will override values specified in the configuration file.
|
||||||
|
--server <SERVER> hostname of vCenter Server
|
||||||
|
--username <USERNAME> username to login to the vCenter Server
|
||||||
|
--password <PASSWORD> password to login to the vCenter Server
|
||||||
|
--cluster <CLUSTER> The name of the cluster to be tagged
|
||||||
|
--truststorepath <ABSOLUTE PATH OF JAVA TRUSTSTORE FILE> Specify the absolute path to the file containing the trusted server certificates. This
|
||||||
|
option can be skipped if the parameter skip-server-verification is specified.
|
||||||
|
--truststorepassword <JAVA TRUSTSTORE PASSWORD> Specify the password for the java truststore. This option can be skipped if the
|
||||||
|
parameter skip-server-verification is specified.
|
||||||
|
--cleardata OPTIONAL: Specify this option to undo all persistent results of running the sample.
|
||||||
|
--skip-server-verification OPTIONAL: Specify this option if you do not want to perform SSL certificate
|
||||||
|
verification.
|
||||||
|
NOTE: Circumventing SSL trust in this manner is unsafe and should not be used with
|
||||||
|
production code. This is ONLY FOR THE PURPOSE OF DEVELOPMENT ENVIRONMENT.
|
||||||
|
````
|
||||||
|
|
||||||
|
Use a command like the following to run a sample using only command line parameters:
|
||||||
|
```` bash
|
||||||
|
$java -cp target/samples-6.5.0-jar-with-dependencies.jar vmware.samples.tagging.taggingworkflow.TaggingWorkflow --server servername --username administrator@vsphere.local --password password --cluster vAPISDKCluster --cleardata true --skip-server-verification
|
||||||
|
````
|
||||||
|
|
||||||
|
Use a command like the following to run a sample using only a configuration file:
|
||||||
|
```` bash
|
||||||
|
$java -cp target/samples-6.5.0-jar-with-dependencies.jar vmware.samples.tagging.workflow.TaggingWorkflow --config-file sample.properties
|
||||||
|
````
|
||||||
|
|
||||||
|
Use the following command to run the sample using a combination of configuration file and command line parameters:
|
||||||
|
```` bash
|
||||||
|
$java -cp target/samples-6.5.0-jar-with-dependencies.jar vmware.samples.tagging.workflow.TaggingWorkflow --config-file sample.properties --cluster Cluster1
|
||||||
|
````
|
||||||
|
|
||||||
|
### API Documentation and Programming Guide
|
||||||
|
The API documentation for the samples can be found here :
|
||||||
|
|
||||||
|
The programming guide for vSphere Automation SDK for Java can be found here:
|
||||||
|
|
||||||
|
## Submitting samples
|
||||||
|
The following information must be included in the README.md for each submitted sample.
|
||||||
|
* 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 ?
|
||||||
|
* vSphere version against which the sample was developed/tested
|
||||||
|
* SDK version against which the sample was developed/tested
|
||||||
|
* Java version against which the sample was developed/tested
|
||||||
|
* Any KNOWN limitations or dependencies
|
||||||
|
|
||||||
|
## 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 repository’s 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://developercenter.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.
|
||||||
|
|
||||||
|
## LICENSE AGREEMENT
|
||||||
|
License Agreement: <https://<path to license file>
|
||||||
|
|
||||||
|
# Repository Administrator Resources
|
||||||
|
## Table of Contents
|
||||||
|
* Board Members
|
||||||
|
* Approval of Additions
|
||||||
|
|
||||||
|
## 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:
|
||||||
|
|
||||||
|
## 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
11
bin/run_sample.bat
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
@echo off
|
||||||
|
setlocal ENABLEDELAYEDEXPANSION
|
||||||
|
:: Clear the command-prompt screen
|
||||||
|
cls
|
||||||
|
set SRCDIR=%cd%\..\samples\src
|
||||||
|
set LIBDIR=%cd%\..\lib
|
||||||
|
set PYTHONPATH=%PYTHONPATH%;%SRCDIR%
|
||||||
|
setlocal DisableDelayedExpansion
|
||||||
|
:: Run the sample
|
||||||
|
python %*
|
||||||
|
endlocal
|
13
bin/run_sample.sh
Normal file
13
bin/run_sample.sh
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
SCRIPTDIR=`dirname $0`
|
||||||
|
cd $SCRIPTDIR
|
||||||
|
PATHDIR=`pwd`
|
||||||
|
PROJECT_ROOT=$PATHDIR/..
|
||||||
|
SRCDIR=$PROJECT_ROOT/samples/src
|
||||||
|
LIBDIR=$PROJECT_ROOT/lib
|
||||||
|
|
||||||
|
# add the src directory to the python path
|
||||||
|
export PYTHONPATH=$PYTHONPATH:$SRCDIR
|
||||||
|
|
||||||
|
# run the sample
|
||||||
|
python $@
|
BIN
docs/.DS_Store
vendored
Normal file
BIN
docs/.DS_Store
vendored
Normal file
Binary file not shown.
BIN
docs/client/.DS_Store
vendored
Normal file
BIN
docs/client/.DS_Store
vendored
Normal file
Binary file not shown.
@ -0,0 +1,394 @@
|
|||||||
|
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3c.org/tr/1999/REC-html401-19991224/loose.dtd">
|
||||||
|
<html><head>
|
||||||
|
<title>VMware vSphere Automation Python SDK: client samples README</title>
|
||||||
|
|
||||||
|
<meta content="VMware, Inc. All rights reserved." name="copyright"></meta>
|
||||||
|
<link rel="stylesheet" type="text/css" href="../../docs/resources/template.css"></link>
|
||||||
|
<script src="../../docs/resources/version.js" type="text/javascript"></script>
|
||||||
|
<style type="text/css">
|
||||||
|
|
||||||
|
h4 {
|
||||||
|
padding: 0;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: bold;
|
||||||
|
border-top: 1px solid #dedede;
|
||||||
|
background-color:#E6EDF6;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.Parameter {
|
||||||
|
margin: 0 0 7px 0;
|
||||||
|
width: 100%;
|
||||||
|
font-size: 11px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Code
|
||||||
|
{
|
||||||
|
font-size: 11px; font-family:
|
||||||
|
"Courier New", Courier, monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Console
|
||||||
|
{
|
||||||
|
font-size: 11px; font-family:
|
||||||
|
"Courier New", Courier, monospace;
|
||||||
|
color: #ffffff;
|
||||||
|
font-weight: bold;
|
||||||
|
background: #000000;
|
||||||
|
}
|
||||||
|
.Caption {
|
||||||
|
font-size:11px; line-height:12px; text-transform: uppercase; FONT-WEIGHT: bold; COLOR: #000000; TEXT-DECORATION: none
|
||||||
|
}
|
||||||
|
.Exp {
|
||||||
|
font-size:11px; text-transform: uppercase; FONT-WEIGHT: bold; COLOR: #3366AA;
|
||||||
|
}
|
||||||
|
.Large { font-size: 16px; FONT-WEIGHT: bold; }
|
||||||
|
|
||||||
|
.TableText {
|
||||||
|
FONT-SIZE: 11px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.TableHead {
|
||||||
|
FONT-SIZE: 10px; font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.BoldRedText {
|
||||||
|
FONT-WEIGHT: bold; COLOR: #CC0000; TEXT-DECORATION: none
|
||||||
|
}
|
||||||
|
.BoldBlue {
|
||||||
|
FONT-WEIGHT: bold; COLOR: #3366AA; TEXT-DECORATION: none
|
||||||
|
}
|
||||||
|
.Miniscule {font-size: 9px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Nav {font-size: 11px; COLOR: #3366AA;
|
||||||
|
}
|
||||||
|
.Large { font-size: 16px; FONT-WEIGHT: bold; }
|
||||||
|
</style>
|
||||||
|
|
||||||
|
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<table cellpadding="0" cellspacing="5" id="main-table">
|
||||||
|
<tr><td id="main-body" align="left">
|
||||||
|
<!-- ///*** start of content area ***/// -->
|
||||||
|
|
||||||
|
|
||||||
|
<table width="100%" cellpadding="5">
|
||||||
|
<tr>
|
||||||
|
<td><h1>VMware vSphere Automation Python SDK: client samples README</h1></td>
|
||||||
|
<td align="right">
|
||||||
|
<img src="../../docs/resources/vmware.gif" alt="VMware logo" width="187" height="72" border="0"></img>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<p class="Nav">
|
||||||
|
<img src="../../docs/resources/page.gif" alt="vSphere Automation Python SDK client README" width="13" height="16" border="0"></img>
|
||||||
|
<a href="../vSphere-Automation-Client-SDK-Python-README.html" title="vSphere Automation Python SDK client README...">VMware vSphere Automation Python SDK: client README</a><br />
|
||||||
|
</p>
|
||||||
|
<hr/>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<script type="text/javascript">
|
||||||
|
document.write('This document describes the vSphere Automation Python SDK samples that use the vSphere Automation python client library.')
|
||||||
|
document.write(' (vapi_common_client-' + gVersions.vapiversion + ') ')
|
||||||
|
document.write('and vAPI runtime library')
|
||||||
|
document.write(' (vapi_runtime-' + gVersions.vapiversion + ').')
|
||||||
|
</script>
|
||||||
|
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
|
||||||
|
(<a href="https://github.com/vmware/pyvmomi">pyVmomi</a>)
|
||||||
|
to be installed on the client.
|
||||||
|
The examples have been developed to work with python <strong>2.7</strong>,
|
||||||
|
<strong>3.3</strong>, <strong>3.4</strong> and <strong>3.5</strong>.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
The following sections provide information about using the samples..
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li><a href="#dependencies">Python SDK and 3rd party Library Dependencies</a></li>
|
||||||
|
<li><a href="#packaging">Feature Samples</a></li>
|
||||||
|
<li><a href="#vcentersample">vAPI Samples for Managing vSphere Infrastructure and Virtual Machines</a></li>
|
||||||
|
<li><a href="#cltaggingsample">Content Library and Tagging Samples</a></li>
|
||||||
|
<li><a href="#connectionsample">Connection Workflow Samples</a></li>
|
||||||
|
<li><a href="#runningsample">Running the Samples</a></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
|
||||||
|
<a name="dependencies"></a>
|
||||||
|
<h2>Python SDK and 3rd party Dependencies</h2>
|
||||||
|
<p>
|
||||||
|
Please see the instructions for
|
||||||
|
<a href="../vSphere-Automation-Client-SDK-Python-README.html#installingsdklibs">
|
||||||
|
installing the SDK and 3rd party libraries</a>.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<a name="packaging"></a>
|
||||||
|
<h2>Feature Samples</h2>
|
||||||
|
|
||||||
|
<p> The vSphere Automation Python SDK samples are located in the client sample
|
||||||
|
directory:
|
||||||
|
<strong>samples</strong><br/><br/>
|
||||||
|
The following table shows the sample sub-directories and their contents.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<table border="1" cellpadding="5">
|
||||||
|
<tr><th>Directory</th><th>Description</th></tr>
|
||||||
|
<tr><td>vsphere.samples.common</td><td>Samples common classes and abstractions; This package does NOT contain any sample</td></tr>
|
||||||
|
<tr><td>vsphere.samples.vim.helpers</td><td>Samples and utilities for accessing and manipulating VC objects using pyVmomi</td></tr>
|
||||||
|
<tr><td>vsphere.samples.lookupservice</td><td>Service discovery sample using lookup service APIs</td></tr>
|
||||||
|
<tr><td>vsphere.samples.vcenter</td><td>vAPI samples for managing vSphere infrastructure and virtual machines</td></tr>
|
||||||
|
<tr><td>vsphere.samples.workflow</td><td>Various vAPI work flow samples</td></tr>
|
||||||
|
<tr><td>vsphere.samples.inventory</td><td>Samples for inventory APIs for retrieving information about vCenter datastore and network objects.</td></tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<a name="vcentersample"></a>
|
||||||
|
<h2>vAPI Samples for Managing vSphere Infrastructure and Virtual Machines</h2>
|
||||||
|
<p>
|
||||||
|
The directory vsphere.samples.vcenter contains samples for the vSphere infrastructure and virtual machine APIs.
|
||||||
|
|
||||||
|
You have two options to run samples inside this package:
|
||||||
|
<ol>
|
||||||
|
<li>
|
||||||
|
Run the whole sample suite which contains all vCenter samples using main.py in vsphere.samples.vcenter.setup package. Please see the README in the setup package for detailed steps.
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
Run an individual sample in an existing environment. You can either pass the environment parameters through command line arguments or specify them in setup.py in the setup package.
|
||||||
|
<br/>
|
||||||
|
For example, to run the create_default_vm sample in the vsphere.samples.vcenter.vm.create package:
|
||||||
|
<ul>
|
||||||
|
<li><code>$ cd /path/to/VMware-vSphere-Automation-SDK-Python-<version>/client/bin</code></li>
|
||||||
|
<li>Run the sample with the testbed settings specified in setup.py in a Linux machine:<br/>
|
||||||
|
<code>$ ./run_sample.sh ../samples/src/vsphere/samples/vcenter/vm/create/create_default_vm.py -v</code>
|
||||||
|
</li>
|
||||||
|
<li>Or specify the credentials using command line parameters:<br/>
|
||||||
|
<code>$ ./run_sample.sh ../samples/src/vsphere/samples/vcenter/vm/create/create_default_vm.py -s <server> -u <username> -p <password> -v</code>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</li>
|
||||||
|
</ol>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<a name="cltaggingsample"></a>
|
||||||
|
<h2>Sample Program Structure for the Content Library and Tagging Samples</h2>
|
||||||
|
<p>
|
||||||
|
The Content Library and Tagging samples use a framework to facilitate different
|
||||||
|
aspects of using the samples. Some of the framework capabilities are:
|
||||||
|
<ul>
|
||||||
|
<li>Command line argument parsing.</li>
|
||||||
|
<li>Specifying mandatory and optional arguments for a sample.</li>
|
||||||
|
<li>Sample setup, execution and post-execution cleanup.</li>
|
||||||
|
<li>Information about samples.</li>
|
||||||
|
</ul>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
Each sample extends the class <code>samples_base</code>.
|
||||||
|
This class uses <code>service_manager_factory</code> to create and manage the
|
||||||
|
vAPI service endpoint and vSphere service port. Every sample implements the
|
||||||
|
following methods from the class <code>samples_base</code>:
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li><code>_options()</code> - Called by <code>samples_base</code> during <code>parse_args</code> phase. This occurs during initialization.</li>
|
||||||
|
<li><code>_setup()</code> - Called by <code>samples_base</code> during <code>before</code> phase. This occurs after authentication and vAPI and vSphere service initialization.</li>
|
||||||
|
<li><code>_execute()</code> - Called by <code>samples_base</code> during <code>run</code> phase. At this point all the connections and services are initialized.</li>
|
||||||
|
<li><code>_cleanup()</code> - Called by <code>samples_base</code> during <code>after</code> phase. This occurs before disconnecting the services.</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h3>Samples configuration</h3>
|
||||||
|
You can specify server, username and password in the configuration file
|
||||||
|
(sample.cfg). If you use a configuration file, you can run samples without
|
||||||
|
specifying these options on the command line.
|
||||||
|
When you run a sample, you can override the configuration file values by
|
||||||
|
specifying command line options.
|
||||||
|
|
||||||
|
<pre style="border: 2px solid #A9A9A9; width: 60em; max-width: 60em; background-color:#DCDCDC;">
|
||||||
|
[connection]
|
||||||
|
server=vCenter server IP
|
||||||
|
username=username
|
||||||
|
password=password
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
The sample.cfg file can be found under <code>VMware-vSphere-Automation-SDK-Python-<version>/client/samples/src</code>
|
||||||
|
</br>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<a name="connectionsample"></a>
|
||||||
|
<h2>
|
||||||
|
Connection Workflow Samples:
|
||||||
|
</h2>
|
||||||
|
<p>
|
||||||
|
To work with the VMWare-supported deployment configurations of
|
||||||
|
Platform Services Controllers (Single Sign-On) and vCenter Servers,
|
||||||
|
applications need to dynamically discover service URLs to make service requests.
|
||||||
|
Before making service requests, applications need to authenticate.
|
||||||
|
They can authenticate using a username and password or with a token obtained
|
||||||
|
from the Single Sign-On service.
|
||||||
|
<br/>
|
||||||
|
vApi connection workflow sample performs the following basic steps to connect
|
||||||
|
to the vAPI service endpoint (on a management node).
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li>Step 1: Retrieve the vAPI service endpoint URL from the lookup service.</li>
|
||||||
|
<li>Step 2: Connect to the vAPI service endpoint.</li>
|
||||||
|
<li>Step 3: Use the username/password to login to the vAPI service endpoint.</li>
|
||||||
|
<li>Step 4: Create a vAPI session.</li>
|
||||||
|
<li>Step 5: Validate some of the vAPI services.</li>
|
||||||
|
<li>Step 6: Delete the vAPI session.</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
The call sequence shown above is implemented in the samples framework through the following modules:</br>
|
||||||
|
<ul>
|
||||||
|
<li><code>src/vsphere/samples/common/lookup_service_helper</code> provides methods for discovering management nodes and service endpoint URLs on management nodes from lookup service.</li>
|
||||||
|
<li><code>src/vsphere/samples/common/platform_service_controller</code> uses lookup_service_helper to discover the Single Sign-On URL (on any of the Platform Service Controller node) and then retrieves the SAML token from the Single Sign-On server by authenticating the given user.</li>
|
||||||
|
<li><code>src/vsphere/samples/common/service_manager</code> login to the vAPI and vim service endpoints (on a management node).</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h3>Running the Connection Workflow Samples:</h3>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
The following parameters are needed for running the samples:
|
||||||
|
</p>
|
||||||
|
<ul>
|
||||||
|
<li><code>lswsdlurl</code> -lookup service WSDL file URL. See <a href="#using_wsdl"> Using WSDL</a></li>
|
||||||
|
<li><code>lssoapurl</code> - Platform Service controller's/node's (any, since data is replicated) lookupservice soap URL. Ex: https://psc/lookupservice/sdk</li>
|
||||||
|
<li><code>mgmtinstancename</code> - 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.</li>
|
||||||
|
<li><code>username</code> - username for authentication with the SSO server</li>
|
||||||
|
<li><code>password</code> - password for the SSO user</li>
|
||||||
|
<li><code>skipverification</code> - Do not verify server certificate</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
You can also specify these parameters in the configuration file (sample.cfg).
|
||||||
|
If you use a configuration file, you can run samples without specifying these
|
||||||
|
options on the command line.
|
||||||
|
|
||||||
|
<a name="using_wsdl"></a>
|
||||||
|
<h3>Working with lookup service WSDL</h3>
|
||||||
|
The vSphere Automation SDK for Python samples use the vSphere Automation 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.
|
||||||
|
<br/>
|
||||||
|
The Lookup Service WSDL files are located in the following SDK directory:
|
||||||
|
<br/>
|
||||||
|
<code>VMware-vSphere-Automation-SDK-Python-<version>/client/wsdl</code>.
|
||||||
|
<br/>
|
||||||
|
You must specify the WSDL file location in the <code>client/samples/src/sample.cfg</code> file and in the lookupservice.wsdl file (located in the WSDL directory).
|
||||||
|
|
||||||
|
<ol>
|
||||||
|
<li>In sample.cfg, set 'lswsdlurl' to the lokkupservice WSDL file location. Use a local file URL specification:
|
||||||
|
e.g. lswsdlurl=file:///path/to/the/VMware-vSphere-Automation-SDK-Python-6.5.0/client/wsdl/lookupservice.wsdl</br>
|
||||||
|
(Note: You can also specify the lookup service WSDL path to the sample as a command line option)</li>
|
||||||
|
<li>In lookupservice.wsdl, set 'import location' to the local lookup WSDL file. Use a local file URL specification.
|
||||||
|
<pre>
|
||||||
|
<import location="file:///path/to/the/VMware-vSphere-Automation-SDK-Python-6.5.0/client/wsdl/lookup.wsdl" namespace="urn:lookup" />
|
||||||
|
<service name="LsService">
|
||||||
|
<port binding="interface:LsBinding" name="LsPort">
|
||||||
|
<soap:address location="http://localhost:8080/lookupservice/sdk" />
|
||||||
|
</port>
|
||||||
|
</service>
|
||||||
|
</pre>
|
||||||
|
</li>
|
||||||
|
</ol>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<a name="runningsample"></a>
|
||||||
|
<h2>Running the samples from the command line</h2>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
You can run the samples from command line using the scripts supplied in <code>VMware-vSphere-Automation-SDK-Python-<version>/client/bin</code> directory:
|
||||||
|
</p>
|
||||||
|
Before running the samples:
|
||||||
|
<ol>
|
||||||
|
<li>You must set the <code>PYTHON_HOME</code> environment variable to the base directory for the python 2.7</li>
|
||||||
|
<li>You must install all the dependencies required by the samples on client. See <a href="#dependencies"> Sample Dependencies</a></li>
|
||||||
|
</ol>
|
||||||
|
<p>
|
||||||
|
<strong>Examples:</strong>
|
||||||
|
</p>
|
||||||
|
<pre>
|
||||||
|
$cd /path/to/VMware-vSphere-Automation-SDK-Python-<version>/client/bin
|
||||||
|
$run_sample.sh ../samples/src/vsphere/samples/workflow/connection_workflow.py \
|
||||||
|
-vapiurl https://203.0.113.0/api \
|
||||||
|
-stsurl https://203.0.113.0:443/sts/STSService/vsphere.local \
|
||||||
|
-username administrator@vsphere.local \
|
||||||
|
-password AdminPassword
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
</br>
|
||||||
|
Use the -h option to print information about a sample.
|
||||||
|
The following example shows the help for the vAPI connection workflow sample.
|
||||||
|
<pre>
|
||||||
|
$ ./run_sample.sh ../samples/src/vsphere/samples/workflow/vapi_connection_workflow.py -h
|
||||||
|
usage: vapi_connection_workflow.py [-h] [-w LSWSDLURL] [-s LSSOAPURL]
|
||||||
|
[-m MGMTINSTANCENAME] [-u USERNAME]
|
||||||
|
[-p PASSWORD] [-v]
|
||||||
|
|
||||||
|
Demonstrates vAPI connection and service initialization call flow using the
|
||||||
|
username and password.
|
||||||
|
Step 1: Retrieve the vAPI service endpoint URL from lookup service.
|
||||||
|
Step 2: Connect to the vAPI service endpoint.
|
||||||
|
Step 3: Use the username/password to login to the vAPI service endpoint.
|
||||||
|
Step 4: Create a vAPI session.
|
||||||
|
Step 5: Validate some of the vAPI services.
|
||||||
|
Step 6: Delete the vAPI session.
|
||||||
|
|
||||||
|
optional arguments:
|
||||||
|
-h, --help show this help message and exit
|
||||||
|
-w LSWSDLURL, --lswsdlurl LSWSDLURL
|
||||||
|
Lookup service WSDL URL
|
||||||
|
-s LSSOAPURL, --lssoapurl LSSOAPURL
|
||||||
|
Lookup service SOAP URL
|
||||||
|
-m MGMTINSTANCENAME, --mgmtinstancename MGMTINSTANCENAME
|
||||||
|
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.
|
||||||
|
-u USERNAME, --username USERNAME
|
||||||
|
SSO user name
|
||||||
|
-p PASSWORD, --password PASSWORD
|
||||||
|
SSO user password
|
||||||
|
-v, --skipverification
|
||||||
|
Do not verify server certificate
|
||||||
|
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Note: In the above example <b>mgmtinstancename</b> is optional and can be omitted if there's a single vCenter Server management node in the deployment.
|
||||||
|
When there is more than one management node, the user MUST specify the management node instance name against which the sample needs
|
||||||
|
to run, else the sample throws <b>MultipleManagementNodeException</b>.
|
||||||
|
Example of a multiple management node exception:
|
||||||
|
<pre>
|
||||||
|
raise MultipleManagementNodeException(MultipleManagementNodeException.format(result))
|
||||||
|
vsphere.samples.common.lookup_service_helper.MultipleManagementNodeException: Multiple Management Node Found on server
|
||||||
|
Node name: vcenter-1.example.com uuid: de2afd86-790e-11e4-9c20-0200087f55c6
|
||||||
|
Node name: vcenter-2.example.com uuid: 545da868-7910-11e4-81e1-020008e89d83
|
||||||
|
</pre>
|
||||||
|
Example exception when an invalid management instance name is specified by the user:
|
||||||
|
<pre>
|
||||||
|
ValueError: abc is not a valid management node instance name
|
||||||
|
Available management nodes:
|
||||||
|
Node name: vcenter-2.example.com uuid: 545da868-7910-11e4-81e1-020008e89d83
|
||||||
|
Node name: vcenter-1.example.com uuid: de2afd86-790e-11e4-9c20-0200087f55c6
|
||||||
|
</pre>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
|
||||||
|
<hr />
|
||||||
|
<table border="0" width="100%">
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<p class="Miniscule">Copyright © 2015, 2016 VMware, Inc. All rights not expressly granted herein are reserved.</p>
|
||||||
|
</td>
|
||||||
|
<td align="right"><p class="Miniscule">Last updated: 20 Oct 2016 | VMware vSphere Automation SDK for Python</p></td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
</td></tr></table>
|
||||||
|
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
299
docs/client/vSphere-Automation-Client-SDK-Python-README.html
Normal file
299
docs/client/vSphere-Automation-Client-SDK-Python-README.html
Normal file
@ -0,0 +1,299 @@
|
|||||||
|
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3c.org/tr/1999/REC-html401-19991224/loose.dtd">
|
||||||
|
<html><head>
|
||||||
|
<title>VMware vSphere Automation Python SDK: client README</title>
|
||||||
|
|
||||||
|
<meta content="VMware, Inc. All rights reserved." name="copyright"></meta>
|
||||||
|
<link rel="stylesheet" type="text/css" href="../docs/resources/template.css"></link>
|
||||||
|
<script src="../docs/resources/version.js" type="text/javascript"></script>
|
||||||
|
<style type="text/css">
|
||||||
|
|
||||||
|
h4 {
|
||||||
|
padding: 0;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: bold;
|
||||||
|
border-top: 1px solid #dedede;
|
||||||
|
background-color:#E6EDF6;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.Parameter {
|
||||||
|
margin: 0 0 7px 0;
|
||||||
|
width: 100%;
|
||||||
|
font-size: 11px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Code
|
||||||
|
{
|
||||||
|
font-size: 11px; font-family:
|
||||||
|
"Courier New", Courier, monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Console
|
||||||
|
{
|
||||||
|
font-size: 11px; font-family:
|
||||||
|
"Courier New", Courier, monospace;
|
||||||
|
color: #ffffff;
|
||||||
|
font-weight: bold;
|
||||||
|
background: #000000;
|
||||||
|
}
|
||||||
|
.Caption {
|
||||||
|
font-size:11px; line-height:12px; text-transform: uppercase; FONT-WEIGHT: bold; COLOR: #000000; TEXT-DECORATION: none
|
||||||
|
}
|
||||||
|
.Exp {
|
||||||
|
font-size:11px; text-transform: uppercase; FONT-WEIGHT: bold; COLOR: #3366AA;
|
||||||
|
}
|
||||||
|
.Large { font-size: 16px; FONT-WEIGHT: bold; }
|
||||||
|
|
||||||
|
.TableText {
|
||||||
|
FONT-SIZE: 11px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.TableHead {
|
||||||
|
FONT-SIZE: 10px; font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.BoldRedText {
|
||||||
|
FONT-WEIGHT: bold; COLOR: #CC0000; TEXT-DECORATION: none
|
||||||
|
}
|
||||||
|
.BoldBlue {
|
||||||
|
FONT-WEIGHT: bold; COLOR: #3366AA; TEXT-DECORATION: none
|
||||||
|
}
|
||||||
|
.Miniscule {font-size: 9px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Nav {font-size: 11px; COLOR: #3366AA;
|
||||||
|
}
|
||||||
|
.Large { font-size: 16px; FONT-WEIGHT: bold; }
|
||||||
|
</style>
|
||||||
|
|
||||||
|
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<table cellpadding="0" cellspacing="5" id="main-table">
|
||||||
|
<tr><td id="main-body" align="left">
|
||||||
|
<!-- ///*** start of content area ***/// -->
|
||||||
|
|
||||||
|
|
||||||
|
<table width="100%" cellpadding="5">
|
||||||
|
<tr>
|
||||||
|
<td><h1>VMware vSphere Automation Python SDK: client README</h1></td>
|
||||||
|
<td align="right">
|
||||||
|
<img src="../docs/resources/vmware.gif" alt="VMware logo" width="187" height="72" border="0"></img>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<p class="Nav">
|
||||||
|
<img src="../docs/resources/page.gif" alt="Python SDK client samples README" width="13" height="16" border="0"></img>
|
||||||
|
<a href="samples/vSphere-Automation-Client-SDK-Python-Samples-README.html" title="README for the Python SDK samples...">README for Python SDK samples</a><br />
|
||||||
|
<img src="../docs/resources/page.gif" alt="vSphere Automation Python SDK README" width="13" height="16" border="0"></img>
|
||||||
|
<a href="../vSphere-Automation-SDK-Python-README.html" title="vSphere Automation Python SDK README...">vSphere Automation Python SDK README</a><br />
|
||||||
|
</p>
|
||||||
|
<hr/>
|
||||||
|
|
||||||
|
|
||||||
|
The following section describes the current directory contents:
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li><a href="#packagecontents">Directory structure</a></li>
|
||||||
|
<li><a href="#apidocs">Python SDK API Docs</a></li>
|
||||||
|
<li><a href="#lib">SDK libraries</a></li>
|
||||||
|
<li><a href="#installingsdklibs">Installing SDK and 3rd party libraries</a></li>
|
||||||
|
<li><a href="#runningsample">Running a sample</a></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
<a name="packagecontents"></a>
|
||||||
|
<h2>Directory structure</h2>
|
||||||
|
<p>The vSphere Automation Client SDK for Python provides client bindings, documentation, samples, and WSDL files. The following table shows the client directories and their contents.</p>
|
||||||
|
<table cellpadding="5" cellspacing="0" border="1" width="100%" class="TableText">
|
||||||
|
<tr><th width="15%">Directory</th><th width="35%">Description</th><th width="60%">Contents</th></tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>bin</td>
|
||||||
|
<td>Command scripts for sample execution</td>
|
||||||
|
<td>run_sample.bat</br>run_sample.sh</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>lib</td>
|
||||||
|
<td>VMware python libraries for accessing vSphere Automation services</td>
|
||||||
|
<script type="text/javascript">
|
||||||
|
document.write('<td>')
|
||||||
|
document.write('vapi_runtime-' + gVersions.vapiversion + '.zip' + '</br>')
|
||||||
|
document.write('vapi_common_client-' + gVersions.vapiversion + '.zip' + '</br>')
|
||||||
|
document.write('vapi_client_bindings-' + gVersions.bindingsversion + '.zip' + '</br>')
|
||||||
|
document.write('</td>')
|
||||||
|
</script>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>samples</td>
|
||||||
|
<td>Python samples that demonstrate the use of the vSphere Automation API</td>
|
||||||
|
<td>See the <a href="samples/vSphere-Automation-Client-SDK-Python-Samples-README.html">Python samples README</a><br />
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>wsdl</td>
|
||||||
|
<td>Lookup Service WSDL files.</td>
|
||||||
|
<td>lookup.wsdl<br/>lookupservice.wsdl</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
</table>
|
||||||
|
<br>
|
||||||
|
|
||||||
|
<a name="apidocs"></a>
|
||||||
|
<h2>Python SDK API Docs</h2>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
<strong>apidocs</strong> directory contains the generated python API reference documentation for vSphere Automation features like Content Library and Tagging.
|
||||||
|
The README page also includes a hyperlink to pyVmomi API reference documentation for convenience.
|
||||||
|
Please Refer to <a href="../docs/apidocs/vSphere-Automation-SDK-Python-APIRef-README.html"> vSphere Automation SDK Pythondoc</a> for details.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<a name="lib"></a>
|
||||||
|
<h2>SDK libraries</h2>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
For python developers, client libraries are supplied for testing and development purposes.
|
||||||
|
All the supplied libraries are located under <strong>lib</strong> directory.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<table border="1" cellpadding="5">
|
||||||
|
|
||||||
|
<table cellpadding="5" cellspacing="0" border="1" width="100%" class="TableText">
|
||||||
|
<tr><th width="40%">Name</th><th width="60%">Description</th></tr>
|
||||||
|
<script type="text/javascript">
|
||||||
|
document.write('<tr><td>vapi_runtime-' + gVersions.vapiversion + '</td><td>vAPI runtime responsible for serialization/de-serialization of objects and wire protocol</td></tr>')
|
||||||
|
document.write('<tr><td>vapi_common_client-' + gVersions.vapiversion + '</td><td>vAPI common client code</td></tr>')
|
||||||
|
document.write('<tr><td>vapi_client_bindings-' + gVersions.bindingsversion + '</td><td>client stubs for vSphere Automation APIs</td></tr>')
|
||||||
|
</script>
|
||||||
|
</table>
|
||||||
|
<br>
|
||||||
|
|
||||||
|
<a name="installingsdklibs"></a>
|
||||||
|
<h2>Installing SDK and 3rd party libraries</h2>
|
||||||
|
|
||||||
|
The supplied python libs can be installed using <strong>pip install</strong>;
|
||||||
|
For details on how to install python packages using pip please refer to
|
||||||
|
<a href="http://pip.readthedocs.io/en/latest/user_guide/">pip user guide</a>.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h3>vapi_runtime</h3>
|
||||||
|
<p>
|
||||||
|
This library is needed for accessing features like Content Library and Tagging.
|
||||||
|
</p>
|
||||||
|
<pre>> pip install /path/to/VMware-vSphere-Automation-SDK-Python/client/lib/vapi_runtime-2.5.0.zip</pre>
|
||||||
|
</br>
|
||||||
|
<strong>pyOpenSSL</strong> is required by vapi_runtime. Please see the <a href="#pyopenssl">pyOpenSSL installation</a> steps for details.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h3>vapi_common_client</h3>
|
||||||
|
<p>
|
||||||
|
This library is needed for accessing features like Content Library and Tagging.
|
||||||
|
</p>
|
||||||
|
<pre>> pip install /path/to/VMware-vSphere-Automation-SDK-Python/client/lib/vapi_common_client-2.5.0.zip</pre>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h3>vapi_client_bindings</h3>
|
||||||
|
<p>
|
||||||
|
This library is needed for accessing features like Content Library and Tagging.
|
||||||
|
</p>
|
||||||
|
<pre>> pip install /path/to/VMware-vSphere-Automation-SDK-Python/client/lib/vapi_client_bindings-2.5.0.zip</pre>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h3>pyVmomi</h3>
|
||||||
|
<p>
|
||||||
|
This library is needed for accessing/manipulating vCenter Server managed objects using vSphere APIs;
|
||||||
|
For more information please refer to <a href="https://github.com/vmware/pyvmomi">vmware pyVmomi</a>
|
||||||
|
</p>
|
||||||
|
<pre>> pip install pyvmomi</pre>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<strong>The following 3rd party python libraries are required to be installed for running the sample.</strong>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li>pyOpenSSL</li>
|
||||||
|
<li>lxml</li>
|
||||||
|
<li>suds (suds-jurko for python 3.x)</li>
|
||||||
|
</ul>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<a name="pyopenssl"></a>
|
||||||
|
<h3>pyOpenSSL</h3>
|
||||||
|
<p>
|
||||||
|
This requires python <strong>cryptography</strong> package to be installed as a pre-requisite.</br>
|
||||||
|
Please follow the detailed instruction from <a href="https://cryptography.io/en/latest/installation/">installing cryptography dev documentation</a></br>
|
||||||
|
VMware strongly recommends using openssl version <strong>1.0.1j</strong> or, higher. SDK and samples are tested against openssl version >= 1.0.1j.</br>
|
||||||
|
</br>
|
||||||
|
pyOpenSSL version 0.14 is needed for the SDK (vapi_runtime) and samples. For details on how to install the package please go to
|
||||||
|
<a href="https://pypi.python.org/pypi/pyOpenSSL/0.14">pypi.python.org/pypi/pyOpenSSL/0.14</a>.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h3>lxml</h3>
|
||||||
|
<p>
|
||||||
|
Please follow detailed instructions from <a href="http://lxml.de/installation.html">Installing lxml</a>
|
||||||
|
<pre>> pip install lxml</pre>
|
||||||
|
</p>
|
||||||
|
<h4>Notes for the Windows client</h4>
|
||||||
|
<strong>How to use MinGW's gcc compiler when installing python package using pip?</strong>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li>install MinGW with gcc Compiler option checked</li>
|
||||||
|
<li>add C:\MinGW\bin to your PATH</li>
|
||||||
|
<li><span style="line-height: 1.5em;">In </span><strong>PYTHONPATH\Lib\distutils</strong><span style="line-height: 1.5em;">, create a file </span><strong>distutils.cfg</strong><span style="line-height: 1.5em;"> and add these lines:</span></li>
|
||||||
|
<pre>[build]
|
||||||
|
compiler=mingw32
|
||||||
|
</pre>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
Here's an <strong>alternative</strong> method:
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li>Download Libxml-python (Libxml-python are bindings for the libxml2 and libxslt libraries). Windows 64-bit installer for python 2.7 can be found <a href="http://www.lfd.uci.edu/~gohlke/pythonlibs/">here</a></li>
|
||||||
|
<li>Run the installer to install libxml2 and libxslt</li>
|
||||||
|
<li>Download lxml 3.3.1 windows 64-bit installer for python 2.7. <a href="https://pypi.python.org/packages/2.7/l/lxml/lxml-3.3.1.win-amd64-py2.7.exe#md5=6233aa58eebaa857e1f2a6b2ea71a85c">link</a></li>
|
||||||
|
<li>Run the installer to install lxml</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h3>suds(suds-jurko)</h3>
|
||||||
|
<p>
|
||||||
|
This library is needed for lookup service queries; For more information please refer to <a href="https://fedorahosted.org/suds/wiki/Documentation">suds Documentation</a>
|
||||||
|
</p>
|
||||||
|
<pre>> pip install suds</pre>
|
||||||
|
Use suds-jurko for python 3.x
|
||||||
|
<pre>> pip install suds-jurko</pre>
|
||||||
|
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<a name="runningsample"></a>
|
||||||
|
<h2>Running a sample</h2>
|
||||||
|
|
||||||
|
Please refer to <a href="samples/vSphere-Automation-Client-SDK-Python-Samples-README.html#vcentersample">running a vcenter sample</a> for detailed steps to run a vCenter sample. <br/>
|
||||||
|
Please refer to <a href="samples/vSphere-Automation-Client-SDK-Python-Samples-README.html#runningsample">running a workflow sample</a> for detailed steps to run a vCenter Single Sign-On, Content Library or Tagging sample.
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li><strong>run_sample.sh</strong> is needed for running the samples in UNIX/mac OS X environment</li>
|
||||||
|
<li><strong>run_sample.bat</strong> is a windows bat file needed for running the samples in windows</li>
|
||||||
|
</ul>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<hr />
|
||||||
|
<table border="0" width="100%">
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<p class="Miniscule">Copyright © 2015 VMware, Inc. All rights not expressly granted herein are reserved.</p>
|
||||||
|
</td>
|
||||||
|
<td align="right"><p class="Miniscule">Last updated: 23rd January 2015 | VMware vSphere Automation Python SDK</p></td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
</td></tr></table>
|
||||||
|
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
@ -0,0 +1,117 @@
|
|||||||
|
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3c.org/tr/1999/REC-html401-19991224/loose.dtd">
|
||||||
|
<html><head>
|
||||||
|
<title>VMware vSphere Automation Python SDK: Client API References</title>
|
||||||
|
|
||||||
|
<meta content="VMware, Inc. All rights reserved." name="copyright"></meta>
|
||||||
|
<link rel="stylesheet" type="text/css" href="../resources/template.css"></link>
|
||||||
|
<style type="text/css">
|
||||||
|
|
||||||
|
h4 {
|
||||||
|
padding: 0;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: bold;
|
||||||
|
border-top: 1px solid #dedede;
|
||||||
|
background-color:#E6EDF6;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.Parameter {
|
||||||
|
margin: 0 0 7px 0;
|
||||||
|
width: 100%;
|
||||||
|
font-size: 11px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Code
|
||||||
|
{
|
||||||
|
font-size: 11px; font-family:
|
||||||
|
"Courier New", Courier, monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Console
|
||||||
|
{
|
||||||
|
font-size: 11px; font-family:
|
||||||
|
"Courier New", Courier, monospace;
|
||||||
|
color: #ffffff;
|
||||||
|
font-weight: bold;
|
||||||
|
background: #000000;
|
||||||
|
}
|
||||||
|
.Caption {
|
||||||
|
font-size:11px; line-height:12px; text-transform: uppercase; FONT-WEIGHT: bold; COLOR: #000000; TEXT-DECORATION: none
|
||||||
|
}
|
||||||
|
.Exp {
|
||||||
|
font-size:11px; text-transform: uppercase; FONT-WEIGHT: bold; COLOR: #3366AA;
|
||||||
|
}
|
||||||
|
.Large { font-size: 16px; FONT-WEIGHT: bold; }
|
||||||
|
|
||||||
|
.TableText {
|
||||||
|
FONT-SIZE: 11px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.TableHead {
|
||||||
|
FONT-SIZE: 10px; font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.BoldRedText {
|
||||||
|
FONT-WEIGHT: bold; COLOR: #CC0000; TEXT-DECORATION: none
|
||||||
|
}
|
||||||
|
.BoldBlue {
|
||||||
|
FONT-WEIGHT: bold; COLOR: #3366AA; TEXT-DECORATION: none
|
||||||
|
}
|
||||||
|
.Miniscule {font-size: 9px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Nav {font-size: 11px; COLOR: #3366AA;
|
||||||
|
}
|
||||||
|
.Large { font-size: 16px; FONT-WEIGHT: bold; }
|
||||||
|
</style>
|
||||||
|
|
||||||
|
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<table cellpadding="0" cellspacing="5" id="main-table">
|
||||||
|
<tr><td id="main-body" align="left">
|
||||||
|
<!-- ///*** start of content area ***/// -->
|
||||||
|
|
||||||
|
|
||||||
|
<table width="100%" cellpadding="5">
|
||||||
|
<tr>
|
||||||
|
<td><h1>VMware vSphere Automation Python SDK: Client API References</h1></td>
|
||||||
|
<td align="right">
|
||||||
|
<img src="../resources/vmware.gif" alt="VMware logo" width="187" height="72" border="0"></img>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
|
||||||
|
<p class="Nav">
|
||||||
|
<img src="../resources/page.gif" alt="vSphere Automation SDK for Python Readme" width="13" height="16" border="0"></img>
|
||||||
|
<a href="../../vSphere-Automation-SDK-Python-README.html">README for vSphere Automation SDK for Python</a>.
|
||||||
|
</p>
|
||||||
|
<hr />
|
||||||
|
|
||||||
|
<h2>Python SDK API Docs</h2>
|
||||||
|
<p>
|
||||||
|
<ul>
|
||||||
|
<li><a href="client/py-modindex.html#cap-c">API reference documentation</a> for tagging and content library</li>
|
||||||
|
<li><a href="https://github.com/vmware/pyvmomi/tree/master/docs">pyVmomi API reference documentation</a> for vSpehere API</li>
|
||||||
|
</ul>
|
||||||
|
</p>
|
||||||
|
<hr />
|
||||||
|
<table border="0" width="100%">
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<p class="Miniscule">Copyright © 2015 VMware, Inc. All rights not expressly granted herein are reserved.</p>
|
||||||
|
</td>
|
||||||
|
<td align="right"><p class="Miniscule">Last updated: 23rd January 2015 | VMware vSphere Automation SDK for Python</p></td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
BIN
docs/resources/button_print.gif
Normal file
BIN
docs/resources/button_print.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 91 B |
BIN
docs/resources/page.gif
Normal file
BIN
docs/resources/page.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 109 B |
1770
docs/resources/template.css
Normal file
1770
docs/resources/template.css
Normal file
File diff suppressed because it is too large
Load Diff
BIN
docs/resources/vmware.gif
Normal file
BIN
docs/resources/vmware.gif
Normal file
Binary file not shown.
After Width: | Height: | Size: 2.7 KiB |
206
docs/vSphere-Automation-SDK-Python-README.html
Normal file
206
docs/vSphere-Automation-SDK-Python-README.html
Normal file
@ -0,0 +1,206 @@
|
|||||||
|
<!DOCTYPE html PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3c.org/tr/1999/REC-html401-19991224/loose.dtd">
|
||||||
|
<html><head>
|
||||||
|
<title>VMware vSphere Automation Python SDK README</title>
|
||||||
|
|
||||||
|
<meta content="VMware, Inc. All rights reserved." name="copyright"></meta>
|
||||||
|
<link rel="stylesheet" type="text/css" href="docs/resources/template.css"></link>
|
||||||
|
<style type="text/css">
|
||||||
|
|
||||||
|
h4 {
|
||||||
|
padding: 0;
|
||||||
|
font-size: 12px;
|
||||||
|
font-weight: bold;
|
||||||
|
border-top: 1px solid #dedede;
|
||||||
|
background-color:#E6EDF6;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
.Parameter {
|
||||||
|
margin: 0 0 7px 0;
|
||||||
|
width: 100%;
|
||||||
|
font-size: 11px;
|
||||||
|
font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Code
|
||||||
|
{
|
||||||
|
font-size: 11px; font-family:
|
||||||
|
"Courier New", Courier, monospace;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Console
|
||||||
|
{
|
||||||
|
font-size: 11px; font-family:
|
||||||
|
"Courier New", Courier, monospace;
|
||||||
|
color: #ffffff;
|
||||||
|
font-weight: bold;
|
||||||
|
background: #000000;
|
||||||
|
}
|
||||||
|
.Caption {
|
||||||
|
font-size:11px; line-height:12px; text-transform: uppercase; FONT-WEIGHT: bold; COLOR: #000000; TEXT-DECORATION: none
|
||||||
|
}
|
||||||
|
.Exp {
|
||||||
|
font-size:11px; text-transform: uppercase; FONT-WEIGHT: bold; COLOR: #3366AA;
|
||||||
|
}
|
||||||
|
.Large { font-size: 16px; FONT-WEIGHT: bold; }
|
||||||
|
|
||||||
|
.TableText {
|
||||||
|
FONT-SIZE: 11px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.TableHead {
|
||||||
|
FONT-SIZE: 10px; font-weight: bold;
|
||||||
|
}
|
||||||
|
|
||||||
|
.BoldRedText {
|
||||||
|
FONT-WEIGHT: bold; COLOR: #CC0000; TEXT-DECORATION: none
|
||||||
|
}
|
||||||
|
.BoldBlue {
|
||||||
|
FONT-WEIGHT: bold; COLOR: #3366AA; TEXT-DECORATION: none
|
||||||
|
}
|
||||||
|
.Miniscule {font-size: 9px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.Nav {font-size: 11px; COLOR: #3366AA;
|
||||||
|
}
|
||||||
|
.Large { font-size: 16px; FONT-WEIGHT: bold; }
|
||||||
|
</style>
|
||||||
|
|
||||||
|
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
|
||||||
|
<table cellpadding="0" cellspacing="5" id="main-table">
|
||||||
|
<tr><td id="main-body" align="left">
|
||||||
|
<!-- ///*** start of content area ***/// -->
|
||||||
|
|
||||||
|
|
||||||
|
<table width="100%" cellpadding="5">
|
||||||
|
<tr>
|
||||||
|
<td><h1>VMware vSphere Automation Python SDK README</h1></td>
|
||||||
|
<td align="right">
|
||||||
|
<img src="docs/resources/vmware.gif" alt="VMware logo" width="187" height="72" border="0"></img>
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
<p class="Nav">
|
||||||
|
<img src="docs/resources/page.gif" alt="README for client SDK" width="13" height="16" border="0"></img>
|
||||||
|
<a href="client/vSphere-Automation-Client-SDK-Python-README.html" title="README for client SDK...">README for client SDK</a><br />
|
||||||
|
</p>
|
||||||
|
<hr/>
|
||||||
|
|
||||||
|
<table cellpadding="0" cellspacing="0" width="100%">
|
||||||
|
<tr><td width="50%" vAlign="top">
|
||||||
|
|
||||||
|
|
||||||
|
<p>The <strong>VMware vSphere Automation SDK for Python</strong> enables programmatic access to vSphere.
|
||||||
|
Access to capabilities exposed through the vSphere Web Services API is done using the open-source
|
||||||
|
<a href="https://github.com/vmware/pyvmomi">pyVmomi</a> project. The SDK includes python libraries
|
||||||
|
for accessing new features like Content Library and existing features like Tagging which did not
|
||||||
|
support a public API prior to vSphere 6.5.
|
||||||
|
<br/>
|
||||||
|
The SDK contains samples for the features mentioned above as well as samples to demonstrate how to interoperate with vSphere APIs.
|
||||||
|
If you want to look at the vSphere API samples, please refer to <a href="https://github.com/vmware/pyvmomi-community-samples">pyVmomi community samples</a>.
|
||||||
|
</br>
|
||||||
|
This README contains the following topics:</p>
|
||||||
|
|
||||||
|
<ul>
|
||||||
|
<li><a href="#audience" target="_top">Intended Audience</a></li>
|
||||||
|
<li><a href="#prerequisites" target="_top">Prerequisites</a></li>
|
||||||
|
<li><a href="#systemrequirements" target="_top">System Requirements</a></li>
|
||||||
|
<li><a href="#packagecontents" target="_top">What’s in the SDK Package?</a></li>
|
||||||
|
<li><a href="#resources" target="_top">VMware Resources</a></li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
</td><td vAlign="top" align="right">
|
||||||
|
|
||||||
|
</td></tr></table>
|
||||||
|
|
||||||
|
<a name="audience"></a>
|
||||||
|
<h2><strong>Intended Audience</strong></h2>
|
||||||
|
<p>The VMware vSphere Automation SDK for Python is intended for the following audiences:</p>
|
||||||
|
<ul>
|
||||||
|
<li>Developers who want to write new application(s) for vSphere 6.5.</li>
|
||||||
|
<li>Developers migrating an existing vSphere application to use new features.</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<a name="prerequisites"></a>
|
||||||
|
<h2><strong>Prerequisites</strong></h2>
|
||||||
|
<p>For exercising the samples included in this SDK, you need a vSphere 6.5 deployment.
|
||||||
|
Refer to <a href="https://www.vmware.com/support/pubs/vsphere-esxi-vcenter-server-pubs.html">vSphere product documentation</a>
|
||||||
|
for more information and specific installation and deployment options.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<a name="systemrequirements"></a>
|
||||||
|
<h2><strong>System Requirements</strong></h2>
|
||||||
|
vSphere Automation SDK for Python 6.5 supports python 2.7, 3.3, 3.4 and 3.5</br>
|
||||||
|
Note: VMware strongly recommends using <a href="https://www.openssl.org/">openssl</a> version <strong>1.0.1j or, higher</strong> because of some critical security fixes.</br>
|
||||||
|
Currently we test the SDK and samples on python 2.7, 3.3, 3.4 and 3.5 on these operating systems:</br>
|
||||||
|
<ul>
|
||||||
|
<li>x86-64 RHEL 7</li>
|
||||||
|
<li>64 bit Windows 10</li>
|
||||||
|
<li>OS X 10.11.6 El Capitan</li>
|
||||||
|
</ul>
|
||||||
|
</p>
|
||||||
|
Please see the instructions for <a href="client/vSphere-Automation-Client-SDK-Python-README.html#installingsdklibs">installing the SDK and 3rd party libraries</a>.
|
||||||
|
|
||||||
|
</p>
|
||||||
|
<a name="packagecontents"></a>
|
||||||
|
<h2><strong>What’s in the SDK Package?</strong></h2>
|
||||||
|
<p>The vSphere Automation SDK for Python contains:
|
||||||
|
<ul>
|
||||||
|
<li>Python libraries, API reference documentation for features like Content Library and Tagging.</li>
|
||||||
|
<li>WSDL for lookup service API (required for Service Registration and Discovery).</li>
|
||||||
|
<li>Samples for new features and services which also demonstrate how to interoperate new APIs with vSphere APIs.</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
The following table contains a brief description of the contents of the vSphere Automation SDK for Python.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h3>Directory structure (under VMware-vSphereAutomation-Python-SDK): </h3>
|
||||||
|
|
||||||
|
<table cellpadding="5" cellspacing="0" border="1" width="100%" class="TableText">
|
||||||
|
<tr><th width="15%">Directory</th><th width="60%">Contents</th><th width="35%">Documentation</th></tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>client</td>
|
||||||
|
<td>Client libraries, API documentation and samples</td>
|
||||||
|
<td>
|
||||||
|
<a href="client/vSphere-Automation-Client-SDK-Python-README.html">Client SDK README</a><br />
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
<tr>
|
||||||
|
<td>docs</td>
|
||||||
|
<td>API reference documentation and documentation resource files</td>
|
||||||
|
<td>
|
||||||
|
<a href="docs/apidocs/vSphere-Automation-SDK-Python-APIRef-README.html">Client SDK API Reference Index</a><br />
|
||||||
|
</td>
|
||||||
|
</tr>
|
||||||
|
|
||||||
|
</table>
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<a name="resources"></a>
|
||||||
|
<h2><strong>VMware Resources</strong></h2>
|
||||||
|
<ul>
|
||||||
|
<li><a href="https://developercenter.vmware.com/home">Developer Center</a></li>
|
||||||
|
<li><a href="https://communities.vmware.com/community/vmtn/developer">VMware Developer Community</a> </li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<hr />
|
||||||
|
<table border="0" width="100%">
|
||||||
|
<tr>
|
||||||
|
<td>
|
||||||
|
<p class="Miniscule">Copyright © 2015-2016 VMware, Inc. All rights not expressly granted herein are reserved.</p>
|
||||||
|
</td>
|
||||||
|
<td align="right"><p class="Miniscule">Last updated: 26 Oct 2016 | VMware vSphere Automation Python SDK</p></td>
|
||||||
|
</tr>
|
||||||
|
</table>
|
||||||
|
|
||||||
|
</td></tr></table>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
BIN
lib/vapi_client_bindings-2.5.0.zip
Normal file
BIN
lib/vapi_client_bindings-2.5.0.zip
Normal file
Binary file not shown.
BIN
lib/vapi_common_client-2.5.0.zip
Normal file
BIN
lib/vapi_common_client-2.5.0.zip
Normal file
Binary file not shown.
BIN
lib/vapi_runtime-2.5.0.zip
Normal file
BIN
lib/vapi_runtime-2.5.0.zip
Normal file
Binary file not shown.
BIN
licenses/.DS_Store
vendored
Normal file
BIN
licenses/.DS_Store
vendored
Normal file
Binary file not shown.
200
licenses/SDK-EULA.txt
Normal file
200
licenses/SDK-EULA.txt
Normal file
@ -0,0 +1,200 @@
|
|||||||
|
VMware(r) vSphere Software Development Kit License Agreement
|
||||||
|
|
||||||
|
VMware, Inc. ("VMware") provides the VMware vSphere Software
|
||||||
|
Development Kit (collectively the "Software") to you subject to the
|
||||||
|
following terms and conditions. By downloading, installing, or using
|
||||||
|
the Software, you (the individual or legal entity) agree to be bound by
|
||||||
|
the terms of this license agreement (the "Agreement"). If you disagree
|
||||||
|
with any of the following terms, then do not use the Software.
|
||||||
|
|
||||||
|
1. The Software contains a variety of materials, interface definitions,
|
||||||
|
documentation, sample utility applications and sample code regarding
|
||||||
|
programming interfaces to one or more VMware products that are referenced
|
||||||
|
in such materials (the referenced products, "VMware Products"). This
|
||||||
|
Software is intended to be used to develop software that interacts with the
|
||||||
|
VMware Products.
|
||||||
|
|
||||||
|
2. USE RIGHTS: Subject to the restrictions below, you may download and
|
||||||
|
make a reasonable number of copies of the Software for your use solely for
|
||||||
|
the purpose of creating software that communicates with VMware Products
|
||||||
|
(your software, "Developer Software"). Some code may be designated as
|
||||||
|
"distributable code" and/or "modifiable code" at
|
||||||
|
http://www.vmware.com/go/vwssdk-redistribution-info. You may use and
|
||||||
|
merge all or portions of the "distributable code" with your Developer Software.
|
||||||
|
Any merged portion of any "distributable code" is subject to this Agreement.
|
||||||
|
Additionally, you may modify or create derivative works of all or portions of
|
||||||
|
the "modifiable code." You are permitted to re-distribute the "distributable
|
||||||
|
code" and the modified or derivative works of the "modifiable code" only as
|
||||||
|
part of your Developer Software for non-commercial or commercial use;
|
||||||
|
provided that you shall only distribute such code subject to a license
|
||||||
|
agreement that protects VMware's and its licensors' interests consistent with
|
||||||
|
the terms contained in this Agreement. Open source software components
|
||||||
|
provided with the Software are licensed to you under the terms of the
|
||||||
|
applicable license agreements included with such open source software
|
||||||
|
components. The open source software licenses can be found in the
|
||||||
|
open_source_licenses.txt file, other materials accompanying the Software,
|
||||||
|
the documentation or corresponding source files available at
|
||||||
|
http://www.vmware.com/download/open_source.html.
|
||||||
|
|
||||||
|
3. RESTRICTIONS: You agree that you will not (1) use the Software to
|
||||||
|
create, design or develop anything other than Developer Software; (2) make
|
||||||
|
any more copies of the Software than are reasonably necessary for the
|
||||||
|
authorized use and backup and archival purposes; (3) modify, create
|
||||||
|
derivative works of, reverse engineer, reverse compile, or disassemble the
|
||||||
|
Software except as expressly permitted in Section 2; (4) distribute, sell, lease,
|
||||||
|
rent, lend, or sublicense any part of the Software to any third party except as
|
||||||
|
expressly permitted in Section 2; or (5) use the Software in any manner to (a)
|
||||||
|
circumvent any technical restrictions of VMware Products or violate any
|
||||||
|
additional licensing terms applicable to VMware Products that VMware
|
||||||
|
provides through product documentation, email notification on the VMware
|
||||||
|
website or in the terms of the End User License Agreements; (b) disable,
|
||||||
|
remove, over-ride or modify the display of any VMware Product End User
|
||||||
|
License Agreements that the VMware Products present to the end customers;
|
||||||
|
or (c) upload or otherwise transmit any material containing software viruses or
|
||||||
|
other computer code, files or programs designed to interrupt, destroy, or limit
|
||||||
|
the functionality of any software or hardware.
|
||||||
|
|
||||||
|
The restrictions in this Section 3 shall not apply if and to the extent they
|
||||||
|
contradict mandatory local law (including, but not limited to, law implementing
|
||||||
|
the EC Software Directive).
|
||||||
|
|
||||||
|
4. VMware retains ownership of the Software and all intellectual property
|
||||||
|
rights embodied in the Software, including without limitation all copyrights,
|
||||||
|
trade secrets and patents. You may not remove, delete or modify any of
|
||||||
|
VMware copyright statements in the Software. ALL RIGHTS NOT
|
||||||
|
EXPRESSLY GRANTED HEREUNDER ARE RESERVED TO VMWARE.
|
||||||
|
|
||||||
|
5. You may not use VMware's name, trademarks or service marks in
|
||||||
|
connection with your Developer Software in a way that suggests your
|
||||||
|
Developer Software is certified or endorsed by VMware.
|
||||||
|
|
||||||
|
6. You are not entitled under this Agreement to receive any VMware support
|
||||||
|
or subscription services for the Software or any other services from VMware
|
||||||
|
in connection with the Software. If you have purchased support and/or
|
||||||
|
subscription services for a VMware product, such support and/or subscription
|
||||||
|
services shall not apply to the Software or your use of the Software.
|
||||||
|
|
||||||
|
7. TERM, TERMINATION & CHANGES: This Agreement shall continue as
|
||||||
|
long as you are in compliance with the terms specified herein or until
|
||||||
|
otherwise terminated. You or VMware each may terminate this Agreement for
|
||||||
|
any reason at any time. You agree, upon termination, to destroy all copies of
|
||||||
|
the Software within your possession or control. The Confidential Information,
|
||||||
|
Limitations of Warranties and Liability, and Indemnification sections set out in
|
||||||
|
this Agreement shall survive any termination or expiration of this Agreement.
|
||||||
|
|
||||||
|
8. CONFIDENTIAL INFORMATION: "Confidential Information" means any
|
||||||
|
information disclosed by VMware to you pursuant to this Agreement that is
|
||||||
|
marked "Confidential," "Proprietary," or in some similar manner and any
|
||||||
|
information which you knew or reasonably should have known to be
|
||||||
|
confidential. You shall treat as confidential all Confidential Information of
|
||||||
|
VMware and shall not use such Confidential Information except to exercise
|
||||||
|
your rights or perform your obligations under this Agreement. You will protect
|
||||||
|
Confidential Information from unauthorized use, access, or disclosure in the
|
||||||
|
same manner as you protect your own confidential or proprietary information
|
||||||
|
of a similar nature but with no less than reasonable care. You shall not
|
||||||
|
disclose such Confidential Information to any third party during or after the
|
||||||
|
term of this Agreement. This paragraph will not apply to any Confidential
|
||||||
|
Information that: (a) was rightfully in your possession prior to receipt of such
|
||||||
|
Confidential Information from VMware; (b) is or becomes a matter of public
|
||||||
|
knowledge through no fault of you; (c) is rightfully received from a third party
|
||||||
|
without a duty of confidentiality; (d) is independently developed by you without
|
||||||
|
breach of any confidentiality obligations; (e) is disclosed by you with
|
||||||
|
VMware's prior written approval; or (f) you are required to disclose by
|
||||||
|
applicable law or court order, provided that you notify VMware of such
|
||||||
|
required disclosure promptly in writing and cooperate with VMware in any
|
||||||
|
lawful action to contest or limit the scope of such required disclosure. You
|
||||||
|
acknowledge that breach of this Section 8 will cause irreparable damage to
|
||||||
|
VMware for which monetary damages will be an inadequate remedy.
|
||||||
|
Accordingly, VMware will be entitled to seek and obtain injunctive and any
|
||||||
|
other relief (legal or equitable) to restrain any breach or anticipated breach of
|
||||||
|
this Section 8.
|
||||||
|
|
||||||
|
9. LIMITATIONS OF WARRANTIES & LIABILITY: THE SOFTWARE IS
|
||||||
|
PROVIDED "AS IS" WITHOUT ANY WARRANTIES OF ANY KIND. TO THE
|
||||||
|
MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, VMWARE
|
||||||
|
DISCLAIMS ANY IMPLIED WARRANTIES, INCLUDING, WITHOUT
|
||||||
|
LIMITATION, ANY IMPLIED WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT OF
|
||||||
|
INTELLECTUAL PROPERTY RIGHTS.
|
||||||
|
|
||||||
|
TO THE MAXIMUM EXTENT PERMITTED BY APPLICABLE LAW, IN NO
|
||||||
|
EVENT WILL VMWARE BE LIABLE FOR ANY LOST PROFITS OR
|
||||||
|
BUSINESS OPPORTUNITIES, LOSS OF USE, BUSINESS INTERRUPTION,
|
||||||
|
LOSS OF DATA, OR ANY OTHER INDIRECT, SPECIAL, INCIDENTAL, OR
|
||||||
|
CONSEQUENTIAL DAMAGES ARISING OUT OF THE SOFTWARE OR
|
||||||
|
YOUR USE OF THE SOFTWARE, UNDER ANY THEORY OF LIABILITY,
|
||||||
|
WHETHER BASED IN CONTRACT, TORT, NEGLIGENCE, PRODUCT
|
||||||
|
LIABILITY, OR OTHERWISE. BECAUSE SOME JURISDICTIONS DO NOT
|
||||||
|
ALLOW THE EXCLUSION OR LIMITATION OF LIABILITY FOR
|
||||||
|
CONSEQUENTIAL OR INCIDENTAL DAMAGES, THE PRECEDING
|
||||||
|
LIMITATION MAY NOT APPLY TO YOU.
|
||||||
|
|
||||||
|
VMWARE'S LIABILITY ARISING OUT OF THIS AGREEMENT AND THE
|
||||||
|
SOFTWARE PROVIDED HEREUNDER WILL NOT, IN ANY EVENT,
|
||||||
|
EXCEED US$100.00.
|
||||||
|
|
||||||
|
THE FOREGOING LIMITATIONS SHALL APPLY TO THE MAXIMUM
|
||||||
|
EXTENT PERMITTED BY APPLICABLE LAW, REGARDLESS OF
|
||||||
|
WHETHER VMWARE HAS BEEN ADVISED OF THE POSSIBILITY OF
|
||||||
|
SUCH DAMAGES AND REGARDLESS OF WHETHER ANY REMEDY
|
||||||
|
FAILS OF ITS ESSENTIAL PURPOSE.
|
||||||
|
|
||||||
|
10. INDEMNIFICATION: You agree to defend, indemnify and hold harmless
|
||||||
|
VMware, and any of its directors, officers, employees, affiliates and agents,
|
||||||
|
from and against any and all claims, losses, damages, liabilities and other
|
||||||
|
expenses (including reasonable attorneys' fees), arising from your
|
||||||
|
modification of the "modifiable code," the distribution or use of your Developer
|
||||||
|
Software by you or anyone else, and your breach of this Agreement.
|
||||||
|
|
||||||
|
11. EXPORT CONTROL: You acknowledge that the Software is of United
|
||||||
|
States origin, is provided subject to the U.S. Export Administration
|
||||||
|
Regulations, may be subject to the export control laws of the applicable
|
||||||
|
territory, and that diversion contrary to applicable export control laws is
|
||||||
|
prohibited. You represent, warrant and covenant that (1) you are not, and are
|
||||||
|
not acting on behalf of, (a) any person who is a citizen, national, or resident
|
||||||
|
of, or who is controlled by the government of any country to which the United
|
||||||
|
States has prohibited export transactions; or (b) any person or entity listed on
|
||||||
|
the U.S. Treasury Department list of Specially Designated Nationals and
|
||||||
|
Blocked Persons, or the U.S. Commerce Department Denied Persons List or
|
||||||
|
Entity List; and (2) you will not permit the Software to be used for any
|
||||||
|
purposes prohibited by law, including, any prohibited development, design,
|
||||||
|
manufacture or production of missiles or nuclear, chemical or biological
|
||||||
|
weapons.
|
||||||
|
|
||||||
|
12. DATA PRIVACY:
|
||||||
|
|
||||||
|
(a) Consent for Collection and Use of Technical Data. You agree
|
||||||
|
that VMware may periodically collect, process and store technical
|
||||||
|
and related information about your device, system, application,
|
||||||
|
peripherals and your use of the Software, including without
|
||||||
|
limitation: internet protocol address, hardware identification,
|
||||||
|
operating system, application software, peripheral hardware,
|
||||||
|
number of active plugins and software development kits, the
|
||||||
|
successful installation and launch of Software, and Software usage
|
||||||
|
statistics (collectively, "Technical Data"). VMware will use Technical
|
||||||
|
Data for internal statistical and analytical purposes to facilitate
|
||||||
|
support, invoicing or online services, the provisioning of updates,
|
||||||
|
and the development of VMware products and services. VMware
|
||||||
|
may transfer Technical Data to other companies in the VMware
|
||||||
|
worldwide group of companies from time to time.
|
||||||
|
|
||||||
|
(b) Log Files. You acknowledge that correspondence and log files
|
||||||
|
generated in conjunction with a request for support services may
|
||||||
|
contain sensitive, confidential or personal information. You are
|
||||||
|
solely responsible for taking the steps necessary to protect such
|
||||||
|
data, including obfuscating the logs or otherwise guarding such
|
||||||
|
information prior to sending it to VMware.
|
||||||
|
|
||||||
|
13. These terms are governed by the laws of the State of California and the
|
||||||
|
United States of America without regard to conflict of laws principles. The
|
||||||
|
United Nations Convention for the International Sale of Goods shall not apply.
|
||||||
|
You may not assign this Agreement. Any attempted assignment by you shall
|
||||||
|
be void. These terms constitute the entire agreement between you and
|
||||||
|
VMware with respect to the Software and supersede all prior written or oral
|
||||||
|
communications, understandings and agreements. Any waiver of these terms
|
||||||
|
must be in writing and signed by the waiving party to be effective. If any
|
||||||
|
provision of these terms is found to be invalid or unenforceable, the remaining
|
||||||
|
terms will continue to be valid and enforceable to the fullest extent permitted
|
||||||
|
by law.
|
||||||
|
|
||||||
|
|
BIN
samples/resources/isoImages/test-2.iso
Normal file
BIN
samples/resources/isoImages/test-2.iso
Normal file
Binary file not shown.
BIN
samples/resources/isoImages/test.iso
Normal file
BIN
samples/resources/isoImages/test.iso
Normal file
Binary file not shown.
115
samples/resources/plainVmTemplate/plain-vm.ovf
Normal file
115
samples/resources/plainVmTemplate/plain-vm.ovf
Normal 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>
|
BIN
samples/resources/plainVmTemplate/plain-vm.vmdk
Normal file
BIN
samples/resources/plainVmTemplate/plain-vm.vmdk
Normal file
Binary file not shown.
18
samples/resources/simpleVmTemplate/descriptor.ovf
Normal file
18
samples/resources/simpleVmTemplate/descriptor.ovf
Normal 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>
|
BIN
samples/resources/simpleVmTemplate/disk-0.vmdk
Normal file
BIN
samples/resources/simpleVmTemplate/disk-0.vmdk
Normal file
Binary file not shown.
44
samples/src/logging.conf
Normal file
44
samples/src/logging.conf
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
[loggers]
|
||||||
|
keys=root,suds
|
||||||
|
|
||||||
|
[logger_root]
|
||||||
|
level=NOTSET
|
||||||
|
handlers=console,file
|
||||||
|
|
||||||
|
[logger_suds]
|
||||||
|
level=INFO
|
||||||
|
handlers=console,file
|
||||||
|
qualname=suds
|
||||||
|
propagate=0
|
||||||
|
|
||||||
|
[formatters]
|
||||||
|
keys=simple,complex
|
||||||
|
|
||||||
|
[formatter_simple]
|
||||||
|
format=%(asctime)s %(levelname)-8s %(name)-15s %(message)s
|
||||||
|
|
||||||
|
[formatter_complex]
|
||||||
|
format=%(asctime)s %(levelname)-8s %(name)-15s [%(module)s, %(lineno)d] %(message)s
|
||||||
|
|
||||||
|
[handlers]
|
||||||
|
keys=file,console
|
||||||
|
|
||||||
|
[handler_file]
|
||||||
|
class=handlers.TimedRotatingFileHandler
|
||||||
|
interval=midnight
|
||||||
|
backupCount=5
|
||||||
|
formatter=complex
|
||||||
|
level=DEBUG
|
||||||
|
args=('/tmp/vsphereautomationpythonsdksamples.log',)
|
||||||
|
|
||||||
|
[handler_console]
|
||||||
|
class=StreamHandler
|
||||||
|
formatter=simple
|
||||||
|
level=INFO
|
||||||
|
args=(sys.stdout,)
|
||||||
|
|
||||||
|
[vmware.vapi.protocol.client.msg.json_connector]
|
||||||
|
processors=vmware.vapi.dsig.jsonlib.JSONSSOSigner
|
||||||
|
|
||||||
|
[vmware.vapi.protocol.server.msg.json_handler]
|
||||||
|
processors=vmware.vapi.dsig.jsonlib.JSONSSOVerifier
|
5
samples/src/sample.cfg
Normal file
5
samples/src/sample.cfg
Normal file
@ -0,0 +1,5 @@
|
|||||||
|
[connection]
|
||||||
|
lswsdlurl=file:///path/to/the/VMware-vSphere-Automation-SDK-Python-<version>/client/wsdl/lookupservice.wsdl
|
||||||
|
lssoapurl=https://myserver.mydomain.com/lookupservice/sdk
|
||||||
|
ssousername=admin
|
||||||
|
ssopassword=adminpassword
|
8
samples/src/vsphere/__init__.py
Normal file
8
samples/src/vsphere/__init__.py
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
# 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
|
8
samples/src/vsphere/samples/__init__.py
Normal file
8
samples/src/vsphere/samples/__init__.py
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
# 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
|
8
samples/src/vsphere/samples/common/__init__.py
Normal file
8
samples/src/vsphere/samples/common/__init__.py
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
# 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
|
41
samples/src/vsphere/samples/common/id_generator.py
Normal file
41
samples/src/vsphere/samples/common/id_generator.py
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
"""
|
||||||
|
* *******************************************************
|
||||||
|
* 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()
|
37
samples/src/vsphere/samples/common/logging_context.py
Normal file
37
samples/src/vsphere/samples/common/logging_context.py
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
"""
|
||||||
|
* *******************************************************
|
||||||
|
* 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'
|
||||||
|
__copyright__ = 'Copyright 2013 VMware, Inc. All rights reserved.'
|
||||||
|
|
||||||
|
from os import path
|
||||||
|
import logging.config
|
||||||
|
|
||||||
|
|
||||||
|
class LoggingContext(object):
|
||||||
|
logging.config.fileConfig(path.join(path.dirname(path.realpath(__file__)), '../../../logging.conf'), disable_existing_loggers=False)
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_logger(cls, name):
|
||||||
|
return logging.getLogger(name)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
logger = LoggingContext.get_logger(__name__)
|
||||||
|
logger.critical('critical')
|
||||||
|
logger.info('info')
|
||||||
|
logger.debug('debug')
|
||||||
|
|
||||||
|
# Start program
|
||||||
|
# just for testing
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
350
samples/src/vsphere/samples/common/lookup_service_helper.py
Normal file
350
samples/src/vsphere/samples/common/lookup_service_helper.py
Normal file
@ -0,0 +1,350 @@
|
|||||||
|
"""
|
||||||
|
* *******************************************************
|
||||||
|
* 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
|
||||||
|
from vsphere.samples.common.logging_context import LoggingContext
|
||||||
|
|
||||||
|
logger = LoggingContext.get_logger('vsphere.samples.common.lookup_service_helper')
|
||||||
|
|
||||||
|
|
||||||
|
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
|
||||||
|
logger.info(self.client)
|
||||||
|
self.client.set_options(service='LsService', port='LsPort')
|
||||||
|
|
||||||
|
self.managedObjectReference = self.client.factory.create('ns0:ManagedObjectReference')
|
||||||
|
self.managedObjectReference._type = 'LookupServiceInstance'
|
||||||
|
self.managedObjectReference.value = 'ServiceInstance'
|
||||||
|
logger.debug(self.managedObjectReference)
|
||||||
|
|
||||||
|
lookupServiceContent = self.client.service.RetrieveServiceContent(self.managedObjectReference)
|
||||||
|
logger.debug(lookupServiceContent)
|
||||||
|
|
||||||
|
self.serviceRegistration = lookupServiceContent.serviceRegistration
|
||||||
|
logger.info(self.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)
|
||||||
|
logger.debug(lookupServiceRegistrationFilter)
|
||||||
|
|
||||||
|
result = self.client.service.List(self.serviceRegistration, lookupServiceRegistrationFilter)
|
||||||
|
logger.debug(result)
|
||||||
|
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)
|
||||||
|
logger.debug(lookupServiceRegistrationFilter)
|
||||||
|
|
||||||
|
result = self.client.service.List(self.serviceRegistration, lookupServiceRegistrationFilter)
|
||||||
|
logger.debug(result)
|
||||||
|
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'
|
||||||
|
logger.debug(lookupServiceRegistrationServiceType)
|
||||||
|
|
||||||
|
lookupServiceRegistrationEndpointType = self.client.factory.create('ns0:LookupServiceRegistrationEndpointType')
|
||||||
|
lookupServiceRegistrationEndpointType.type = 'com.vmware.vim'
|
||||||
|
lookupServiceRegistrationEndpointType.protocol = 'vmomi'
|
||||||
|
logger.debug(lookupServiceRegistrationEndpointType)
|
||||||
|
|
||||||
|
lookupServiceRegistrationFilter = self.client.factory.create('ns0:LookupServiceRegistrationFilter')
|
||||||
|
lookupServiceRegistrationFilter.serviceType = lookupServiceRegistrationServiceType
|
||||||
|
lookupServiceRegistrationFilter.endpointType = lookupServiceRegistrationEndpointType
|
||||||
|
logger.debug(lookupServiceRegistrationFilter)
|
||||||
|
|
||||||
|
result = self.client.service.List(self.serviceRegistration, lookupServiceRegistrationFilter)
|
||||||
|
logger.debug(result)
|
||||||
|
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()
|
@ -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 vsphere.samples.common import sso
|
||||||
|
from vmware.vapi.security.sso import create_saml_bearer_security_context
|
||||||
|
from vsphere.samples.common.lookup_service_helper import LookupServiceHelper
|
||||||
|
from vsphere.samples.common.logging_context import LoggingContext
|
||||||
|
from vsphere.samples.common.ssl_helper import get_unverified_context
|
||||||
|
|
||||||
|
logger = LoggingContext.get_logger('vsphere.samples.common.platform_service_controller')
|
||||||
|
|
||||||
|
|
||||||
|
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
|
||||||
|
"""
|
||||||
|
logger.info('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
|
||||||
|
|
||||||
|
logger.info('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)
|
114
samples/src/vsphere/samples/common/sample_base.py
Normal file
114
samples/src/vsphere/samples/common/sample_base.py
Normal file
@ -0,0 +1,114 @@
|
|||||||
|
"""
|
||||||
|
* *******************************************************
|
||||||
|
* 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 vsphere.samples.common.service_manager_factory import ServiceManagerFactory
|
||||||
|
from vsphere.samples.common.logging_context import LoggingContext
|
||||||
|
from vsphere.samples.common.sample_config import SampleConfig
|
||||||
|
|
||||||
|
logger = LoggingContext.get_logger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
if self.args.server is None:
|
||||||
|
self.server = SampleConfig.get_server_url() # look for server IP in the sample config
|
||||||
|
else:
|
||||||
|
self.server = self.args.server
|
||||||
|
assert self.server is not None
|
||||||
|
logger.info('server: {0}'.format(self.server))
|
||||||
|
|
||||||
|
if self.args.username is None:
|
||||||
|
self.username = SampleConfig.get_username() # look for username in the sample config
|
||||||
|
else:
|
||||||
|
self.username = self.args.username
|
||||||
|
assert self.username is not None
|
||||||
|
|
||||||
|
if self.args.password is None:
|
||||||
|
self.password = SampleConfig.get_password() # look for password in the sample config
|
||||||
|
else:
|
||||||
|
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.
|
||||||
|
logger.exception(e)
|
||||||
|
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)
|
50
samples/src/vsphere/samples/common/sample_cli.py
Normal file
50
samples/src/vsphere/samples/common/sample_cli.py
Normal file
@ -0,0 +1,50 @@
|
|||||||
|
"""
|
||||||
|
* *******************************************************
|
||||||
|
* 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.
|
||||||
|
"""
|
||||||
|
|
||||||
|
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
|
55
samples/src/vsphere/samples/common/sample_config.py
Normal file
55
samples/src/vsphere/samples/common/sample_config.py
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
"""
|
||||||
|
* *******************************************************
|
||||||
|
* 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 os import path
|
||||||
|
try:
|
||||||
|
import configparser
|
||||||
|
except ImportError:
|
||||||
|
import ConfigParser as configparser
|
||||||
|
|
||||||
|
|
||||||
|
class SampleConfig(object):
|
||||||
|
config = configparser.RawConfigParser()
|
||||||
|
config.read(path.join(path.dirname(path.realpath(__file__)), '../../../sample.cfg'))
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_sample_config(cls):
|
||||||
|
return cls.config
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_server_url(cls):
|
||||||
|
config = SampleConfig.get_sample_config()
|
||||||
|
return config.get('connection', 'server')
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_username(cls):
|
||||||
|
config = SampleConfig.get_sample_config()
|
||||||
|
return config.get('connection', 'username')
|
||||||
|
|
||||||
|
@classmethod
|
||||||
|
def get_password(cls):
|
||||||
|
config = SampleConfig.get_sample_config()
|
||||||
|
return config.get('connection', 'password')
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
print('serverurl: {0}'.format(SampleConfig.get_server_url()))
|
||||||
|
print('username: {0}'.format(SampleConfig.get_username()))
|
||||||
|
print('password: {0}'.format(SampleConfig.get_password()))
|
||||||
|
|
||||||
|
# Start program
|
||||||
|
# just for testing
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
166
samples/src/vsphere/samples/common/sample_util.py
Normal file
166
samples/src/vsphere/samples/common/sample_util.py
Normal file
@ -0,0 +1,166 @@
|
|||||||
|
"""
|
||||||
|
* *******************************************************
|
||||||
|
* 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.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from six.moves import cStringIO
|
||||||
|
from vmware.vapi.bindings.struct import PrettyPrinter
|
||||||
|
|
||||||
|
from vsphere.samples.common import sample_cli
|
||||||
|
from vsphere.samples.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("Using vm name({}) specified in testbed.py".format(vm_name))
|
||||||
|
if not vm_name:
|
||||||
|
exit("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:
|
||||||
|
exit("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:
|
||||||
|
exit("vc user is required")
|
||||||
|
print("vc user = {}".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)
|
70
samples/src/vsphere/samples/common/service_manager.py
Normal file
70
samples/src/vsphere/samples/common/service_manager.py
Normal file
@ -0,0 +1,70 @@
|
|||||||
|
"""
|
||||||
|
* *******************************************************
|
||||||
|
* 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 vsphere.samples.common import vapiconnect
|
||||||
|
from vsphere.samples.common.logging_context import LoggingContext
|
||||||
|
from vsphere.samples.common.ssl_helper import get_unverified_context
|
||||||
|
|
||||||
|
logger = LoggingContext.get_logger('vsphere.samples.common.service_manager')
|
||||||
|
|
||||||
|
|
||||||
|
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):
|
||||||
|
logger.info('disconnecting the session')
|
||||||
|
vapiconnect.logout(self.stub_config)
|
||||||
|
Disconnect(self.si)
|
||||||
|
|
@ -0,0 +1,40 @@
|
|||||||
|
"""
|
||||||
|
* *******************************************************
|
||||||
|
* 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 vsphere.samples.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)
|
24
samples/src/vsphere/samples/common/ssl_helper.py
Normal file
24
samples/src/vsphere/samples/common/ssl_helper.py
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
"""
|
||||||
|
* *******************************************************
|
||||||
|
* 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.
|
||||||
|
"""
|
||||||
|
|
||||||
|
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
|
538
samples/src/vsphere/samples/common/sso.py
Normal file
538
samples/src/vsphere/samples/common/sso.py
Normal file
@ -0,0 +1,538 @@
|
|||||||
|
"""
|
||||||
|
* *******************************************************
|
||||||
|
* 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 re
|
||||||
|
import cgi
|
||||||
|
import sys
|
||||||
|
import time
|
||||||
|
import base64
|
||||||
|
import hashlib
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
from vsphere.samples.common.ssl_helper import get_unverified_context
|
||||||
|
|
||||||
|
# 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>"""
|
91
samples/src/vsphere/samples/common/vapiconnect.py
Normal file
91
samples/src/vsphere/samples/common/vapiconnect.py
Normal 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.
|
||||||
|
"""
|
||||||
|
|
||||||
|
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 configuraiton 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.
|
||||||
|
"""
|
||||||
|
session_svc = Session(stub_config)
|
||||||
|
session_svc.delete()
|
||||||
|
|
||||||
|
|
||||||
|
def create_unverified_session(session, suppress_warning):
|
||||||
|
"""
|
||||||
|
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
|
31
samples/src/vsphere/samples/contentlibrary/README.md
Normal file
31
samples/src/vsphere/samples/contentlibrary/README.md
Normal 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/VMware-vSphere-Automation-SDK-Python-<version>/client/bin
|
||||||
|
* $ ./run_sample.sh ../samples/src/vsphere/samples/contentlibrary/<sample-dir>/<sample>.py --server <vCenter Server IP> --name <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
|
||||||
|
|
25
samples/src/vsphere/samples/contentlibrary/__init__.py
Normal file
25
samples/src/vsphere/samples/contentlibrary/__init__.py
Normal 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. -- VMware Confidential'
|
||||||
|
|
||||||
|
|
||||||
|
# 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
|
@ -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. -- VMware Confidential'
|
||||||
|
|
||||||
|
|
||||||
|
# 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
|
@ -0,0 +1,177 @@
|
|||||||
|
#!/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.
|
||||||
|
"""
|
||||||
|
|
||||||
|
try:
|
||||||
|
import urllib2
|
||||||
|
except ImportError:
|
||||||
|
import urllib.request as urllib2
|
||||||
|
|
||||||
|
from com.vmware.content.library.item_client import UpdateSessionModel
|
||||||
|
from vsphere.samples.common.id_generator import generate_random_uuid
|
||||||
|
from vsphere.samples.common.logging_context import LoggingContext
|
||||||
|
from vsphere.samples.common.sample_base import SampleBase
|
||||||
|
from vsphere.samples.contentlibrary.lib.cls_api_client import ClsApiClient
|
||||||
|
from vsphere.samples.contentlibrary.lib.cls_api_helper import ClsApiHelper
|
||||||
|
|
||||||
|
__author__ = 'VMware, Inc.'
|
||||||
|
__copyright__ = 'Copyright 2016 VMware, Inc. All rights reserved.'
|
||||||
|
|
||||||
|
logger = LoggingContext.get_logger('vsphere.samples.contentlibrary.content_update')
|
||||||
|
|
||||||
|
|
||||||
|
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')
|
||||||
|
logger.info('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)
|
||||||
|
logger.info('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)
|
||||||
|
logger.info('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
|
||||||
|
logger.info('Library item created id: {0}'.format(ovf_item_id))
|
||||||
|
logger.info('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)
|
||||||
|
logger.info('Uploaded ovf and vmdk files to library item {0}'.format(ovf_item_id))
|
||||||
|
original_version = self.get_item_version(ovf_item_id)
|
||||||
|
logger.info('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:
|
||||||
|
logger.info('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)
|
||||||
|
logger.info('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)
|
||||||
|
logger.info('Deleted Library Id: {0}'.format(self.local_library.id))
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
content_update_sample = ContentUpdate()
|
||||||
|
content_update_sample.main()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
25
samples/src/vsphere/samples/contentlibrary/crud/__init__.py
Normal file
25
samples/src/vsphere/samples/contentlibrary/crud/__init__.py
Normal 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. -- VMware Confidential'
|
||||||
|
|
||||||
|
|
||||||
|
# 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
|
118
samples/src/vsphere/samples/contentlibrary/crud/library_crud.py
Normal file
118
samples/src/vsphere/samples/contentlibrary/crud/library_crud.py
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
#!/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.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
from com.vmware.content_client import LibraryModel
|
||||||
|
from com.vmware.content.library_client import StorageBacking
|
||||||
|
|
||||||
|
from vsphere.samples.common.id_generator import generate_random_uuid
|
||||||
|
from vsphere.samples.common.sample_base import SampleBase
|
||||||
|
from vsphere.samples.common.logging_context import LoggingContext
|
||||||
|
from vsphere.samples.contentlibrary.lib.cls_api_client import ClsApiClient
|
||||||
|
from vsphere.samples.vim.helpers.get_datastore_by_name import get_datastore_id
|
||||||
|
|
||||||
|
|
||||||
|
__author__ = 'VMware, Inc.'
|
||||||
|
__copyright__ = 'Copyright 2016 VMware, Inc. All rights reserved. -- VMware Confidential'
|
||||||
|
|
||||||
|
|
||||||
|
logger = LoggingContext.get_logger('vsphere.samples.contentlibrary')
|
||||||
|
|
||||||
|
|
||||||
|
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)
|
||||||
|
logger.info('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
|
||||||
|
logger.info('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())
|
||||||
|
logger.info('Local library created: ID: {0}'.format(library_id))
|
||||||
|
|
||||||
|
# Retrieve the local content library
|
||||||
|
self.local_library = self.client.local_library_service.get(library_id)
|
||||||
|
logger.info('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)
|
||||||
|
logger.info('Updated library description')
|
||||||
|
|
||||||
|
def _cleanup(self):
|
||||||
|
if self.local_library:
|
||||||
|
self.client.local_library_service.delete(library_id=self.local_library.id)
|
||||||
|
logger.info('Deleted Library Id: {0}'.format(self.local_library.id))
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
sample = LibraryCrud()
|
||||||
|
sample.main()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
|
|
@ -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. -- VMware Confidential'
|
||||||
|
|
||||||
|
|
||||||
|
# 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
|
108
samples/src/vsphere/samples/contentlibrary/isomount/iso_mount.py
Normal file
108
samples/src/vsphere/samples/contentlibrary/isomount/iso_mount.py
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
#!/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.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
import os
|
||||||
|
|
||||||
|
from vsphere.samples.common.sample_base import SampleBase
|
||||||
|
from vsphere.samples.common.logging_context import LoggingContext
|
||||||
|
from vsphere.samples.contentlibrary.lib.cls_api_client import ClsApiClient
|
||||||
|
from vsphere.samples.contentlibrary.lib.cls_api_helper import ClsApiHelper
|
||||||
|
from vsphere.samples.vcenter.helper.vm_helper import get_vm
|
||||||
|
|
||||||
|
|
||||||
|
__author__ = 'VMware, Inc.'
|
||||||
|
__copyright__ = 'Copyright 2016 VMware, Inc. All rights reserved.'
|
||||||
|
|
||||||
|
|
||||||
|
logger = LoggingContext.get_logger('vsphere.samples.contentlibrary.iso_mount')
|
||||||
|
|
||||||
|
|
||||||
|
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
|
||||||
|
logger.info('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)
|
||||||
|
logger.info('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)
|
||||||
|
logger.info('Deleted Library Id: {0}'.format(self.local_library.id))
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
iso_mount_sample = IsoMount()
|
||||||
|
iso_mount_sample.main()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
25
samples/src/vsphere/samples/contentlibrary/lib/__init__.py
Normal file
25
samples/src/vsphere/samples/contentlibrary/lib/__init__.py
Normal 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. -- VMware Confidential'
|
||||||
|
|
||||||
|
|
||||||
|
# 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
|
@ -0,0 +1,78 @@
|
|||||||
|
"""
|
||||||
|
* *******************************************************
|
||||||
|
* 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.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
|
||||||
|
__author__ = 'VMware, Inc.'
|
||||||
|
__copyright__ = 'Copyright 2016 VMware, Inc. All rights reserved.'
|
||||||
|
|
||||||
|
|
||||||
|
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
|
253
samples/src/vsphere/samples/contentlibrary/lib/cls_api_helper.py
Normal file
253
samples/src/vsphere/samples/contentlibrary/lib/cls_api_helper.py
Normal file
@ -0,0 +1,253 @@
|
|||||||
|
"""
|
||||||
|
* *******************************************************
|
||||||
|
* 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.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import os
|
||||||
|
import time
|
||||||
|
import ssl
|
||||||
|
|
||||||
|
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 vsphere.samples.common.id_generator import generate_random_uuid
|
||||||
|
from vsphere.samples.common.logging_context import LoggingContext
|
||||||
|
from vsphere.samples.vim.helpers.get_datastore_by_name import get_datastore_id
|
||||||
|
|
||||||
|
__author__ = 'VMware, Inc.'
|
||||||
|
__copyright__ = 'Copyright 2016 VMware, Inc. All rights reserved.'
|
||||||
|
|
||||||
|
logger = LoggingContext.get_logger('vsphere.samples.contentlibrary.lib')
|
||||||
|
|
||||||
|
|
||||||
|
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())
|
||||||
|
logger.info('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
|
||||||
|
logger.info('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)
|
||||||
|
logger.info('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))
|
@ -0,0 +1,115 @@
|
|||||||
|
import time
|
||||||
|
|
||||||
|
__author__ = 'VMware, Inc.'
|
||||||
|
__copyright__ = 'Copyright 2016 VMware, Inc. All rights reserved.'
|
||||||
|
|
||||||
|
|
||||||
|
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 != None:
|
||||||
|
if (sub_lib.last_sync_time == 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
|
@ -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. -- VMware Confidential'
|
||||||
|
|
||||||
|
|
||||||
|
# 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
|
@ -0,0 +1,161 @@
|
|||||||
|
#!/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.
|
||||||
|
"""
|
||||||
|
|
||||||
|
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 vsphere.samples.common.id_generator import generate_random_uuid
|
||||||
|
from vsphere.samples.common.sample_base import SampleBase
|
||||||
|
from vsphere.samples.common.logging_context import LoggingContext
|
||||||
|
from vsphere.samples.contentlibrary.lib.cls_api_client import ClsApiClient
|
||||||
|
from vsphere.samples.contentlibrary.lib.cls_api_helper import ClsApiHelper
|
||||||
|
from vsphere.samples.vim.helpers.vim_utils import (
|
||||||
|
get_obj, get_obj_by_moId, poweron_vm, poweroff_vm, delete_object)
|
||||||
|
|
||||||
|
__author__ = 'VMware, Inc.'
|
||||||
|
__copyright__ = 'Copyright 2016 VMware, Inc. All rights reserved.'
|
||||||
|
|
||||||
|
|
||||||
|
logger = LoggingContext.get_logger('vsphere.samples.contentlibrary.deploy_ovf_template')
|
||||||
|
|
||||||
|
|
||||||
|
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 VM to be created in the cluster.')
|
||||||
|
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
|
||||||
|
logger.info("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)
|
||||||
|
logger.info('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:
|
||||||
|
logger.info('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:
|
||||||
|
logger.warn('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:
|
||||||
|
logger.error('Deployment failed.')
|
||||||
|
for error in result.error.errors:
|
||||||
|
logger.error('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()
|
@ -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. -- VMware Confidential'
|
||||||
|
|
||||||
|
|
||||||
|
# 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
|
@ -0,0 +1,129 @@
|
|||||||
|
#!/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.
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
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 ItemModel, StorageBacking
|
||||||
|
from vsphere.samples.common.id_generator import generate_random_uuid
|
||||||
|
from vsphere.samples.common.sample_base import SampleBase
|
||||||
|
from vsphere.samples.common.logging_context import LoggingContext
|
||||||
|
from vsphere.samples.contentlibrary.lib.cls_api_client import ClsApiClient
|
||||||
|
from vsphere.samples.contentlibrary.lib.cls_api_helper import ClsApiHelper
|
||||||
|
from vsphere.samples.vim.helpers.get_datastore_by_name import get_datastore_id
|
||||||
|
|
||||||
|
|
||||||
|
__author__ = 'VMware, Inc.'
|
||||||
|
__copyright__ = 'Copyright 2016 VMware, Inc. All rights reserved.'
|
||||||
|
|
||||||
|
|
||||||
|
logger = LoggingContext.get_logger('vsphere.samples.contentlibrary.ovef_import_export')
|
||||||
|
|
||||||
|
|
||||||
|
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
|
||||||
|
logger.info('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())
|
||||||
|
logger.info('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
|
||||||
|
logger.info('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)
|
||||||
|
logger.info('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-')
|
||||||
|
logger.info('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)
|
||||||
|
logger.info('Deleted Library Id: {0}'.format(self.local_library.id))
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
sample = OvfImportExport()
|
||||||
|
sample.main()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
@ -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. -- VMware Confidential'
|
||||||
|
|
||||||
|
|
||||||
|
# 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
|
@ -0,0 +1,199 @@
|
|||||||
|
#!/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.
|
||||||
|
"""
|
||||||
|
|
||||||
|
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 vsphere.samples.common.id_generator import generate_random_uuid
|
||||||
|
from vsphere.samples.common.sample_base import SampleBase
|
||||||
|
from vsphere.samples.common.logging_context import LoggingContext
|
||||||
|
from vsphere.samples.contentlibrary.lib.cls_api_client import ClsApiClient
|
||||||
|
from vsphere.samples.contentlibrary.lib.cls_api_helper import ClsApiHelper
|
||||||
|
from vsphere.samples.contentlibrary.lib.cls_sync_helper import ClsSyncHelper
|
||||||
|
|
||||||
|
__author__ = 'VMware, Inc.'
|
||||||
|
__copyright__ = 'Copyright 2016 VMware, Inc. All rights reserved.'
|
||||||
|
|
||||||
|
|
||||||
|
logger = LoggingContext.get_logger('vsphere.samples.contentlibrary.library_publish_subscribe')
|
||||||
|
|
||||||
|
|
||||||
|
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
|
||||||
|
logger.info('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
|
||||||
|
logger.info('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
|
||||||
|
logger.info('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)
|
||||||
|
logger.info('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)
|
||||||
|
logger.info('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)
|
||||||
|
logger.info('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)
|
||||||
|
logger.info('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)
|
||||||
|
logger.info('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)
|
||||||
|
logger.info('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)
|
||||||
|
logger.info('Deleted published library Id : {0}'.format(self.pub_lib_id))
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
sample = LibraryPublishSubscribe()
|
||||||
|
sample.main()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
@ -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. -- VMware Confidential'
|
||||||
|
|
||||||
|
|
||||||
|
# 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
|
@ -0,0 +1,125 @@
|
|||||||
|
#!/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.
|
||||||
|
"""
|
||||||
|
|
||||||
|
try:
|
||||||
|
import urllib2
|
||||||
|
except ImportError:
|
||||||
|
import urllib.request as urllib2
|
||||||
|
from com.vmware.vcenter.ovf_client import LibraryItem
|
||||||
|
from vsphere.samples.common.id_generator import generate_random_uuid
|
||||||
|
from vsphere.samples.common.sample_base import SampleBase
|
||||||
|
from vsphere.samples.common.logging_context import LoggingContext
|
||||||
|
from vsphere.samples.contentlibrary.lib.cls_api_client import ClsApiClient
|
||||||
|
from vsphere.samples.contentlibrary.lib.cls_api_helper import ClsApiHelper
|
||||||
|
from vsphere.samples.vcenter.helper.vm_helper import get_vm
|
||||||
|
|
||||||
|
__author__ = 'VMware, Inc.'
|
||||||
|
__copyright__ = 'Copyright 2016 VMware, Inc. All rights reserved.'
|
||||||
|
|
||||||
|
logger = LoggingContext.get_logger('vsphere.samples.contentlibrary.vm_template_capture')
|
||||||
|
|
||||||
|
|
||||||
|
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)
|
||||||
|
|
||||||
|
logger.info('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
|
||||||
|
logger.info('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)
|
||||||
|
logger.info('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()
|
8
samples/src/vsphere/samples/inventory/__init__.py
Normal file
8
samples/src/vsphere/samples/inventory/__init__.py
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
# 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
|
103
samples/src/vsphere/samples/inventory/find_cl_datastore.py
Normal file
103
samples/src/vsphere/samples/inventory/find_cl_datastore.py
Normal file
@ -0,0 +1,103 @@
|
|||||||
|
"""
|
||||||
|
* *******************************************************
|
||||||
|
* 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.'
|
||||||
|
|
||||||
|
|
||||||
|
import pyVmomi
|
||||||
|
from com.vmware.content_client import Library
|
||||||
|
from com.vmware.vcenter.inventory_client import Datastore
|
||||||
|
from vsphere.samples.vim.helpers.vim_utils import get_obj_by_moId
|
||||||
|
from vsphere.samples.common.sample_base import SampleBase
|
||||||
|
from vsphere.samples.common.logging_context import LoggingContext
|
||||||
|
|
||||||
|
logger = LoggingContext.get_logger('vsphere.samples.inventory.find_cl_datastore')
|
||||||
|
|
||||||
|
|
||||||
|
class FindClDatastore(SampleBase):
|
||||||
|
"""
|
||||||
|
Demonstrate inventory APIs for retrieving information about vCenter datastore and network objects.
|
||||||
|
Step 1: Retrieve an existing content library from its name.
|
||||||
|
Step 2: Find out the content library storage backing.
|
||||||
|
Step 3: Find out the vCenter object from the storage ID using datastore inventory API.
|
||||||
|
Note: This sample needs an existing content library on the server
|
||||||
|
(Please refer to vsphere.samples.contentlibrary.library_crud for details on how to create a content library)
|
||||||
|
"""
|
||||||
|
def __init__(self):
|
||||||
|
SampleBase.__init__(self, self.__doc__)
|
||||||
|
self.servicemanager = None
|
||||||
|
self.cl_name = None
|
||||||
|
self.library_service = None
|
||||||
|
self.inv_datastore_service = None
|
||||||
|
|
||||||
|
def _options(self):
|
||||||
|
self.argparser.add_argument('-clname', '--clname', help='The name of the content library.')
|
||||||
|
|
||||||
|
def _setup(self):
|
||||||
|
if self.cl_name is None:
|
||||||
|
self.cl_name = self.args.clname
|
||||||
|
assert self.cl_name is not None
|
||||||
|
|
||||||
|
if self.servicemanager is None:
|
||||||
|
self.servicemanager = self.get_service_manager()
|
||||||
|
|
||||||
|
self.library_service = Library(self.servicemanager.stub_config)
|
||||||
|
self.inv_datastore_service = Datastore(self.servicemanager.stub_config)
|
||||||
|
|
||||||
|
def _execute(self):
|
||||||
|
library_model = self.find_cl_by_name()
|
||||||
|
assert library_model is not None
|
||||||
|
logger.info('Found CL: {0} Id: {1}'.format(library_model.name, library_model.id))
|
||||||
|
|
||||||
|
datastore_ids = []
|
||||||
|
for storage_backing in library_model.storage_backings:
|
||||||
|
logger.info('Storage backing datastore id: {0} storage uri:{1}'
|
||||||
|
.format(storage_backing.datastore_id, storage_backing.storage_uri))
|
||||||
|
if storage_backing.datastore_id is not None:
|
||||||
|
datastore_ids.append(storage_backing.datastore_id)
|
||||||
|
|
||||||
|
self.datastore_vim_objs = [] # for testing only
|
||||||
|
datastores = self.inv_datastore_service.find(datastore_ids)
|
||||||
|
for moid, info in datastores.items():
|
||||||
|
logger.info('Datastore moid: {0} type: {1}'.format(moid, info.type))
|
||||||
|
vim_type = self.get_vim_type(info.type)
|
||||||
|
datastore = get_obj_by_moId(self.servicemanager.content, [vim_type], moid)
|
||||||
|
assert datastore is not None
|
||||||
|
logger.info('Vim object retrieved for datastore: {0}'.format(datastore.name))
|
||||||
|
self.datastore_vim_objs.append(datastore) # for testing only
|
||||||
|
|
||||||
|
def _cleanup(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
def find_cl_by_name(self):
|
||||||
|
for library_id in self.library_service.list():
|
||||||
|
library_model = self.library_service.get(library_id)
|
||||||
|
if library_model.name == self.cl_name:
|
||||||
|
return library_model
|
||||||
|
return None
|
||||||
|
|
||||||
|
def get_vim_type(self, t):
|
||||||
|
"""
|
||||||
|
Returns the vim type
|
||||||
|
raises KeyError: If the type is not found
|
||||||
|
"""
|
||||||
|
return pyVmomi.VmomiSupport.GetWsdlType('urn:vim25', t)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
find_cl_datastore = FindClDatastore()
|
||||||
|
find_cl_datastore.main()
|
||||||
|
|
||||||
|
# Start program
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
8
samples/src/vsphere/samples/lookupservice/__init__.py
Normal file
8
samples/src/vsphere/samples/lookupservice/__init__.py
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
# 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
|
92
samples/src/vsphere/samples/lookupservice/print_services.py
Normal file
92
samples/src/vsphere/samples/lookupservice/print_services.py
Normal file
@ -0,0 +1,92 @@
|
|||||||
|
"""
|
||||||
|
* *******************************************************
|
||||||
|
* Copyright (c) VMware, Inc. 2014. 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 VMware, Inc. All rights reserved.'
|
||||||
|
|
||||||
|
import argparse
|
||||||
|
from vsphere.samples.common.sample_config import SampleConfig
|
||||||
|
from vsphere.samples.common.lookup_service_helper import LookupServiceHelper
|
||||||
|
from vsphere.samples.common.logging_context import LoggingContext
|
||||||
|
|
||||||
|
logger = LoggingContext.get_logger('vsphere.samples.lookupservice.print_services')
|
||||||
|
|
||||||
|
|
||||||
|
class PrintServices(object):
|
||||||
|
"""
|
||||||
|
Demonstrates service discovery using lookup service APIs.
|
||||||
|
The sample prints all the PSC (Platform Service Controller) and Management Node (vCenter Server) and
|
||||||
|
some of the critical services (SSO, VAPI, VIM etc.) running on these nodes. This sample can also be used
|
||||||
|
to find out the server deployment (e.g. MxN setup with multiple PSC/Management nodes).
|
||||||
|
"""
|
||||||
|
|
||||||
|
def __init__(self):
|
||||||
|
self.lswsdlurl = None
|
||||||
|
self.lssoapurl = None
|
||||||
|
|
||||||
|
def options(self):
|
||||||
|
self.argparser = argparse.ArgumentParser(description=self.__doc__)
|
||||||
|
# setup the argument parser
|
||||||
|
self.argparser.add_argument('-lswsdlurl', '--lswsdlurl', help='Lookup service WSDL URL')
|
||||||
|
self.argparser.add_argument('-lssoapurl', '--lssoapurl', help='Lookup service SOAP URL')
|
||||||
|
self.args = self.argparser.parse_args() # parse all the sample arguments when they are all set
|
||||||
|
|
||||||
|
def setup(self):
|
||||||
|
if self.args.lswsdlurl is None:
|
||||||
|
self.lswsdlurl = SampleConfig.get_ls_wsdl_url() # look for lookup service WSDL in the sample config
|
||||||
|
else:
|
||||||
|
self.lswsdlurl = self.args.lswsdlurl
|
||||||
|
assert self.lswsdlurl is not None
|
||||||
|
logger.info('lswsdlurl: {0}'.format(self.lswsdlurl))
|
||||||
|
|
||||||
|
if self.args.lssoapurl is None:
|
||||||
|
self.lssoapurl = SampleConfig.get_ls_soap_url() # look for lookup service SOAP URL in the sample config
|
||||||
|
else:
|
||||||
|
self.lssoapurl = self.args.lssoapurl
|
||||||
|
assert self.lssoapurl is not None
|
||||||
|
logger.info('lssoapurl: {0}'.format(self.lssoapurl))
|
||||||
|
|
||||||
|
def execute(self):
|
||||||
|
logger.info('Connecting to lookup service url: {0}'.format(self.lssoapurl))
|
||||||
|
lookupservicehelper = LookupServiceHelper(wsdl_url=self.lswsdlurl, soap_url=self.lssoapurl)
|
||||||
|
lookupservicehelper.connect()
|
||||||
|
|
||||||
|
# print the PSC nodes and SSO service endpoint URLs
|
||||||
|
for index, sso_url in enumerate(lookupservicehelper.find_sso_urls(), start=1):
|
||||||
|
logger.info('=============================')
|
||||||
|
logger.info('PSC node: {0}'.format(index))
|
||||||
|
logger.info(' SSO URL: {0}'.format(sso_url))
|
||||||
|
logger.info('=============================')
|
||||||
|
|
||||||
|
# print the mgmt (vCenter Server) nodes and some of the critical service endpoint URLs
|
||||||
|
for instance_name, node_id in lookupservicehelper.find_mgmt_nodes().items():
|
||||||
|
logger.info('=============================')
|
||||||
|
logger.info('Mgmt node instance name: {0} node_id: {1}'.format(instance_name, node_id))
|
||||||
|
logger.info(' VAPI URL: {0}'.format(lookupservicehelper.find_vapi_url(node_id)))
|
||||||
|
logger.info(' VIM URL: {0}'.format(lookupservicehelper.find_vim_url(node_id)))
|
||||||
|
logger.info(' SPBM URL: {0}'.format(lookupservicehelper.find_vim_pbm_url(node_id)))
|
||||||
|
logger.info('=============================')
|
||||||
|
|
||||||
|
def cleanup(self):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
printServices = PrintServices()
|
||||||
|
printServices.options()
|
||||||
|
printServices.setup()
|
||||||
|
printServices.execute()
|
||||||
|
printServices.cleanup()
|
||||||
|
|
||||||
|
# Start program
|
||||||
|
if __name__ == "__main__":
|
||||||
|
main()
|
25
samples/src/vsphere/samples/tagging/__init__.py
Normal file
25
samples/src/vsphere/samples/tagging/__init__.py
Normal 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. -- VMware Confidential'
|
||||||
|
|
||||||
|
|
||||||
|
# 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
|
210
samples/src/vsphere/samples/tagging/tagging_workflow.py
Normal file
210
samples/src/vsphere/samples/tagging/tagging_workflow.py
Normal file
@ -0,0 +1,210 @@
|
|||||||
|
#!/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.'
|
||||||
|
|
||||||
|
import time
|
||||||
|
from com.vmware.vapi.std_client import DynamicID
|
||||||
|
from com.vmware.cis.tagging_client import (
|
||||||
|
Category, CategoryModel, Tag, TagAssociation)
|
||||||
|
from vsphere.samples.vim.helpers.get_cluster_by_name import get_cluster_id
|
||||||
|
from vsphere.samples.common.sample_base import SampleBase
|
||||||
|
from vsphere.samples.common.logging_context import LoggingContext
|
||||||
|
|
||||||
|
logger = LoggingContext.get_logger('vsphere.samples.workflow.tagging_workflow')
|
||||||
|
|
||||||
|
|
||||||
|
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
|
||||||
|
logger.info('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
|
||||||
|
logger.info('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
|
||||||
|
logger.info('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
|
||||||
|
logger.info('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
|
||||||
|
logger.info('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):
|
||||||
|
logger.info('List all the existing categories user has access to...')
|
||||||
|
categories = self.category_svc.list()
|
||||||
|
if len(categories) > 0:
|
||||||
|
for category in categories:
|
||||||
|
logger.info('Found Category: {0}'.format(category))
|
||||||
|
else:
|
||||||
|
logger.info('No Tag Category Found...')
|
||||||
|
|
||||||
|
logger.info('List all the existing tags user has access to...')
|
||||||
|
tags = self.tag_svc.list()
|
||||||
|
if len(tags) > 0:
|
||||||
|
for tag in tags:
|
||||||
|
logger.info('Found Tag: {0}'.format(tag))
|
||||||
|
else:
|
||||||
|
logger.info('No Tag Found...')
|
||||||
|
|
||||||
|
logger.info('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
|
||||||
|
logger.info('Tag category created; Id: {0}'.format(self.category_id))
|
||||||
|
|
||||||
|
logger.info("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
|
||||||
|
logger.info('Tag created; Id: {0}'.format(self.tag_id))
|
||||||
|
|
||||||
|
logger.info('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)
|
||||||
|
logger.info('Tag updated; Id: {0}'.format(self.tag_id))
|
||||||
|
|
||||||
|
logger.info('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
|
||||||
|
logger.info('Found cluster:{0} mo_id:{1}'.format('vAPISDKCluster', self.cluster_moid))
|
||||||
|
|
||||||
|
logger.info('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
|
||||||
|
logger.info('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)
|
||||||
|
logger.info('Removed tag from cluster: {0}'.format(self.cluster_moid))
|
||||||
|
|
||||||
|
if self.tag_id is not None:
|
||||||
|
self.delete_tag(self.tag_id)
|
||||||
|
logger.info('Tag deleted; Id: {0}'.format(self.tag_id))
|
||||||
|
|
||||||
|
if self.category_id is not None:
|
||||||
|
self.delete_tag_category(self.category_id)
|
||||||
|
logger.info('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()
|
0
samples/src/vsphere/samples/vcenter/__init__.py
Normal file
0
samples/src/vsphere/samples/vcenter/__init__.py
Normal file
8
samples/src/vsphere/samples/vcenter/helper/__init__.py
Normal file
8
samples/src/vsphere/samples/vcenter/helper/__init__.py
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
# 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
|
41
samples/src/vsphere/samples/vcenter/helper/cluster_helper.py
Normal file
41
samples/src/vsphere/samples/vcenter/helper/cluster_helper.py
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
"""
|
||||||
|
* *******************************************************
|
||||||
|
* 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.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from com.vmware.vcenter_client import Cluster
|
||||||
|
|
||||||
|
from vsphere.samples.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
|
@ -0,0 +1,30 @@
|
|||||||
|
"""
|
||||||
|
* *******************************************************
|
||||||
|
* 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.
|
||||||
|
"""
|
||||||
|
|
||||||
|
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
|
@ -0,0 +1,38 @@
|
|||||||
|
"""
|
||||||
|
* *******************************************************
|
||||||
|
* 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.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from com.vmware.vcenter_client import Datastore
|
||||||
|
|
||||||
|
from vsphere.samples.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
|
41
samples/src/vsphere/samples/vcenter/helper/folder_helper.py
Normal file
41
samples/src/vsphere/samples/vcenter/helper/folder_helper.py
Normal file
@ -0,0 +1,41 @@
|
|||||||
|
"""
|
||||||
|
* *******************************************************
|
||||||
|
* 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.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from com.vmware.vcenter_client import Folder
|
||||||
|
|
||||||
|
from vsphere.samples.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
|
77
samples/src/vsphere/samples/vcenter/helper/network_helper.py
Normal file
77
samples/src/vsphere/samples/vcenter/helper/network_helper.py
Normal file
@ -0,0 +1,77 @@
|
|||||||
|
"""
|
||||||
|
* *******************************************************
|
||||||
|
* 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.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from com.vmware.vcenter_client import Network
|
||||||
|
|
||||||
|
from vsphere.samples.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
|
@ -0,0 +1,38 @@
|
|||||||
|
"""
|
||||||
|
* *******************************************************
|
||||||
|
* 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.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from com.vmware.vcenter_client import ResourcePool
|
||||||
|
|
||||||
|
from vsphere.samples.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
|
44
samples/src/vsphere/samples/vcenter/helper/vm_helper.py
Normal file
44
samples/src/vsphere/samples/vcenter/helper/vm_helper.py
Normal file
@ -0,0 +1,44 @@
|
|||||||
|
"""
|
||||||
|
* *******************************************************
|
||||||
|
* 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.
|
||||||
|
"""
|
||||||
|
|
||||||
|
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
|
@ -0,0 +1,47 @@
|
|||||||
|
"""
|
||||||
|
* *******************************************************
|
||||||
|
* 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.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from com.vmware.vcenter_client import VM
|
||||||
|
|
||||||
|
from vsphere.samples.vcenter.helper import datastore_helper
|
||||||
|
from vsphere.samples.vcenter.helper import folder_helper
|
||||||
|
from vsphere.samples.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
|
19
samples/src/vsphere/samples/vcenter/setup/README.md
Normal file
19
samples/src/vsphere/samples/vcenter/setup/README.md
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
This directory contains sample scripts to setup the testbed required to run
|
||||||
|
the vCenter APIs samples. You can also use main.py to run all the samples
|
||||||
|
inside the vcenter.vm package.
|
||||||
|
|
||||||
|
* Testbed Requirement:
|
||||||
|
- 1 vCenter Server
|
||||||
|
- 2 ESX hosts
|
||||||
|
- 1 NFS datastore with at least 3G free capacity.
|
||||||
|
|
||||||
|
* Prepare testbed using setup script:
|
||||||
|
- Edit testbed.py with your settings. In particular, you need to set the IP addresses and credentials in this file.
|
||||||
|
$ cd /path/to/VMware-vSphere-Automation-SDK-Python-<version>/client/bin
|
||||||
|
$ ./run_sample.sh ../samples/src/vsphere/samples/vcenter/setup/main.py -st
|
||||||
|
|
||||||
|
* Run the vAPI vCenter sample suite:
|
||||||
|
$ ./run_sample.sh ../samples/src/vsphere/samples/vcenter/setup/main.py -rit
|
||||||
|
|
||||||
|
* To check available options:
|
||||||
|
$ ./run_sample.sh ../samples/src/vsphere/samples/vcenter/setup/main.py -h
|
8
samples/src/vsphere/samples/vcenter/setup/__init__.py
Normal file
8
samples/src/vsphere/samples/vcenter/setup/__init__.py
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
# 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
|
@ -0,0 +1,87 @@
|
|||||||
|
"""
|
||||||
|
* *******************************************************
|
||||||
|
* 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.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from vsphere.samples.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']))
|
143
samples/src/vsphere/samples/vcenter/setup/cluster.py
Normal file
143
samples/src/vsphere/samples/vcenter/setup/cluster.py
Normal file
@ -0,0 +1,143 @@
|
|||||||
|
"""
|
||||||
|
* *******************************************************
|
||||||
|
* 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.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import pyVim.task
|
||||||
|
from com.vmware.vcenter_client import Cluster
|
||||||
|
from pyVmomi import vim
|
||||||
|
|
||||||
|
from vsphere.samples.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)
|
113
samples/src/vsphere/samples/vcenter/setup/datacenter.py
Normal file
113
samples/src/vsphere/samples/vcenter/setup/datacenter.py
Normal file
@ -0,0 +1,113 @@
|
|||||||
|
"""
|
||||||
|
* *******************************************************
|
||||||
|
* 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.
|
||||||
|
"""
|
||||||
|
|
||||||
|
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)
|
258
samples/src/vsphere/samples/vcenter/setup/datastore.py
Normal file
258
samples/src/vsphere/samples/vcenter/setup/datastore.py
Normal file
@ -0,0 +1,258 @@
|
|||||||
|
"""
|
||||||
|
* *******************************************************
|
||||||
|
* 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.
|
||||||
|
"""
|
||||||
|
|
||||||
|
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))
|
69
samples/src/vsphere/samples/vcenter/setup/floppy_image.py
Normal file
69
samples/src/vsphere/samples/vcenter/setup/floppy_image.py
Normal file
@ -0,0 +1,69 @@
|
|||||||
|
"""
|
||||||
|
* *******************************************************
|
||||||
|
* 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.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from vsphere.samples.vim import datastore_file
|
||||||
|
from vsphere.samples.vim.file import (detect_file, delete_file,
|
||||||
|
parse_datastore_path)
|
||||||
|
from vsphere.samples.vim.inventory import get_datastore_mo
|
||||||
|
|
||||||
|
|
||||||
|
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)
|
120
samples/src/vsphere/samples/vcenter/setup/folder.py
Normal file
120
samples/src/vsphere/samples/vcenter/setup/folder.py
Normal file
@ -0,0 +1,120 @@
|
|||||||
|
"""
|
||||||
|
* *******************************************************
|
||||||
|
* 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.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import pyVim.task
|
||||||
|
from com.vmware.vcenter_client import (Folder)
|
||||||
|
from pyVmomi import vim
|
||||||
|
|
||||||
|
from vsphere.samples.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)
|
209
samples/src/vsphere/samples/vcenter/setup/host.py
Normal file
209
samples/src/vsphere/samples/vcenter/setup/host.py
Normal file
@ -0,0 +1,209 @@
|
|||||||
|
"""
|
||||||
|
* *******************************************************
|
||||||
|
* 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.
|
||||||
|
"""
|
||||||
|
|
||||||
|
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)
|
67
samples/src/vsphere/samples/vcenter/setup/iso_image.py
Normal file
67
samples/src/vsphere/samples/vcenter/setup/iso_image.py
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
"""
|
||||||
|
* *******************************************************
|
||||||
|
* 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.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from vsphere.samples.vim import datastore_file
|
||||||
|
from vsphere.samples.vim.file import (detect_file, delete_file,
|
||||||
|
parse_datastore_path)
|
||||||
|
from vsphere.samples.vim.inventory import get_datastore_mo
|
||||||
|
|
||||||
|
|
||||||
|
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)
|
108
samples/src/vsphere/samples/vcenter/setup/main.py
Normal file
108
samples/src/vsphere/samples/vcenter/setup/main.py
Normal file
@ -0,0 +1,108 @@
|
|||||||
|
#!/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.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import pyVim.connect
|
||||||
|
|
||||||
|
from vsphere.samples.common import sample_util
|
||||||
|
from vsphere.samples.common import vapiconnect
|
||||||
|
from vsphere.samples.common.ssl_helper import get_unverified_context
|
||||||
|
from vsphere.samples.vcenter.setup import testbed
|
||||||
|
from vsphere.samples.vcenter.setup.setup_cli import build_arg_parser
|
||||||
|
from vsphere.samples.vcenter.setup.testbed_setup import cleanup as testbed_cleanup
|
||||||
|
from vsphere.samples.vcenter.setup.testbed_setup import setup as testbed_setup
|
||||||
|
from vsphere.samples.vcenter.setup.testbed_setup import validate as testbed_validate
|
||||||
|
from vsphere.samples.vcenter.vm.main import cleanup as sample_cleanup
|
||||||
|
from vsphere.samples.vcenter.vm.main import run as sample_run
|
||||||
|
|
||||||
|
|
||||||
|
# Parse command line params for setup script
|
||||||
|
args = build_arg_parser().parse_args()
|
||||||
|
|
||||||
|
_testbed = testbed.get()
|
||||||
|
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)
|
||||||
|
|
276
samples/src/vsphere/samples/vcenter/setup/network.py
Normal file
276
samples/src/vsphere/samples/vcenter/setup/network.py
Normal file
@ -0,0 +1,276 @@
|
|||||||
|
"""
|
||||||
|
* *******************************************************
|
||||||
|
* 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.
|
||||||
|
"""
|
||||||
|
|
||||||
|
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))
|
78
samples/src/vsphere/samples/vcenter/setup/setup_cli.py
Normal file
78
samples/src/vsphere/samples/vcenter/setup/setup_cli.py
Normal file
@ -0,0 +1,78 @@
|
|||||||
|
"""
|
||||||
|
* *******************************************************
|
||||||
|
* 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
|
||||||
|
"""
|
||||||
|
import argparse
|
||||||
|
|
||||||
|
|
||||||
|
def build_arg_parser():
|
||||||
|
"""
|
||||||
|
Builds a standard argument parser with arguments for executing sample
|
||||||
|
setup script
|
||||||
|
|
||||||
|
-s, --testbed_setup
|
||||||
|
-v, --testbed_validate
|
||||||
|
-c, --testbed_cleanup
|
||||||
|
-o, --iso_cleanup
|
||||||
|
-e, --samples_setup
|
||||||
|
-r, --samples
|
||||||
|
-i, --samples_incremental
|
||||||
|
-l, --samples_cleanup
|
||||||
|
-t, --skipverification
|
||||||
|
|
||||||
|
"""
|
||||||
|
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('-v', '--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('-t', '--skipverification',
|
||||||
|
action='store_true',
|
||||||
|
help='Verify server certificate when connecting to '
|
||||||
|
'vcenter. ')
|
||||||
|
|
||||||
|
return parser
|
137
samples/src/vsphere/samples/vcenter/setup/testbed.py
Normal file
137
samples/src/vsphere/samples/vcenter/setup/testbed.py
Normal file
@ -0,0 +1,137 @@
|
|||||||
|
#!/usr/bin/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.
|
||||||
|
"""
|
||||||
|
|
||||||
|
config = {}
|
||||||
|
config["SERVER"] = ""
|
||||||
|
config["USERNAME"] = ""
|
||||||
|
config["PASSWORD"] = ""
|
||||||
|
|
||||||
|
config["ESX_HOST1"] = ""
|
||||||
|
config["ESX_HOST2"] = ""
|
||||||
|
config["ESX_USER"] = ""
|
||||||
|
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"] = "Cluster 1"
|
||||||
|
|
||||||
|
config["VDSWITCH1_NAME"] = "DSwitch 1"
|
||||||
|
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
|
107
samples/src/vsphere/samples/vcenter/setup/testbed_setup.py
Normal file
107
samples/src/vsphere/samples/vcenter/setup/testbed_setup.py
Normal file
@ -0,0 +1,107 @@
|
|||||||
|
"""
|
||||||
|
* *******************************************************
|
||||||
|
* 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.
|
||||||
|
"""
|
||||||
|
|
||||||
|
import vsphere.samples.vcenter.setup.backend_directory as backend_directory
|
||||||
|
import vsphere.samples.vcenter.setup.cluster as cluster
|
||||||
|
import vsphere.samples.vcenter.setup.datacenter as datacenter
|
||||||
|
import vsphere.samples.vcenter.setup.datastore as datastore
|
||||||
|
import vsphere.samples.vcenter.setup.floppy_image as floppy_image
|
||||||
|
import vsphere.samples.vcenter.setup.folder as folder
|
||||||
|
import vsphere.samples.vcenter.setup.host as host
|
||||||
|
import vsphere.samples.vcenter.setup.iso_image as iso_image
|
||||||
|
import vsphere.samples.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
|
45
samples/src/vsphere/samples/vcenter/vm/README.md
Normal file
45
samples/src/vsphere/samples/vcenter/vm/README.md
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
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
|
||||||
|
|
||||||
|
You have two options to run samples inside this package:
|
||||||
|
|
||||||
|
1. Run the whole sample suite which contains all vcenter samples using main.py
|
||||||
|
in vsphere.samples.vcenter.setup package.
|
||||||
|
Please see the README in the setup package for detailed steps.
|
||||||
|
|
||||||
|
2. Run an individual sample in an existing environment.
|
||||||
|
You can either pass the testbed settings through command line
|
||||||
|
arguments or specify them in setup.py in the setup package.
|
||||||
|
|
||||||
|
For example, to run the create_default_vm sample in the vsphere.samples.vcenter.vm.create package:
|
||||||
|
|
||||||
|
* $ cd /path/to/VMware-vSphere-Automation-SDK-Python-<version>/client/bin
|
||||||
|
|
||||||
|
* Run the sample with the testbed settings specified in setup.py in a Linux machine:
|
||||||
|
|
||||||
|
$ ./run_sample.sh ../samples/src/vsphere/samples/vcenter/vm/create/create_default_vm.py -v
|
||||||
|
|
||||||
|
* Or specify the credentials using command line parameters:
|
||||||
|
|
||||||
|
$ ./run_sample.sh ../samples/src/vsphere/samples/vcenter/vm/create/create_default_vm.py -s <server> -u <username> -p <password> -v
|
0
samples/src/vsphere/samples/vcenter/vm/__init__.py
Normal file
0
samples/src/vsphere/samples/vcenter/vm/__init__.py
Normal file
@ -0,0 +1,8 @@
|
|||||||
|
# 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
|
165
samples/src/vsphere/samples/vcenter/vm/create/create_basic_vm.py
Normal file
165
samples/src/vsphere/samples/vcenter/vm/create/create_basic_vm.py
Normal file
@ -0,0 +1,165 @@
|
|||||||
|
#!/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.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from com.vmware.vcenter.vm.hardware.boot_client import Device as BootDevice
|
||||||
|
from com.vmware.vcenter.vm.hardware_client import (
|
||||||
|
Disk, Ethernet)
|
||||||
|
from com.vmware.vcenter.vm.hardware_client import ScsiAddressSpec
|
||||||
|
from com.vmware.vcenter.vm_client import (Power)
|
||||||
|
from com.vmware.vcenter_client import VM
|
||||||
|
|
||||||
|
from vsphere.samples.common import vapiconnect
|
||||||
|
from vsphere.samples.common.sample_util import parse_cli_args_vm
|
||||||
|
from vsphere.samples.common.sample_util import pp
|
||||||
|
from vsphere.samples.vcenter.helper import network_helper
|
||||||
|
from vsphere.samples.vcenter.helper import vm_placement_helper
|
||||||
|
from vsphere.samples.vcenter.helper.vm_helper import get_vm
|
||||||
|
from vsphere.samples.vcenter.setup import testbed
|
||||||
|
|
||||||
|
"""
|
||||||
|
Demonstrates how to create a basic VM with following configuration:
|
||||||
|
2 disks, 1 nic
|
||||||
|
|
||||||
|
Sample Prerequisites:
|
||||||
|
- datacenter
|
||||||
|
- vm folder
|
||||||
|
- datastore
|
||||||
|
- cluster
|
||||||
|
- standard switch network
|
||||||
|
"""
|
||||||
|
|
||||||
|
stub_config = None
|
||||||
|
cleardata = False
|
||||||
|
vm_name = None
|
||||||
|
|
||||||
|
|
||||||
|
def setup(context=None):
|
||||||
|
global stub_config, cleardata, vm_name
|
||||||
|
if context:
|
||||||
|
# Run sample suite via setup script
|
||||||
|
vm_name = testbed.config['VM_NAME_BASIC']
|
||||||
|
stub_config = context.stub_config
|
||||||
|
else:
|
||||||
|
# Run sample in standalone mode
|
||||||
|
server, username, password, cleardata, skip_verification, vm_name = \
|
||||||
|
parse_cli_args_vm(testbed.config['VM_NAME_BASIC'])
|
||||||
|
stub_config = vapiconnect.connect(server,
|
||||||
|
username,
|
||||||
|
password,
|
||||||
|
skip_verification)
|
||||||
|
|
||||||
|
|
||||||
|
def run():
|
||||||
|
# Get a placement spec
|
||||||
|
datacenter_name = testbed.config['DATACENTER2_NAME']
|
||||||
|
vm_folder_name = testbed.config['VM_FOLDER2_NAME']
|
||||||
|
datastore_name = testbed.config['NFS_DATASTORE_NAME']
|
||||||
|
std_portgroup_name = testbed.config['STDPORTGROUP_NAME']
|
||||||
|
placement_spec = vm_placement_helper.get_placement_spec_for_resource_pool(
|
||||||
|
stub_config,
|
||||||
|
datacenter_name,
|
||||||
|
vm_folder_name,
|
||||||
|
datastore_name)
|
||||||
|
|
||||||
|
# Get a standard network backing
|
||||||
|
standard_network = network_helper.get_standard_network_backing(
|
||||||
|
stub_config,
|
||||||
|
std_portgroup_name,
|
||||||
|
datacenter_name)
|
||||||
|
|
||||||
|
create_basic_vm(stub_config, placement_spec, standard_network)
|
||||||
|
|
||||||
|
|
||||||
|
def create_basic_vm(stub_config, placement_spec, standard_network):
|
||||||
|
"""
|
||||||
|
Create a basic VM.
|
||||||
|
|
||||||
|
Using the provided PlacementSpec, create a VM with a selected Guest OS
|
||||||
|
and provided name.
|
||||||
|
|
||||||
|
Create a VM with the following configuration:
|
||||||
|
* Create 2 disks and specify one of them on scsi0:0 since it's the boot disk
|
||||||
|
* Specify 1 ethernet adapter using a Standard Portgroup backing
|
||||||
|
* Setup for PXE install by selecting network as first boot device
|
||||||
|
|
||||||
|
Use guest and system provided defaults for most configuration settings.
|
||||||
|
"""
|
||||||
|
guest_os = testbed.config['VM_GUESTOS']
|
||||||
|
|
||||||
|
boot_disk = Disk.CreateSpec(type=Disk.HostBusAdapterType.SCSI,
|
||||||
|
scsi=ScsiAddressSpec(bus=0, unit=0),
|
||||||
|
new_vmdk=Disk.VmdkCreateSpec())
|
||||||
|
data_disk = Disk.CreateSpec(new_vmdk=Disk.VmdkCreateSpec())
|
||||||
|
|
||||||
|
nic = Ethernet.CreateSpec(
|
||||||
|
start_connected=True,
|
||||||
|
backing=Ethernet.BackingSpec(
|
||||||
|
type=Ethernet.BackingType.STANDARD_PORTGROUP,
|
||||||
|
network=standard_network))
|
||||||
|
|
||||||
|
# TODO Should DISK be put before ETHERNET? Does the BIOS automatically try
|
||||||
|
# the next device if the DISK is empty?
|
||||||
|
boot_device_order = [BootDevice.EntryCreateSpec(BootDevice.Type.ETHERNET),
|
||||||
|
BootDevice.EntryCreateSpec(BootDevice.Type.DISK)]
|
||||||
|
|
||||||
|
vm_create_spec = VM.CreateSpec(name=vm_name,
|
||||||
|
guest_os=guest_os,
|
||||||
|
placement=placement_spec,
|
||||||
|
disks=[boot_disk, data_disk],
|
||||||
|
nics=[nic],
|
||||||
|
boot_devices=boot_device_order)
|
||||||
|
print('\n# Example: create_basic_vm: Creating a VM using spec\n-----')
|
||||||
|
print(pp(vm_create_spec))
|
||||||
|
print('-----')
|
||||||
|
|
||||||
|
vm_svc = VM(stub_config)
|
||||||
|
vm = vm_svc.create(vm_create_spec)
|
||||||
|
|
||||||
|
print("create_basic_vm: Created VM '{}' ({})".format(vm_name, vm))
|
||||||
|
|
||||||
|
vm_info = vm_svc.get(vm)
|
||||||
|
print('vm.get({}) -> {}'.format(vm, pp(vm_info)))
|
||||||
|
|
||||||
|
return vm
|
||||||
|
|
||||||
|
|
||||||
|
def cleanup():
|
||||||
|
vm = get_vm(stub_config, vm_name)
|
||||||
|
if vm:
|
||||||
|
power_svc = Power(stub_config)
|
||||||
|
vm_svc = VM(stub_config)
|
||||||
|
state = power_svc.get(vm)
|
||||||
|
if state == Power.Info(state=Power.State.POWERED_ON):
|
||||||
|
power_svc.stop(vm)
|
||||||
|
elif state == Power.Info(state=Power.State.SUSPENDED):
|
||||||
|
power_svc.start(vm)
|
||||||
|
power_svc.stop(vm)
|
||||||
|
print("Deleting VM '{}' ({})".format(vm_name, vm))
|
||||||
|
vm_svc.delete(vm)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
try:
|
||||||
|
setup()
|
||||||
|
cleanup()
|
||||||
|
run()
|
||||||
|
if cleardata:
|
||||||
|
cleanup()
|
||||||
|
finally:
|
||||||
|
if stub_config:
|
||||||
|
vapiconnect.logout(stub_config)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
@ -0,0 +1,124 @@
|
|||||||
|
#!/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.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from com.vmware.vcenter.vm_client import Power
|
||||||
|
from com.vmware.vcenter_client import VM
|
||||||
|
|
||||||
|
from vsphere.samples.common import vapiconnect
|
||||||
|
from vsphere.samples.common.sample_util import parse_cli_args_vm
|
||||||
|
from vsphere.samples.common.sample_util import pp
|
||||||
|
from vsphere.samples.vcenter.helper import vm_placement_helper
|
||||||
|
from vsphere.samples.vcenter.helper.vm_helper import get_vm
|
||||||
|
from vsphere.samples.vcenter.setup import testbed
|
||||||
|
|
||||||
|
"""
|
||||||
|
Demonstrates how to create a VM with system provided defaults
|
||||||
|
|
||||||
|
Sample Prerequisites:
|
||||||
|
- datacenter
|
||||||
|
- vm folder
|
||||||
|
- datastore
|
||||||
|
- cluster
|
||||||
|
- standard switch network
|
||||||
|
"""
|
||||||
|
|
||||||
|
stub_config = None
|
||||||
|
cleardata = False
|
||||||
|
vm_name = None
|
||||||
|
|
||||||
|
|
||||||
|
def setup(context=None):
|
||||||
|
global stub_config, cleardata, vm_name
|
||||||
|
if context:
|
||||||
|
# Run sample suite via setup script
|
||||||
|
vm_name = testbed.config['VM_NAME_DEFAULT']
|
||||||
|
stub_config = context.stub_config
|
||||||
|
else:
|
||||||
|
# Run sample in standalone mode
|
||||||
|
server, username, password, cleardata, skip_verification, vm_name = \
|
||||||
|
parse_cli_args_vm(testbed.config['VM_NAME_DEFAULT'])
|
||||||
|
stub_config = vapiconnect.connect(server,
|
||||||
|
username,
|
||||||
|
password,
|
||||||
|
skip_verification)
|
||||||
|
|
||||||
|
|
||||||
|
def run():
|
||||||
|
# Get a placement spec
|
||||||
|
datacenter_name = testbed.config['DATACENTER2_NAME']
|
||||||
|
vm_folder_name = testbed.config['VM_FOLDER2_NAME']
|
||||||
|
datastore_name = testbed.config['NFS_DATASTORE_NAME']
|
||||||
|
placement_spec = vm_placement_helper.get_placement_spec_for_resource_pool(
|
||||||
|
stub_config,
|
||||||
|
datacenter_name,
|
||||||
|
vm_folder_name,
|
||||||
|
datastore_name)
|
||||||
|
|
||||||
|
# Create the VMs
|
||||||
|
create_default_vm(stub_config, placement_spec)
|
||||||
|
|
||||||
|
|
||||||
|
def create_default_vm(stub_config, placement_spec):
|
||||||
|
"""
|
||||||
|
Create a default VM.
|
||||||
|
|
||||||
|
Using the provided PlacementSpec, create a VM with a selected Guest OS
|
||||||
|
and provided name. Use all the guest and system provided defaults.
|
||||||
|
"""
|
||||||
|
guest_os = testbed.config['VM_GUESTOS']
|
||||||
|
vm_create_spec = VM.CreateSpec(name=vm_name,
|
||||||
|
guest_os=guest_os,
|
||||||
|
placement=placement_spec)
|
||||||
|
print('\n# Example: create_default_vm: Creating a VM using spec\n-----')
|
||||||
|
print(pp(vm_create_spec))
|
||||||
|
print('-----')
|
||||||
|
|
||||||
|
vm_svc = VM(stub_config)
|
||||||
|
vm = vm_svc.create(vm_create_spec)
|
||||||
|
print("create_default_vm: Created VM '{}' ({})".format(vm_name, vm))
|
||||||
|
|
||||||
|
vm_info = vm_svc.get(vm)
|
||||||
|
print('vm.get({}) -> {}'.format(vm, pp(vm_info)))
|
||||||
|
return vm
|
||||||
|
|
||||||
|
|
||||||
|
def cleanup():
|
||||||
|
vm = get_vm(stub_config, vm_name)
|
||||||
|
if vm:
|
||||||
|
power_svc = Power(stub_config)
|
||||||
|
vm_svc = VM(stub_config)
|
||||||
|
state = power_svc.get(vm)
|
||||||
|
if state == Power.Info(state=Power.State.POWERED_ON):
|
||||||
|
power_svc.stop(vm)
|
||||||
|
elif state == Power.Info(state=Power.State.SUSPENDED):
|
||||||
|
power_svc.start(vm)
|
||||||
|
power_svc.stop(vm)
|
||||||
|
print("Deleting VM '{}' ({})".format(vm_name, vm))
|
||||||
|
vm_svc.delete(vm)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
try:
|
||||||
|
setup()
|
||||||
|
cleanup()
|
||||||
|
run()
|
||||||
|
if cleardata:
|
||||||
|
cleanup()
|
||||||
|
finally:
|
||||||
|
if stub_config:
|
||||||
|
vapiconnect.logout(stub_config)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
@ -0,0 +1,253 @@
|
|||||||
|
#!/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.
|
||||||
|
"""
|
||||||
|
|
||||||
|
from com.vmware.vcenter.vm.hardware.boot_client import Device as BootDevice
|
||||||
|
from com.vmware.vcenter.vm.hardware_client import (
|
||||||
|
Cpu, Memory, Disk, Ethernet, Cdrom, Serial, Parallel, Floppy, Boot)
|
||||||
|
from com.vmware.vcenter.vm.hardware_client import ScsiAddressSpec
|
||||||
|
from com.vmware.vcenter.vm_client import (Hardware, Power)
|
||||||
|
from com.vmware.vcenter_client import VM
|
||||||
|
|
||||||
|
from vsphere.samples.common import vapiconnect
|
||||||
|
from vsphere.samples.common.sample_util import parse_cli_args_vm
|
||||||
|
from vsphere.samples.common.sample_util import pp
|
||||||
|
from vsphere.samples.vcenter.helper import network_helper
|
||||||
|
from vsphere.samples.vcenter.helper import vm_placement_helper
|
||||||
|
from vsphere.samples.vcenter.helper.vm_helper import get_vm
|
||||||
|
from vsphere.samples.vcenter.setup import testbed
|
||||||
|
|
||||||
|
"""
|
||||||
|
Demonstrates how to create a exhaustive VM with the below configuration:
|
||||||
|
3 disks, 2 nics, 2 vcpu, 2 GB, memory, boot=BIOS, 1 cdrom, 1 serial port,
|
||||||
|
1 parallel port, 1 floppy, boot_device=[CDROM, DISK, ETHERNET])
|
||||||
|
|
||||||
|
Sample Prerequisites:
|
||||||
|
- datacenter
|
||||||
|
- vm folder
|
||||||
|
- resource pool
|
||||||
|
- datastore
|
||||||
|
- cluster
|
||||||
|
- standard switch network
|
||||||
|
- distributed switch network
|
||||||
|
- An iso file on the datastore mentioned above
|
||||||
|
"""
|
||||||
|
|
||||||
|
stub_config = None
|
||||||
|
cleardata = False
|
||||||
|
vm_name = None
|
||||||
|
|
||||||
|
|
||||||
|
def setup(context=None):
|
||||||
|
global stub_config, cleardata, vm_name
|
||||||
|
if context:
|
||||||
|
# Run sample suite via setup script
|
||||||
|
vm_name = testbed.config['VM_NAME_EXHAUSTIVE']
|
||||||
|
stub_config = context.stub_config
|
||||||
|
else:
|
||||||
|
# Run sample in standalone mode
|
||||||
|
server, username, password, cleardata, skip_verification, vm_name = \
|
||||||
|
parse_cli_args_vm(testbed.config['VM_NAME_EXHAUSTIVE'])
|
||||||
|
stub_config = vapiconnect.connect(server,
|
||||||
|
username,
|
||||||
|
password,
|
||||||
|
skip_verification)
|
||||||
|
|
||||||
|
|
||||||
|
def run():
|
||||||
|
# Get a placement spec
|
||||||
|
datacenter_name = testbed.config['DATACENTER2_NAME']
|
||||||
|
vm_folder_name = testbed.config['VM_FOLDER2_NAME']
|
||||||
|
datastore_name = testbed.config['NFS_DATASTORE_NAME']
|
||||||
|
std_portgroup_name = testbed.config['STDPORTGROUP_NAME']
|
||||||
|
dv_portgroup_name = testbed.config['VDPORTGROUP1_NAME']
|
||||||
|
placement_spec = vm_placement_helper.get_placement_spec_for_resource_pool(
|
||||||
|
stub_config,
|
||||||
|
datacenter_name,
|
||||||
|
vm_folder_name,
|
||||||
|
datastore_name)
|
||||||
|
|
||||||
|
# Get a standard network backing
|
||||||
|
standard_network = network_helper.get_standard_network_backing(
|
||||||
|
stub_config,
|
||||||
|
std_portgroup_name,
|
||||||
|
datacenter_name)
|
||||||
|
|
||||||
|
# Get a distributed network backing
|
||||||
|
distributed_network = network_helper.get_distributed_network_backing(
|
||||||
|
stub_config,
|
||||||
|
dv_portgroup_name,
|
||||||
|
datacenter_name)
|
||||||
|
|
||||||
|
create_exhaustive_vm(stub_config, placement_spec, standard_network,
|
||||||
|
distributed_network)
|
||||||
|
|
||||||
|
|
||||||
|
def create_exhaustive_vm(stub_config, placement_spec, standard_network,
|
||||||
|
distributed_network):
|
||||||
|
"""
|
||||||
|
Create an exhaustive VM.
|
||||||
|
|
||||||
|
Using the provided PlacementSpec, create a VM with a selected Guest OS
|
||||||
|
and provided name.
|
||||||
|
|
||||||
|
Create a VM with the following configuration:
|
||||||
|
* Hardware Version = VMX_11 (for 6.0)
|
||||||
|
* CPU (count = 2, coresPerSocket = 2, hotAddEnabled = false,
|
||||||
|
hotRemoveEnabled = false)
|
||||||
|
* Memory (size_mib = 2 GB, hotAddEnabled = false)
|
||||||
|
* 3 Disks and specify each of the HBAs and the unit numbers
|
||||||
|
* (capacity=40 GB, name=<some value>, spaceEfficient=true)
|
||||||
|
* Specify 2 ethernet adapters, one using a Standard Portgroup backing and
|
||||||
|
the
|
||||||
|
other using a DISTRIBUTED_PORTGROUP networking backing.
|
||||||
|
* nic1: Specify Ethernet (macType=MANUAL, macAddress=<some value>)
|
||||||
|
* nic2: Specify Ethernet (macType=GENERATED)
|
||||||
|
* 1 CDROM (type=ISO_FILE, file="os.iso", startConnected=true)
|
||||||
|
* 1 Serial Port (type=NETWORK_SERVER, file="tcp://localhost/16000",
|
||||||
|
startConnected=true)
|
||||||
|
* 1 Parallel Port (type=HOST_DEVICE, startConnected=false)
|
||||||
|
* 1 Floppy Drive (type=CLIENT_DEVICE)
|
||||||
|
* Boot, type=BIOS
|
||||||
|
* BootDevice order: CDROM, DISK, ETHERNET
|
||||||
|
|
||||||
|
Use guest and system provided defaults for remaining configuration settings.
|
||||||
|
"""
|
||||||
|
guest_os = testbed.config['VM_GUESTOS']
|
||||||
|
iso_datastore_path = testbed.config['ISO_DATASTORE_PATH']
|
||||||
|
serial_port_network_location = \
|
||||||
|
testbed.config['SERIAL_PORT_NETWORK_SERVER_LOCATION']
|
||||||
|
|
||||||
|
GiB = 1024 * 1024 * 1024
|
||||||
|
GiBMemory = 1024
|
||||||
|
|
||||||
|
vm_create_spec = VM.CreateSpec(
|
||||||
|
guest_os=guest_os,
|
||||||
|
name=vm_name,
|
||||||
|
placement=placement_spec,
|
||||||
|
hardware_version=Hardware.Version.VMX_11,
|
||||||
|
cpu=Cpu.UpdateSpec(count=2,
|
||||||
|
cores_per_socket=1,
|
||||||
|
hot_add_enabled=False,
|
||||||
|
hot_remove_enabled=False),
|
||||||
|
memory=Memory.UpdateSpec(size_mib=2 * GiBMemory,
|
||||||
|
hot_add_enabled=False),
|
||||||
|
disks=[
|
||||||
|
Disk.CreateSpec(type=Disk.HostBusAdapterType.SCSI,
|
||||||
|
scsi=ScsiAddressSpec(bus=0, unit=0),
|
||||||
|
new_vmdk=Disk.VmdkCreateSpec(name='boot',
|
||||||
|
capacity=40 * GiB)),
|
||||||
|
Disk.CreateSpec(new_vmdk=Disk.VmdkCreateSpec(name='data1',
|
||||||
|
capacity=10 * GiB)),
|
||||||
|
Disk.CreateSpec(new_vmdk=Disk.VmdkCreateSpec(name='data2',
|
||||||
|
capacity=10 * GiB))
|
||||||
|
],
|
||||||
|
nics=[
|
||||||
|
Ethernet.CreateSpec(
|
||||||
|
start_connected=True,
|
||||||
|
mac_type=Ethernet.MacAddressType.MANUAL,
|
||||||
|
mac_address='11:23:58:13:21:34',
|
||||||
|
backing=Ethernet.BackingSpec(
|
||||||
|
type=Ethernet.BackingType.STANDARD_PORTGROUP,
|
||||||
|
network=standard_network)),
|
||||||
|
Ethernet.CreateSpec(
|
||||||
|
start_connected=True,
|
||||||
|
mac_type=Ethernet.MacAddressType.GENERATED,
|
||||||
|
backing=Ethernet.BackingSpec(
|
||||||
|
type=Ethernet.BackingType.DISTRIBUTED_PORTGROUP,
|
||||||
|
network=distributed_network)),
|
||||||
|
],
|
||||||
|
cdroms=[
|
||||||
|
Cdrom.CreateSpec(
|
||||||
|
start_connected=True,
|
||||||
|
backing=Cdrom.BackingSpec(type=Cdrom.BackingType.ISO_FILE,
|
||||||
|
iso_file=iso_datastore_path)
|
||||||
|
)
|
||||||
|
],
|
||||||
|
serial_ports=[
|
||||||
|
Serial.CreateSpec(
|
||||||
|
start_connected=False,
|
||||||
|
backing=Serial.BackingSpec(
|
||||||
|
type=Serial.BackingType.NETWORK_SERVER,
|
||||||
|
network_location=serial_port_network_location)
|
||||||
|
)
|
||||||
|
],
|
||||||
|
parallel_ports=[
|
||||||
|
Parallel.CreateSpec(
|
||||||
|
start_connected=False,
|
||||||
|
backing=Parallel.BackingSpec(
|
||||||
|
type=Parallel.BackingType.HOST_DEVICE)
|
||||||
|
)
|
||||||
|
],
|
||||||
|
floppies=[
|
||||||
|
Floppy.CreateSpec(
|
||||||
|
backing=Floppy.BackingSpec(
|
||||||
|
type=Floppy.BackingType.CLIENT_DEVICE)
|
||||||
|
)
|
||||||
|
],
|
||||||
|
boot=Boot.CreateSpec(type=Boot.Type.BIOS,
|
||||||
|
delay=0,
|
||||||
|
enter_setup_mode=False
|
||||||
|
),
|
||||||
|
# TODO Should DISK be put before CDROM and ETHERNET? Does the BIOS
|
||||||
|
# automatically try the next device if the DISK is empty?
|
||||||
|
boot_devices=[
|
||||||
|
BootDevice.EntryCreateSpec(BootDevice.Type.CDROM),
|
||||||
|
BootDevice.EntryCreateSpec(BootDevice.Type.DISK),
|
||||||
|
BootDevice.EntryCreateSpec(BootDevice.Type.ETHERNET)
|
||||||
|
]
|
||||||
|
)
|
||||||
|
print('# Example: create_exhaustive_vm: Creating a VM using spec\n-----')
|
||||||
|
print(pp(vm_create_spec))
|
||||||
|
print('-----')
|
||||||
|
|
||||||
|
vm_svc = VM(stub_config)
|
||||||
|
vm = vm_svc.create(vm_create_spec)
|
||||||
|
|
||||||
|
print("create_exhaustive_vm: Created VM '{}' ({})".format(vm_name, vm))
|
||||||
|
|
||||||
|
vm_info = vm_svc.get(vm)
|
||||||
|
print('vm.get({}) -> {}'.format(vm, pp(vm_info)))
|
||||||
|
|
||||||
|
return vm
|
||||||
|
|
||||||
|
|
||||||
|
def cleanup():
|
||||||
|
vm = get_vm(stub_config, vm_name)
|
||||||
|
if vm:
|
||||||
|
power_svc = Power(stub_config)
|
||||||
|
vm_svc = VM(stub_config)
|
||||||
|
state = power_svc.get(vm)
|
||||||
|
if state == Power.Info(state=Power.State.POWERED_ON):
|
||||||
|
power_svc.stop(vm)
|
||||||
|
elif state == Power.Info(state=Power.State.SUSPENDED):
|
||||||
|
power_svc.start(vm)
|
||||||
|
power_svc.stop(vm)
|
||||||
|
print("Deleting VM '{}' ({})".format(vm_name, vm))
|
||||||
|
vm_svc.delete(vm)
|
||||||
|
|
||||||
|
|
||||||
|
def main():
|
||||||
|
try:
|
||||||
|
setup()
|
||||||
|
cleanup()
|
||||||
|
run()
|
||||||
|
if cleardata:
|
||||||
|
cleanup()
|
||||||
|
finally:
|
||||||
|
if stub_config:
|
||||||
|
vapiconnect.logout(stub_config)
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
24
samples/src/vsphere/samples/vcenter/vm/hardware/README.md
Normal file
24
samples/src/vsphere/samples/vcenter/vm/hardware/README.md
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
This directory contains the samples for the vCenter VM hardware APIs.
|
||||||
|
|
||||||
|
You have two options to run samples inside this package:
|
||||||
|
|
||||||
|
1. Run the whole test suite contains all vcenter samples using main.py in
|
||||||
|
setup package. Please see README in setup package for detailed steps.
|
||||||
|
|
||||||
|
2. Run individual sample on existing environment. You can either pass the
|
||||||
|
environment parameters through command line arguments or specify them in
|
||||||
|
setup.py in setup package. TODO: have property file in each test folder.
|
||||||
|
|
||||||
|
For example, to run memory sample in vcenter.vm.hardware package:
|
||||||
|
|
||||||
|
* Navigate to bin folder.
|
||||||
|
|
||||||
|
* To run the sample with settings specified in setup.py
|
||||||
|
in linux machine:
|
||||||
|
|
||||||
|
$ ./run_sample.sh ../samples/vcenter/vm/hardware/memory.py
|
||||||
|
|
||||||
|
* Or specify the credentials via command line input:
|
||||||
|
|
||||||
|
$ ./run_sample.sh ../samples/vcenter/vm/hardware/memory.py \
|
||||||
|
-s <server> -u <username> -p <password> -n <vm_name>
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user