mirror of
https://github.com/vmware/vsphere-automation-sdk-python.git
synced 2024-11-21 17:29:59 -05:00
New sample to demonstrates the VMTX push sync workflow to publish and subscribe VMTX items
This commit is contained in:
parent
1e26c683b9
commit
63dbb27b50
@ -1,6 +1,6 @@
|
||||
"""
|
||||
* *******************************************************
|
||||
* Copyright VMware, Inc. 2016-2018. All Rights Reserved.
|
||||
* Copyright VMware, Inc. 2016-2019. All Rights Reserved.
|
||||
* SPDX-License-Identifier: MIT
|
||||
* *******************************************************
|
||||
*
|
||||
@ -17,7 +17,7 @@ __vcenter_version__ = '6.0+'
|
||||
from com.vmware.content_client import (Library,
|
||||
LocalLibrary,
|
||||
SubscribedLibrary)
|
||||
from com.vmware.content.library_client import Item, SubscribedItem
|
||||
from com.vmware.content.library_client import Item, SubscribedItem, Subscriptions
|
||||
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
|
||||
@ -77,6 +77,9 @@ class ClsApiClient(object):
|
||||
# machine templates
|
||||
self.vmtx_service = VmtxLibraryItem(self.service_manager.stub_config)
|
||||
|
||||
# ####
|
||||
self.subscriptions = Subscriptions(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
|
||||
|
25
samples/vsphere/contentlibrary/vmtx_sync/__init__.py
Normal file
25
samples/vsphere/contentlibrary/vmtx_sync/__init__.py
Normal file
@ -0,0 +1,25 @@
|
||||
"""
|
||||
* *******************************************************
|
||||
* Copyright VMware, Inc. 2019. All Rights Reserved.
|
||||
* SPDX-License-Identifier: MIT
|
||||
* *******************************************************
|
||||
*
|
||||
* 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.'
|
||||
|
||||
|
||||
# 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
|
403
samples/vsphere/contentlibrary/vmtx_sync/vmtx_publish.py
Normal file
403
samples/vsphere/contentlibrary/vmtx_sync/vmtx_publish.py
Normal file
@ -0,0 +1,403 @@
|
||||
#!/usr/bin/env python
|
||||
|
||||
"""
|
||||
* *******************************************************
|
||||
* Copyright VMware, Inc. 2019. All Rights Reserved.
|
||||
* SPDX-License-Identifier: MIT
|
||||
* *******************************************************
|
||||
*
|
||||
* 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.'
|
||||
__vcenter_version__ = '6.7U2+'
|
||||
|
||||
import time
|
||||
import uuid
|
||||
|
||||
from com.vmware.content_client import LibraryModel
|
||||
from com.vmware.content.library_client import (PublishInfo, SubscriptionInfo,
|
||||
StorageBacking,
|
||||
Subscriptions)
|
||||
from com.vmware.vcenter.ovf_client import LibraryItem
|
||||
from com.vmware.vcenter.vm_template_client import LibraryItems as VmtxLibraryItem
|
||||
|
||||
from pyVmomi import vim
|
||||
|
||||
from vmware.vapi.vsphere.client import create_vsphere_client
|
||||
|
||||
from samples.vsphere.common.id_generator import generate_random_uuid
|
||||
from samples.vsphere.common.sample_base import SampleBase
|
||||
from samples.vsphere.common.ssl_helper import get_unverified_session
|
||||
from samples.vsphere.common.vim.helpers.get_datastore_by_name import get_datastore_id
|
||||
from samples.vsphere.contentlibrary.lib.cls_api_client import ClsApiClient
|
||||
from samples.vsphere.contentlibrary.lib.cls_api_helper import ClsApiHelper
|
||||
from samples.vsphere.common.vim.helpers.vim_utils import (get_obj, get_obj_by_moId, delete_object)
|
||||
from samples.vsphere.vcenter.helper.folder_helper import get_folder
|
||||
|
||||
|
||||
class VmtxPublish(SampleBase):
|
||||
"""
|
||||
Demonstrates the VMTX push sync workflow to publish and subscribe VMTX items.
|
||||
Note: the workflow needs an existing VC datastore with available storage.
|
||||
"""
|
||||
|
||||
SYNC_TIMEOUT_SEC = 60
|
||||
|
||||
def __init__(self):
|
||||
SampleBase.__init__(self, self.__doc__)
|
||||
|
||||
self.servicemanager = None
|
||||
self.client = None
|
||||
self.helper = None
|
||||
self.datastore_name = None
|
||||
self.resource_pool_id = None
|
||||
self.folder_id = None
|
||||
|
||||
self.pub_libs_to_clean = []
|
||||
self.sub_libs_to_clean = []
|
||||
self.vms_to_clean = []
|
||||
|
||||
def _options(self):
|
||||
self.argparser.add_argument('-datacentername', '--datacentername', required=True,
|
||||
help='The name of the datacenter')
|
||||
self.argparser.add_argument('-datastorename', '--datastorename', required=True,
|
||||
help='The name of the datastore.')
|
||||
self.argparser.add_argument('-clustername', '--clustername', required=True,
|
||||
help='The name of the cluster to be used.')
|
||||
self.argparser.add_argument('-foldername', '--foldername', required=True,
|
||||
help='The name of the folder in the '
|
||||
'datacenter for creating a subscription')
|
||||
|
||||
def _setup(self):
|
||||
self.datastore_name = self.args.datastorename
|
||||
self.cluster_name = self.args.clustername
|
||||
self.folder_name = self.args.foldername
|
||||
self.datacenter_name = self.args.datacentername
|
||||
self.servicemanager = self.get_service_manager()
|
||||
|
||||
self.datastore_id = get_datastore_id(service_manager=self.servicemanager,
|
||||
datastore_name=self.datastore_name)
|
||||
self.client = ClsApiClient(self.servicemanager)
|
||||
self.helper = ClsApiHelper(self.client, self.skip_verification)
|
||||
session = get_unverified_session() if self.skip_verification else None
|
||||
self.vsphere_client = create_vsphere_client(server=self.server,
|
||||
username=self.username,
|
||||
password=self.password,
|
||||
session=session)
|
||||
self.folder_id = get_folder(self.vsphere_client,
|
||||
self.datacenter_name,
|
||||
self.folder_name)
|
||||
self.storage_backings = self.helper.create_storage_backings(
|
||||
self.servicemanager, self.datastore_name)
|
||||
cluster_obj = get_obj(self.servicemanager.content,
|
||||
[vim.ClusterComputeResource], self.cluster_name)
|
||||
self.resource_pool_id = cluster_obj.resourcePool._GetMoId()
|
||||
|
||||
def _execute(self):
|
||||
self.create_new_subscription()
|
||||
self.create_subscription_from_existing_subscribed_library()
|
||||
|
||||
def create_new_subscription(self):
|
||||
"""
|
||||
Sample code for creating a new subscription for VMTX templates
|
||||
"""
|
||||
|
||||
# Create a published library and a new subscription
|
||||
pub_lib_name = "pub_lib_new_" + str(uuid.uuid4())
|
||||
pub_lib_id = self.create_published_library(pub_lib_name).id
|
||||
self.pub_libs_to_clean.append(pub_lib_id)
|
||||
sub_lib_name = "sub_lib_new_" + str(uuid.uuid4())
|
||||
subscription_id = self.create_subscription_new(pub_lib_id, sub_lib_name)
|
||||
|
||||
# Get the subscribed library associated with the subscription
|
||||
subscription_info = self.client.subscriptions.get(pub_lib_id, subscription_id)
|
||||
sub_lib = self.client.library_service.get(subscription_info.subscribed_library)
|
||||
self.sub_libs_to_clean.append(sub_lib.id)
|
||||
|
||||
# - Create a VMTX item on the published library
|
||||
# - Push-synchronize the subscription and verify the sync
|
||||
vm_name = "sample_vm_new_" + str(uuid.uuid4())
|
||||
vmtx_item_name = "sample_vmtx_item_existing_" + str(uuid.uuid4())
|
||||
vmtx_item_id = self.create_vmtx_item(pub_lib_id, vm_name, vmtx_item_name)
|
||||
self.client.local_library_service.publish(pub_lib_id)
|
||||
assert self.verify_vmtx_sync(sub_lib, vmtx_item_id)
|
||||
|
||||
def create_subscription_from_existing_subscribed_library(self):
|
||||
"""
|
||||
Sample code for converting existing Subscribed library
|
||||
to use a VMTX subscription
|
||||
"""
|
||||
|
||||
# Create a published library and get its publish URL
|
||||
pub_lib_name = "pub_lib_existing_" + str(uuid.uuid4())
|
||||
pub_lib = self.create_published_library(pub_lib_name)
|
||||
self.pub_libs_to_clean.append(pub_lib.id)
|
||||
pub_lib_url = pub_lib.publish_info.publish_url
|
||||
|
||||
# Create a subscribed library
|
||||
sub_lib_name = "sub_lib_existing_" + str(uuid.uuid4())
|
||||
sub_lib = self.create_subscribed_library(pub_lib_url, sub_lib_name)
|
||||
self.create_subscription_for_existing_subscribed_library(pub_lib.id, sub_lib.id)
|
||||
|
||||
# - Create a VMTX item on the published library
|
||||
# - Push-synchronize the subscription and verify the sync
|
||||
vm_name = "sample_vm_existing_" + str(uuid.uuid4())
|
||||
vmtx_item_name = "sample_vmtx_item_existing_" + str(uuid.uuid4())
|
||||
vmtx_item_id = self.create_vmtx_item(pub_lib.id, vm_name, vmtx_item_name)
|
||||
self.client.local_library_service.publish(pub_lib.id)
|
||||
assert self.verify_vmtx_sync(sub_lib, vmtx_item_id)
|
||||
|
||||
def create_vmtx_item(self, pub_lib_id, vm_name, vmtx_item_name):
|
||||
# Upload OVF, create a VM, and use that VM to create a VMTX item
|
||||
ovf_item_id = self.create_ovf_template_item(pub_lib_id)
|
||||
source_vmtx_vm_id = self.create_vm(ovf_item_id, vm_name)
|
||||
self.vms_to_clean.append(source_vmtx_vm_id)
|
||||
vmtx_item_id = self.create_vmtx_item_from_vm(
|
||||
pub_lib_id, source_vmtx_vm_id, vmtx_item_name)
|
||||
return vmtx_item_id
|
||||
|
||||
def create_published_library(self, pub_lib_name):
|
||||
pub_info = PublishInfo()
|
||||
pub_info.published = True
|
||||
# VMTX sync needs the authentication to be turned off
|
||||
pub_info.authentication_method = PublishInfo.AuthenticationMethod.NONE
|
||||
pub_spec = LibraryModel()
|
||||
pub_spec.name = pub_lib_name
|
||||
pub_spec.description = "Sample Published library"
|
||||
pub_spec.publish_info = pub_info
|
||||
pub_spec.type = pub_spec.LibraryType.LOCAL
|
||||
pub_spec.storage_backings = self.storage_backings
|
||||
|
||||
pub_lib_id = self.client.local_library_service.create(
|
||||
create_spec=pub_spec, client_token=generate_random_uuid())
|
||||
print("Published library created, id: {0}".format(pub_lib_id))
|
||||
|
||||
pub_lib = self.client.library_service.get(pub_lib_id)
|
||||
return pub_lib
|
||||
|
||||
def create_subscribed_library(self, pub_lib_url, sub_lib_name):
|
||||
# Build the subscription information using the publish URL of the published
|
||||
# library
|
||||
|
||||
sub_info = SubscriptionInfo()
|
||||
sub_info.authentication_method = SubscriptionInfo.AuthenticationMethod.NONE
|
||||
# on_demand = False for library and item level publish
|
||||
# on_demand = True for only item level publish, the library level
|
||||
# publish will only sync the item metadata
|
||||
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 = sub_lib_name
|
||||
sub_spec.type = sub_spec.LibraryType.SUBSCRIBED
|
||||
sub_spec.subscription_info = sub_info
|
||||
sub_spec.storage_backings = self.storage_backings
|
||||
|
||||
sub_lib_id = self.client.subscribed_library_service.create(
|
||||
create_spec=sub_spec, client_token=generate_random_uuid())
|
||||
self.sub_libs_to_clean.append(sub_lib_id)
|
||||
print("Subscribed library created, id: {0}".format(sub_lib_id))
|
||||
sub_lib = self.client.subscribed_library_service.get(sub_lib_id)
|
||||
return sub_lib
|
||||
|
||||
def create_subscription_new(self, pub_lib_id, sub_lib_name):
|
||||
# Create a new subscription. Such subscription is created on the published
|
||||
# library, and can be later used for a push-sync
|
||||
#
|
||||
# spec
|
||||
# +--subscribed_library
|
||||
# +--target: CREATE_NEW
|
||||
# +--subscribed_library: DO NOT SPECIFY as this is new
|
||||
# +--new_subscribed_library
|
||||
# +--name, description, automatic_sync_enabled, on_demand
|
||||
# +--location: LOCAL/REMOTE
|
||||
# +--subscribed_library_vcenter: (VcenterInfo) DO NOT SPECIFY for location=LOCAL
|
||||
# +--placement:
|
||||
# +--Resource pool and folder for the VM
|
||||
# +--network for the VM
|
||||
|
||||
client_token = str(uuid.uuid4())
|
||||
spec = Subscriptions.CreateSpec()
|
||||
subscribed_library = Subscriptions.CreateSpecSubscribedLibrary()
|
||||
subscribed_library.location = Subscriptions.Location.LOCAL
|
||||
|
||||
subscribed_library.target = \
|
||||
Subscriptions.CreateSpecSubscribedLibrary.Target.CREATE_NEW
|
||||
new_subscribed_library = Subscriptions.CreateSpecNewSubscribedLibrary()
|
||||
new_subscribed_library.name = sub_lib_name
|
||||
new_subscribed_library.description = "Sample subscribed library"
|
||||
|
||||
backing = StorageBacking(StorageBacking.Type.DATASTORE, self.datastore_id)
|
||||
new_subscribed_library.storage_backings = [backing]
|
||||
|
||||
new_subscribed_library.automatic_sync_enabled = False
|
||||
# on_demand = False for library and item level publish
|
||||
# on_demand = True for only item level publish, the library level
|
||||
# publish will only sync the item metadata
|
||||
new_subscribed_library.on_demand = False
|
||||
subscribed_library.new_subscribed_library = new_subscribed_library
|
||||
|
||||
placement = Subscriptions.CreateSpecPlacement()
|
||||
placement.resource_pool = self.resource_pool_id
|
||||
placement.folder = self.folder_id
|
||||
|
||||
# Setting network to null implies that the subscription will use the
|
||||
# same network as the source VM
|
||||
# Warning - this may lead to failure if the same network is not
|
||||
# available to the subscriber
|
||||
placement.network = None
|
||||
|
||||
subscribed_library.placement = placement
|
||||
spec.subscribed_library = subscribed_library
|
||||
|
||||
subscription_id = self.client.subscriptions.create(
|
||||
pub_lib_id, spec, client_token)
|
||||
print("Subscription created, id: {0}".format(subscription_id))
|
||||
return subscription_id
|
||||
|
||||
def create_subscription_for_existing_subscribed_library(self, pub_lib_id, sub_lib_id):
|
||||
# Create a subscription for an existing subscribed library. This subscription
|
||||
# and can be later used for a push-sync to that subscribed library
|
||||
#
|
||||
# spec
|
||||
# +--subscribed_library
|
||||
# +--target: USE_EXISTING
|
||||
# +--subscribed_library: ID of existing subscribed library
|
||||
# +--new_subscribed_library: DO NOT SPECIFY for target=USE_EXISTING
|
||||
# +--location: LOCAL/REMOTE
|
||||
# +--subscribed_library_vcenter: (VcenterInfo) DO NOT SPECIFY from location=LOCAL
|
||||
# +--placement:
|
||||
# +--Resource pool and folder for the VM
|
||||
# +--network for the VM
|
||||
|
||||
client_token = str(uuid.uuid4())
|
||||
spec = Subscriptions.CreateSpec()
|
||||
subscribed_library = Subscriptions.CreateSpecSubscribedLibrary()
|
||||
|
||||
subscribed_library.target = \
|
||||
Subscriptions.CreateSpecSubscribedLibrary.Target.USE_EXISTING
|
||||
subscribed_library.subscribed_library = sub_lib_id
|
||||
subscribed_library.location = "LOCAL"
|
||||
placement = Subscriptions.CreateSpecPlacement()
|
||||
placement.resource_pool = self.resource_pool_id
|
||||
placement.folder = self.folder_id
|
||||
|
||||
# Setting network to null implies that the subscription will use the
|
||||
# same network as the source VM
|
||||
# Warning - this may lead to failure if the same network is not
|
||||
# available to the subscriber
|
||||
placement.network = None
|
||||
|
||||
subscribed_library.placement = placement
|
||||
spec.subscribed_library = subscribed_library
|
||||
|
||||
subscription_id = self.client.subscriptions.create(
|
||||
pub_lib_id, spec, client_token)
|
||||
print("Subscription created id: {0}".format(subscription_id))
|
||||
return subscription_id
|
||||
|
||||
def create_ovf_template_item(self, library_id):
|
||||
# Create an OVF item
|
||||
ovf_item_id = self.helper.create_library_item(library_id=library_id,
|
||||
item_name='sample-ovf-item',
|
||||
item_description='Sample OVF template',
|
||||
item_type='ovf')
|
||||
print('Library item created id: {0}'.format(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)
|
||||
return ovf_item_id
|
||||
|
||||
def create_vm(self, ovf_item_id, vm_name):
|
||||
# Deploy a VM using the given ovf template
|
||||
deployment_target = LibraryItem.DeploymentTarget(resource_pool_id=self.resource_pool_id)
|
||||
ovf_summary = self.client.ovf_lib_item_service.filter(ovf_library_item_id=ovf_item_id,
|
||||
target=deployment_target)
|
||||
vm_id = self.deploy_ovf_template(ovf_item_id, ovf_summary, deployment_target, vm_name)
|
||||
print("Virtual Machine created, id: {0}".format(vm_id))
|
||||
return vm_id
|
||||
|
||||
def deploy_ovf_template(self, lib_item_id, ovf_summary, deployment_target, vm_name):
|
||||
# Build the deployment spec
|
||||
deployment_spec = LibraryItem.ResourcePoolDeploymentSpec(
|
||||
name=vm_name, annotation=ovf_summary.annotation, accept_all_eula=True)
|
||||
|
||||
# Deploy the ovf template
|
||||
result = self.client.ovf_lib_item_service.deploy(
|
||||
lib_item_id, deployment_target,
|
||||
deployment_spec, client_token=generate_random_uuid())
|
||||
if result.succeeded:
|
||||
vm_id = result.resource_id.id
|
||||
return vm_id
|
||||
else:
|
||||
print('Deployment failed.')
|
||||
for error in result.error.errors:
|
||||
print('OVF error: {}'.format(error.message))
|
||||
raise Exception('OVF deploy failed.')
|
||||
|
||||
def create_vmtx_item_from_vm(self, library_id, source_vm_id, vmtx_item_name):
|
||||
# Create a VMTX item using the given VM as source
|
||||
create_spec = VmtxLibraryItem.CreateSpec()
|
||||
create_spec.source_vm = source_vm_id
|
||||
create_spec.library = library_id
|
||||
create_spec.name = vmtx_item_name
|
||||
create_spec.description = 'sample-vmtx-description'
|
||||
create_spec.placement = VmtxLibraryItem.CreatePlacementSpec()
|
||||
create_spec.placement.resource_pool = self.resource_pool_id
|
||||
vmtx_item_id = self.client.vmtx_service.create(create_spec)
|
||||
print("VMTX item created id: {0}".format(vmtx_item_id))
|
||||
return vmtx_item_id
|
||||
|
||||
def verify_vmtx_sync(self, sub_lib, vmtx_item_id):
|
||||
# Wait until the VMTX item in the subscription is synchronized with
|
||||
# the one in the published library
|
||||
|
||||
start_time = time.time()
|
||||
while time.time() - start_time < self.SYNC_TIMEOUT_SEC:
|
||||
sub_item_ids = self.client.library_item_service.list(sub_lib.id)
|
||||
# Only vmtx item will be synced using the push mechanism, so check
|
||||
# the length to be one
|
||||
if len(sub_item_ids) == 1:
|
||||
source_id = self.client.library_item_service.get(
|
||||
sub_item_ids[0]).source_id
|
||||
# Verify that the source for the VMTX item in the subscribed
|
||||
# library is the VMTX item in the published library
|
||||
if source_id == vmtx_item_id:
|
||||
return True
|
||||
else:
|
||||
print("VMTX source item id mismatch")
|
||||
return False
|
||||
# Give some more time for sync
|
||||
time.sleep(1)
|
||||
|
||||
print("Timed out while waiting for sync")
|
||||
return False
|
||||
|
||||
def _cleanup(self):
|
||||
for lib_id in self.pub_libs_to_clean:
|
||||
print("deleting published library: {0}".format(lib_id))
|
||||
self.client.local_library_service.delete(lib_id)
|
||||
for lib_id in self.sub_libs_to_clean:
|
||||
print("deleting subscribed library: {0}".format(lib_id))
|
||||
self.client.subscribed_library_service.delete(lib_id)
|
||||
for vm_id in self.vms_to_clean:
|
||||
vm_obj = get_obj_by_moId(self.servicemanager.content,
|
||||
[vim.VirtualMachine], vm_id)
|
||||
delete_object(self.servicemanager.content, vm_obj)
|
||||
|
||||
|
||||
def main():
|
||||
sample = VmtxPublish()
|
||||
sample.main()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
Loading…
Reference in New Issue
Block a user