initial commit

This commit is contained in:
Kosta Mushkin
2025-04-12 14:33:32 -04:00
parent 955ec79014
commit ba16ef9a08
83 changed files with 10290 additions and 2 deletions
+106
View File
@@ -0,0 +1,106 @@
# Legal Disclaimer
# This script is an example script and is not supported under any Zerto support program or service.
# The author and Zerto further disclaim all implied warranties including, without limitation,
# any implied warranties of merchantability or of fitness for a particular purpose.
# In no event shall Zerto, its authors or anyone else involved in the creation,
# production or delivery of the scripts be liable for any damages whatsoever (including,
# without limitation, damages for loss of business profits, business interruption, loss of business
# information, or other pecuniary loss) arising out of the use of or the inability to use the sample
# scripts or documentation, even if the author or Zerto has been advised of the possibility of such damages.
# The entire risk arising out of the use or performance of the sample scripts and documentation remains with you.
"""
Zerto Alert Management Example Script
This script demonstrates basic alert management using the Zerto Virtual Manager (ZVM) API.
It shows how to list alerts and perform basic alert operations (dismiss/undismiss).
Key Features:
1. Alert Monitoring:
- List all current alerts
- Display alert details
- Manage alert states (dismiss/undismiss)
Required Arguments:
--zvm_address: ZVM server address
--client_id: Keycloak client ID
--client_secret: Keycloak client secret
--ignore_ssl: Ignore SSL certificate verification (optional)
Example Usage:
python examples/alerts_example.py \
--zvm_address "192.168.111.20" \
--client_id "zerto-api" \
--client_secret "your-secret-here" \
--ignore_ssl
"""
import sys
import os
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
import argparse
import logging
import urllib3
import json
from zvml import ZVMLClient
# Disable SSL warnings
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
def main():
parser = argparse.ArgumentParser(description="Zerto Alerts Example")
parser.add_argument("--zvm_address", required=True, help="ZVM address")
parser.add_argument('--client_id', required=True, help='Keycloak client ID')
parser.add_argument('--client_secret', required=True, help='Keycloak client secret')
parser.add_argument("--ignore_ssl", action="store_true", help="Ignore SSL certificate verification")
args = parser.parse_args()
logging.basicConfig(level=logging.INFO)
try:
# Connect to ZVM
client = ZVMLClient(
zvm_address=args.zvm_address,
client_id=args.client_id,
client_secret=args.client_secret,
verify_certificate=not args.ignore_ssl
)
# Get current alerts
alerts = client.alerts.get_alerts()
if not alerts:
logging.info("No alerts found in the system")
return
# Display alerts
logging.info(f"Found {len(alerts)} alerts:")
for alert in alerts:
logging.info(f"\nAlert Details:")
logging.info(f" Description: {alert.get('Description')}")
logging.info(f" Status: {alert.get('Status')}")
logging.info(f" Level: {alert.get('Level')}")
logging.info(f" Turn off Time: {alert.get('TurnedOffTime')}")
logging.info(f" Entity: {alert.get('Entity')}")
logging.info(f" Help Identifier: {alert.get('HelpIdentifier')}")
# Get alert identifier
alert_id = alert.get('Link', {}).get('identifier')
if alert_id:
# Dismiss alert
input(f"\nPress Enter to dismiss alert {alert_id}...")
client.alerts.dismiss_alert(alert_identifier=alert_id)
logging.info(f"Alert {alert_id} dismissed")
# Undismiss alert
input(f"Press Enter to undismiss alert {alert_id}...")
client.alerts.undismiss_alert(alert_identifier=alert_id)
logging.info(f"Alert {alert_id} undismissed")
except Exception as e:
logging.exception("Error:")
logging.error(f"Error: {e}")
if __name__ == "__main__":
main()
+100
View File
@@ -0,0 +1,100 @@
# Legal Disclaimer
# This script is an example script and is not supported under any Zerto support program or service.
# The author and Zerto further disclaim all implied warranties including, without limitation,
# any implied warranties of merchantability or of fitness for a particular purpose.
# In no event shall Zerto, its authors or anyone else involved in the creation,
# production or delivery of the scripts be liable for any damages whatsoever (including,
# without limitation, damages for loss of business profits, business interruption, loss of business
# information, or other pecuniary loss) arising out of the use of or the inability to use the sample
# scripts or documentation, even if the author or Zerto has been advised of the possibility of such damages.
# The entire risk arising out of the use or performance of the sample scripts and documentation remains with you.
"""
Zerto Datastores Example Script
This script demonstrates how to retrieve and list datastores from a Zerto environment.
The script performs the following steps:
1. Connects to Zerto Virtual Manager (ZVM)
2. Gets the local site identifier
3. Lists all datastores in the site
4. Gets detailed information about a specific datastore
Required Arguments:
--zvm_address: ZVM address
--client_id: Keycloak client ID
--client_secret: Keycloak client secret
Optional Arguments:
--ignore_ssl: Ignore SSL certificate verification
Example Usage:
python examples/datastore_example.py \
--zvm_address <zvm_address> \
--client_id <client_id> \
--client_secret <client_secret> \
--ignore_ssl
"""
import sys
import os
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
import argparse
import logging
import urllib3
import json
from zvml import ZVMLClient
# Disable SSL warnings
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
def main():
parser = argparse.ArgumentParser(description="Zerto Datastores Example")
parser.add_argument("--zvm_address", required=True, help="ZVM address")
parser.add_argument('--client_id', required=True, help='Keycloak client ID')
parser.add_argument('--client_secret', required=True, help='Keycloak client secret')
parser.add_argument("--ignore_ssl", action="store_true", help="Ignore SSL certificate verification")
args = parser.parse_args()
# Configure logging
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s'
)
try:
# Connect to ZVM
logging.info(f"Connecting to ZVM at {args.zvm_address}")
client = ZVMLClient(
zvm_address=args.zvm_address,
client_id=args.client_id,
client_secret=args.client_secret,
verify_certificate=not args.ignore_ssl
)
# Get local site identifier
local_site = client.localsite.get_local_site()
site_identifier = local_site.get('SiteIdentifier')
logging.info(f"Local site identifier: {site_identifier}")
# Get datastores using VirtualizationSites API
datastores = client.virtualization_sites.get_virtualization_site_datastores(site_identifier)
logging.info("\nDatastores in site:")
logging.info(json.dumps(datastores, indent=2))
# Get specific datastore details if any exist
if datastores:
first_ds_id = datastores[0].get('DatastoreIdentifier')
logging.info(f"\nGetting details for specific datastore: {first_ds_id}")
ds_details = client.datastores.list_datastores(first_ds_id)
logging.info("Datastore details:")
logging.info(json.dumps(ds_details, indent=2))
except Exception as e:
logging.error(f"Error occurred: {e}")
raise
if __name__ == "__main__":
main()
+117
View File
@@ -0,0 +1,117 @@
#!/usr/bin/env python3
# Legal Disclaimer
# This script is an example script and is not supported under any Zerto support program or service.
# The author and Zerto further disclaim all implied warranties including, without limitation,
# any implied warranties of merchantability or of fitness for a particular purpose.
import argparse
import sys
import os
import time
import paramiko
import logging
import urllib3
from zvml.client import Client
from zvml.encryptiondetection import EncryptionDetection
# Disable SSL warnings
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
def setup_client(args):
"""Initialize and return Zerto client"""
client = Client(
zvm_address=args.zvm_address,
client_id=args.client_id,
client_secret=args.client_secret,
verify_certificate=not args.ignore_ssl
)
return client
def setup_encrypted_volume(ssh_host: str, ssh_user: str, ssh_password: str):
"""Create and encrypt a volume on the Linux VM."""
try:
# Connect to the Linux VM
ssh = paramiko.SSHClient()
ssh.set_missing_host_key_policy(paramiko.AutoAddPolicy())
ssh.connect(ssh_host, username=ssh_user, password=ssh_password)
logging.info(f"Successfully connected to {ssh_host}")
# Create a test file system
commands = [
"sudo dd if=/dev/zero of=/root/container.img bs=1M count=100", # Create 100MB file
"sudo losetup /dev/loop0 /root/container.img", # Set up loop device
"sudo cryptsetup -y luksFormat /dev/loop0", # Encrypt with LUKS
"echo 'YES' | sudo cryptsetup luksOpen /dev/loop0 encrypted_volume", # Open encrypted volume
"sudo mkfs.ext4 /dev/mapper/encrypted_volume", # Create filesystem
"sudo mkdir -p /mnt/encrypted", # Create mount point
"sudo mount /dev/mapper/encrypted_volume /mnt/encrypted", # Mount encrypted volume
"sudo dd if=/dev/urandom of=/mnt/encrypted/testfile bs=1M count=50" # Create test file with random data
]
for cmd in commands:
logging.info(f"Executing: {cmd}")
stdin, stdout, stderr = ssh.exec_command(cmd)
exit_status = stdout.channel.recv_exit_status()
if exit_status != 0:
error = stderr.read().decode()
logging.error(f"Command failed with status {exit_status}: {error}")
raise Exception(f"Command failed: {cmd}")
logging.info("Successfully created and encrypted test volume")
except Exception as e:
logging.error(f"Failed to setup encrypted volume: {str(e)}")
raise
finally:
ssh.close()
def main():
parser = argparse.ArgumentParser(description="Encryption Detection Example")
parser.add_argument("--zvm_address", required=True, help="ZVM address")
parser.add_argument('--client_id', required=True, help='Keycloak client ID')
parser.add_argument('--client_secret', required=True, help='Keycloak client secret')
parser.add_argument("--ignore_ssl", action="store_true", help="Ignore SSL certificate verification")
parser.add_argument("--vm_address", required=True, help="Linux VM address")
parser.add_argument("--vm_user", required=True, help="Linux VM username")
parser.add_argument("--vm_password", required=True, help="Linux VM password")
args = parser.parse_args()
# Configure logging
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s'
)
try:
# Setup client
client = setup_client(args)
encryption_detection = EncryptionDetection(client)
logging.info("Successfully connected to ZVM")
# Setup encrypted volume on Linux VM
setup_encrypted_volume(args.vm_address, args.vm_user, args.vm_password)
# Wait for encryption detection to process
logging.info("Waiting for encryption detection to process (30 seconds)...")
time.sleep(30)
# Check for suspected encrypted volumes
detections = encryption_detection.list_suspected_volumes()
if detections:
logging.info("Suspected encrypted volumes detected:")
for detection in detections:
logging.info(f"Volume: {detection.get('VolumeName', 'Unknown')}")
logging.info(f"Detection Type: {detection.get('DetectionType', 'Unknown')}")
logging.info(f"Confidence Level: {detection.get('ConfidenceLevel', 'Unknown')}")
logging.info("---")
else:
logging.info("No suspected encrypted volumes detected")
except Exception as e:
logging.exception("Error occurred:")
sys.exit(1)
if __name__ == "__main__":
main()
+136
View File
@@ -0,0 +1,136 @@
# Legal Disclaimer
# This script is an example script and is not supported under any Zerto support program or service.
# The author and Zerto further disclaim all implied warranties including, without limitation,
# any implied warranties of merchantability or of fitness for a particular purpose.
# In no event shall Zerto, its authors or anyone else involved in the creation,
# production or delivery of the scripts be liable for any damages whatsoever (including,
# without limitation, damages for loss of business profits, business interruption, loss of business
# information, or other pecuniary loss) arising out of the use of or the inability to use the sample
# scripts or documentation, even if the author or Zerto has been advised of the possibility of such damages.
# The entire risk arising out of the use or performance of the sample scripts and documentation remains with you.
"""
Zerto Events Example Script
This script demonstrates how to retrieve and manage events in a Zerto environment.
The script performs the following steps:
1. Connects to Zerto Virtual Manager (ZVM)
2. Lists available event types
3. Lists available event entities
4. Lists available event categories
5. Retrieves events from the last hour
6. Demonstrates filtered event queries
7. Gets detailed information about specific events
Required Arguments:
--zvm_address: ZVM address
--client_id: Keycloak client ID
--client_secret: Keycloak client secret
Optional Arguments:
--ignore_ssl: Ignore SSL certificate verification
Example Usage:
python examples/events_example.py \
--zvm_address <zvm_address> \
--client_id <client_id> \
--client_secret <client_secret> \
--ignore_ssl
"""
import sys
import os
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
import argparse
import logging
import urllib3
import json
from zvml import ZVMLClient
from datetime import datetime, timedelta
# Disable SSL warnings
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
def main():
parser = argparse.ArgumentParser(description="Zerto Events Example")
parser.add_argument("--zvm_address", required=True, help="ZVM address")
parser.add_argument('--client_id', required=True, help='Keycloak client ID')
parser.add_argument('--client_secret', required=True, help='Keycloak client secret')
parser.add_argument("--ignore_ssl", action="store_true", help="Ignore SSL certificate verification")
args = parser.parse_args()
# Configure logging
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s'
)
try:
# Connect to ZVM
logging.info(f"Connecting to ZVM at {args.zvm_address}")
client = ZVMLClient(
zvm_address=args.zvm_address,
client_id=args.client_id,
client_secret=args.client_secret,
verify_certificate=not args.ignore_ssl
)
# Get event types
logging.info("\nFetching event types...")
event_types = client.events.list_event_types()
logging.info(f"Found {len(event_types)} event types:")
logging.info(json.dumps(event_types[:3], indent=2)) # Show first 3 for brevity
# Get event entities
logging.info("\nFetching event entities...")
event_entities = client.events.list_event_entities()
logging.info(f"Found {len(event_entities)} event entities:")
logging.info(json.dumps(event_entities[:3], indent=2)) # Show first 3 for brevity
# Get event categories
logging.info("\nFetching event categories...")
event_categories = client.events.list_event_categories()
logging.info(f"Found {len(event_categories)} event categories:")
logging.info(json.dumps(event_categories[:3], indent=2)) # Show first 3 for brevity
# Get events from the last 1 hour
start_date = (datetime.utcnow() - timedelta(hours=1)).isoformat() + 'Z'
end_date = datetime.utcnow().isoformat() + 'Z'
logging.info(f"\nFetching events from {start_date} to {end_date}...")
events = client.events.list_events(
start_date=start_date,
end_date=end_date
)
logging.info(f"Found {len(events)} events in the last 24 hours:")
if events:
logging.info(json.dumps(events[:3], indent=2)) # Show first 3 for brevity
# Get events with filters
logging.info("\nFetching filtered events...")
filtered_events = client.events.list_events(
start_date=start_date,
end_date=end_date,
event_type=18, # Using numeric event type
category="Events" # Using correct category from list_event_categories
)
logging.info(f"Found {len(filtered_events)} filtered events:")
if filtered_events:
logging.info(json.dumps(filtered_events[:3], indent=2)) # Show first 3 for brevity
# If we have any events, get details for a specific event
if events:
event_id = events[0].get('EventIdentifier')
logging.info(f"\nFetching details for event {event_id}...")
event_details = client.events.list_events(event_identifier=event_id)
logging.info("Event details:")
logging.info(json.dumps(event_details, indent=2))
except Exception as e:
logging.error(f"Error occurred: {e}")
raise
if __name__ == "__main__":
main()
+127
View File
@@ -0,0 +1,127 @@
# Legal Disclaimer
# This script is an example script and is not supported under any Zerto support program or service.
# The author and Zerto further disclaim all implied warranties including, without limitation,
# any implied warranties of merchantability or of fitness for a particular purpose.
# In no event shall Zerto, its authors or anyone else involved in the creation,
# production or delivery of the scripts be liable for any damages whatsoever (including,
# without limitation, damages for loss of business profits, business interruption, loss of business
# information, or other pecuniary loss) arising out of the use of or the inability to use the sample
# scripts or documentation, even if the author or Zerto has been advised of the possibility of such damages.
# The entire risk arising out of the use or performance of the sample scripts and documentation remains with you.
"""
Zerto License Management Example Script
This script demonstrates how to manage Zerto licenses through the API.
The script performs the following steps:
1. Connects to Zerto Virtual Manager (ZVM)
2. Retrieves current license information
3. Updates the license if a new key is provided
4. Verifies the updated license details
5. Optionally can delete the license (commented out for safety)
Required Arguments:
--zvm_address: ZVM address
--client_id: Keycloak client ID
--client_secret: Keycloak client secret
Optional Arguments:
--license_key: License key to add/update
--ignore_ssl: Ignore SSL certificate verification
Example Usage:
python examples/license_example.py \
--zvm_address <zvm_address> \
--client_id <client_id> \
--client_secret <client_secret> \
--license_key <license_key> \
--ignore_ssl
"""
import sys
import os
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
import argparse
import logging
import urllib3
import json
from zvml import ZVMLClient
# Disable SSL warnings
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
def main():
parser = argparse.ArgumentParser(description="Zerto License Example")
parser.add_argument("--zvm_address", required=True, help="ZVM address")
parser.add_argument('--client_id', required=True, help='Keycloak client ID')
parser.add_argument('--client_secret', required=True, help='Keycloak client secret')
parser.add_argument("--license_key", help="License key to add/update")
parser.add_argument("--ignore_ssl", action="store_true", help="Ignore SSL certificate verification")
args = parser.parse_args()
# Configure logging
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s'
)
try:
# Connect to ZVM
logging.info(f"Connecting to ZVM at {args.zvm_address}")
client = ZVMLClient(
zvm_address=args.zvm_address,
client_id=args.client_id,
client_secret=args.client_secret,
verify_certificate=not args.ignore_ssl
)
# Get current license information
logging.info("\nFetching current license information...")
license_info = client.license.get_license()
if license_info:
logging.info("Current license details:")
logging.info(json.dumps(license_info, indent=2))
else:
logging.info("No license currently installed")
# If license key is provided, update the license
if args.license_key:
logging.info(f"\nUpdating license with new key...")
update_result = client.license.put_license(args.license_key)
if update_result:
logging.info("License update result:")
logging.info(json.dumps(update_result, indent=2))
else:
logging.info("License updated successfully (no content returned)")
# Get updated license information
logging.info("\nFetching updated license information...")
updated_license = client.license.get_license()
if updated_license:
logging.info("Updated license details:")
logging.info(json.dumps(updated_license, indent=2))
# Delete license (commented out for safety - uncomment if needed)
"""
logging.info("\nDeleting license...")
delete_result = client.license.delete_license()
if delete_result:
logging.info("License deletion result:")
logging.info(json.dumps(delete_result, indent=2))
else:
logging.info("License deleted successfully (no content returned)")
# Verify license is deleted
final_check = client.license.get_license()
if not final_check:
logging.info("License successfully removed")
"""
except Exception as e:
logging.error(f"Error occurred: {e}")
raise
if __name__ == "__main__":
main()
+138
View File
@@ -0,0 +1,138 @@
# Legal Disclaimer
# This script is an example script and is not supported under any Zerto support program or service.
# The author and Zerto further disclaim all implied warranties including, without limitation,
# any implied warranties of merchantability or of fitness for a particular purpose.
# In no event shall Zerto, its authors or anyone else involved in the creation,
# production or delivery of the scripts be liable for any damages whatsoever (including,
# without limitation, damages for loss of business profits, business interruption, loss of business
# information, or other pecuniary loss) arising out of the use of or the inability to use the sample
# scripts or documentation, even if the author or Zerto has been advised of the possibility of such damages.
# The entire risk arising out of the use or performance of the sample scripts and documentation remains with you.
"""
Zerto Local Site Management Example Script
This script demonstrates how to manage and retrieve information about the local Zerto site.
The script performs the following steps:
1. Connects to Zerto Virtual Manager (ZVM)
2. Retrieves local site information
3. Gets site pairing statuses
4. Sends usage data to Zerto
5. Manages login banner settings:
- Gets current banner configuration
- Sets a new test banner
- Verifies the updated settings
- Disables the banner
Required Arguments:
--zvm_address: ZVM address
--client_id: Keycloak client ID
--client_secret: Keycloak client secret
Optional Arguments:
--ignore_ssl: Ignore SSL certificate verification
Example Usage:
python examples/localsite_example.py \
--zvm_address <zvm_address> \
--client_id <client_id> \
--client_secret <client_secret> \
--ignore_ssl
"""
import sys
import os
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
import argparse
import logging
import urllib3
import json
from zvml import ZVMLClient
# Disable SSL warnings
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
def main():
parser = argparse.ArgumentParser(description="Zerto Local Site Example")
parser.add_argument("--zvm_address", required=True, help="ZVM address")
parser.add_argument('--client_id', required=True, help='Keycloak client ID')
parser.add_argument('--client_secret', required=True, help='Keycloak client secret')
parser.add_argument("--ignore_ssl", action="store_true", help="Ignore SSL certificate verification")
args = parser.parse_args()
# Configure logging
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s'
)
try:
# Connect to ZVM
logging.info(f"Connecting to ZVM at {args.zvm_address}")
client = ZVMLClient(
zvm_address=args.zvm_address,
client_id=args.client_id,
client_secret=args.client_secret,
verify_certificate=not args.ignore_ssl
)
# Get local site information
logging.info("\nFetching local site information...")
local_site = client.localsite.get_local_site()
logging.info("Local site details:")
logging.info(json.dumps(local_site, indent=2))
# Get pairing statuses
logging.info("\nFetching pairing statuses...")
pairing_statuses = client.localsite.get_pairing_statuses()
logging.info("Pairing statuses:")
logging.info(json.dumps(pairing_statuses, indent=2))
# Send usage data
logging.info("\nSending usage data...")
usage_result = client.localsite.send_usage()
if usage_result:
logging.info("Usage data result:")
logging.info(json.dumps(usage_result, indent=2))
else:
logging.info("Usage data sent successfully (no content returned)")
# Get current login banner settings
logging.info("\nFetching current login banner settings...")
current_banner = client.localsite.get_login_banner()
logging.info("Current login banner settings:")
logging.info(json.dumps(current_banner, indent=2))
# Set new login banner
test_banner = "This is a test login banner.\nAccess restricted to authorized users only."
logging.info("\nSetting new login banner...")
banner_result = client.localsite.set_login_banner(
is_enabled=True,
banner_text=test_banner
)
logging.info("Login banner update result:")
logging.info(banner_result)
# Verify the new banner settings
logging.info("\nVerifying updated login banner settings...")
updated_banner = client.localsite.get_login_banner()
logging.info("Updated login banner settings:")
logging.info(json.dumps(updated_banner, indent=2))
# Disable the login banner
logging.info("\nDisabling login banner...")
disable_result = client.localsite.set_login_banner(
is_enabled=False,
banner_text=""
)
logging.info("Login banner disable result:")
logging.info(disable_result)
except Exception as e:
logging.error(f"Error occurred: {e}")
raise
if __name__ == "__main__":
main()
+147
View File
@@ -0,0 +1,147 @@
# Legal Disclaimer
# This script is an example script and is not supported under any Zerto support program or service.
# The author and Zerto further disclaim all implied warranties including, without limitation,
# any implied warranties of merchantability or of fitness for a particular purpose.
# In no event shall Zerto, its authors or anyone else involved in the creation,
# production or delivery of the scripts be liable for any damages whatsoever (including,
# without limitation, damages for loss of business profits, business interruption, loss of business
# information, or other pecuniary loss) arising out of the use of or the inability to use the sample
# scripts or documentation, even if the author or Zerto has been advised of the possibility of such damages.
# The entire risk arising out of the use or performance of the sample scripts and documentation remains with you.
"""
Zerto Peer Sites Management Example Script
This script demonstrates how to manage peer site relationships between Zerto Virtual Managers (ZVMs).
The script performs the following steps:
1. Connects to two Zerto Virtual Managers (ZVMs)
2. Lists existing peer sites from site 1
3. Checks for and removes any existing pairing with site 2
4. Generates a pairing token at site 2
5. Pairs site 1 with site 2 using the token
6. Verifies the pairing by checking the updated peer sites list
Required Arguments:
--site1_zvm_address: Site 1 ZVM address
--site1_client_id: Site 1 Keycloak client ID
--site1_client_secret: Site 1 Keycloak client secret
--site2_zvm_address: Site 2 ZVM address
--site2_client_id: Site 2 Keycloak client ID
--site2_client_secret: Site 2 Keycloak client secret
Optional Arguments:
--ignore_ssl: Ignore SSL certificate verification
Example Usage:
python examples/peersites_example.py \
--site1_zvm_address <zvm1_address> \
--site1_client_id <client_id1> \
--site1_client_secret <secret1> \
--site2_zvm_address <zvm2_address> \
--site2_client_id <client_id2> \
--site2_client_secret <secret2> \
--ignore_ssl
"""
import sys
import os
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
import argparse
import logging
import urllib3
import json
import time
from zvml import ZVMLClient
# Disable SSL warnings
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
def main():
parser = argparse.ArgumentParser(description="Zerto Peer Sites Example")
parser.add_argument("--site1_zvm_address", required=True, help="site 1 ZVM address")
parser.add_argument('--site1_client_id', required=True, help='site 1 Keycloak client ID')
parser.add_argument('--site1_client_secret', required=True, help='site 1 Keycloak client secret')
parser.add_argument("--site2_zvm_address", required=True, help="site 2 ZVM address")
parser.add_argument('--site2_client_id', required=True, help='site 2 Keycloak client ID')
parser.add_argument('--site2_client_secret', required=True, help='site 2 Keycloak client secret')
parser.add_argument("--ignore_ssl", action="store_true", help="Ignore SSL certificate verification")
args = parser.parse_args()
# Configure logging
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s'
)
try:
# Initialize the site 1 client
site1_client = ZVMLClient(
zvm_address=args.site1_zvm_address,
client_id=args.site1_client_id,
client_secret=args.site1_client_secret,
verify_certificate=not args.ignore_ssl
)
# Initialize the site 2 client
site2_client = ZVMLClient(
zvm_address=args.site2_zvm_address,
client_id=args.site2_client_id,
client_secret=args.site2_client_secret,
verify_certificate=not args.ignore_ssl
)
# Example 1: Get all peer sites from site 1
logging.info("\nExample 1: Getting all peer sites from site 1")
peer_sites = site1_client.peersites.get_peer_sites()
logging.info(f"Found {len(peer_sites)} peer sites:")
logging.info(json.dumps(peer_sites, indent=2))
# Check if site2 is already paired and delete if necessary
site2_already_paired = False
site2_identifier = None
for site in peer_sites:
if site['HostName'] == args.site2_zvm_address:
site2_already_paired = True
site2_identifier = site['SiteIdentifier']
break
if site2_already_paired:
logging.info(f"\nFound existing pairing with {args.site2_zvm_address}, deleting...")
site1_client.peersites.delete_peer_site(site2_identifier)
logging.info("Existing pairing deleted")
# Wait for deletion to complete
time.sleep(5)
# Example 2: Generate pairing token at site 2
logging.info("\nExample 2: Generating pairing token at site 2")
token = site2_client.peersites.generate_token()
logging.info("Generated token:")
logging.info(json.dumps(token, indent=2))
# Example 3: Pair site 1 with site 2
logging.info(f"\nExample 3: Pairing site 1 with site 2 ({args.site2_zvm_address})")
pair_result = site1_client.peersites.pair_site(
hostname=args.site2_zvm_address,
token=token['Token'],
port=9071
)
logging.info("Pairing result:")
logging.info(json.dumps(pair_result, indent=2))
# Wait for pairing to complete
time.sleep(5)
# Example 4: Verify pairing by getting updated peer sites list
logging.info("\nExample 4: Verifying pairing by getting updated peer sites list")
updated_peer_sites = site1_client.peersites.get_peer_sites()
logging.info(f"Found {len(updated_peer_sites)} peer sites:")
logging.info(json.dumps(updated_peer_sites, indent=2))
except Exception as e:
logging.error(f"Error occurred: {e}")
raise
if __name__ == "__main__":
main()
+78
View File
@@ -0,0 +1,78 @@
#!/usr/bin/env python3
import os
import argparse
import logging
import shutil
def create_dataset(base_dir: str, number_of_files: int):
"""Create test files filled with specific content."""
try:
# Validate input
if number_of_files <= 0:
raise ValueError("Number of files must be positive")
# Create directory if it doesn't exist
os.makedirs(base_dir, exist_ok=True)
# Calculate required disk space (approximate)
required_space = number_of_files * 1024 * 1024 # 1MB per file
free_space = shutil.disk_usage(base_dir).free
if free_space < required_space:
raise ValueError(
f"Not enough disk space. Need {required_space / (1024**3):.2f} GB, "
f"but only {free_space / (1024**3):.2f} GB available"
)
# Calculate how many lines we need for ~1MB file
# Each line is about 6 bytes (5 chars + newline)
# 1MB = 1048576 bytes
# Actual calculation: 1048576 / 6 = 174762.67
lines_per_file = 174763
# Create files
for i in range(number_of_files):
file_path = os.path.join(base_dir, f"file{i:04d}.txt")
with open(file_path, 'w') as f:
for _ in range(lines_per_file):
f.write(f'file{i:04d}\n')
# Log every 100 files
if (i + 1) % 100 == 0:
logging.info(f"Created {i + 1} files...")
logging.info(f"Created dataset in {base_dir}")
logging.info(f"Total files created: {number_of_files}")
# Log total size of the dataset
total_size = sum(os.path.getsize(os.path.join(base_dir, f))
for f in os.listdir(base_dir))
logging.info(f"Total dataset size: {total_size / (1024*1024):.2f} MB")
logging.info(f"Average file size: {total_size / (number_of_files * 1024*1024):.2f} MB")
except Exception as e:
logging.error(f"Failed to create dataset: {str(e)}")
raise
def main():
parser = argparse.ArgumentParser(description="Create test dataset")
parser.add_argument("--base_dir", default="~/encryption_test",
help="Base directory for test files (default: ~/encryption_test)")
parser.add_argument("--number_of_files", type=int, required=True,
help="Number of files to create")
args = parser.parse_args()
# Configure logging
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s'
)
# Expand user path (~/...)
base_dir = os.path.expanduser(args.base_dir)
create_dataset(base_dir, args.number_of_files)
if __name__ == "__main__":
main()
+129
View File
@@ -0,0 +1,129 @@
#!/usr/bin/env python3
import os
import argparse
import logging
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.primitives import padding
from cryptography.hazmat.backends import default_backend
import base64
import sys
def generate_key(password: str) -> bytes:
"""Generate an AES key from a password."""
# Using a fixed key for testing (similar to PowerShell script)
key = "Q5KyUru6wn82hlY9k8xUjJOPIC9da41jgRkpt21jo2L="
return base64.b64decode(key)
def decrypt_file(file_path: str, key: bytes) -> bool:
"""Decrypt a single file using AES."""
try:
# Read the encrypted file
with open(file_path, 'rb') as file:
# Read IV (first 16 bytes) and encrypted data
iv = file.read(16)
encrypted_data = file.read()
# Create AES cipher
cipher = Cipher(
algorithms.AES(key),
modes.CBC(iv),
backend=default_backend()
)
decryptor = cipher.decryptor()
# Decrypt the data
padded_data = decryptor.update(encrypted_data) + decryptor.finalize()
# Remove padding
unpadder = padding.PKCS7(128).unpadder()
decrypted_data = unpadder.update(padded_data) + unpadder.finalize()
# Write the decrypted data to a new file (remove .encrypted suffix)
decrypted_path = file_path.rsplit('.encrypted', 1)[0]
with open(decrypted_path, 'wb') as file:
file.write(decrypted_data)
# Remove the encrypted file
os.remove(file_path)
return True
except Exception as e:
logging.error(f"Failed to decrypt {file_path}: {str(e)}")
return False
def decrypt_directory(base_dir: str, password: str):
"""Decrypt all encrypted files in the specified directory."""
try:
# Generate decryption key
key = generate_key(password)
# Get list of encrypted files
files = []
for root, _, filenames in os.walk(base_dir):
for filename in filenames:
if filename.endswith('.encrypted'):
files.append(os.path.join(root, filename))
total_files = len(files)
if total_files == 0:
logging.info("No encrypted files found")
return
logging.info(f"Found {total_files} encrypted files")
# Track progress
successful = 0
failed = 0
# Process each file
for i, file_path in enumerate(files, 1):
logging.info(f"Decrypting {file_path}")
if decrypt_file(file_path, key):
successful += 1
else:
failed += 1
# Log progress every 100 files or at the end
if i % 100 == 0 or i == total_files:
logging.info(f"Processed {i}/{total_files} files...")
# Log final results
logging.info("Decryption complete!")
logging.info(f"Successfully decrypted: {successful} files")
if failed > 0:
logging.warning(f"Failed to decrypt: {failed} files")
except Exception as e:
logging.error(f"Decryption failed: {str(e)}")
raise
def main():
parser = argparse.ArgumentParser(description="Decrypt files in directory")
parser.add_argument("--base_dir", default="~/encryption_test",
help="Base directory containing files to decrypt (default: ~/encryption_test)")
parser.add_argument("--password", required=True,
help="Password for decryption (must match encryption password)")
args = parser.parse_args()
# Configure logging
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s'
)
# Expand user path (~/...)
base_dir = os.path.expanduser(args.base_dir)
# Verify directory exists
if not os.path.isdir(base_dir):
logging.error(f"Directory not found: {base_dir}")
sys.exit(1)
decrypt_directory(base_dir, args.password)
if __name__ == "__main__":
main()
+140
View File
@@ -0,0 +1,140 @@
#!/usr/bin/env python3
import os
import argparse
import logging
from cryptography.hazmat.primitives.ciphers import Cipher, algorithms, modes
from cryptography.hazmat.primitives import padding
from cryptography.hazmat.backends import default_backend
import base64
import sys
def generate_key(password: str) -> bytes:
"""Generate an AES key from a password."""
# Using a fixed key for testing (similar to PowerShell script)
key = "Q5KyUru6wn82hlY9k8xUjJOPIC9da41jgRkpt21jo2L="
return base64.b64decode(key)
def encrypt_file(file_path: str, key: bytes) -> bool:
"""Encrypt a single file using AES."""
try:
# Read the original file
with open(file_path, 'rb') as file:
file_data = file.read()
# Create an initialization vector
iv = os.urandom(16)
# Create AES cipher
cipher = Cipher(
algorithms.AES(key),
modes.CBC(iv),
backend=default_backend()
)
encryptor = cipher.encryptor()
# Add padding
padder = padding.PKCS7(128).padder()
padded_data = padder.update(file_data) + padder.finalize()
# Encrypt the data
encrypted_data = encryptor.update(padded_data) + encryptor.finalize()
# Write the encrypted data to a new file
encrypted_path = f"{file_path}.encrypted"
with open(encrypted_path, 'wb') as file:
# Write IV first, then encrypted data
file.write(iv)
file.write(encrypted_data)
# Remove the original file
os.remove(file_path)
return True
except Exception as e:
logging.error(f"Failed to encrypt {file_path}: {str(e)}")
return False
def encrypt_directory(base_dir: str, password: str):
"""Encrypt all files in the specified directory."""
try:
# Generate encryption key
key = generate_key(password)
# Define target file extensions (same as PowerShell script)
target_extensions = [
'.pdf', '.xls', '.xlsx', '.ppt', '.pptx', '.doc', '.docx',
'.rtf', '.txt', '.csv', '.jpg', '.jpeg', '.png', '.gif',
'.avi', '.midi', '.mov', '.mp3', '.mp4', '.mpeg', '.mpg', '.ogg'
]
# Get list of files to encrypt
files = []
for root, _, filenames in os.walk(base_dir):
for filename in filenames:
if any(filename.lower().endswith(ext) for ext in target_extensions) and \
not filename.endswith('.encrypted'):
files.append(os.path.join(root, filename))
total_files = len(files)
if total_files == 0:
logging.info("No files found to encrypt")
return
logging.info(f"Found {total_files} files to encrypt")
# Track progress
successful = 0
failed = 0
# Process each file
for i, file_path in enumerate(files, 1):
logging.info(f"Encrypting {file_path}")
if encrypt_file(file_path, key):
successful += 1
else:
failed += 1
# Log progress every 100 files or at the end
if i % 100 == 0 or i == total_files:
logging.info(f"Processed {i}/{total_files} files...")
# Log final results
logging.info("Encryption complete!")
logging.info(f"Successfully encrypted: {successful} files")
if failed > 0:
logging.warning(f"Failed to encrypt: {failed} files")
except Exception as e:
logging.error(f"Encryption failed: {str(e)}")
raise
def main():
parser = argparse.ArgumentParser(description="Encrypt files in directory")
parser.add_argument("--base_dir", default="~/encryption_test",
help="Base directory containing files to encrypt (default: ~/encryption_test)")
parser.add_argument("--password", required=True,
help="Password for encryption")
args = parser.parse_args()
# Configure logging
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s'
)
# Expand user path (~/...)
base_dir = os.path.expanduser(args.base_dir)
# Verify directory exists
if not os.path.isdir(base_dir):
logging.error(f"Directory not found: {base_dir}")
sys.exit(1)
encrypt_directory(base_dir, args.password)
if __name__ == "__main__":
main()
+41
View File
@@ -0,0 +1,41 @@
# Legal Disclaimer
# This script is an example script and is not supported under any Zerto support program or service.
# The author and Zerto further disclaim all implied warranties including, without limitation,
# any implied warranties of merchantability or of fitness for a particular purpose.
# In no event shall Zerto, its authors or anyone else involved in the creation,
# production or delivery of the scripts be liable for any damages whatsoever (including,
# without limitation, damages for loss of business profits, business interruption, loss of business
# information, or other pecuniary loss) arising out of the use of or the inability to use the sample
# scripts or documentation, even if the author or Zerto has been advised of the possibility of such damages.
# The entire risk arising out of the use or performance of the sample scripts and documentation remains with you.
"""
Zerto Reports Example
Note: The reports functionality is demonstrated in vpg_failover_example.py, which includes:
1. Recovery Reports:
- Getting recovery reports for VPGs
- Filtering reports by date range
- Getting specific recovery operation details
- Getting latest failover test reports
2. Resource Reports:
- Getting resource reports with various filters
- Filtering by site, cluster, and organization
- Getting detailed resource information
Please refer to vpg_failover_example.py for practical examples of using the reports functionality.
You can run vpg_failover_example.py with:
python vpg_failover_example.py \
--zvm_address <zvm_ip> \
--client_id <client_id> \
--client_secret <client_secret> \
--ignore_ssl
For more information about the reports API, see the RecoveryReports class in zvml/recovery_reports.py
"""
if __name__ == "__main__":
print(__doc__)
+98
View File
@@ -0,0 +1,98 @@
# Legal Disclaimer
# This script is an example script and is not supported under any Zerto support program or service.
# The author and Zerto further disclaim all implied warranties including, without limitation,
# any implied warranties of merchantability or of fitness for a particular purpose.
# In no event shall Zerto, its authors or anyone else involved in the creation,
# production or delivery of the scripts be liable for any damages whatsoever (including,
# without limitation, damages for loss of business profits, business interruption, loss of business
# information, or other pecuniary loss) arising out of the use of or the inability to use the sample
# scripts or documentation, even if the author or Zerto has been advised of the possibility of such damages.
# The entire risk arising out of the use or performance of the sample scripts and documentation remains with you.
"""
Zerto Server Date-Time Example Script
This script demonstrates how to retrieve server time information in different formats from a Zerto Virtual Manager (ZVM).
The script performs the following steps:
1. Connects to Zerto Virtual Manager (ZVM)
2. Retrieves server time in three different formats:
- Local time
- UTC time
- Argument format (used for API parameters)
3. Displays the time information for each format
Required Arguments:
--zvm_address: ZVM address
--client_id: Keycloak client ID
--client_secret: Keycloak client secret
Optional Arguments:
--ignore_ssl: Ignore SSL certificate verification
Example Usage:
python examples/server_date_time_example.py \
--zvm_address <zvm_address> \
--client_id <client_id> \
--client_secret <client_secret> \
--ignore_ssl
"""
import sys
import os
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
import argparse
import logging
import urllib3
from zvml import ZVMLClient
from zvml.server_date_time import DateTimeFormat
# Disable SSL warnings
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
def main():
parser = argparse.ArgumentParser(description="Zerto Server Date-Time Example")
parser.add_argument("--zvm_address", required=True, help="ZVM address")
parser.add_argument('--client_id', required=True, help='Keycloak client ID')
parser.add_argument('--client_secret', required=True, help='Keycloak client secret')
parser.add_argument("--ignore_ssl", action="store_true", help="Ignore SSL certificate verification")
args = parser.parse_args()
# Configure logging
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s'
)
try:
# Connect to ZVM
logging.info(f"Connecting to ZVM at {args.zvm_address}")
client = ZVMLClient(
zvm_address=args.zvm_address,
client_id=args.client_id,
client_secret=args.client_secret,
verify_certificate=not args.ignore_ssl
)
# Test all three date-time formats
logging.info("\nTesting all server date-time formats:")
# Get local time
local_time = client.server_date_time.get_server_date_time(DateTimeFormat.LOCAL)
logging.info(f"\nLocal Time: {local_time}")
# Get UTC time
utc_time = client.server_date_time.get_server_date_time(DateTimeFormat.UTC)
logging.info(f"UTC Time: {utc_time}")
# Get argument format
arg_format = client.server_date_time.get_server_date_time(DateTimeFormat.ARGUMENT)
logging.info(f"Argument Format: {arg_format}")
except Exception as e:
logging.error(f"Error occurred: {e}")
raise
if __name__ == "__main__":
main()
+111
View File
@@ -0,0 +1,111 @@
# Legal Disclaimer
# This script is an example script and is not supported under any Zerto support program or service.
# The author and Zerto further disclaim all implied warranties including, without limitation,
# any implied warranties of merchantability or of fitness for a particular purpose.
# In no event shall Zerto, its authors or anyone else involved in the creation,
# production or delivery of the scripts be liable for any damages whatsoever (including,
# without limitation, damages for loss of business profits, business interruption, loss of business
# information, or other pecuniary loss) arising out of the use of or the inability to use the sample
# scripts or documentation, even if the author or Zerto has been advised of the possibility of such damages.
# The entire risk arising out of the use or performance of the sample scripts and documentation remains with you.
"""
Zerto Service Profiles Example Script
This script demonstrates how to retrieve and display service profile information from a Zerto Virtual Manager (ZVM).
The script performs the following steps:
1. Connects to Zerto Virtual Manager (ZVM)
2. Retrieves service profiles (optionally filtered by site)
3. Displays detailed information for each profile:
- Profile name
- RPO settings
- History configuration
- Journal size limits
- Test intervals
- Profile description
Required Arguments:
--zvm_address: ZVM address
--client_id: Keycloak client ID
--client_secret: Keycloak client secret
Optional Arguments:
--site_identifier: Site identifier to filter profiles
--ignore_ssl: Ignore SSL certificate verification
Example Usage:
python examples/service_profiles_example.py \
--zvm_address <zvm_address> \
--client_id <client_id> \
--client_secret <client_secret> \
--site_identifier <site_id> \
--ignore_ssl
"""
import sys
import os
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
import argparse
import logging
import urllib3
import json
from zvml import ZVMLClient
# Disable SSL warnings
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
def main():
parser = argparse.ArgumentParser(description="Zerto Service Profiles Example")
parser.add_argument("--zvm_address", required=True, help="ZVM address")
parser.add_argument('--client_id', required=True, help='Keycloak client ID')
parser.add_argument('--client_secret', required=True, help='Keycloak client secret')
parser.add_argument("--site_identifier", help="Optional site identifier to filter profiles")
parser.add_argument("--ignore_ssl", action="store_true", help="Ignore SSL certificate verification")
args = parser.parse_args()
# Configure logging
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s'
)
try:
# Connect to ZVM
logging.info(f"Connecting to ZVM at {args.zvm_address}")
client = ZVMLClient(
zvm_address=args.zvm_address,
client_id=args.client_id,
client_secret=args.client_secret,
verify_certificate=not args.ignore_ssl
)
# Get all service profiles
logging.info("\nFetching service profiles...")
profiles = client.service_profiles.get_service_profiles(
site_identifier=args.site_identifier
)
# Display service profiles information
if profiles:
logging.info(f"\nFound {len(profiles)} service profiles:")
for profile in profiles:
logging.info("\nService Profile Details:")
logging.info(f"Name: {profile.get('serviceProfileName')}")
logging.info(f"RPO: {profile.get('rpo')}")
logging.info(f"History: {profile.get('history')}")
logging.info(f"Max Journal Size: {profile.get('maxJournalSizeInPercent')}%")
logging.info(f"Test Interval: {profile.get('testInterval')}")
if profile.get('description'):
logging.info(f"Description: {profile.get('description')}")
logging.info("-" * 50)
else:
logging.warning("No service profiles found")
except Exception as e:
logging.error(f"Error occurred: {e}")
raise
if __name__ == "__main__":
main()
+156
View File
@@ -0,0 +1,156 @@
#!/usr/bin/env python3
# Legal Disclaimer
# This script is an example script and is not supported under any Zerto support program or service.
# The author and Zerto further disclaim all implied warranties including, without limitation,
# any implied warranties of merchantability or of fitness for a particular purpose.
# In no event shall Zerto, its authors or anyone else involved in the creation,
# production or delivery of the scripts be liable for any damages whatsoever (including,
# without limitation, damages for loss of business profits, business interruption, loss of business
# information, or other pecuniary loss) arising out of the use of or the inability to use the sample
# scripts or documentation, even if the author or Zerto has been advised of the possibility of such damages.
# The entire risk arising out of the use or performance of the sample scripts and documentation remains with you.
"""
Zerto Tweaks Management Example Script
This script demonstrates how to manage Zerto system tweaks, which are advanced configuration settings.
The script performs the following steps:
1. Connects to Zerto Virtual Manager (ZVM)
2. Lists all available system tweaks
3. Sets a specific tweak value (t_ransomwareEngCuSumThrsDiff)
4. Displays the updated tweak details
5. Deletes the tweak setting
6. Verifies the deletion by listing tweaks again
Required Arguments:
--zvm_address: ZVM address
--client_id: Keycloak client ID
--client_secret: Keycloak client secret
Optional Arguments:
--ignore_ssl: Ignore SSL certificate verification
Example Usage:
python examples/tweaks_example.py \
--zvm_address <zvm_address> \
--client_id <client_id> \
--client_secret <client_secret> \
--ignore_ssl
"""
import argparse
import logging
import urllib3
import json
import sys
import os
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from zvml.zvml import ZVMLClient
from zvml.tweaks import Tweaks
from zvml.common import ZertoTweakType
# Disable SSL warnings
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
def setup_client(args):
"""Initialize and return Zerto client"""
client = ZVMLClient(
zvm_address=args.zvm_address,
client_id=args.client_id,
client_secret=args.client_secret,
verify_certificate=not args.ignore_ssl
)
return client
def format_tweaks_table(result):
"""Format tweaks into a table"""
# Calculate maximum lengths for formatting
max_name_len = max(len(str(tweak.get('name', ''))) for tweak in result)
max_value_len = max(len(str(tweak.get('value', ''))) for tweak in result)
max_type_len = max(len(str(tweak.get('type', ''))) for tweak in result)
max_comment_len = max(len(str(tweak.get('comment', ''))) for tweak in result)
# Print header
header = f"{'Name':<{max_name_len}} | {'Value':<{max_value_len}} | {'Type':<{max_type_len}} | Description | {'Comment':<{max_comment_len}}"
logging.info(header)
logging.info("-" * len(header))
# Print tweaks in a formatted table
for tweak in result:
name = str(tweak.get('name', 'N/A'))
value = str(tweak.get('value', 'N/A'))
tweak_type = str(tweak.get('type', 'N/A'))
description = str(tweak.get('description', 'No description available'))
comment = str(tweak.get('comment', ''))
logging.info(f"{name:<{max_name_len}} | {value:<{max_value_len}} | {tweak_type:<{max_type_len}} | {description} | {comment}")
logging.info("-" * 80)
def manage_tweaks(client: ZVMLClient):
"""List and manage ZVM tweaks"""
tweaks = Tweaks(client)
# Set a specific tweak
tweak_name = "t_ransomwareEngCuSumThrsDiff"
logging.info(f"\nSetting tweak {tweak_name}:")
updated_tweak = tweaks.set_tweak(
tweak_name=tweak_name,
value="5",
tweak_type=ZertoTweakType.ZVM,
comment="mycomment"
)
# List all tweaks
logging.info("\nListing all tweaks:")
result = tweaks.list_tweaks()
logging.info(f"Found {len(result)} ZVM tweaks:")
logging.info("-" * 80)
format_tweaks_table(result)
# Show the specific tweak
logging.info("\nShowing specific tweak details:")
specific_result = tweaks.list_tweaks(tweak_name=tweak_name)
format_tweaks_table(specific_result)
# Delete the tweak
logging.info(f"\nDeleting tweak {tweak_name}:")
tweaks.delete_tweak(tweak_name)
# Verify deletion by listing all tweaks again
logging.info("\nVerifying deletion - listing all tweaks:")
result = tweaks.list_tweaks()
logging.info(f"Found {len(result)} ZVM tweaks:")
logging.info("-" * 80)
format_tweaks_table(result)
def main():
parser = argparse.ArgumentParser(description="ZVM Tweaks Management Example")
parser.add_argument("--zvm_address", required=True, help="ZVM address")
parser.add_argument('--client_id', required=True, help='Keycloak client ID')
parser.add_argument('--client_secret', required=True, help='Keycloak client secret')
parser.add_argument("--ignore_ssl", action="store_true", help="Ignore SSL certificate verification")
args = parser.parse_args()
# Configure logging
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s'
)
try:
# Setup client
client = setup_client(args)
# Manage tweaks
manage_tweaks(client)
except Exception as e:
logging.exception("Error occurred:")
sys.exit(1)
if __name__ == "__main__":
main()
+230
View File
@@ -0,0 +1,230 @@
#!/usr/bin/python3
# Legal Disclaimer
# This script is an example script and is not supported under any Zerto support program or service.
# The author and Zerto further disclaim all implied warranties including, without limitation,
# any implied warranties of merchantability or of fitness for a particular purpose.
# In no event shall Zerto, its authors or anyone else involved in the creation,
# production or delivery of the scripts be liable for any damages whatsoever (including,
# without limitation, damages for loss of business profits, business interruption, loss of business
# information, or other pecuniary loss) arising out of the use of or the inability to use the sample
# scripts or documentation, even if the author or Zerto has been advised of the possibility of such damages.
# The entire risk arising out of the use or performance of the sample scripts and documentation remains with you.
"""
Zerto VPG Bulk Update Example Script
This script demonstrates how to update multiple Virtual Protection Groups (VPGs) settings in bulk.
The script performs the following steps:
1. Connects to Zerto Virtual Manager (ZVM)
2. Lists peer sites and their resources:
- Available datastores
- Available networks
3. Retrieves current VPG settings for all VPGs
4. Prompts for new settings:
- Target datastore
- Failover network
- Test network
5. Updates all VPGs with the new settings after confirmation
Required Arguments:
--zvm_address: Site 1 ZVM address
--client_id: Site 1 Keycloak client ID
--client_secret: Site 1 Keycloak client secret
Optional Arguments:
--ignore_ssl: Ignore SSL certificate verification
Example Usage:
python examples/update_existing_vpgs.py \
--zvm_address <zvm_address> \
--client_id <client_id> \
--client_secret <client_secret> \
--ignore_ssl
"""
import argparse
import logging
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s'
)
import urllib3
import sys
import os
import json
from typing import Dict, List
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from zvml import ZVMLClient
# Disable SSL warnings
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
def setup_client(args):
"""Initialize and return Zerto client"""
client = ZVMLClient(
zvm_address=args.zvm_address,
client_id=args.client_id,
client_secret=args.client_secret,
verify_certificate=not args.ignore_ssl
)
return client
def print_site_resources(client, site_identifier: str, site_name: str):
"""Print site resources in a visual way"""
print(f"\nSite: {site_name}")
print(f"Site ID: {site_identifier}")
# Get and print datastores
print("\nDatastores:")
datastores = client.virtualization_sites.get_virtualization_site_datastores(site_identifier)
datastore_map = {}
for idx, ds in enumerate(datastores, 1):
datastore_map[idx] = ds['DatastoreIdentifier']
name = ds.get('DatastoreName', 'N/A')
logical_name = ds.get('LogicalName', 'N/A')
print(f" {idx}. ID: {ds['DatastoreIdentifier']}")
print(f" Name: {name}")
print(f" Logical Name: {logical_name}")
# Get and print networks
print("\nNetworks:")
networks = client.virtualization_sites.get_virtualization_site_networks(site_identifier)
network_map = {}
for idx, net in enumerate(networks, 1):
network_map[idx] = net['NetworkIdentifier']
name = net.get('VirtualizationNetworkName', 'N/A')
print(f" {idx}. ID: {net['NetworkIdentifier']}")
print(f" Name: {name}")
return datastore_map, network_map
def get_vpg_settings(client, vpgs: List[Dict]):
"""Get current VPG settings"""
vpg_settings = []
for vpg in vpgs:
vpg_id = vpg['VpgIdentifier']
vpg_name = vpg['VpgName']
# Create new settings based on existing VPG
settings_id = client.vpgs.create_vpg_settings(
basic=None,
journal=None,
recovery=None,
networks=None,
vpg_identifier=vpg_id
)
# Get the settings details
settings = client.vpgs.get_vpg_settings_by_id(vpg_settings_id=settings_id)
vpg_settings.append({
'vpg_name': vpg_name,
'vpg_id': vpg_id,
'settings_id': settings_id,
'current_settings': settings,
'default_datastore': settings.get('Recovery', {}).get('DefaultDatastoreIdentifier'),
'failover_network': settings.get('Networks', {}).get('Failover', {}).get('Hypervisor', {}).get('DefaultNetworkIdentifier'),
'test_network': settings.get('Networks', {}).get('FailoverTest', {}).get('Hypervisor', {}).get('DefaultNetworkIdentifier')
})
print(f"\nVPG: {vpg_name}")
print(f" Current Datastore: {settings.get('Recovery', {}).get('DefaultDatastoreIdentifier')}")
print(f" Current Failover Network: {settings.get('Networks', {}).get('Failover', {}).get('Hypervisor', {}).get('DefaultNetworkIdentifier')}")
print(f" Current Test Network: {settings.get('Networks', {}).get('FailoverTest', {}).get('Hypervisor', {}).get('DefaultNetworkIdentifier')}")
return vpg_settings
def update_vpg_settings(client, vpg_settings: List[Dict], new_datastore: str, new_failover_network: str, new_test_network: str):
"""Update all VPG settings with new values"""
for vpg in vpg_settings:
settings = vpg['current_settings']
# Update datastore
settings['Recovery']['DefaultDatastoreIdentifier'] = new_datastore
# Update networks
if 'Networks' not in settings:
settings['Networks'] = {'Failover': {'Hypervisor': {}}, 'FailoverTest': {'Hypervisor': {}}}
settings['Networks']['Failover']['Hypervisor']['DefaultNetworkIdentifier'] = new_failover_network
settings['Networks']['FailoverTest']['Hypervisor']['DefaultNetworkIdentifier'] = new_test_network
# Update the settings
client.vpgs.update_vpg_settings(vpg_settings_id=vpg['settings_id'], payload=settings)
# Commit the changes
client.vpgs.commit_vpg(vpg['settings_id'], vpg['vpg_name'], sync=False)
print(f"Updated and committed settings for VPG: {vpg['vpg_name']}")
def main():
parser = argparse.ArgumentParser(description="Update existing VPGs settings")
parser.add_argument("--zvm_address", required=True, help="Site 1 ZVM address")
parser.add_argument('--client_id', required=True, help='Site 1 Keycloak client ID')
parser.add_argument('--client_secret', required=True, help='Site 1 Keycloak client secret')
parser.add_argument("--ignore_ssl", action="store_true", help="Ignore SSL certificate verification")
args = parser.parse_args()
try:
# Setup client
client = setup_client(args)
# Get peer sites
peer_sites = client.peersites.get_peer_sites()
logging.debug(f"Peer sites: {peer_sites}")
if not peer_sites:
raise ValueError("No peer sites found")
# Get the first peer site
peer_site = peer_sites[0]
peer_site_id = peer_site['SiteIdentifier']
peer_site_name = peer_site.get('PeerSiteName')
# Print resources and get mapping for peer site
datastore_map, network_map = print_site_resources(client, peer_site_id, peer_site_name)
# Get and print current VPG settings
vpgs = client.vpgs.list_vpgs()
vpg_settings = get_vpg_settings(client, vpgs)
logging.debug(f"VPG settings: {json.dumps(vpg_settings, indent=4)}")
# Get user input
print("\nEnter sequential numbers for new settings:")
ds_num = int(input("Datastore number: "))
fo_net_num = int(input("Failover network number: "))
test_net_num = int(input("Failover test network number: "))
# Validate input
if not all(num in datastore_map for num in [ds_num]) or \
not all(num in network_map for num in [fo_net_num, test_net_num]):
raise ValueError("Invalid sequential number entered")
# Get actual IDs
new_datastore = datastore_map[ds_num]
new_failover_network = network_map[fo_net_num]
new_test_network = network_map[test_net_num]
# Confirm with user
print(f"\nAbout to update all VPGs with:")
print(f"New datastore: {new_datastore}")
print(f"New failover network: {new_failover_network}")
print(f"New test network: {new_test_network}")
if input("\nContinue? (y/n): ").lower() != 'y':
print("Operation cancelled")
return
# Update all VPGs
update_vpg_settings(client, vpg_settings, new_datastore, new_failover_network, new_test_network)
print("\nAll VPGs have been updated successfully")
except Exception as e:
logging.exception("Error occurred:")
sys.exit(1)
if __name__ == "__main__":
main()
+282
View File
@@ -0,0 +1,282 @@
# Legal Disclaimer
# This script is an example script and is not supported under any Zerto support program or service.
# The author and Zerto further disclaim all implied warranties including, without limitation,
# any implied warranties of merchantability or of fitness for a particular purpose.
# In no event shall Zerto, its authors or anyone else involved in the creation,
# production or delivery of the scripts be liable for any damages whatsoever (including,
# without limitation, damages for loss of business profits, business interruption, loss of business
# information, or other pecuniary loss) arising out of the use of or the inability to use the sample
# scripts or documentation, even if the author or Zerto has been advised of the possibility of such damages.
# The entire risk arising out of the use or performance of the sample scripts and documentation remains with you.
"""
Zerto Virtualization Sites Example Script
This script demonstrates how to retrieve and manage virtualization site information from Zerto.
The script performs the following steps:
1. Connects to Zerto Virtual Manager (ZVM)
2. Retrieves information about virtualization sites:
- Basic site details
- Unprotected VMs and vApps
- Storage resources (datastores, clusters)
- Network configurations
- Host information
- Cloud resources (networks, subnets, security)
3. For each site, retrieves detailed information about:
- Organization VDCs
- Storage policies
- Network configurations
- Host devices and clusters
Required Arguments:
--zvm_address: ZVM address
--client_id: Keycloak client ID
--client_secret: Keycloak client secret
Optional Arguments:
--ignore_ssl: Ignore SSL certificate verification
Example Usage:
python examples/virtualization_sites_example.py \
--zvm_address <zvm_address> \
--client_id <client_id> \
--client_secret <client_secret> \
--ignore_ssl
"""
import sys
import os
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
import argparse
import logging
import urllib3
import json
from zvml import ZVMLClient
# Disable SSL warnings
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
def main():
parser = argparse.ArgumentParser(description="Zerto Virtualization Sites Example")
parser.add_argument("--zvm_address", required=True, help="ZVM IP address")
parser.add_argument('--client_id', required=True, help='Keycloak client ID')
parser.add_argument('--client_secret', required=True, help='Keycloak client secret')
parser.add_argument("--ignore_ssl", action="store_true", help="Ignore SSL certificate verification")
args = parser.parse_args()
# Configure logging
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s'
)
try:
# Initialize the client
client = ZVMLClient(
zvm_address=args.zvm_address,
client_id=args.client_id,
client_secret=args.client_secret,
verify_certificate=not args.ignore_ssl
)
# Example 1: Get all virtualization sites
logging.info("\nExample 1: Getting all virtualization sites")
sites = client.virtualization_sites.get_virtualization_sites()
logging.info("All sites:")
logging.info(json.dumps(sites, indent=2))
# Example 2: Get details for each site individually
for site in sites:
site_id = site['SiteIdentifier']
site_name = site['VirtualizationSiteName']
logging.info(f"\nExample 2: Getting details for site {site_name} (ID: {site_id})")
site_details = client.virtualization_sites.get_virtualization_sites(site_identifier=site_id)
logging.info("Site Details:")
logging.info(json.dumps(site_details, indent=2))
# Example 3: Get unprotected VMs for each site
logging.info(f"\nExample 3: Getting unprotected VMs for site {site_name}")
vms = client.virtualization_sites.get_virtualization_site_vms(site_id)
logging.info(f"Found {len(vms)} unprotected VMs:")
logging.info(json.dumps(vms, indent=2))
# Example 4: Get unprotected VCD vApps for each site
logging.info(f"\nExample 4: Getting unprotected VCD vApps for site {site_name}")
vapps = client.virtualization_sites.get_virtualization_site_vcd_vapps(site_id)
logging.info(f"Found {len(vapps)} unprotected VCD vApps:")
logging.info(json.dumps(vapps, indent=2))
# Example 5: Get datastores for each site
logging.info(f"\nExample 5: Getting datastores for site {site_name}")
datastores = client.virtualization_sites.get_virtualization_site_datastores(site_id)
logging.info(f"Found {len(datastores)} datastores:")
logging.info(json.dumps(datastores, indent=2))
# Example 6: Get folders for each site
logging.info(f"\nExample 6: Getting folders for site {site_name}")
folders = client.virtualization_sites.get_virtualization_site_folders(site_id)
logging.info(f"Found {len(folders)} folders:")
logging.info(json.dumps(folders, indent=2))
# Example 7: Get datastore clusters for each site
logging.info(f"\nExample 7: Getting datastore clusters for site {site_name}")
datastore_clusters = client.virtualization_sites.get_virtualization_site_datastore_clusters(site_id)
logging.info(f"Found {len(datastore_clusters)} datastore clusters:")
logging.info(json.dumps(datastore_clusters, indent=2))
# Example 8: Get resource pools for each site
logging.info(f"\nExample 8: Getting resource pools for site {site_name}")
resource_pools = client.virtualization_sites.get_virtualization_site_resource_pools(site_id)
logging.info(f"Found {len(resource_pools)} resource pools:")
logging.info(json.dumps(resource_pools, indent=2))
# Example 9: Get organization VDCs for each site
logging.info(f"\nExample 9: Getting organization VDCs for site {site_name}")
org_vdcs = client.virtualization_sites.get_virtualization_site_org_vdcs(site_id)
logging.info(f"Found {len(org_vdcs)} organization VDCs:")
logging.info(json.dumps(org_vdcs, indent=2))
# Example 10: Get networks for each site
logging.info(f"\nExample 10: Getting networks for site {site_name}")
networks = client.virtualization_sites.get_virtualization_site_networks(site_id)
logging.info(f"Found {len(networks)} networks:")
logging.info(json.dumps(networks, indent=2))
# Example 11: Get hosts for each site
logging.info(f"\nExample 11: Getting hosts for site {site_name}")
hosts = client.virtualization_sites.get_virtualization_site_hosts(site_id)
logging.info(f"Found {len(hosts)} hosts:")
logging.info(json.dumps(hosts, indent=2))
# Example 12: Get host clusters for each site
logging.info(f"\nExample 12: Getting host clusters for site {site_name}")
host_clusters = client.virtualization_sites.get_virtualization_site_host_clusters(site_id)
logging.info(f"Found {len(host_clusters)} host clusters:")
logging.info(json.dumps(host_clusters, indent=2))
# Example 13: Get repositories for each site
logging.info(f"\nExample 13: Getting repositories for site {site_name}")
repositories = client.virtualization_sites.get_virtualization_site_repositories(site_id)
logging.info(f"Found {len(repositories)} repositories:")
logging.info(json.dumps(repositories, indent=2))
# Example 14: Get networks for each org VDC
logging.info(f"\nExample 14: Getting org VDC networks for site {site_name}")
org_vdcs = client.virtualization_sites.get_virtualization_site_org_vdcs(site_id)
for org_vdc in org_vdcs:
org_vdc_id = org_vdc['OrgVdcIdentifier']
org_vdc_name = org_vdc['VcdVdcName']
logging.info(f"\nFetching networks for org VDC: {org_vdc_name}")
networks = client.virtualization_sites.get_virtualization_site_org_vdc_networks(site_id, org_vdc_id)
logging.info(f"Found {len(networks)} networks in org VDC {org_vdc_name}:")
logging.info(json.dumps(networks, indent=2))
# Example 15: Get storage policies for each org VDC
logging.info(f"\nExample 15: Getting storage policies for org VDC: {org_vdc_name}")
storage_policies = client.virtualization_sites.get_virtualization_site_org_vdc_storage_policies(site_id, org_vdc_id)
logging.info(f"Found {len(storage_policies)} storage policies in org VDC {org_vdc_name}:")
logging.info(json.dumps(storage_policies, indent=2))
# Example 16: Get devices for each site
logging.info(f"\nExample 16a: Getting all devices for site {site_name}")
devices = client.virtualization_sites.get_virtualization_site_devices(site_id)
logging.info(f"Found {len(devices)} devices:")
logging.info(json.dumps(devices, indent=2))
# If we have hosts, get devices for the first host
if hosts:
host_id = hosts[0]['HostIdentifier']
logging.info(f"\nExample 16b: Getting devices for host {host_id} in site {site_name}")
host_devices = client.virtualization_sites.get_virtualization_site_devices(
site_id,
host_identifier=host_id
)
logging.info(f"Found {len(host_devices)} devices for host {host_id}:")
logging.info(json.dumps(host_devices, indent=2))
# If we found any devices, try filtering by the first device name
if host_devices:
device_name = host_devices[0]['DeviceName']
logging.info(f"\nExample 16c: Getting devices with name {device_name} in site {site_name}")
filtered_devices = client.virtualization_sites.get_virtualization_site_devices(
site_id,
device_name=device_name
)
logging.info(f"Found {len(filtered_devices)} devices with name {device_name}:")
logging.info(json.dumps(filtered_devices, indent=2))
# Example 17: Get public cloud virtual networks for each site
logging.info(f"\nExample 17: Getting public cloud virtual networks for site {site_name}")
cloud_networks = client.virtualization_sites.get_virtualization_site_public_cloud_networks(site_id)
logging.info(f"Found {len(cloud_networks)} public cloud virtual networks:")
logging.info(json.dumps(cloud_networks, indent=2))
# Example 18: Get public cloud subnets for each site
logging.info(f"\nExample 18: Getting public cloud subnets for site {site_name}")
cloud_subnets = client.virtualization_sites.get_virtualization_site_public_cloud_subnets(site_id)
logging.info(f"Found {len(cloud_subnets)} public cloud subnets:")
logging.info(json.dumps(cloud_subnets, indent=2))
# Example 19: Get public cloud security groups for each site
logging.info(f"\nExample 19: Getting public cloud security groups for site {site_name}")
security_groups = client.virtualization_sites.get_virtualization_site_public_cloud_security_groups(site_id)
logging.info(f"Found {len(security_groups)} public cloud security groups:")
logging.info(json.dumps(security_groups, indent=2))
# Example 20: Get public cloud VM instance types for each site
logging.info(f"\nExample 20: Getting public cloud VM instance types for site {site_name}")
instance_types = client.virtualization_sites.get_virtualization_site_public_cloud_vm_instance_types(site_id)
logging.info(f"Found {len(instance_types)} public cloud VM instance types:")
logging.info(json.dumps(instance_types, indent=2))
# Example 21: Get public cloud resource groups for each site
# currently this API returns a 500 error
# logging.info(f"\nExample 21: Getting public cloud resource groups for site {site_name}")
# resource_groups = client.virtualization_sites.get_virtualization_site_public_cloud_resource_groups(site_id)
# logging.info(f"Found {len(resource_groups)} public cloud resource groups:")
# logging.info(json.dumps(resource_groups, indent=2))
# Example 22: Get public cloud keys containers for each site
# currently this API returns a 500 error
# logging.info(f"\nExample 22: Getting public cloud keys containers for site {site_name}")
# keys_containers = client.virtualization_sites.get_virtualization_site_public_cloud_keys_containers(site_id)
# logging.info(f"Found {len(keys_containers)} public cloud keys containers:")
# logging.info(json.dumps(keys_containers, indent=2))
# Example 23: Get all encryption keys
# currently this API returns a 500 error if does not exist
# logging.info(f"\nExample 23a: Getting all encryption keys for site {site_name}")
# encryption_keys = client.virtualization_sites.get_virtualization_site_public_cloud_encryption_keys(site_id)
# logging.info(f"Found {len(encryption_keys)} encryption keys:")
# logging.info(json.dumps(encryption_keys, indent=2))
# Example 23b: Get details of specific encryption keys if any exist
# if encryption_keys:
# key_id = encryption_keys[0]['Id']
# logging.info(f"\nExample 23b: Getting details for encryption key {key_id}")
# key_details = client.virtualization_sites.get_virtualization_site_public_cloud_encryption_keys(site_id, key_id)
# logging.info("Encryption key details:")
# logging.info(json.dumps(key_details, indent=2))
# Example 24: Get public cloud managed identities for each site
# currently this API returns a 500 error if does not exist
# logging.info(f"\nExample 24: Getting public cloud managed identities for site {site_name}")
# managed_identities = client.virtualization_sites.get_virtualization_site_public_cloud_managed_identities(site_id)
# logging.info(f"Found {len(managed_identities)} managed identities:")
# logging.info(json.dumps(managed_identities, indent=2))
# Example 25: Get public cloud disk encryption keys for each site
# currently this API returns a 500 error if does not exist
# logging.info(f"\nExample 25: Getting public cloud disk encryption keys for site {site_name}")
# disk_encryption_keys = client.virtualization_sites.get_virtualization_site_public_cloud_disk_encryption_keys(site_id)
# logging.info(f"Found {len(disk_encryption_keys)} disk encryption keys:")
# logging.info(json.dumps(disk_encryption_keys, indent=2))
except Exception as e:
logging.error(f"Error occurred: {e}")
raise
if __name__ == "__main__":
main()
+243
View File
@@ -0,0 +1,243 @@
#!/usr/bin/python3
# Legal Disclaimer
# This script is an example script and is not supported under any Zerto support program or service.
# The author and Zerto further disclaim all implied warranties including, without limitation,
# any implied warranties of merchantability or of fitness for a particular purpose.
# In no event shall Zerto, its authors or anyone else involved in the creation,
# production or delivery of the scripts be liable for any damages whatsoever (including,
# without limitation, damages for loss of business profits, business interruption, loss of business
# information, or other pecuniary loss) arising out of the use of or the inability to use the sample
# scripts or documentation, even if the author or Zerto has been advised of the possibility of such damages.
# The entire risk arising out of the use or performance of the sample scripts and documentation remains with you.
"""
Zerto Virtual Machines Example Script
This script demonstrates how to manage and retrieve information about protected virtual machines in Zerto.
The script performs the following steps:
1. Connects to Zerto Virtual Manager (ZVM)
2. Gets site information and resources:
- Local and peer site details
- Available datastores
- Network configurations
3. Demonstrates VM operations:
- Lists all protected VMs
- Gets detailed information for specific VMs
- Filters VMs by VPG name
- Manages VM restore points:
* Lists available checkpoints
* Gets points in time
* Retrieves recovery statistics
4. Shows VM restore capabilities:
- Configures restore settings
- Handles network and storage mappings
- Manages restore operations
Required Arguments:
--zvm_address: ZVM address
--client_id: Keycloak client ID
--client_secret: Keycloak client secret
Optional Arguments:
--ignore_ssl: Ignore SSL certificate verification
Example Usage:
python examples/vms_example.py \
--zvm_address <zvm_address> \
--client_id <client_id> \
--client_secret <client_secret> \
--ignore_ssl
Note: VM restore functionality is commented out in this example as it may return a 500 error.
"""
# NOTE
# this example assumes that at least one VPG exists on the ZVM and protected VMs exist in the VPG
# the vm restore is commnted out as it fails with a 500
import sys
import os
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
import argparse
import logging
import urllib3
import json
from zvml import ZVMLClient
# Disable SSL warnings
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
def main():
parser = argparse.ArgumentParser(description="Zerto Virtual Machines Example")
parser.add_argument("--zvm_address", required=True, help="ZVM address")
parser.add_argument('--client_id', required=True, help='Keycloak client ID')
parser.add_argument('--client_secret', required=True, help='Keycloak client secret')
parser.add_argument("--ignore_ssl", action="store_true", help="Ignore SSL certificate verification")
args = parser.parse_args()
# Configure logging
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s'
)
try:
# Connect to ZVM
logging.info(f"Connecting to ZVM at {args.zvm_address}")
client = ZVMLClient(
zvm_address=args.zvm_address,
client_id=args.client_id,
client_secret=args.client_secret,
verify_certificate=not args.ignore_ssl
)
# Get both sites information
sites = client.virtualization_sites.get_virtualization_sites()
logging.info(f"Found {len(sites)} sites:")
for site in sites:
logging.info(f"Site: {site['VirtualizationSiteName']} (ID: {site['SiteIdentifier']})")
# Get the peer (second) site identifier
local_site = client.localsite.get_local_site()
peer_site = next(site for site in sites
if site['SiteIdentifier'] != local_site['SiteIdentifier'])
peer_site_id = peer_site['SiteIdentifier']
logging.info(f"Peer site identifier: {peer_site_id}")
# Get datastores from peer site
datastores = client.virtualization_sites.get_virtualization_site_datastores(peer_site_id)
if not datastores:
raise ValueError("No datastores found in peer site")
# logging.info(json.dumps(datastores, indent=2))
datastore_id = datastores[0]['DatastoreIdentifier'] # Use first datastore
logging.info(f"Selected datastore ID from peer site: {datastore_id}")
# Get networks from peer site
networks = client.virtualization_sites.get_virtualization_site_networks(peer_site_id)
if not networks:
raise ValueError("No networks found in peer site")
network_id = networks[0]['NetworkIdentifier'] # Use first network
logging.info(f"Selected network ID from peer site: {network_id}")
# Example 1: Get all protected VMs
logging.info("\nExample 1: Getting all protected VMs")
vms = client.vms.list_vms()
# logging.info(f'vms: {json.dumps(vms, indent=2)}')
if len(vms) == 0:
raise ValueError("No protected VMs found")
# Example 2: If we found any VMs, get details for the first one
first_vm = vms[0]
vm_id = first_vm['VmIdentifier']
vpg_id = first_vm.get('VpgIdentifier') # VpgIdentifier might be optional
logging.info(f"\nExample 2: Getting details for VM {vm_id}")
vm_details = client.vms.list_vms(
vm_identifier=vm_id,
vpg_identifier=vpg_id
)
# logging.info("VM details:")
# logging.info(json.dumps(vm_details, indent=2))
# Example 3: Get VMs filtered by VPG name
vpg_name = first_vm.get('VpgName')
if vpg_name:
logging.info(f"\nExample 3: Getting VMs filtered by VPG name: {vpg_name}")
filtered_vms = client.vms.list_vms(vpg_name=vpg_name)
# logging.info(f"Found {len(filtered_vms)} VMs in VPG {vpg_name}:")
# logging.info(json.dumps(filtered_vms, indent=2))
# Example 4: Restore the VM if it has checkpoints
logging.info("\nExample 4: Restoring VM from checkpoint")
vpg_info = client.vpgs.list_vpgs(vpg_identifier=vpg_id)
vpg_name = vpg_info['VpgName']
checkpoints = client.vpgs.list_checkpoints(vpg_name=vpg_name)
# logging.info(f"checkpoints: {json.dumps(checkpoints, indent=2)}")
if not checkpoints:
logging.warning("No checkpoints found for VPG")
raise ValueError("No checkpoints found for VPG")
checkpoint_id = checkpoints[0]['CheckpointIdentifier']
# Prepare restore settings using IDs from peer site
restore_settings = {
"datastoreIdentifier": datastore_id,
"nics": [
{
"hypervisor": {
"dnsSuffix": "",
"ipConfig": {
"gateway": "",
"isDhcp": True,
"primaryDns": "",
"secondaryDns": "",
"staticIp": "",
"subnetMask": ""
},
"networkIdentifier": network_id,
"shouldReplaceMacAddress": True
},
"nicIdentifier": first_vm['Nics'][0]['NicIdentifier']
}
],
"volumes": [
{
"datastore": {
"datastoreIdentifier": datastore_id,
"isThin": True
},
"volumeIdentifier": volume['VmVolumeIdentifier']
} for volume in first_vm['Volumes']
]
}
# Initiate VM restore
# temporary commented out as it fails with a 500
# logging.info(f"Restoring VM {first_vm['VmName']} from checkpoint {checkpoint_id}")
# restore_result = client.vms.restore_vm(
# vm_identifier=vm_id,
# vpg_identifier=vpg_id,
# restored_vm_name=f"{first_vm['VmName']}_restored",
# checkpoint_identifier=checkpoint_id,
# journal_vm_restore_settings=restore_settings
# )
# logging.info(f"Restore initiated: {json.dumps(restore_result, indent=2)}")
# Example 7: Get points in time for a VM
logging.info("\nExample 7: Getting points in time for VM")
try:
# You can optionally specify start_date and end_date in ISO format
# e.g., "2024-01-01T00:00:00.000Z"
points_in_time = client.vms.list_vm_points_in_time(
vm_identifier=vm_id,
vpg_identifier=vpg_id
)
logging.info(f"Found {len(points_in_time)} points in time:")
logging.info(json.dumps(points_in_time, indent=2))
except Exception as e:
logging.error(f"Failed to get VM points in time: {e}")
# Example 8: Get points in time stats for a VM
logging.info("\nExample 8: Getting points in time stats for VM")
try:
points_in_time_stats = client.vms.list_vm_points_in_time_stats(
vm_identifier=vm_id,
vpg_identifier=vpg_id # Optional, but may be required if VM is in multiple VPGs
)
logging.info("Points in time stats:")
logging.info(json.dumps(points_in_time_stats, indent=2))
except Exception as e:
logging.error(f"Failed to get VM points in time stats: {e}")
except Exception as e:
logging.error(f"Error occurred: {e}")
raise
if __name__ == "__main__":
main()
+138
View File
@@ -0,0 +1,138 @@
#!/usr/bin/python3
# Legal Disclaimer
# This script is an example script and is not supported under any Zerto support program or service.
# The author and Zerto further disclaim all implied warranties including, without limitation,
# any implied warranties of merchantability or of fitness for a particular purpose.
# In no event shall Zerto, its authors or anyone else involved in the creation,
# production or delivery of the scripts be liable for any damages whatsoever (including,
# without limitation, damages for loss of business profits, business interruption, loss of business
# information, or other pecuniary loss) arising out of the use of or the inability to use the sample
# scripts or documentation, even if the author or Zerto has been advised of the possibility of such damages.
# The entire risk arising out of the use or performance of the sample scripts and documentation remains with you.
"""
Zerto Volumes Example Script
This script demonstrates how to retrieve volume information from Zerto Virtual Manager (ZVM).
It shows how to list and filter volumes based on different criteria, making it useful for
volume management and monitoring.
Key Features:
1. List all volumes in the system
2. Filter volumes by:
- VPG association
- Datastore location
- Protected VM attachment
3. Display volume details:
- Volume identifiers
- Storage information
- Protection status
- Resource associations
Required Arguments:
--zvm_address: Site 1 ZVM address
client_id: Site 1 Keycloak client ID
client_secret: Site 1 Keycloak client secret
--ignore_ssl: Ignore SSL certificate verification (optional)
Example Usage:
python examples/volumes_example.py \
--zvm_address "192.168.1.100" \
client_id "zerto-api" \
client_secret "your-secret-here" \
--ignore_ssl
Note: This script focuses on volume operations and requires only Site 1 credentials
since it performs read-only operations on the protected site.
"""
import sys
import os
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
import urllib3
import argparse
import logging
import json
from zvml import ZVMLClient
# Disable SSL warnings
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
def main():
parser = argparse.ArgumentParser(description="Zerto Volumes Example")
parser.add_argument("--zvm_address", required=True, help="ZVM address")
parser.add_argument('--client_id', required=True, help='Keycloak client ID')
parser.add_argument('--client_secret', required=True, help='Keycloak client secret')
parser.add_argument("--ignore_ssl", action="store_true", help="Ignore SSL certificate verification")
args = parser.parse_args()
# Configure logging
logging.basicConfig(level=logging.INFO, format='%(asctime)s - %(levelname)s - %(message)s')
try:
# Initialize the client
client = ZVMLClient(args.zvm_address, args.client_id, args.client_secret, not args.ignore_ssl)
# Example 1: List all volumes
logging.info("\nExample 1: Listing all volumes")
try:
volumes = client.volumes.list_volumes()
logging.info(f"Found {len(volumes)} volumes:")
logging.info(json.dumps(volumes, indent=2))
except Exception as e:
logging.error(f"Failed to list volumes: {e}")
# Example 2: List volumes for a specific VPG
logging.info("\nExample 2: Listing volumes for a specific VPG")
try:
# First get a VPG ID
vpgs = client.vpgs.list_vpgs()
# logging.info(f"vpgs: {json.dumps(vpgs, indent=2)}")
if vpgs:
vpg_id = vpgs[0]['VpgIdentifier']
logging.info(f"vpg_id: {vpg_id}")
volumes = client.volumes.list_volumes(vpg_identifier=vpg_id)
logging.info(f"Found {len(volumes)} volumes for VPG {vpg_id}:")
logging.info(json.dumps(volumes, indent=2))
except Exception as e:
logging.error(f"Failed to list volumes for VPG: {e}")
# Example 3: List volumes for a specific datastore
logging.info("\nExample 3: Listing volumes for a specific datastore")
try:
local_site1_identifier = client.localsite.get_local_site().get('SiteIdentifier')
logging.info(f"local_site1_identifier: {local_site1_identifier}")
# First get a datastore ID
datastores = client.virtualization_sites.get_virtualization_site_datastores(
site_identifier=local_site1_identifier
)
for datastore in datastores:
datastore_id = datastore['DatastoreIdentifier']
volumes = client.volumes.list_volumes(datastore_identifier=datastore_id)
logging.info(f"Found {len(volumes)} volumes for datastore {datastore_id}:")
logging.info(json.dumps(volumes, indent=2))
except Exception as e:
logging.error(f"Failed to list volumes for datastore: {e}")
# Example 4: List volumes for a specific protected VM
logging.info("\nExample 4: Listing volumes for a specific protected VM")
try:
# First get a VM ID
vms = client.vms.list_vms()
if vms:
vm_id = vms[0]['VmIdentifier']
volumes = client.volumes.list_volumes(protected_vm_identifier=vm_id)
logging.info(f"Found {len(volumes)} volumes for protected VM {vm_id}:")
logging.info(json.dumps(volumes, indent=2))
except Exception as e:
logging.error(f"Failed to list volumes for protected VM: {e}")
except Exception as e:
logging.error(f"Error occurred: {e}")
raise
if __name__ == "__main__":
main()
+422
View File
@@ -0,0 +1,422 @@
# Legal Disclaimer
# This script is an example script and is not supported under any Zerto support program or service.
# The author and Zerto further disclaim all implied warranties including, without limitation,
# any implied warranties of merchantability or of fitness for a particular purpose.
# In no event shall Zerto, its authors or anyone else involved in the creation,
# production or delivery of the scripts be liable for any damages whatsoever (including,
# without limitation, damages for loss of business profits, business interruption, loss of business
# information, or other pecuniary loss) arising out of the use of or the inability to use the sample
# scripts or documentation, even if the author or Zerto has been advised of the possibility of such damages.
# The entire risk arising out of the use or performance of the sample scripts and documentation remains with you.
"""
Zerto VPG Failover Example Script
This script demonstrates how to perform parallel failover tests for multiple Virtual Protection Groups (VPGs)
using the Zerto Virtual Manager (ZVM) API. It showcases complete VPG lifecycle management from creation
to testing and cleanup.
Key Features:
1. Site Management:
- Connect to protected site
- Retrieve local and peer site identifiers
- Manage cross-site replication using peer site information
2. VPG Operations:
- Create multiple VPGs with custom settings
- Add VMs to VPGs
- Monitor initial synchronization
- Create checkpoints
- Run parallel failover tests
- Generate test reports
- Clean up resources
3. Resource Management:
- Identify and select peer site datastores
- Configure peer site hosts and networks
- Set up peer site resource pools
- Manage VM folders
- Monitor volume replication
Required Arguments:
--zvm_address: Protected site ZVM address
--client_id: Protected site Keycloak client ID
--client_secret: Protected site Keycloak client secret
--ignore_ssl: Ignore SSL certificate verification (optional)
Example Usage:
python examples/vpg_failover_example.py \
--zvm_address "192.168.111.20" \
--client_id "zerto-api" \
--client_secret "your-secret-here" \
--ignore_ssl
Note: This script requires credentials only for the protected site. All recovery site information
is retrieved using the peer site API, eliminating the need for direct access to the recovery site.
Resource identifiers and configuration details for both sites are managed through the protected
site's ZVM API.
Script Flow:
1. Connects to protected site ZVM
2. Gets local and peer site information
3. Creates two VPGs in parallel:
- VpgTest1 protecting VM 'SmallCentOS'
- VpgTest2 protecting VM 'light-vm1'
4. Waits for both VPGs to reach MeetingSLA status
5. Performs parallel failover tests
6. Waits for user confirmation to stop tests
7. Stops failover tests in parallel
8. Generates test reports
9. Cleans up by deleting both VPGs
"""
import sys
import os
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
import argparse
import logging
import urllib3
import json
from zvml import ZVMLClient
import time
from zvml.common import ZertoVPGStatus, ZertoVPGSubstatus
from zvml.recovery_reports import RecoveryReports
import threading
from concurrent.futures import ThreadPoolExecutor, as_completed
# Disable SSL warnings
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
#name sure the api client lifespan settion is complete the initial sync, in my case I set it to 3600 seconds
def setup_clients(args):
"""
Initialize and return Zerto clients and their local site identifiers for both sites
Args:
args: Parsed command line arguments
Returns:
tuple: (zvm_client, client2, local_site1_id, local_site2_id)
"""
# Create clients for both sites
zvm_client = ZVMLClient(
zvm_address=args.zvm_address,
client_id=args.client_id,
client_secret=args.client_secret,
verify_certificate=not args.ignore_ssl
)
#get all virtualization sites
virtualization_sites = zvm_client.virtualization_sites.get_virtualization_sites()
logging.info(f"Virtualization Sites: {json.dumps(virtualization_sites, indent=4)}")
# Get local site ids
local_site_identifier = zvm_client.localsite.get_local_site().get('SiteIdentifier')
logging.info(f"Site 1 Local Site ID: {local_site_identifier}")
#peer_site_identifier is site in the list that is not the local site
peer_site_identifier = next((site['SiteIdentifier'] for site in virtualization_sites if site['SiteIdentifier'] != local_site_identifier), None)
logging.info(f"Site 2 Local Site ID: {peer_site_identifier}")
return zvm_client, local_site_identifier, peer_site_identifier
def construct_vpg_settings(vpg_name, local_site_identifier, peer_site_identifier, site2_datastore_identifier,
site2_host_identifier, resource_pool_identifier, site2_folder_identifier, site2_network_identifier):
basic = {
"Name": vpg_name,
"VpgType": "Remote",
"RpoInSeconds": 300,
"JournalHistoryInHours": 1,
"Priority": "Medium",
"UseWanCompression": True,
"ProtectedSiteIdentifier": local_site_identifier,
"RecoverySiteIdentifier": peer_site_identifier
}
# Fill journal structure
journal = {
"DatastoreIdentifier": site2_datastore_identifier,
"Limitation": {
"HardLimitInMB": 153600,
"WarningThresholdInMB": 115200
}
}
# Fill recovery structure
recovery = {
"DefaultHostIdentifier": site2_host_identifier,
"DefaultDatastoreIdentifier": site2_datastore_identifier,
"DefaultResourcePoolIdentifier": resource_pool_identifier,
"DefaultFolderIdentifier": site2_folder_identifier
}
# Fill Networks structure
networks = {
"Failover": {
"Hypervisor": {
"DefaultNetworkIdentifier": site2_network_identifier
}
},
"FailoverTest": {
"Hypervisor": {
"DefaultNetworkIdentifier": site2_network_identifier
}
}
}
return basic, journal, recovery, networks
def perform_failover_test(client, vpg_name):
"""Execute failover test for a single VPG and get its report"""
try:
task_id = client.vpgs.failover_test(vpg_name)
logging.info(f"Failover test started for VPG {vpg_name}, task ID: {task_id}")
# Wait for task completion
client.tasks.wait_for_task_completion(task_id)
# Get the latest failover test report
latest_report = client.recovery_reports.get_latest_failover_test_report(vpg_name)
if latest_report:
logging.info(f"Failover test completed for VPG {vpg_name}")
return vpg_name, latest_report
return vpg_name, None
except Exception as e:
logging.error(f"Error in failover test for VPG {vpg_name}: {e}")
raise
def run_parallel_failover_tests(client, vpg_names):
"""Run failover tests in parallel for multiple VPGs"""
logging.info(f"Starting parallel failover tests for VPGs: {vpg_names}")
with ThreadPoolExecutor(max_workers=len(vpg_names)) as executor:
# Submit all failover tasks
future_to_vpg = {
executor.submit(perform_failover_test, client, vpg_name): vpg_name
for vpg_name in vpg_names
}
# Wait for all tasks to complete and collect results
results = {}
for future in as_completed(future_to_vpg):
vpg_name = future_to_vpg[future]
try:
vpg_name, report = future.result()
results[vpg_name] = report
logging.info(f"Completed failover test for VPG {vpg_name}")
except Exception as e:
logging.error(f"Failover test failed for VPG {vpg_name}: {e}")
results[vpg_name] = None
return results
def main():
parser = argparse.ArgumentParser(description="zvml Client")
parser.add_argument("--zvm_address", required=True, help="ZVM address")
parser.add_argument('--client_id', required=True, help='Keycloak client ID')
parser.add_argument('--client_secret', required=True, help='Keycloak client secret')
# parser.add_argument("--site2_address", required=True, help="Site 2 ZVM address")
# parser.add_argument('--site2_client_id', required=True, help='Site 2 Keycloak client ID')
# parser.add_argument('--site2_client_secret', required=True, help='Site 2 Keycloak client secret')
parser.add_argument("--ignore_ssl", action="store_true", help="Ignore SSL certificate verification")
args = parser.parse_args()
logging.basicConfig(level=logging.DEBUG)
try:
vpg_structure = [
{
'vpg_name': 'VpgTest1',
'vm_name': 'SmallCentOS'
},
{
'vpg_name': 'VpgTest2',
'vm_name': 'light-vm1'
}
]
# Setup clients and get site identifiers
zvm_client, local_site_identifier, peer_site_identifier = setup_clients(args)
# Get datastore identifier from site 2 using ZVM API
site2_datastores = zvm_client.virtualization_sites.get_virtualization_site_datastores(
site_identifier=peer_site_identifier
)
selected_datastore = next((ds for ds in site2_datastores if ds.get('DatastoreName') == "DS_VM_Right"), None)
site2_datastore_identifier = selected_datastore.get('DatastoreIdentifier')
logging.info(f"Site 2 Datastore ID: {site2_datastore_identifier}")
# Get host identifier from site 2 using ZVM API
site2_hosts = zvm_client.virtualization_sites.get_virtualization_site_hosts(
site_identifier=peer_site_identifier
)
# logging.info(f"Site 2 Hosts: {site2_hosts}")
# Get the first host from the list
selected_host = site2_hosts[0]
site2_host_identifier = selected_host.get('HostIdentifier')
# logging.info(f"Site 2 Host ID: {site2_host_identifier}")
# Get resource pools from site 2 using ZVM API
resource_pools = zvm_client.virtualization_sites.get_virtualization_site_resource_pools(
site_identifier=peer_site_identifier
)
if resource_pools:
resource_pool_identifier = resource_pools[0].get('ResourcePoolIdentifier')
logging.info(f"Resource Pool ID: {resource_pool_identifier}")
else:
logging.error("No resource pools found on site 2.")
return
# Get networks from site 2 using ZVM API
networks = zvm_client.virtualization_sites.get_virtualization_site_networks(
site_identifier=peer_site_identifier
)
if networks:
site2_network_identifier = networks[0].get('NetworkIdentifier')
logging.info(f"Network ID: {site2_network_identifier}")
else:
logging.error("No networks found on site 2.")
return
# Get folders from site 2 using ZVM API
folders = zvm_client.virtualization_sites.get_virtualization_site_folders(
site_identifier=peer_site_identifier
)
for folder in folders:
if folder.get('FolderName') == '/':
site2_folder_identifier = folder.get('FolderIdentifier')
logging.info(f"Folder ID: {site2_folder_identifier}")
break
# Get VMs from site 1 using ZVM API
site_1_vms = zvm_client.virtualization_sites.get_virtualization_site_vms(
site_identifier=local_site_identifier
)
logging.info(f"Found {len(site_1_vms)} VMs on site 1")
def create_vpg_with_vm(vpg_config):
"""Create a VPG and add a VM to it"""
try:
vpg_name = vpg_config['vpg_name']
vm_name = vpg_config['vm_name']
# Create VPG settings
basic, journal, recovery, networks = construct_vpg_settings(
vpg_name, local_site_identifier, peer_site_identifier,
site2_datastore_identifier, site2_host_identifier,
resource_pool_identifier, site2_folder_identifier, site2_network_identifier
)
# Create VPG
vpg_id = zvm_client.vpgs.create_vpg(
basic=basic, journal=journal, recovery=recovery, networks=networks, sync=True
)
logging.info(f"VPG {vpg_name} created successfully with ID: {vpg_id}")
# Find and add VM to VPG
vm = next((vm for vm in site_1_vms if vm.get('VmName') == vm_name), None)
if vm:
vm_payload = {
"VmIdentifier": vm.get('VmIdentifier'),
"Recovery": {
"HostIdentifier": site2_host_identifier,
"DatastoreIdentifier": site2_datastore_identifier,
"FolderIdentifier": site2_folder_identifier
}
}
task_id = zvm_client.vpgs.add_vm_to_vpg(vpg_name, vm_list_payload=vm_payload)
logging.info(f"Task ID: {task_id} to add VM {vm_name} to VPG {vpg_name}")
return vpg_name, vpg_id
else:
logging.error(f"VM {vm_name} not found")
return vpg_name, None
except Exception as e:
logging.error(f"Error creating VPG {vpg_name}: {e}")
return vpg_name, None
# Create VPGs in parallel
with ThreadPoolExecutor(max_workers=len(vpg_structure)) as executor:
# Submit all VPG creation tasks
future_to_vpg = {
executor.submit(create_vpg_with_vm, vpg_config): vpg_config
for vpg_config in vpg_structure
}
# Wait for all tasks to complete
created_vpgs = []
for future in as_completed(future_to_vpg):
vpg_name, vpg_id = future.result()
if vpg_id:
created_vpgs.append(vpg_name)
logging.info(f"Successfully created VPG {vpg_name}")
# Wait for all VPGs to reach MeetingSLA status
if created_vpgs:
logging.info("Waiting for VPGs to reach MeetingSLA status...")
while True:
all_vpgs_ready = True
for vpg_name in created_vpgs:
vpg_info = zvm_client.vpgs.list_vpgs(vpg_name=vpg_name)
status = vpg_info.get('Status')
substatus = vpg_info.get('SubStatus')
logging.info(f"VPG {vpg_name} - Status: {ZertoVPGStatus.get_name_by_value(status)}, "
f"SubStatus: {ZertoVPGSubstatus.get_name_by_value(substatus)}")
if not ((status == ZertoVPGStatus.MeetingSLA.value and
(substatus == ZertoVPGSubstatus.Sync.value or substatus == ZertoVPGSubstatus.NONE.value)) or
(status == ZertoVPGStatus.HistoryNotMeetingSLA.value)):
all_vpgs_ready = False
break
if all_vpgs_ready:
logging.info("All VPGs are now meeting SLA")
break
logging.info("Waiting for VPGs to reach MeetingSLA status...")
time.sleep(30) # Wait 30 seconds before checking again
input("Press Enter to start parallel failover tests for both VPGs...")
# Run parallel failover tests
failover_results = run_parallel_failover_tests(zvm_client, created_vpgs)
logging.info(f"Failover results: {json.dumps(failover_results, indent=4)}")
input("Press Enter to stop failover tests and rollback both VPGs...")
# Stop failover tests in parallel
with ThreadPoolExecutor(max_workers=len(created_vpgs)) as executor:
futures = [
executor.submit(zvm_client.vpgs.stop_failover_test, vpg_name)
for vpg_name in created_vpgs
]
for future in as_completed(futures):
try:
task_id = future.result()
logging.info(f"Failover test stop initiated, task ID: {task_id}")
except Exception as e:
logging.error(f"Error stopping failover test: {e}")
# After running failover tests
for vpg_name in created_vpgs:
# Get the latest failover test report
latest_report = zvm_client.recovery_reports.get_latest_failover_test_report(vpg_name)
if latest_report:
logging.info(f"Failover test report for {vpg_name} latest_report=:{json.dumps(latest_report, indent=4)}")
input("Press Enter to delete both VPGs...")
# Delete both VPGs
zvm_client.vpgs.delete_vpg(created_vpgs[0], force=True, keep_recovery_volumes=False)
logging.info(f"VPG {created_vpgs[0]} deleted successfully.")
zvm_client.vpgs.delete_vpg(created_vpgs[1], force=True, keep_recovery_volumes=False)
logging.info(f"VPG {created_vpgs[1]} deleted successfully.")
except Exception as e:
logging.exception("Error:")
logging.error(f"Error: {e}")
if __name__ == "__main__":
main()
+181
View File
@@ -0,0 +1,181 @@
# Legal Disclaimer
# This script is an example script and is not supported under any Zerto support program or service.
# The author and Zerto further disclaim all implied warranties including, without limitation,
# any implied warranties of merchantability or of fitness for a particular purpose.
# In no event shall Zerto, its authors or anyone else involved in the creation,
# production or delivery of the scripts be liable for any damages whatsoever (including,
# without limitation, damages for loss of business profits, business interruption, loss of business
# information, or other pecuniary loss) arising out of the use of or the inability to use the sample
# scripts or documentation, even if the author or Zerto has been advised of the possibility of such damages.
# The entire risk arising out of the use or performance of the sample scripts and documentation remains with you.
"""
Zerto VPG Settings Export/Import Example Script
This script demonstrates how to export and import Virtual Protection Group (VPG) settings
using the Zerto Virtual Manager (ZVM) API. It allows for backup and restoration of VPG
configurations, which is useful for disaster recovery planning and VPG replication.
Key Features:
1. VPG Settings Export:
- Export settings for specific VPGs or all VPGs
- Save exported settings to a JSON file
- Include all VPG configuration parameters
- Capture recovery site mappings
2. Settings Verification:
- List all available exported settings
- Read and display detailed settings
- Show summary of exported VPG configurations
- Verify export timestamp and status
3. VPG Settings Import:
- Import settings back to create new VPGs
- Restore original VPG configurations
- Support for multiple VPGs in single operation
- Validate import results
Required Arguments:
--zvm_address: Protected site ZVM address
--client_id: Protected site Keycloak client ID
--client_secret: Protected site Keycloak client secret
--ignore_ssl: Ignore SSL certificate verification (optional)
--vpg_names: Comma-separated list of VPG names to export (optional)
--output_file: File path to save exported settings (optional)
Example Usage:
python examples/vpg_setting_export_example.py \
--zvm_address "192.168.111.20" \
--client_id "zerto-api" \
--client_secret "your-secret-here" \
--vpg_names "VpgTest1,VpgTest2" \
--output_file "vpg_settings.json" \
--ignore_ssl
Script Flow:
1. Connects to protected site ZVM
2. Exports VPG settings:
- For specified VPGs if vpg_names provided
- For all VPGs if no vpg_names specified
3. Saves settings to file if output_file specified
4. Verifies export by reading settings
5. Displays VPG configuration summaries:
- VPG names
- Source and target sites
- RPO and journal history
6. Pauses for manual VPG deletion
7. Imports settings to recreate VPGs
8. Verifies import success
Note: This script requires only protected site credentials. It's designed for VPG
configuration backup and restore scenarios, allowing you to quickly recreate VPGs
with identical settings after changes or in disaster recovery situations.
"""
import argparse
import logging
logging.basicConfig(
level=logging.DEBUG,
format='%(asctime)s - %(levelname)s - %(message)s'
)
import urllib3
import json
import sys
import os
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from zvml import ZVMLClient
# Disable SSL warningss
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
def setup_client(args):
"""Initialize and return Zerto client"""
client = ZVMLClient(
zvm_address=args.zvm_address,
client_id=args.client_id,
client_secret=args.client_secret,
verify_certificate=not args.ignore_ssl
)
return client
def main():
parser = argparse.ArgumentParser(description="Export and Import VPG settings example")
parser.add_argument("--zvm_address", required=True, help="Site 1 ZVM address")
parser.add_argument('--client_id', required=True, help='Site 1 Keycloak client ID')
parser.add_argument('--client_secret', required=True, help='Site 1 Keycloak client secret')
parser.add_argument("--ignore_ssl", action="store_true", help="Ignore SSL certificate verification")
parser.add_argument("--vpg_names", help="Comma-separated list of VPG names to export settings for")
parser.add_argument("--output_file", help="Optional file to save the exported settings")
args = parser.parse_args()
try:
# Setup client
client = setup_client(args)
# If no VPG names provided, get all VPGs
if not args.vpg_names:
vpgs = client.vpgs.list_vpgs()
vpg_names = [vpg['VpgName'] for vpg in vpgs]
logging.info(f"No VPG names provided, exporting all {len(vpg_names)} VPGs")
else:
# Split the comma-separated string and strip whitespace
vpg_names = [name.strip() for name in args.vpg_names.split(',')]
logging.info(f"Exporting settings for VPGs: {vpg_names}")
# Step 1: Export VPG settings
print("\nStep 1: Exporting VPG settings...")
result = client.vpgs.export_vpg_settings(vpg_names)
print("Export Result:")
print(f"Timestamp: {result.get('TimeStamp')}")
print(f"Result: {result.get('ExportResult', {}).get('Result')}")
print(f"Message: {result.get('ExportResult', {}).get('Message')}")
# Save to file if specified
if args.output_file:
with open(args.output_file, 'w') as f:
json.dump(result, f, indent=2)
print(f"\nExported settings saved to: {args.output_file}")
# Step 2: Verify export and read settings
print("\nStep 2: Reading exported settings...")
exported_settings = client.vpgs.list_exported_vpg_settings()
export_timestamp = result.get('TimeStamp', '').split('.')[0] + '.000Z'
if any(setting.get('TimeStamp') == export_timestamp for setting in exported_settings):
print(f"Found export with timestamp {export_timestamp}")
settings = client.vpgs.read_exported_vpg_settings(export_timestamp)
# Display summary of exported VPG settings
vpg_settings = settings.get('ExportedVpgSettingsApi', [])
print(f"\nFound settings for {len(vpg_settings)} VPGs:")
for vpg in vpg_settings:
basic = vpg.get('Basic', {})
print(f"\nVPG Name: {basic.get('Name')}")
print(f"Source Site: {vpg.get('SourceSiteName')}")
print(f"Target Site: {vpg.get('TargetSiteName')}")
print(f"RPO (seconds): {basic.get('RpoInSeconds')}")
print(f"Journal History (hours): {basic.get('JournalHistoryInHours')}")
#pause
input("Delte VPG manually and Press Enter to continue...")
# Step 3: Import the settings back
print("\nStep 3: Importing VPG settings...")
import_result = client.vpgs.import_vpg_settings(settings)
print("\nImport Result:")
print(f"Result: {import_result.get('Result')}")
print(f"Message: {import_result.get('Message')}")
if import_result.get('VpgSettingsIds'):
print(f"Created VPG Settings IDs: {', '.join(import_result.get('VpgSettingsIds'))}")
#pause
input("Look at the VPG and verify whether the manual channges are reverted back to the original settings. Press Enter to continue...")
else:
print(f"\nWarning: Export with timestamp {export_timestamp} not found in exported settings list")
except Exception as e:
logging.exception("Error occurred:")
sys.exit(1)
if __name__ == "__main__":
main()
+304
View File
@@ -0,0 +1,304 @@
# Legal Disclaimer
# This script is an example script and is not supported under any Zerto support program or service.
# The author and Zerto further disclaim all implied warranties including, without limitation,
# any implied warranties of merchantability or of fitness for a particular purpose.
# In no event shall Zerto, its authors or anyone else involved in the creation,
# production or delivery of the scripts be liable for any damages whatsoever (including,
# without limitation, damages for loss of business profits, business interruption, loss of business
# information, or other pecuniary loss) arising out of the use of or the inability to use the sample
# scripts or documentation, even if the author or Zerto has been advised of the possibility of such damages.
# The entire risk arising out of the use or performance of the sample scripts and documentation remains with you.
"""
Zerto VPG VM Management Example Script
This script demonstrates how to manage Virtual Machines (VMs) within Virtual Protection Groups (VPGs)
using the Zerto Virtual Manager (ZVM) API. It showcases VPG creation, VM addition/removal, and cleanup.
Key Features:
1. Site Management:
- Connect to protected site
- Retrieve local and peer site identifiers
- Manage cross-site replication using peer site information
2. VPG Operations:
- Create multiple VPGs with custom settings
- Add multiple VMs to a VPG
- Remove VMs from VPGs
- Move VMs between VPGs
- Clean up resources
3. Resource Management:
- Identify and select peer site datastores, hosts, networks, folders and resource pools
Required Arguments:
--zvm_address: Protected site ZVM address
--client_id: Protected site Keycloak client ID
--client_secret: Protected site Keycloak client secret
--ignore_ssl: Ignore SSL certificate verification (optional)
Example Usage:
python examples/vpg_vms_example.py \
--zvm_address "192.168.111.20" \
--client_id "zerto-api" \
--client_secret "your-secret-here" \
--ignore_ssl
Note: This script requires credentials only for the protected site. All recovery site information
is retrieved using the peer site API, eliminating the need for direct access to the recovery site.
Script Flow:
1. Connects to protected site ZVM
2. Gets local and peer site information
3. Creates first VPG 'VpgTest1'
4. Adds two VMs (vm1 and vm2) to first VPG
5. Removes vm1 from first VPG
6. Creates second VPG 'VpgTest2'
7. Adds removed VM (vm1) to second VPG
8. Cleans up by deleting both VPGs
"""
import logging
# Configure logging before any other imports or code
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s'
)
import argparse
import urllib3
import json
import sys
import os
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from zvml import ZVMLClient
# Disable SSL warnings
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
def setup_clients(args):
"""
Initialize and return Zerto clients and their local site identifiers for both sites
Args:
args: Parsed command line arguments
Returns:
tuple: (client1, local_site1_id, local_peer_id)
"""
# Create clients for both sites
client = ZVMLClient(
zvm_address=args.zvm_address,
client_id=args.client_id,
client_secret=args.client_secret,
verify_certificate=not args.ignore_ssl
)
return client
def main():
parser = argparse.ArgumentParser(description="zvml Client")
parser.add_argument("--zvm_address", required=True, help="Site 1 ZVM address")
parser.add_argument('--client_id', required=True, help='Site 1 Keycloak client ID')
parser.add_argument('--client_secret', required=True, help='Site 1 Keycloak client secret')
parser.add_argument("--ignore_ssl", action="store_true", help="Ignore SSL certificate verification")
parser.add_argument("--vm1", required=True, help="Name of first VM to protect")
parser.add_argument("--vm2", required=True, help="Name of second VM to protect")
args = parser.parse_args()
try:
# Setup clients and get site identifiers
client1 = setup_clients(args)
virtualization_sites = client1.virtualization_sites.get_virtualization_sites()
logging.debug(f"Virtualization Sites: {json.dumps(virtualization_sites, indent=4)}")
# Get local site ids
local_site_identifier = client1.localsite.get_local_site().get('SiteIdentifier')
logging.info(f"Site 1 Local Site ID: {local_site_identifier}")
peer_site_identifier = next((site['SiteIdentifier'] for site in virtualization_sites if site['SiteIdentifier'] != local_site_identifier), None)
logging.info(f"Site 2 Local Site ID: {peer_site_identifier}")
# Get datastore identifier from site 2
peer_datastores = client1.virtualization_sites.get_virtualization_site_datastores(
site_identifier=peer_site_identifier
)
logging.debug(f"Site 2 Datastores: {json.dumps(peer_datastores, indent=4)}")
selected_datastore = next((ds for ds in peer_datastores if ds.get('DatastoreName') == "DS_VM_Right"), None)
peer_datastore_identifier = selected_datastore.get('DatastoreIdentifier')
logging.info(f"Site 2 Datastore ID: {peer_datastore_identifier}")
# Fill basic VPG settings info
vpg_name = 'VpgTest1'
basic = {
"Name": vpg_name,
"VpgType": "Remote",
"RpoInSeconds": 300,
"JournalHistoryInHours": 1,
"Priority": "Medium",
"UseWanCompression": True,
"ProtectedSiteIdentifier": local_site_identifier,
"RecoverySiteIdentifier": peer_site_identifier
}
# Fill journal structure
journal = {
"DatastoreIdentifier": peer_datastore_identifier,
"Limitation": {
"HardLimitInMB": 153600,
"WarningThresholdInMB": 115200
}
}
resource_pools = client1.virtualization_sites.get_virtualization_site_resource_pools(
site_identifier=peer_site_identifier
)
logging.debug(f"Resource Pools: {json.dumps(resource_pools, indent=4)}")
# Extract resource pool identifier from the first resource pool on the list
if resource_pools:
resource_pool_identifier = resource_pools[0].get('Identifier')
logging.info(f"Resource Pool Identifier from the first resource pool: {resource_pool_identifier}")
else:
logging.error("No resource pools found on site 2.")
return
# List networks from peer site
networks_list = client1.virtualization_sites.get_virtualization_site_networks(
site_identifier=peer_site_identifier
)
logging.debug(f"Networks: {json.dumps(networks_list, indent=4)}")
# Extract network identifier from the first network on the list
if networks_list:
network_identifier = networks_list[0].get('NetworkIdentifier')
logging.info(f"Network Identifier from the first network: {network_identifier}")
else:
logging.error("No networks found on site 2.")
return
#list folders from peer
folders = client1.virtualization_sites.get_virtualization_site_folders(
site_identifier=peer_site_identifier
)
logging.debug(f"Site 2 Folders: {json.dumps(folders, indent=4)}")
for folder in folders:
if folder.get('FolderName') == '/':
peer_folder_identifier = folder.get('FolderIdentifier')
logging.info(f"Folder Identifier: {peer_folder_identifier}")
break
peer_hosts = client1.virtualization_sites.get_virtualization_site_hosts(
site_identifier=peer_site_identifier
)
logging.debug(f"Site 2 Hosts: {json.dumps(peer_hosts, indent=4)}")
# get the second host from the list
peer_site_host_identifier = peer_hosts[1].get('HostIdentifier')
logging.info(f"Host Identifier from the second host: {peer_site_host_identifier}")
# Fill recovery structure
recovery = {
"DefaultHostIdentifier": peer_site_host_identifier,
"DefaultDatastoreIdentifier": peer_datastore_identifier,
"DefaultResourcePoolIdentifier": resource_pool_identifier,
"DefaultFolderIdentifier": peer_folder_identifier
}
# Fill Networks structure
networks = {
"Failover": {
"Hypervisor": {
"DefaultNetworkIdentifier": network_identifier
}
},
"FailoverTest": {
"Hypervisor": {
"DefaultNetworkIdentifier": network_identifier
}
}
}
input("Press Enter to create the first VPG...")
vpg_id = client1.vpgs.create_vpg(basic=basic, journal=journal,
recovery=recovery, networks=networks, sync=True)
logging.info(f"VPG ID: {vpg_id} created successfully.")
# Add VMs to the first VPG
vms = client1.virtualization_sites.get_virtualization_site_vms(
site_identifier=local_site_identifier
)
logging.debug(f"Site 1 VMs: {json.dumps(vms, indent=4)}")
vms_to_add = [args.vm1, args.vm2]
vm_list = []
for vm in vms:
logging.info(f"VM: Name={vm.get('VmName')}, VM Identifier={vm.get('VmIdentifier')}")
if vm.get('VmName') in vms_to_add:
logging.info(f"Adding VM {vm.get('VmName')} to VPG...")
vm_payload = {
"VmIdentifier": vm.get('VmIdentifier'),
"Recovery": {
"HostIdentifier": peer_site_host_identifier,
"DatastoreIdentifier": peer_datastore_identifier,
"FolderIdentifier": peer_folder_identifier
}
}
vm_list.append(vm_payload)
task_id = client1.vpgs.add_vm_to_vpg(vpg_name, vm_list_payload=vm_payload)
logging.info(f"Task ID: {task_id} to add VM {vm.get('VmName')} to VPG.")
input(f"Press Enter to remove {args.vm1} VM from the first VPG...")
# Remove first VM from the first VPG
vm_to_remove = args.vm1
vm_identifier_to_remove = None
for vm in vms:
if vm.get('VmName') == vm_to_remove:
vm_identifier_to_remove = vm.get('VmIdentifier')
task_id = client1.vpgs.remove_vm_from_vpg(vpg_name, vm_identifier_to_remove)
logging.info(f"Task ID: {task_id} to remove VM {vm_to_remove} from VPG {vpg_name}")
break
input("Press Enter to create second VPG...")
# Create second VPG
vpg_name_2 = 'VpgTest2'
basic['Name'] = vpg_name_2 # Update VPG name for second VPG
vpg_id_2 = client1.vpgs.create_vpg(basic=basic, journal=journal,
recovery=recovery, networks=networks, sync=True)
logging.info(f"Second VPG ID: {vpg_id_2} created successfully.")
# Add the removed VM to the second VPG
if vm_identifier_to_remove:
vm_payload = {
"VmIdentifier": vm_identifier_to_remove,
"Recovery": {
"HostIdentifier": peer_site_host_identifier,
"DatastoreIdentifier": peer_datastore_identifier,
"FolderIdentifier": peer_folder_identifier
}
}
task_id = client1.vpgs.add_vm_to_vpg(vpg_name_2, vm_list_payload=vm_payload)
logging.info(f"Task ID: {task_id} to add VM {vm_to_remove} to VPG {vpg_name_2}")
except Exception as e:
logging.exception("Error:")
logging.error(f"Error: {e}")
# wait for user input to continue
input("Press Enter to delete the VPGs...")
# Delete the VPGs
client1.vpgs.delete_vpg(vpg_name, force=True, keep_recovery_volumes=False)
logging.info(f"VPG {vpg_name} deleted successfully.")
client1.vpgs.delete_vpg(vpg_name_2, force=True, keep_recovery_volumes=False)
logging.info(f"VPG {vpg_name_2} deleted successfully.")
if __name__ == "__main__":
main()
+262
View File
@@ -0,0 +1,262 @@
# Legal Disclaimer
# This script is an example script and is not supported under any Zerto support program or service.
# The author and Zerto further disclaim all implied warranties including, without limitation,
# any implied warranties of merchantability or of fitness for a particular purpose.
# In no event shall Zerto, its authors or anyone else involved in the creation,
# production or delivery of the scripts be liable for any damages whatsoever (including,
# without limitation, damages for loss of business profits, business interruption, loss of business
# information, or other pecuniary loss) arising out of the use of or the inability to use the sample
# scripts or documentation, even if the author or Zerto has been advised of the possibility of such damages.
# The entire risk arising out of the use or performance of the sample scripts and documentation remains with you.
"""
Zerto Virtual Replication Appliance (VRA) Management Example Script
This script demonstrates how to manage VRAs using the Zerto Virtual Manager (ZVM) API.
It showcases VRA deployment, configuration, and cleanup operations.
Key Features:
1. VRA Management:
- List existing VRAs and their details
- Delete existing VRAs
- Deploy new VRAs with custom configurations
- Monitor VRA deployment status
2. Resource Selection:
- Interactive selection of hosts
- Interactive selection of datastores
- Interactive selection of networks
- Custom IP configuration for VRAs
3. Parallel Operations:
- Deploy multiple VRAs simultaneously
- Delete multiple VRAs in parallel
- Monitor multiple VRA operations
Required Arguments:
--zvm_address: ZVM server address
--client_id: Keycloak client ID
--client_secret: Keycloak client secret
--ignore_ssl: Ignore SSL certificate verification (optional)
Example Usage:
python examples/vras_example.py \
--zvm_address "192.168.111.20" \
--client_id "zerto-api" \
--client_secret "your-secret-here" \
--ignore_ssl
Script Flow:
1. Lists all existing VRAs and their details
2. Optionally deletes all existing VRAs
3. Creates new VRAs with user-selected resources:
- First VRA with IP 192.168.111.30
- Second VRA with IP 192.168.111.31 (optional)
4. Verifies final VRA configuration
Note: This script includes interactive prompts for resource selection and operation
confirmation. It demonstrates proper error handling and logging for VRA management
operations.
"""
#!/usr/bin/python3
import argparse
import logging
# logging.basicConfig(level=logging.DEBUG)
import urllib3
import json
import sys
import os
import time
from typing import Dict, List
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
from zvml import ZVMLClient
# Disable SSL warnings
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
def setup_client(args):
"""Initialize and return Zerto client"""
client = ZVMLClient(
zvm_address=args.zvm_address,
client_id=args.client_id,
client_secret=args.client_secret,
verify_certificate=not args.ignore_ssl
)
return client
def get_user_confirmation(prompt: str) -> bool:
"""Get user confirmation for an action"""
while True:
response = input(f"\n{prompt} (yes/no): ").lower().strip()
if response in ['yes', 'y']:
return True
if response in ['no', 'n']:
return False
print("Please answer 'yes' or 'no'")
def select_from_list(items, item_type: str):
"""Let user select an item from a list"""
logging.info(f"select_from_list: {json.dumps(items, indent=2)}")
print(f"\nAvailable {item_type}s:")
for idx, item in enumerate(items, 1):
if 'VirtualizationHostName' in item: # For hosts
print(f"{idx}. {item['VirtualizationHostName']} ({item['HostIdentifier']})")
elif 'DatastoreName' in item: # For datastores
print(f"{idx}. {item['DatastoreName']} ({item['DatastoreIdentifier']})")
elif 'VirtualizationNetworkName' in item: # For networks
print(f"{idx}. {item['VirtualizationNetworkName']} ({item['NetworkIdentifier']})")
while True:
try:
choice = int(input(f"\nSelect {item_type} (1-{len(items)}): "))
if 1 <= choice <= len(items):
return items[choice - 1]
except ValueError:
pass
print(f"Please enter a number between 1 and {len(items)}")
def list_vras(client: ZVMLClient):
"""List all VRAs and their details"""
vras = client.vras.list_vras()
print(f"\nFound {len(vras)} VRAs:")
for vra in vras:
print(f"\nVRA Details:")
print(f" Name: {vra.get('VraName')}")
print(f" Status: {vra.get('Status')}")
print(f" IP Address: {vra.get('IpAddress')}")
print(f" Version: {vra.get('VraVersion')}")
print(f" Host: {vra.get('HostName')}")
def create_vra_with_selection(client: ZVMLClient, vra_number: int) -> Dict:
"""Create a VRA with user-selected resources"""
# Get local site information
local_site = client.localsite.get_local_site()
site_id = local_site['SiteIdentifier']
# Get available resources for the local site
print("\nRetrieving available resources...")
hosts = client.virtualization_sites.get_virtualization_site_hosts(site_id)
if not hosts:
raise ValueError("No hosts found in local site")
datastores = client.virtualization_sites.get_virtualization_site_datastores(site_id)
if not datastores:
raise ValueError("No datastores found in local site")
networks = client.virtualization_sites.get_virtualization_site_networks(site_id)
if not networks:
raise ValueError("No networks found in local site")
# Let user select resources
print("\nSelect resources for VRA deployment:")
host = select_from_list(hosts, "Host")
datastore = select_from_list(datastores, "Datastore")
network = select_from_list(networks, "Network")
while True:
# Let user customize IP address
default_ip = f"192.168.111.{30 + vra_number - 1}"
custom_ip = input(f"\nEnter VRA IP address (press Enter to use default {default_ip}): ").strip()
vra_ip = custom_ip if custom_ip else default_ip
# Create VRA configuration
vra_config = {
"hostIdentifier": host['HostIdentifier'],
"datastoreIdentifier": datastore['DatastoreIdentifier'],
"networkIdentifier": network['NetworkIdentifier'],
"hostRootPassword": input("\nEnter host root password: "),
"memoryInGb": 3,
"groupName": f"VRA_Group{vra_number}",
"vraNetworkDataApi": {
"vraIPConfigurationTypeApi": "Static",
"vraIPAddress": vra_ip,
"vraIPAddressRangeEnd": "",
"subnetMask": "255.255.255.0",
"defaultGateway": "192.168.111.254"
},
"usePublicKeyInsteadOfCredentials": False,
"populatePostInstallation": True,
"numOfCpus": 1,
"vmInstanceType": ""
}
# Create VRA
print(f"\nCreating VRA {vra_number} with configuration:")
print(json.dumps(vra_config, indent=2))
response = input("\nProceed with VRA creation? (yes/no/edit): ").lower().strip()
if response in ['yes', 'y']:
result = client.vras.create_vra(vra_config)
print(f"VRA creation initiated: {json.dumps(result, indent=2)}")
return result
elif response in ['no', 'n']:
return None
elif response in ['edit', 'e']:
print("\nRestarting VRA configuration...")
continue
else:
print("Please answer 'yes', 'no', or 'edit'")
def main():
parser = argparse.ArgumentParser(description="VRA Management Example")
parser.add_argument("--zvm_address", required=True, help="ZVM address")
parser.add_argument('--client_id', required=True, help='Keycloak client ID')
parser.add_argument('--client_secret', required=True, help='Keycloak client secret')
parser.add_argument("--ignore_ssl", action="store_true", help="Ignore SSL certificate verification")
args = parser.parse_args()
# Configure logging
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s'
)
try:
# Setup client
client = setup_client(args)
# Step 1: List existing VRAs
print("\nStep 1: Listing existing VRAs...")
list_vras(client)
# Step 2: Ask for deletion confirmation
if get_user_confirmation("Would you like to delete all existing VRAs?"):
print("\nStep 2: Deleting existing VRAs...")
vras = client.vras.list_vras()
for vra in vras:
vra_id = vra.get('VraIdentifier')
print(f"Deleting VRA: {vra.get('VraName')} ({vra_id})")
client.vras.delete_vra(vra_id)
print("Waiting for deletion to complete...")
time.sleep(5) # Give some time for deletion to process
# Step 3: Create new VRAs
if get_user_confirmation("Would you like to create new VRAs?"):
print("\nStep 3: Creating new VRAs...")
# Create first VRA
print("\nConfiguring first VRA...")
result1 = create_vra_with_selection(client, 1)
if result1:
print("Waiting for first VRA deployment to complete...")
time.sleep(30)
# Create second VRA
if get_user_confirmation("Would you like to create a second VRA?"):
print("\nConfiguring second VRA...")
result2 = create_vra_with_selection(client, 2)
if result2:
print("Waiting for second VRA deployment to complete...")
time.sleep(30)
# Step 4: Verify final state
print("\nStep 4: Verifying final VRA configuration...")
list_vras(client)
except Exception as e:
logging.exception("Error occurred:")
sys.exit(1)
if __name__ == "__main__":
main()
+139
View File
@@ -0,0 +1,139 @@
# Legal Disclaimer
# This script is an example script and is not supported under any Zerto support program or service.
# The author and Zerto further disclaim all implied warranties including, without limitation,
# any implied warranties of merchantability or of fitness for a particular purpose.
# In no event shall Zerto, its authors or anyone else involved in the creation,
# production or delivery of the scripts be liable for any damages whatsoever (including,
# without limitation, damages for loss of business profits, business interruption, loss of business
# information, or other pecuniary loss) arising out of the use of or the inability to use the sample
# scripts or documentation, even if the author or Zerto has been advised of the possibility of such damages.
# The entire risk arising out of the use or performance of the sample scripts and documentation remains with you.
"""
Zerto Organizations (ZORG) Management Example Script
This script demonstrates how to manage Zerto Organizations (ZORGs) using the Zerto Virtual Manager (ZVM) API.
It showcases ZORG querying and information retrieval operations.
Key Features:
1. ZORG Management:
- List all ZORGs in the environment
- Query specific ZORG details by ID
- Retrieve detailed ZORG information
- Demonstrate ZORG filtering capabilities
2. Information Retrieval:
- Get ZORG identifiers
- Access ZORG configuration details
- View ZORG relationships and permissions
- Monitor ZORG status
3. Error Handling:
- Robust error handling for API requests
- Detailed logging of operations
- Graceful handling of missing ZORGs
Required Arguments:
--zvm_address: ZVM server address
--client_id: Keycloak client ID
--client_secret: Keycloak client secret
--ignore_ssl: Ignore SSL certificate verification (optional)
--zorg_id: Optional specific ZORG ID to query
Example Usage:
python examples/zorgs_example.py \
--zvm_address "192.168.111.20" \
--client_id "zerto-api" \
--client_secret "your-secret-here" \
--ignore_ssl \
--zorg_id "optional-zorg-id"
Script Flow:
1. Connects to ZVM server
2. Lists all available ZORGs
3. If specific ZORG ID provided:
- Retrieves detailed information for that ZORG
4. Otherwise:
- Gets details of first available ZORG
5. Outputs detailed ZORG information
Note: This script demonstrates basic ZORG management capabilities and can be used
as a foundation for more complex ZORG operations and automation.
"""
import sys
import os
sys.path.append(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
import argparse
import logging
import urllib3
import json
from zvml import ZVMLClient
# Disable SSL warnings
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
def main():
parser = argparse.ArgumentParser(description="Zerto Organizations (ZORG) Example")
parser.add_argument("--zvm_address", required=True, help="ZVM address")
parser.add_argument('--client_id', required=True, help='Keycloak client ID')
parser.add_argument('--client_secret', required=True, help='Keycloak client secret')
parser.add_argument("--ignore_ssl", action="store_true", help="Ignore SSL certificate verification")
parser.add_argument("--zorg_id", help="Optional: Specific ZORG ID to query")
args = parser.parse_args()
# Configure logging
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s'
)
try:
# Connect to ZVM
logging.info(f"Connecting to ZVM at {args.zvm_address}")
client = ZVMLClient(
zvm_address=args.zvm_address,
client_id=args.client_id,
client_secret=args.client_secret,
verify_certificate=not args.ignore_ssl
)
# Test 1: Get all ZORGs
logging.info("\n=== Testing get_zorgs (all) ===")
try:
zorgs = client.zorgs.get_zorgs()
logging.info("All ZORGs:")
logging.info(json.dumps(zorgs, indent=2))
except Exception as e:
logging.error(f"Error getting all ZORGs: {e}")
# Test 2: Get specific ZORG if ID provided
if args.zorg_id:
logging.info(f"\n=== Testing get_zorgs with ID: {args.zorg_id} ===")
try:
zorg_details = client.zorgs.get_zorgs(args.zorg_id)
logging.info("ZORG details:")
logging.info(json.dumps(zorg_details, indent=2))
except Exception as e:
logging.error(f"Error getting ZORG {args.zorg_id}: {e}")
# Test 3: Get first ZORG details if any exist
elif zorgs and len(zorgs) > 0:
first_zorg = zorgs[0]
zorg_identifier = first_zorg.get('ZorgIdentifier')
if zorg_identifier:
logging.info(f"\n=== Testing get_zorgs with first found ID: {zorg_identifier} ===")
try:
zorg_details = client.zorgs.get_zorgs(zorg_identifier)
logging.info("First ZORG details:")
logging.info(json.dumps(zorg_details, indent=2))
except Exception as e:
logging.error(f"Error getting ZORG {zorg_identifier}: {e}")
except Exception as e:
logging.error(f"Error occurred: {e}")
raise
if __name__ == "__main__":
main()