first full version of the exersises

This commit is contained in:
Kosta Mushkin
2025-05-29 19:19:25 -04:00
parent 3a075e5ecf
commit 4690e82e58
15 changed files with 1707 additions and 480 deletions
@@ -9,18 +9,31 @@ Prerequisites:
pip install -e .
2. Update prerequisites/config.py with your ZVM details
Usage:
python create_vpg.py --vm-names "vm1" "vm2" "vm3" [--vpg-name "My-VPG"]
This solution demonstrates:
- Creating a new VPG with basic settings
- Configuring journal, recovery, and network settings
- Adding VMs to the VPG
- Adding specified VMs to the VPG
- Proper error handling and logging
"""
import sys
import os
import logging
# Set up logging with timestamp
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s'
)
import json
import argparse
from pathlib import Path
import urllib3
# Suppress SSL warnings
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
# Add prerequisites to Python path
prerequisites_path = Path(__file__).parent.parent.parent.parent / "prerequisites"
@@ -43,19 +56,65 @@ except ImportError:
print("Expected path:", prerequisites_path / "config.py")
sys.exit(1)
def parse_arguments():
"""Parse command line arguments."""
parser = argparse.ArgumentParser(description='Create VPG and add specified VMs')
parser.add_argument('--vm-names', nargs='+', required=True,
help='List of VM names to add to the VPG (can be space-separated or comma-separated)')
parser.add_argument('--vpg-name', default="Test-VPG-Python",
help='Name of the VPG to create (default: Test-VPG-Python)')
return parser.parse_args()
def find_vms_by_names(client, site_identifier, vm_names):
"""Find VMs by their names in the specified site."""
vms = client.virtualization_sites.get_virtualization_site_vms(site_identifier=site_identifier)
logging.info(f"find_vms_by_names: found vms {json.dumps(vms, indent=4)} VMs in site {site_identifier}")
if not vms:
return [], []
# Create a dictionary of VM name to VM object for easy lookup
vm_dict = {vm.get('VmName'): vm for vm in vms}
# Find requested VMs
found_vms = []
not_found = []
for vm_name in vm_names:
if vm_name in vm_dict:
found_vms.append(vm_dict[vm_name])
logging.info(f"Found VM: {vm_name} (ID: {vm_dict[vm_name].get('VmIdentifier')})")
else:
not_found.append(vm_name)
logging.warning(f"VM not found: {vm_name}")
return found_vms, not_found
def remove_vm_from_vpg(client, vpg_name, vm):
"""Remove a VM from the VPG."""
vm_name = vm.get('VmName')
# vm_id = vm.get('VmIdentifier')
logging.info(f"\nRemoving VM {vm_name} from VPG...")
client.vpgs.remove_vm_from_vpg(vpg_name=vpg_name, vm_name=vm_name)
def main():
"""
Main function to demonstrate VPG creation.
Shows how to:
1. Create a new VPG with basic settings
2. Configure journal, recovery, and network settings
3. Add VMs to the VPG
3. Add specified VMs to the VPG
4. Remove the last added VM from the VPG
"""
# Set up logging with timestamp
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s'
)
# Parse command line arguments
args = parse_arguments()
# Handle both space-separated and comma-separated VM names
vm_names = []
for name in args.vm_names:
vm_names.extend([n.strip() for n in name.split(',') if n.strip()])
# Update args.vm_names with the processed list
args.vm_names = vm_names
try:
# Step 1: Create a ZVMLClient instance
@@ -124,7 +183,7 @@ def main():
# Step 4: Create VPG configuration
logging.info("\nCreating VPG configuration...")
vpg_name = "Test-VPG-Python"
vpg_name = args.vpg_name
# Basic VPG settings
basic = {
@@ -138,13 +197,8 @@ def main():
"RecoverySiteIdentifier": peer_site_identifier
}
# Journal settings
# Journal settings, keep the default settings
journal = {
"DatastoreIdentifier": target_datastore.get('DatastoreIdentifier'),
"Limitation": {
"HardLimitInMB": 153600,
"WarningThresholdInMB": 115200
}
}
# Recovery settings
@@ -180,34 +234,54 @@ def main():
vpg_id = client.vpgs.create_vpg(basic=basic, journal=journal, recovery=recovery, networks=networks, sync=True)
logging.info(f"VPG created successfully with ID: {vpg_id}")
# Step 6: Get available VMs for protection
logging.info("\nRetrieving available VMs for protection...")
vms = client.virtualization_sites.get_virtualization_site_vms(site_identifier=local_site_identifier)
# Step 6: Get specified VMs for protection
logging.info(f"\nRetrieving specified VMs for protection: {args.vm_names}")
found_vms, not_found = find_vms_by_names(client, local_site_identifier, args.vm_names)
if not vms:
logging.warning("No VMs found for protection!")
if not_found:
logging.warning(f"The following VMs were not found: {not_found}")
if not found_vms:
logging.error("No VMs found for protection!")
sys.exit(1)
# Filter out VMs that are already protected
available_vms = [vm for vm in vms if not vm.get('IsProtected')]
logging.info(f"Found {len(available_vms)} available VM(s) for protection")
logging.info(f"Found {len(found_vms)} VM(s) for protection")
# Step 7: Add VMs to VPG
for vm in available_vms[:2]: # Add first two available VMs
logging.info(f"\nAdding VM {vm.get('VmName')} to VPG...")
for vm in found_vms:
vm_name = vm.get('VmName')
vm_id = vm.get('VmIdentifier')
logging.info(f"\nAdding VM {vm_name} (ID: {vm_id}) to VPG...")
vm_payload = {
"VmIdentifier": vm.get('VmIdentifier'),
"VmIdentifier": vm_id,
"Recovery": {
"HostIdentifier": target_host.get('HostIdentifier'),
"DatastoreIdentifier": target_datastore.get('DatastoreIdentifier'),
"FolderIdentifier": target_folder.get('FolderIdentifier')
}
}
task_id = client.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")
task_id = client.vpgs.add_vm_to_vpg(args.vpg_name, vm_list_payload=vm_payload)
logging.info(f"Task ID: {task_id} to add VM {vm_name} to VPG")
# Step 8: Interactive VM removal
if found_vms:
last_vm = found_vms[-1]
vm_name = last_vm.get('VmName')
while True:
response = input(f"\nWould you like to remove the last added VM ({vm_name}) from the VPG? (yes/no): ").lower()
if response in ['yes', 'y']:
remove_vm_from_vpg(client, args.vpg_name, last_vm)
logging.info(f"Successfully removed VM {vm_name} from VPG {args.vpg_name}")
break
elif response in ['no', 'n']:
logging.info("Skipping VM removal.")
break
else:
print("Please answer 'yes' or 'no'")
except Exception as e:
logging.error(f"VPG creation failed: {str(e)}")
logging.error(f"VPG operation failed: {str(e)}")
sys.exit(1)
if __name__ == "__main__":
@@ -1,162 +0,0 @@
#!/usr/bin/env python3
"""
Exercise 5: VPG Operations - Solution (Part 2: VM Management)
This script demonstrates how to manage VMs within VPGs in your Zerto environment.
Prerequisites:
1. Install the zvml package in development mode:
cd /path/to/zvml-python-sdk
pip install -e .
2. Update prerequisites/config.py with your ZVM details
3. Run create_vpg.py first to create a VPG
This solution demonstrates:
- Adding VMs to existing VPGs using add_vm_to_vpg
- Removing VMs from VPGs using remove_vm_from_vpg
- Proper error handling and logging
"""
import sys
import os
import logging
import json
from pathlib import Path
# Add prerequisites to Python path
prerequisites_path = Path(__file__).parent.parent.parent.parent / "prerequisites"
sys.path.append(str(prerequisites_path))
# Import the SDK modules
from zvml import ZVMLClient
# Import configuration
try:
from config import (
ZVM_HOST,
ZVM_PORT,
ZVM_SSL_VERIFY,
CLIENT_ID,
CLIENT_SECRET
)
except ImportError:
print("Error: Please copy config.example.py to config.py and update with your values")
print("Expected path:", prerequisites_path / "config.py")
sys.exit(1)
def main():
"""
Main function to demonstrate VM management in VPGs.
Shows how to:
1. Add VMs to an existing VPG using add_vm_to_vpg
2. Remove VMs from a VPG using remove_vm_from_vpg
"""
# Set up logging with timestamp
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s'
)
try:
# Step 1: Create a ZVMLClient instance
logging.info(f"Initializing ZVMLClient for ZVM at {ZVM_HOST}")
client = ZVMLClient(
zvm_address=ZVM_HOST,
client_id=CLIENT_ID,
client_secret=CLIENT_SECRET,
verify_certificate=ZVM_SSL_VERIFY
)
# Step 2: Find the VPG we created earlier
logging.info("\nRetrieving VPGs...")
vpgs = client.vpgs.get_vpgs()
if not vpgs:
logging.warning("No VPGs found!")
sys.exit(1)
# Find our test VPG
test_vpg = next((vpg for vpg in vpgs if vpg.get('VpgName') == "Test-VPG-Python"), None)
if not test_vpg:
logging.warning("Test VPG not found! Please run create_vpg.py first.")
sys.exit(1)
vpg_name = test_vpg.get('VpgName')
logging.info(f"Found VPG: {json.dumps(test_vpg, indent=4)}")
# Step 3: Get available VMs for adding to VPG
logging.info("\nRetrieving available VMs...")
vms = client.virtualization_sites.get_virtualization_site_vms(site_identifier=test_vpg.get('SourceSiteIdentifier'))
if not vms:
logging.warning("No VMs found!")
sys.exit(1)
# Filter out VMs that are already protected
available_vms = [vm for vm in vms if not vm.get('IsProtected')]
logging.info(f"Found {len(available_vms)} available VM(s)")
if not available_vms:
logging.warning("No available VMs to add!")
sys.exit(1)
# Step 4: Get peer site resources for VM recovery settings
logging.info("\nRetrieving peer site resources...")
peer_site_identifier = test_vpg.get('TargetSiteIdentifier')
# Get peer datastores
peer_datastores = client.virtualization_sites.get_virtualization_site_datastores(site_identifier=peer_site_identifier)
if not peer_datastores:
logging.warning("No datastores found in peer site!")
sys.exit(1)
target_datastore = peer_datastores[0] # Use first available datastore
# Get peer folders
peer_folders = client.virtualization_sites.get_virtualization_site_folders(site_identifier=peer_site_identifier)
if not peer_folders:
logging.warning("No folders found in peer site!")
sys.exit(1)
target_folder = peer_folders[0] # Use first available folder
# Get peer hosts
peer_hosts = client.virtualization_sites.get_virtualization_site_hosts(site_identifier=peer_site_identifier)
if not peer_hosts:
logging.warning("No hosts found in peer site!")
sys.exit(1)
target_host = peer_hosts[0] # Use first available host
# Step 5: Add a new VM to the VPG
logging.info("\nAdding a new VM to the VPG...")
vm_to_add = available_vms[0] # Use first available VM
vm_payload = {
"VmIdentifier": vm_to_add.get('VmIdentifier'),
"Recovery": {
"HostIdentifier": target_host.get('HostIdentifier'),
"DatastoreIdentifier": target_datastore.get('DatastoreIdentifier'),
"FolderIdentifier": target_folder.get('FolderIdentifier')
}
}
task_id = client.vpgs.add_vm_to_vpg(vpg_name, vm_list_payload=vm_payload)
logging.info(f"Task ID: {task_id} to add VM {vm_to_add.get('VmName')} to VPG")
# Step 6: Remove a VM from the VPG
logging.info("\nRemoving a VM from the VPG...")
# Get VPG VMs
vpg_vms = client.vpgs.get_vpg_vms(vpg_name)
if len(vpg_vms) > 1: # Keep at least one VM
vm_to_remove = vpg_vms[-1] # Remove the last VM
vm_identifier = vm_to_remove.get('VmIdentifier')
task_id = client.vpgs.remove_vm_from_vpg(vpg_name, vm_identifier)
logging.info(f"Task ID: {task_id} to remove VM {vm_to_remove.get('VmName')} from VPG")
else:
logging.info("Skipping VM removal to maintain at least one VM in the VPG")
except Exception as e:
logging.error(f"VM management failed: {str(e)}")
sys.exit(1)
if __name__ == "__main__":
main()
+142 -39
View File
@@ -1,69 +1,172 @@
#!/usr/bin/env python3
"""
Exercise 5: VPG Operations - VPG Creation
This script demonstrates how to create and configure a VPG.
Exercise 5: VPG Operations - Template
This script demonstrates how to create and configure VPGs in your Zerto environment.
Prerequisites:
1. Install the zvml package in development mode:
cd /path/to/zvml-python-sdk
pip install -e .
2. Update prerequisites/config.py with your ZVM details
Usage:
python create_vpg.py --vm-names "vm1" "vm2" "vm3" [--vpg-name "My-VPG"]
Your task:
1. Implement the find_vms_by_names function to locate VMs by their names
2. Complete the VPG configuration with appropriate settings
3. Add the found VMs to the VPG
4. Implement VM removal functionality
The script should:
- Create a new VPG with basic settings
- Configure journal, recovery, and network settings
- Add specified VMs to the VPG
- Allow removing VMs from the VPG
"""
import sys
import os
import logging
import json
import argparse
from pathlib import Path
import urllib3
# Add the parent directory to the Python path to import the SDK
sys.path.append(str(Path(__file__).parent.parent.parent.parent))
# Suppress SSL warnings
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
# Add prerequisites to Python path
prerequisites_path = Path(__file__).parent.parent.parent.parent / "prerequisites"
sys.path.append(str(prerequisites_path))
# Import the SDK modules
from zvml import ZertoClient
from zvml.vpgs import VPG
from zvml.common import ZertoVPGError
from zvml import ZVMLClient
# Import configuration
try:
from prerequisites.config import (
from config import (
ZVM_HOST,
ZVM_PORT,
ZVM_SSL_VERIFY,
KEYCLOAK_SERVER_URL,
KEYCLOAK_REALM,
CLIENT_ID,
CLIENT_SECRET
)
except ImportError:
print("Error: Please copy config.example.py to config.py and update with your values")
print("Expected path:", prerequisites_path / "config.py")
sys.exit(1)
def parse_arguments():
"""Parse command line arguments."""
# TODO: Implement argument parsing
# Required arguments:
# --vm-names: List of VM names to add to the VPG
# Optional arguments:
# --vpg-name: Name of the VPG to create (default: "Test-VPG-Python")
pass
def find_vms_by_names(client, site_identifier, vm_names):
"""
Find VMs by their names in the specified site.
Args:
client: ZVMLClient instance
site_identifier: Identifier of the site to search in
vm_names: List of VM names to find
Returns:
tuple: (list of found VMs, list of not found VM names)
TODO: Implement the function to:
1. Get all unprotected VMs from the site
2. Create a dictionary for easy lookup
3. Find requested as an argument VMs
4. Return found and not found VMs
"""
pass
def remove_vm_from_vpg(client, vpg_name, vm):
"""
Remove a VM from the VPG.
Args:
client: ZVMLClient instance
vpg_name: Name of the VPG
vm: VM object to remove
TODO: Implement the function to:
1. Get VM identifier
2. Call the appropriate API to remove the VM
3. Log the operation
"""
pass
def main():
"""
Main function to demonstrate VPG creation.
TODO: Implement the following steps:
1. Parse command line arguments
2. Create ZVMLClient instance
3. Identify local and peer sites
4. Get peer site resources (datastores, folders, networks, hosts)
5. Create VPG configuration
6. Create VPG
7. Find and add VMs to VPG
8. Implement interactive VM removal
"""
# Step 1: Create and authenticate ZertoClient
# TODO: Initialize ZertoClient and authenticate
# Hint: Reuse the authentication code from previous exercises
# Set up logging
logging.basicConfig(
level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s'
)
# Step 2: Get source and target sites
# TODO: Get local site and a peer site
# Hint: Use client.sites.get_local() and client.sites.list()
# Step 3: Configure VPG settings
# TODO: Create VPG settings with required parameters
# Required settings:
# - VPG name
# - Source site
# - Target site
# - Journal history
# - RPO
# - Test network
# - Recovery network
# Step 4: Create the VPG
# TODO: Create a new VPG with the configured settings
# Hint: Use client.vpgs.create() method
# Step 5: Validate the VPG
# TODO: Validate the VPG configuration
# Hint: Use vpg.validate() method
# Step 6: Handle errors
# TODO: Add error handling for VPG operations
# Hint: Use try/except blocks for ZertoVPGError
try:
# TODO: Step 1: Parse command line arguments
# args = parse_arguments()
# TODO: Step 2: Create ZVMLClient instance
# client = ZVMLClient(...)
# TODO: Step 3: Identify local and peer sites
# local_site = client.localsite.get_local_site()
# sites = client.virtualization_sites.get_virtualization_sites()
# TODO: Step 4: Get peer site resources
# peer_datastores = client.virtualization_sites.get_virtualization_site_datastores(...)
# peer_folders = client.virtualization_sites.get_virtualization_site_folders(...)
# peer_networks = client.virtualization_sites.get_virtualization_site_networks(...)
# peer_hosts = client.virtualization_sites.get_virtualization_site_hosts(...)
# TODO: Step 5: Create VPG configuration
# basic = {
# "Name": "Your VPG Name",
# "VpgType": "Remote",
# "RpoInSeconds": 300,
# "JournalHistoryInHours": 24,
# "Priority": "Medium",
# "UseWanCompression": True,
# "ProtectedSiteIdentifier": local_site_identifier,
# "RecoverySiteIdentifier": peer_site_identifier
# }
# TODO: Step 6: Create VPG
# vpg_id = client.vpgs.create_vpg(...)
# TODO: Step 7: Find and add VMs to VPG
# found_vms, not_found = find_vms_by_names(...)
# for vm in found_vms:
# # Add VM to VPG
# TODO: Step 8: Implement interactive VM removal
# if found_vms:
# # Ask user if they want to remove the last VM
# # If yes, remove it
except Exception as e:
logging.error(f"VPG operation failed: {str(e)}")
sys.exit(1)
if __name__ == "__main__":
main()
@@ -1,70 +0,0 @@
#!/usr/bin/env python3
"""
Exercise 5: VPG Operations - VM Management
This script demonstrates how to manage VMs within a VPG.
"""
import sys
from pathlib import Path
# Add the parent directory to the Python path to import the SDK
sys.path.append(str(Path(__file__).parent.parent.parent.parent))
# Import the SDK modules
from zvml import ZertoClient
from zvml.vpgs import VPG
from zvml.common import ZertoVPGError
# Import configuration
try:
from prerequisites.config import (
ZVM_HOST,
ZVM_PORT,
ZVM_SSL_VERIFY,
KEYCLOAK_SERVER_URL,
KEYCLOAK_REALM,
CLIENT_ID,
CLIENT_SECRET
)
except ImportError:
print("Error: Please copy config.example.py to config.py and update with your values")
sys.exit(1)
def main():
"""
Main function to demonstrate VM management in VPGs.
"""
# Step 1: Create and authenticate ZertoClient
# TODO: Initialize ZertoClient and authenticate
# Hint: Reuse the authentication code from previous exercises
# Step 2: Get the VPG
# TODO: Find and get the VPG you want to manage
# Hint: Use client.vpgs.list() and client.vpgs.get()
# Step 3: List current VMs in the VPG
# TODO: Get a list of VMs currently in the VPG
# Hint: Use vpg.get_vms() method
# Step 4: Add VMs to the VPG
# TODO: Add one or more VMs to the VPG
# Required steps:
# - Find eligible VMs
# - Configure VM settings
# - Add VMs to VPG
# Hint: Use vpg.add_vms() method
# Step 5: Remove VMs from the VPG
# TODO: Remove one or more VMs from the VPG
# Hint: Use vpg.remove_vms() method
# Step 6: Validate VPG after changes
# TODO: Validate the VPG after VM changes
# Hint: Use vpg.validate() method
# Step 7: Handle errors
# TODO: Add error handling for VM operations
# Hint: Use try/except blocks for ZertoVPGError
if __name__ == "__main__":
main()