simplified instructions

This commit is contained in:
Kosta Mushkin
2025-06-12 20:09:35 -04:00
parent 4690e82e58
commit bd951d0811
7 changed files with 916 additions and 396 deletions
+41 -5
View File
@@ -58,21 +58,57 @@ The lab is divided into 7 exercises:
``` ```
2. Create and activate a virtual environment: 2. Create and activate a virtual environment:
**On macOS/Linux:**
```bash ```bash
python3 -m venv venv python3 -m venv venv
source venv/bin/activate # On Windows, use: venv\Scripts\activate source venv/bin/activate
``` ```
3. Install required packages: **On Windows:**
```cmd
python -m venv venv
venv\Scripts\activate
```
**On Windows PowerShell:**
```powershell
python -m venv venv
venv\Scripts\Activate.ps1
```
3. Install the Zerto Python SDK (`zvml` module):
**Option 1: Standard install**
```bash
cd ../zvml-python-sdk
pip install -r requirements.txt
pip install .
cd ../Zerto-Python-SDK-Hands-On-Labs
```
**Option 2: Development mode (recommended for contributors)**
```bash
cd ../zvml-python-sdk
pip install -r requirements.txt
pip install -e .
cd ../Zerto-Python-SDK-Hands-On-Labs
```
4. Install required packages:
```bash ```bash
pip install -r prerequisites/requirements.txt pip install -r prerequisites/requirements.txt
``` ```
4. Set up your environment: 5. Set up your environment:
- Copy `prerequisites/config.example.py` to `prerequisites/config.py` - Copy `prerequisites/config.example.py` to `prerequisites/config.py`
- Update the configuration with your ZVM details - Update the configuration with your ZVM details:
- **ZVM_HOST**: Your Zerto Virtual Manager IP address or hostname
- **CLIENT_ID**: Your Keycloak client ID (see Keycloak setup in config.example.py)
- **CLIENT_SECRET**: Your Keycloak client secret
- **Important**: Never commit your `config.py` file as it contains sensitive credentials
5. Start with Exercise 1 in the `exercises` directory 6. Start with Exercise 1 in the `exercises` directory
**Note:** When you're done working on the project, you can deactivate the virtual environment by typing `deactivate` in your terminal. **Note:** When you're done working on the project, you can deactivate the virtual environment by typing `deactivate` in your terminal.
+74 -25
View File
@@ -3,44 +3,93 @@
## Overview ## Overview
In this exercise, you'll learn how to authenticate with the Zerto API using Keycloak. You'll create a client and establish a connection to your ZVM. In this exercise, you'll learn how to authenticate with the Zerto API using Keycloak. You'll create a client and establish a connection to your ZVM.
## Objectives ## What You'll Learn
- Create a Keycloak client - How to create a ZVMLClient object (your "remote control" for ZVM)
- Configure authentication parameters - How to connect to your Zerto Virtual Manager
- Test the connection to ZVM - How to test if the connection works
- Handle authentication errors - How to handle errors if something goes wrong
## Time ## Time
10 minutes 10 minutes
## Prerequisites ## Prerequisites
- Completed Exercise 1 - Completed Exercise 1
- Valid ZVM credentials - Valid ZVM credentials (IP address, client ID, client secret)
- Client ID and secret - ✅ Updated `prerequisites/config.py` with your details
## Exercise Steps ## Step-by-Step Instructions
1. Set up your configuration
2. Create the Keycloak client ### Step 1: Open the Working File
3. Test the connection 1. Navigate to `exercises/02_authentication/working/`
4. Handle authentication errors 2. Open `auth.py` in your code editor
3. Read through the detailed comments - they explain everything!
### Step 2: Complete the Code
The file has three main sections you need to complete:
1. **Create ZVMLClient** - Replace `client = None` with actual code
2. **Test Connection** - Add code to test if it works
3. **Success Message** - Add a final success message
### Step 3: Run Your Code
```bash
cd exercises/02_authentication/working/
python auth.py
```
### Step 4: Check the Results
-**Success**: You'll see "Connection successful!" and ZVM version info
-**Error**: Check the error message and review your config.py
## Working Directory ## Working Directory
The `working` directory contains: The `working` directory contains:
- `auth.py` - Template to complete - `auth.py` - **Beginner-friendly template** with detailed instructions
## Solution ## Solution
The `solution` directory contains: The `solution` directory contains:
- `auth.py` - Complete working example - `auth.py` - Complete working example (check this if you get stuck!)
## Key Concepts ## Key Concepts Explained
- Keycloak authentication
- Client credentials flow
- Error handling
- Connection management
## Common Issues ### What is ZVMLClient?
- Invalid credentials - Think of it as a "remote control" for your Zerto Virtual Manager
- SSL certificate issues - It handles all the communication between your Python code and ZVM
- Network connectivity problems - You need to give it your ZVM address and login credentials
### What is Keycloak?
- It's the authentication system that Zerto uses
- You create a "client" (like a username) and get a "secret" (like a password)
- The ZVMLClient uses these to log into your ZVM
### What is SSL Verification?
- It's a security check to make sure you're connecting to the right server
- Usually set to `False` for Zerto (self-signed certificates)
## Common Issues & Solutions
### ❌ "Configuration file not found"
**Solution**: Copy `prerequisites/config.example.py` to `prerequisites/config.py`
### ❌ "Authentication failed"
**Solutions**:
- Check your ZVM_HOST is correct
- Verify your CLIENT_ID and CLIENT_SECRET
- Make sure your ZVM is running and accessible
### ❌ "SSL certificate" errors
**Solution**: Make sure `ZVM_SSL_VERIFY = False` in your config.py
### ❌ "Connection refused" or "Network unreachable"
**Solutions**:
- Check your ZVM IP address is correct
- Make sure you can ping the ZVM from your computer
- Check firewall settings
## Need Help?
1. Read the detailed comments in the code
2. Check the solution file
3. Review your `config.py` settings
4. Ask your Zerto administrator for help with credentials
## Next Steps ## Next Steps
Proceed to Exercise 3: Site Discovery to start working with Zerto sites. Once you successfully connect, proceed to **Exercise 3: Site Discovery** to start working with Zerto sites.
+97 -41
View File
@@ -1,20 +1,31 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
""" """
Exercise 2: Authentication Exercise 2: Authentication - Beginner-Friendly Instructions
This script demonstrates how to authenticate with Zerto API using Keycloak. This script demonstrates how to authenticate with Zerto API using Keycloak.
Prerequisites: PREREQUISITES (Complete these first):
1. Install the zvml package in development mode: 1. Make sure you have the zvml package installed (see main README)
cd /path/to/zvml-python-sdk 2. Update prerequisites/config.py with your ZVM details:
pip install -e . - ZVM_HOST: Your Zerto Virtual Manager IP address or hostname
2. Update prerequisites/config.py with your ZVM details - CLIENT_ID: Your Keycloak client ID
- CLIENT_SECRET: Your Keycloak client secret
Your task: WHAT YOU NEED TO DO:
1. Initialize ZVMLClient with Keycloak credentials In this exercise, you will:
2. Test connection by retrieving local site information 1. Create a ZVMLClient object to connect to your ZVM
3. Handle authentication and connection errors 2. Test the connection by getting information about your local site
3. Handle any errors that might occur
If you need help, check the solution in the solution directory. STEP-BY-STEP INSTRUCTIONS:
1. Look at the TODO comments below - they tell you exactly what to do
2. Replace the placeholder code with the actual code
3. Each step has hints and examples to help you
4. If you get stuck, check the solution file in the solution/ directory
WHAT IS A ZVMLClient?
- It's like a "remote control" for your Zerto Virtual Manager
- It handles all the communication with your ZVM
- You need to give it your ZVM address and login credentials
""" """
import sys import sys
@@ -23,61 +34,106 @@ import logging
import json import json
from pathlib import Path from pathlib import Path
# Add prerequisites to Python path # Add prerequisites to Python path (this helps Python find your config file)
prerequisites_path = Path(__file__).parent.parent.parent.parent / "prerequisites" prerequisites_path = Path(__file__).parent.parent.parent.parent / "prerequisites"
sys.path.append(str(prerequisites_path)) sys.path.append(str(prerequisites_path))
# Import the SDK modules # Import the Zerto SDK - this gives us the ZVMLClient class
from zvml import ZVMLClient from zvml import ZVMLClient
# Import configuration # Import your configuration settings
try: try:
from config import ( from config import (
ZVM_HOST, ZVM_HOST, # Your ZVM IP address (e.g., "192.168.1.100")
ZVM_PORT, ZVM_PORT, # Usually 443 for HTTPS
ZVM_SSL_VERIFY, ZVM_SSL_VERIFY, # True/False for SSL certificate verification
CLIENT_ID, CLIENT_ID, # Your Keycloak client ID (e.g., "my-api-client")
CLIENT_SECRET CLIENT_SECRET # Your Keycloak client secret
) )
except ImportError: except ImportError:
print("Error: Please copy config.example.py to config.py and update with your values") print("❌ ERROR: Configuration file not found!")
print("Please copy config.example.py to config.py and update with your values")
print("Expected path:", prerequisites_path / "config.py") print("Expected path:", prerequisites_path / "config.py")
sys.exit(1) sys.exit(1)
def main(): def main():
""" """
Main function to demonstrate Zerto authentication. Main function - this is where your code goes!
Complete the following steps: Follow the step-by-step instructions below.
1. Initialize ZVMLClient with Keycloak credentials
2. Test connection by retrieving local site info
3. Handle authentication and connection errors
""" """
# Set up logging with timestamp # Set up logging so you can see what's happening
logging.basicConfig( logging.basicConfig(
level=logging.INFO, level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s' format='%(asctime)s - %(levelname)s - %(message)s'
) )
print("🚀 Starting Zerto Authentication Exercise")
print("=" * 50)
try: try:
# Step 1: Create a ZVMLClient instance # ========================================
# TODO: Initialize the ZVMLClient with your ZVM host and credentials # STEP 1: Create a ZVMLClient instance
# Hint: Use ZVMLClient(zvm_address=ZVM_HOST, client_id=CLIENT_ID, # ========================================
# client_secret=CLIENT_SECRET, verify_certificate=ZVM_SSL_VERIFY) print("\n📝 STEP 1: Creating ZVMLClient...")
client = None # Replace with actual client initialization print("You need to replace the line 'client = None' with actual code.")
print("Look at the hint below for the correct syntax.")
# Step 2: Test the connection # TODO: Replace this line with actual ZVMLClient creation
# TODO: Try to get local site information to verify the connection # HINT: Use this syntax:
# Hint: Use client.localsite.get_local_site() and extract the Version # client = ZVMLClient(
# Hint: Log the version using logging.info() # zvm_address=ZVM_HOST,
pass # Replace with actual connection test # client_id=CLIENT_ID,
# client_secret=CLIENT_SECRET,
# verify_certificate=ZVM_SSL_VERIFY
# )
#
# EXPLANATION:
# - zvm_address: Where your ZVM is located (from config.py)
# - client_id: Your Keycloak client ID (from config.py)
# - client_secret: Your Keycloak client secret (from config.py)
# - verify_certificate: Whether to check SSL certificates (from config.py)
# Step 3: Print connection status client = None # ← REPLACE THIS LINE WITH YOUR CODE
# TODO: Display whether the connection was successful
# Hint: Use logging.info() to show the status # ========================================
# STEP 2: Test the connection
# ========================================
print("\n📝 STEP 2: Testing connection...")
print("You need to test if the connection works by getting local site info.")
print("Look at the hint below for the correct syntax.")
# TODO: Add code to test the connection
# HINT: Use this syntax:
# local_site = client.localsite.get_local_site()
# version = local_site.get('Version')
# logging.info(f"Successfully connected to ZVM version: {version}")
#
# EXPLANATION:
# - client.localsite.get_local_site() gets information about your local ZVM
# - local_site.get('Version') extracts the ZVM version from the response
# - logging.info() displays a success message
# ← ADD YOUR CODE HERE
# ========================================
# STEP 3: Display success message
# ========================================
print("\n📝 STEP 3: Displaying success message...")
print("You need to add a final success message.")
# TODO: Add a success message
# HINT: Use this syntax:
# logging.info("🎉 Connection successful!")
#
# EXPLANATION:
# This confirms that everything worked correctly
# ← ADD YOUR CODE HERE
except Exception as e: except Exception as e:
# TODO: Handle any authentication or connection errors # This catches any errors that might occur
# Hint: Use logging.error() to log the error message print(f"\n❌ ERROR: Something went wrong!")
print(f"Error details: {str(e)}")
logging.error(f"Authentication failed: {str(e)}") logging.error(f"Authentication failed: {str(e)}")
sys.exit(1) sys.exit(1)
+106 -41
View File
@@ -1,19 +1,30 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
""" """
Exercise 3: Site Discovery Exercise 3: Site Discovery - Beginner-Friendly Instructions
This script demonstrates how to discover and work with Zerto virtualization sites. This script demonstrates how to discover and work with Zerto virtualization sites.
Prerequisites: PREREQUISITES (Complete these first):
1. Install the zvml package in development mode: 1. ✅ Completed Exercise 2 (Authentication)
cd /path/to/zvml-python-sdk 2. ✅ Make sure you have the zvml package installed
pip install -e . 3. ✅ Updated prerequisites/config.py with your ZVM details
2. Update prerequisites/config.py with your ZVM details
Your task: WHAT YOU NEED TO DO:
1. List all available virtualization sites In this exercise, you will:
2. Get and display local site information 1. Create a ZVMLClient to connect to your ZVM (same as Exercise 2)
2. Get a list of all available virtualization sites
3. Get detailed information about your local site
If you need help, check the solution in the solution directory. STEP-BY-STEP INSTRUCTIONS:
1. Look at the TODO comments below - they tell you exactly what to do
2. Replace the placeholder code with the actual code
3. Each step has hints and examples to help you
4. If you get stuck, check the solution file in the solution/ directory
WHAT ARE VIRTUALIZATION SITES?
- A "site" in Zerto is a location where you have virtual machines
- Your "local site" is where your ZVM is running
- "Peer sites" are other locations you can replicate to/from
- Each site has information like name, type, version, etc.
""" """
import sys import sys
@@ -22,62 +33,116 @@ import logging
import json import json
from pathlib import Path from pathlib import Path
# Add prerequisites to Python path # Add prerequisites to Python path (this helps Python find your config file)
prerequisites_path = Path(__file__).parent.parent.parent.parent / "prerequisites" prerequisites_path = Path(__file__).parent.parent.parent.parent / "prerequisites"
sys.path.append(str(prerequisites_path)) sys.path.append(str(prerequisites_path))
# Import the SDK modules # Import the Zerto SDK - this gives us the ZVMLClient class
from zvml import ZVMLClient from zvml import ZVMLClient
# Import configuration # Import your configuration settings
try: try:
from config import ( from config import (
ZVM_HOST, ZVM_HOST, # Your ZVM IP address (e.g., "192.168.1.100")
ZVM_PORT, ZVM_PORT, # Usually 443 for HTTPS
ZVM_SSL_VERIFY, ZVM_SSL_VERIFY, # True/False for SSL certificate verification
CLIENT_ID, CLIENT_ID, # Your Keycloak client ID (e.g., "my-api-client")
CLIENT_SECRET CLIENT_SECRET # Your Keycloak client secret
) )
except ImportError: except ImportError:
print("Error: Please copy config.example.py to config.py and update with your values") print("❌ ERROR: Configuration file not found!")
print("Please copy config.example.py to config.py and update with your values")
print("Expected path:", prerequisites_path / "config.py") print("Expected path:", prerequisites_path / "config.py")
sys.exit(1) sys.exit(1)
def main(): def main():
""" """
Main function to demonstrate site discovery. Main function - this is where your code goes!
Complete the following steps: Follow the step-by-step instructions below.
1. List all available virtualization sites
2. Get and display local site information
""" """
# Set up logging with timestamp # Set up logging so you can see what's happening
logging.basicConfig( logging.basicConfig(
level=logging.INFO, level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s' format='%(asctime)s - %(levelname)s - %(message)s'
) )
print("🚀 Starting Zerto Site Discovery Exercise")
print("=" * 50)
try: try:
# Step 1: Create a ZVMLClient instance # ========================================
# TODO: Initialize the ZVMLClient with your ZVM host and credentials # STEP 1: Create a ZVMLClient instance
# Hint: Use ZVMLClient(zvm_address=ZVM_HOST, client_id=CLIENT_ID, # ========================================
# client_secret=CLIENT_SECRET, verify_certificate=ZVM_SSL_VERIFY) print("\n📝 STEP 1: Creating ZVMLClient...")
client = None # Replace with actual client initialization print("This is the same as Exercise 2 - you need to create a client to connect to ZVM.")
# Step 2: List all available sites # TODO: Replace this line with actual ZVMLClient creation
# TODO: Get the list of virtualization sites # HINT: Use this syntax (same as Exercise 2):
# Hint: Use client.virtualization_sites.get_virtualization_sites() # client = ZVMLClient(
# Hint: Log the number of sites found and their details using json.dumps() # zvm_address=ZVM_HOST,
pass # Replace with actual site listing # client_id=CLIENT_ID,
# client_secret=CLIENT_SECRET,
# verify_certificate=ZVM_SSL_VERIFY
# )
#
# EXPLANATION:
# This creates a connection to your ZVM (same as Exercise 2)
# Step 3: Get and display local site information client = None # ← REPLACE THIS LINE WITH YOUR CODE
# TODO: Get and display local site information
# Hint: Use client.localsite.get_local_site() # ========================================
# Hint: Log the local site details using json.dumps() # STEP 2: List all available sites
pass # Replace with actual local site retrieval # ========================================
print("\n📝 STEP 2: Getting list of sites...")
print("You need to get a list of all virtualization sites available to your ZVM.")
# TODO: Add code to get the list of sites
# HINT: Use this syntax:
# sites = client.virtualization_sites.get_virtualization_sites()
#
# EXPLANATION:
# - client.virtualization_sites.get_virtualization_sites() gets all sites
# - This returns a list of site information
# ← ADD YOUR CODE HERE
# TODO: Add code to display the sites
# HINT: Use this syntax:
# if not sites:
# logging.warning("No sites found!")
# else:
# logging.info(f"Found {len(sites)} site(s):")
# logging.info(f'Sites Info: {json.dumps(sites, indent=4)}')
#
# EXPLANATION:
# - len(sites) counts how many sites were found
# - json.dumps(sites, indent=4) formats the site data nicely
# - logging.info() displays the information
# ← ADD YOUR CODE HERE
# ========================================
# STEP 3: Get local site information
# ========================================
print("\n📝 STEP 3: Getting local site details...")
print("You need to get detailed information about your local site.")
# TODO: Add code to get local site information
# HINT: Use this syntax:
# local_site = client.localsite.get_local_site()
# logging.info(f"Local site details: {json.dumps(local_site, indent=4)}")
#
# EXPLANATION:
# - client.localsite.get_local_site() gets info about your local ZVM
# - This includes version, name, type, and other details
# - json.dumps(local_site, indent=4) formats it nicely
# ← ADD YOUR CODE HERE
except Exception as e: except Exception as e:
# TODO: Handle any site discovery errors # This catches any errors that might occur
# Hint: Use logging.error() to log the error message print(f"\n❌ ERROR: Something went wrong!")
print(f"Error details: {str(e)}")
logging.error(f"Site discovery failed: {str(e)}") logging.error(f"Site discovery failed: {str(e)}")
sys.exit(1) sys.exit(1)
@@ -1,19 +1,36 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
""" """
Exercise 4: Resource Discovery Exercise 4: Resource Discovery - Beginner-Friendly Instructions
This script demonstrates how to discover and work with resources in your Zerto environment. This script demonstrates how to discover and work with resources in your Zerto environment.
Prerequisites: PREREQUISITES (Complete these first):
1. Install the zvml package in development mode: 1. ✅ Completed Exercise 3 (Site Discovery)
cd /path/to/zvml-python-sdk 2. ✅ Make sure you have the zvml package installed
pip install -e . 3. ✅ Updated prerequisites/config.py with your ZVM details
2. Update prerequisites/config.py with your ZVM details
Your task: WHAT YOU NEED TO DO:
1. Discover local site resources (VMs) In this exercise, you will:
2. Work with peer site resources (datastores, hosts, folders, networks) 1. Create a ZVMLClient to connect to your ZVM (same as previous exercises)
2. Get a list of all available sites
3. Identify your local site and a peer site
4. Discover different types of resources:
- Local site: Virtual Machines (VMs)
- Peer site: Datastores, Hosts, Folders, Networks
If you need help, check the solution in the solution directory. STEP-BY-STEP INSTRUCTIONS:
1. Look at the TODO comments below - they tell you exactly what to do
2. Replace the placeholder code with the actual code
3. Each step has hints and examples to help you
4. If you get stuck, check the solution file in the solution/ directory
WHAT ARE RESOURCES?
- **VMs**: Virtual machines that can be protected/replicated
- **Datastores**: Storage locations where VMs are stored
- **Hosts**: Physical servers that run the VMs
- **Folders**: Organizational containers for VMs
- **Networks**: Network connections for VMs
- **Local Site**: Your current ZVM location
- **Peer Site**: Another location you can replicate to/from
""" """
import sys import sys
@@ -22,104 +39,173 @@ import logging
import json import json
from pathlib import Path from pathlib import Path
# Add prerequisites to Python path # Add prerequisites to Python path (this helps Python find your config file)
prerequisites_path = Path(__file__).parent.parent.parent.parent / "prerequisites" prerequisites_path = Path(__file__).parent.parent.parent.parent / "prerequisites"
sys.path.append(str(prerequisites_path)) sys.path.append(str(prerequisites_path))
# Import the SDK modules # Import the Zerto SDK - this gives us the ZVMLClient class
from zvml import ZVMLClient from zvml import ZVMLClient
# Import configuration # Import your configuration settings
try: try:
from config import ( from config import (
ZVM_HOST, ZVM_HOST, # Your ZVM IP address (e.g., "192.168.1.100")
ZVM_PORT, ZVM_PORT, # Usually 443 for HTTPS
ZVM_SSL_VERIFY, ZVM_SSL_VERIFY, # True/False for SSL certificate verification
CLIENT_ID, CLIENT_ID, # Your Keycloak client ID (e.g., "my-api-client")
CLIENT_SECRET CLIENT_SECRET # Your Keycloak client secret
) )
except ImportError: except ImportError:
print("Error: Please copy config.example.py to config.py and update with your values") print("❌ ERROR: Configuration file not found!")
print("Please copy config.example.py to config.py and update with your values")
print("Expected path:", prerequisites_path / "config.py") print("Expected path:", prerequisites_path / "config.py")
sys.exit(1) sys.exit(1)
def main(): def main():
""" """
Main function to demonstrate resource discovery. Main function - this is where your code goes!
Complete the following steps: Follow the step-by-step instructions below.
1. Discover local site resources (VMs)
2. Work with peer site resources (datastores, hosts, folders, networks)
""" """
# Set up logging with timestamp # Set up logging so you can see what's happening
logging.basicConfig( logging.basicConfig(
level=logging.INFO, level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s' format='%(asctime)s - %(levelname)s - %(message)s'
) )
print("🚀 Starting Zerto Resource Discovery Exercise")
print("=" * 50)
try: try:
# Step 1: Create a ZVMLClient instance # ========================================
# TODO: Initialize the ZVMLClient with your ZVM host and credentials # STEP 1: Create a ZVMLClient instance
# Hint: Use ZVMLClient(zvm_address=ZVM_HOST, client_id=CLIENT_ID, # ========================================
# client_secret=CLIENT_SECRET, verify_certificate=ZVM_SSL_VERIFY) print("\n📝 STEP 1: Creating ZVMLClient...")
client = None # Replace with actual client initialization print("This is the same as previous exercises - you need to create a client to connect to ZVM.")
# Step 2: Identify local and peer sites # TODO: Replace this line with actual ZVMLClient creation
# Step 2.1: List all available sites # HINT: Use this syntax (same as previous exercises):
# TODO: Get the list of available sites # client = ZVMLClient(
# Hint: Use client.virtualization_sites.get_virtualization_sites() # zvm_address=ZVM_HOST,
# Hint: Log the number of sites found and their details using json.dumps() # client_id=CLIENT_ID,
pass # Replace with actual site listing # client_secret=CLIENT_SECRET,
# verify_certificate=ZVM_SSL_VERIFY
# )
# Step 2.2: Get local and peer site identifiers client = None # ← REPLACE THIS LINE WITH YOUR CODE
# TODO: Get local site identifier
# Hint: Use client.localsite.get_local_site()
# Hint: Extract the SiteIdentifier from the response
local_site_identifier = None # Replace with actual local site identifier
# TODO: Get peer site identifier # ========================================
# Hint: Find the first site that is not the local site # STEP 2: Identify local and peer sites
# Hint: Extract the SiteIdentifier from that site # ========================================
peer_site_identifier = None # Replace with actual peer site identifier print("\n📝 STEP 2.1: Getting list of sites...")
print("You need to get a list of all available sites (same as Exercise 3).")
# Step 3: Get local site resources # TODO: Add code to get the list of sites
# Step 3.1: Get local site VMs # HINT: Use this syntax:
# TODO: Get VMs for the local site # sites = client.virtualization_sites.get_virtualization_sites()
# Hint: Use client.virtualization_sites.get_virtualization_site_vms() #
# Hint: Pass the local_site_identifier as site_identifier parameter # EXPLANATION:
# Hint: Log the VMs information using json.dumps() # This gets all sites available to your ZVM
pass # Replace with actual VM retrieval
# Step 3.2: Get peer site datastores # ← ADD YOUR CODE HERE
# TODO: Get datastores for the peer site
# Hint: Use client.virtualization_sites.get_virtualization_site_datastores()
# Hint: Pass the peer_site_identifier as site_identifier parameter
# Hint: Log the datastores information using json.dumps()
pass # Replace with actual datastore retrieval
# Step 3.3: Get peer site hosts print("\n📝 STEP 2.2: Getting local site identifier...")
# TODO: Get hosts for the peer site print("You need to get the identifier for your local site.")
# Hint: Use client.virtualization_sites.get_virtualization_site_hosts()
# Hint: Pass the peer_site_identifier as site_identifier parameter
# Hint: Log the hosts information using json.dumps()
pass # Replace with actual host retrieval
# Step 3.4: Get peer site folders # TODO: Add code to get local site identifier
# TODO: Get folders for the peer site # HINT: Use this syntax:
# Hint: Use client.virtualization_sites.get_virtualization_site_folders() # local_site_identifier = client.localsite.get_local_site().get('SiteIdentifier')
# Hint: Pass the peer_site_identifier as site_identifier parameter #
# Hint: Log the folders information using json.dumps() # EXPLANATION:
pass # Replace with actual folder retrieval # - client.localsite.get_local_site() gets your local site info
# - .get('SiteIdentifier') extracts the unique identifier
# Step 3.5: Get peer site networks local_site_identifier = None # ← REPLACE THIS LINE WITH YOUR CODE
# TODO: Get networks for the peer site
# Hint: Use client.virtualization_sites.get_virtualization_site_networks() print("\n📝 STEP 2.3: Getting peer site identifier...")
# Hint: Pass the peer_site_identifier as site_identifier parameter print("You need to find a peer site (any site that's not your local site).")
# Hint: Log the networks information using json.dumps()
pass # Replace with actual network retrieval # TODO: Add code to get peer site identifier
# HINT: Use this syntax:
# peer_site = next((site for site in sites if site.get('SiteIdentifier') != local_site_identifier), None)
# peer_site_identifier = peer_site.get('SiteIdentifier')
#
# EXPLANATION:
# - This finds the first site that's not your local site
# - next() gets the first matching site from the list
# - .get('SiteIdentifier') extracts the unique identifier
peer_site_identifier = None # ← REPLACE THIS LINE WITH YOUR CODE
# ========================================
# STEP 3: Get local site resources
# ========================================
print("\n📝 STEP 3.1: Getting local site VMs...")
print("You need to get all virtual machines from your local site.")
# TODO: Add code to get local site VMs
# HINT: Use this syntax:
# local_vms = client.virtualization_sites.get_virtualization_site_vms(site_identifier=local_site_identifier)
#
# EXPLANATION:
# This gets all VMs that can be protected/replicated from your local site
# ← ADD YOUR CODE HERE
# ========================================
# STEP 4: Get peer site resources
# ========================================
print("\n📝 STEP 4.1: Getting peer site datastores...")
print("You need to get datastores from the peer site.")
# TODO: Add code to get peer site datastores
# HINT: Use this syntax:
# peer_datastores = client.virtualization_sites.get_virtualization_site_datastores(site_identifier=peer_site_identifier)
#
# EXPLANATION:
# Datastores are storage locations where VMs can be stored on the peer site
# ← ADD YOUR CODE HERE
print("\n📝 STEP 4.2: Getting peer site hosts...")
print("You need to get hosts from the peer site.")
# TODO: Add code to get peer site hosts
# HINT: Use this syntax:
# peer_hosts = client.virtualization_sites.get_virtualization_site_hosts(site_identifier=peer_site_identifier)
#
# EXPLANATION:
# Hosts are physical servers that can run VMs on the peer site
# ← ADD YOUR CODE HERE
print("\n📝 STEP 4.3: Getting peer site folders...")
print("You need to get folders from the peer site.")
# TODO: Add code to get peer site folders
# HINT: Use this syntax:
# peer_folders = client.virtualization_sites.get_virtualization_site_folders(site_identifier=peer_site_identifier)
#
# EXPLANATION:
# Folders are organizational containers for VMs on the peer site
# ← ADD YOUR CODE HERE
print("\n📝 STEP 4.4: Getting peer site networks...")
print("You need to get networks from the peer site.")
# TODO: Add code to get peer site networks
# HINT: Use this syntax:
# peer_networks = client.virtualization_sites.get_virtualization_site_networks(site_identifier=peer_site_identifier)
#
# EXPLANATION:
# Networks are network connections that VMs can use on the peer site
# ← ADD YOUR CODE HERE
except Exception as e: except Exception as e:
# TODO: Handle any resource discovery errors # This catches any errors that might occur
# Hint: Use logging.error() to log the error message print(f"\n❌ ERROR: Something went wrong!")
print(f"Error details: {str(e)}")
logging.error(f"Resource discovery failed: {str(e)}") logging.error(f"Resource discovery failed: {str(e)}")
sys.exit(1) sys.exit(1)
+247 -88
View File
@@ -1,28 +1,39 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
""" """
Exercise 5: VPG Operations - Template Exercise 5: VPG Operations - Beginner-Friendly Instructions
This script demonstrates how to create and configure VPGs in your Zerto environment. This script demonstrates how to create and configure VPGs in your Zerto environment.
Prerequisites: PREREQUISITES (Complete these first):
1. Install the zvml package in development mode: 1. ✅ Completed Exercise 4 (Resource Discovery)
cd /path/to/zvml-python-sdk 2. ✅ Make sure you have the zvml package installed
pip install -e . 3. ✅ Updated prerequisites/config.py with your ZVM details
2. Update prerequisites/config.py with your ZVM details 4. ✅ Have some unprotected VMs available in your local site
Usage: WHAT YOU NEED TO DO:
python create_vpg.py --vm-names "vm1" "vm2" "vm3" [--vpg-name "My-VPG"] In this exercise, you will:
1. Create a ZVMLClient to connect to your ZVM
2. Parse command line arguments (VM names and VPG name)
3. Find VMs by their names in your local site
4. Get peer site resources (datastores, folders, networks, hosts)
5. Create a VPG configuration with all necessary settings
6. Create the VPG
7. Add VMs to the VPG
8. Optionally remove a VM from the VPG
Your task: STEP-BY-STEP INSTRUCTIONS:
1. Implement the find_vms_by_names function to locate VMs by their names 1. Look at the TODO comments below - they tell you exactly what to do
2. Complete the VPG configuration with appropriate settings 2. Replace the placeholder code with the actual code
3. Add the found VMs to the VPG 3. Each step has hints and examples to help you
4. Implement VM removal functionality 4. If you get stuck, check the solution file in the solution/ directory
The script should: WHAT IS A VPG?
- Create a new VPG with basic settings - **VPG** = Virtual Protection Group
- Configure journal, recovery, and network settings - It's a group of VMs that are protected together
- Add specified VMs to the VPG - All VMs in a VPG have the same protection settings
- Allow removing VMs from the VPG - You can replicate VMs from one site to another using VPGs
USAGE EXAMPLE:
python create_vpg.py --vm-names "vm1" "vm2" "vm3" --vpg-name "My-VPG"
""" """
import sys import sys
@@ -36,112 +47,183 @@ import urllib3
# Suppress SSL warnings # Suppress SSL warnings
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
# Add prerequisites to Python path # Add prerequisites to Python path (this helps Python find your config file)
prerequisites_path = Path(__file__).parent.parent.parent.parent / "prerequisites" prerequisites_path = Path(__file__).parent.parent.parent.parent / "prerequisites"
sys.path.append(str(prerequisites_path)) sys.path.append(str(prerequisites_path))
# Import the SDK modules # Import the Zerto SDK - this gives us the ZVMLClient class
from zvml import ZVMLClient from zvml import ZVMLClient
# Import configuration # Import your configuration settings
try: try:
from config import ( from config import (
ZVM_HOST, ZVM_HOST, # Your ZVM IP address (e.g., "192.168.1.100")
ZVM_PORT, ZVM_PORT, # Usually 443 for HTTPS
ZVM_SSL_VERIFY, ZVM_SSL_VERIFY, # True/False for SSL certificate verification
CLIENT_ID, CLIENT_ID, # Your Keycloak client ID (e.g., "my-api-client")
CLIENT_SECRET CLIENT_SECRET # Your Keycloak client secret
) )
except ImportError: except ImportError:
print("Error: Please copy config.example.py to config.py and update with your values") print("❌ ERROR: Configuration file not found!")
print("Please copy config.example.py to config.py and update with your values")
print("Expected path:", prerequisites_path / "config.py") print("Expected path:", prerequisites_path / "config.py")
sys.exit(1) sys.exit(1)
def parse_arguments(): def parse_arguments():
"""Parse command line arguments.""" """
# TODO: Implement argument parsing Parse command line arguments.
# Required arguments:
# --vm-names: List of VM names to add to the VPG TODO: Implement argument parsing
# Optional arguments: HINT: Use this syntax:
# --vpg-name: Name of the VPG to create (default: "Test-VPG-Python") parser = argparse.ArgumentParser(description='Create VPG and add specified VMs')
pass parser.add_argument('--vm-names', nargs='+', required=True,
help='List of VM names to add to the VPG')
parser.add_argument('--vpg-name', default="Test-VPG-Python",
help='Name of the VPG to create (default: Test-VPG-Python)')
return parser.parse_args()
EXPLANATION:
- argparse helps you get command line arguments
- --vm-names: List of VM names (required)
- --vpg-name: Name for the VPG (optional, has default)
"""
pass # ← REPLACE WITH YOUR CODE
def find_vms_by_names(client, site_identifier, vm_names): def find_vms_by_names(client, site_identifier, vm_names):
""" """
Find VMs by their names in the specified site. 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: TODO: Implement the function to:
1. Get all unprotected VMs from the site 1. Get all VMs from the site using client.virtualization_sites.get_virtualization_site_vms()
2. Create a dictionary for easy lookup 2. Create a dictionary for easy lookup: {vm.get('VmName'): vm for vm in vms}
3. Find requested as an argument VMs 3. Find requested VMs and return found/not found lists
4. Return found and not found VMs
HINT: Use this syntax:
vms = client.virtualization_sites.get_virtualization_site_vms(site_identifier=site_identifier)
vm_dict = {vm.get('VmName'): vm for vm in vms}
found_vms = []
not_found = []
for vm_name in vm_names:
if vm_name in vm_dict:
found_vms.append(vm_dict[vm_name])
else:
not_found.append(vm_name)
return found_vms, not_found
""" """
pass pass # ← REPLACE WITH YOUR CODE
def remove_vm_from_vpg(client, vpg_name, vm): def remove_vm_from_vpg(client, vpg_name, vm):
""" """
Remove a VM from the VPG. 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: TODO: Implement the function to:
1. Get VM identifier 1. Get VM name from vm object
2. Call the appropriate API to remove the VM 2. Call client.vpgs.remove_vm_from_vpg() to remove the VM
3. Log the operation
HINT: Use this syntax:
vm_name = vm.get('VmName')
client.vpgs.remove_vm_from_vpg(vpg_name=vpg_name, vm_name=vm_name)
""" """
pass pass # ← REPLACE WITH YOUR CODE
def main(): def main():
""" """
Main function to demonstrate VPG creation. Main function - this is where your code goes!
Follow the step-by-step instructions below.
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
""" """
# Set up logging # Set up logging so you can see what's happening
logging.basicConfig( logging.basicConfig(
level=logging.INFO, level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s' format='%(asctime)s - %(levelname)s - %(message)s'
) )
print("🚀 Starting Zerto VPG Operations Exercise")
print("=" * 50)
try: try:
# TODO: Step 1: Parse command line arguments # ========================================
# STEP 1: Parse command line arguments
# ========================================
print("\n📝 STEP 1: Parsing command line arguments...")
print("You need to call the parse_arguments() function you created above.")
# TODO: Add code to parse arguments
# HINT: Use this syntax:
# args = parse_arguments() # args = parse_arguments()
#
# EXPLANATION:
# This gets the VM names and VPG name from command line
# TODO: Step 2: Create ZVMLClient instance # ← ADD YOUR CODE HERE
# client = ZVMLClient(...)
# TODO: Step 3: Identify local and peer sites # ========================================
# local_site = client.localsite.get_local_site() # STEP 2: Create ZVMLClient instance
# ========================================
print("\n📝 STEP 2: Creating ZVMLClient...")
print("This is the same as previous exercises.")
# TODO: Add code to create ZVMLClient
# HINT: Use this syntax:
# client = ZVMLClient(
# zvm_address=ZVM_HOST,
# client_id=CLIENT_ID,
# client_secret=CLIENT_SECRET,
# verify_certificate=ZVM_SSL_VERIFY
# )
# ← ADD YOUR CODE HERE
# ========================================
# STEP 3: Identify local and peer sites
# ========================================
print("\n📝 STEP 3: Getting site information...")
print("You need to get local and peer site identifiers.")
# TODO: Add code to get sites and site identifiers
# HINT: Use this syntax:
# sites = client.virtualization_sites.get_virtualization_sites() # sites = client.virtualization_sites.get_virtualization_sites()
# local_site = client.localsite.get_local_site()
# local_site_identifier = local_site.get('SiteIdentifier')
# peer_site = next((site for site in sites if site.get('SiteIdentifier') != local_site_identifier), None)
# peer_site_identifier = peer_site.get('SiteIdentifier')
# TODO: Step 4: Get peer site resources # ← ADD YOUR CODE HERE
# 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 # ========================================
# STEP 4: Get peer site resources
# ========================================
print("\n📝 STEP 4: Getting peer site resources...")
print("You need to get datastores, folders, networks, and hosts from the peer site.")
# TODO: Add code to get peer site resources
# HINT: Use this syntax:
# peer_datastores = client.virtualization_sites.get_virtualization_site_datastores(site_identifier=peer_site_identifier)
# target_datastore = peer_datastores[0] # Use first available
#
# peer_folders = client.virtualization_sites.get_virtualization_site_folders(site_identifier=peer_site_identifier)
# target_folder = peer_folders[0] # Use first available
#
# peer_networks = client.virtualization_sites.get_virtualization_site_networks(site_identifier=peer_site_identifier)
# target_network = peer_networks[0] # Use first available
#
# peer_hosts = client.virtualization_sites.get_virtualization_site_hosts(site_identifier=peer_site_identifier)
# target_host = peer_hosts[0] # Use first available
# ← ADD YOUR CODE HERE
# ========================================
# STEP 5: Create VPG configuration
# ========================================
print("\n📝 STEP 5: Creating VPG configuration...")
print("You need to create the basic, journal, recovery, and network settings.")
# TODO: Add code to create VPG configuration
# HINT: Use this syntax:
# basic = { # basic = {
# "Name": "Your VPG Name", # "Name": args.vpg_name,
# "VpgType": "Remote", # "VpgType": "Remote",
# "RpoInSeconds": 300, # "RpoInSeconds": 300,
# "JournalHistoryInHours": 24, # "JournalHistoryInHours": 24,
@@ -150,21 +232,98 @@ def main():
# "ProtectedSiteIdentifier": local_site_identifier, # "ProtectedSiteIdentifier": local_site_identifier,
# "RecoverySiteIdentifier": peer_site_identifier # "RecoverySiteIdentifier": peer_site_identifier
# } # }
#
# journal = {} # Keep default settings
#
# recovery = {
# "DefaultHostIdentifier": target_host.get('HostIdentifier'),
# "DefaultDatastoreIdentifier": target_datastore.get('DatastoreIdentifier'),
# "DefaultFolderIdentifier": target_folder.get('FolderIdentifier')
# }
#
# networks = {
# "Failover": {
# "Hypervisor": {
# "DefaultNetworkIdentifier": target_network.get('NetworkIdentifier')
# }
# },
# "FailoverTest": {
# "Hypervisor": {
# "DefaultNetworkIdentifier": target_network.get('NetworkIdentifier')
# }
# }
# }
# TODO: Step 6: Create VPG # ← ADD YOUR CODE HERE
# vpg_id = client.vpgs.create_vpg(...)
# TODO: Step 7: Find and add VMs to VPG # ========================================
# found_vms, not_found = find_vms_by_names(...) # STEP 6: Create VPG
# ========================================
print("\n📝 STEP 6: Creating the VPG...")
print("You need to call the create_vpg method with your configuration.")
# TODO: Add code to create VPG
# HINT: Use this syntax:
# vpg_id = client.vpgs.create_vpg(basic=basic, journal=journal, recovery=recovery, networks=networks, sync=True)
#
# EXPLANATION:
# This creates the VPG with all your settings
# ← ADD YOUR CODE HERE
# ========================================
# STEP 7: Find and add VMs to VPG
# ========================================
print("\n📝 STEP 7: Finding and adding VMs...")
print("You need to find the VMs and add them to the VPG.")
# TODO: Add code to find VMs
# HINT: Use this syntax:
# found_vms, not_found = find_vms_by_names(client, local_site_identifier, args.vm_names)
#
# EXPLANATION:
# This finds the VMs you specified in the command line
# ← ADD YOUR CODE HERE
# TODO: Add code to add VMs to VPG
# HINT: Use this syntax:
# for vm in found_vms: # for vm in found_vms:
# # Add VM to VPG # vm_name = vm.get('VmName')
# vm_id = vm.get('VmIdentifier')
# vm_payload = {
# "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(args.vpg_name, vm_list_payload=vm_payload)
# TODO: Step 8: Implement interactive VM removal # ← ADD YOUR CODE HERE
# ========================================
# STEP 8: Interactive VM removal (optional)
# ========================================
print("\n📝 STEP 8: Interactive VM removal...")
print("You can optionally remove the last VM from the VPG.")
# TODO: Add code for interactive VM removal
# HINT: Use this syntax:
# if found_vms: # if found_vms:
# # Ask user if they want to remove the last VM # last_vm = found_vms[-1]
# # If yes, remove it # vm_name = last_vm.get('VmName')
# response = input(f"Remove VM {vm_name} from VPG? (yes/no): ").lower()
# if response in ['yes', 'y']:
# remove_vm_from_vpg(client, args.vpg_name, last_vm)
# ← ADD YOUR CODE HERE
except Exception as e: except Exception as e:
# This catches any errors that might occur
print(f"\n❌ ERROR: Something went wrong!")
print(f"Error details: {str(e)}")
logging.error(f"VPG operation failed: {str(e)}") logging.error(f"VPG operation failed: {str(e)}")
sys.exit(1) sys.exit(1)
+182 -113
View File
@@ -1,28 +1,37 @@
#!/usr/bin/env python3 #!/usr/bin/env python3
""" """
Exercise 6: Failover Testing - Template Exercise 6: Failover Testing - Beginner-Friendly Instructions
This script demonstrates how to perform a failover test on a VPG. This script demonstrates how to perform a failover test on a VPG.
Prerequisites: PREREQUISITES (Complete these first):
1. Install the zvml package in development mode: 1. ✅ Completed Exercise 5 (VPG Operations)
cd /path/to/zvml-python-sdk 2. ✅ Make sure you have the zvml package installed
pip install -e . 3. ✅ Updated prerequisites/config.py with your ZVM details
2. Update prerequisites/config.py with your ZVM details 4. ✅ Have a VPG created and running (from Exercise 5)
Usage: WHAT YOU NEED TO DO:
python failover.py --vpg-name "My-VPG" In this exercise, you will:
1. Create a ZVMLClient to connect to your ZVM
2. Parse command line arguments (VPG name)
3. Find a VPG by its name
4. Start a failover test on the VPG
5. Monitor the test progress
6. Optionally stop the test
Your task: STEP-BY-STEP INSTRUCTIONS:
1. Implement VPG lookup by name using get_vpgs() 1. Look at the TODO comments below - they tell you exactly what to do
2. Start a failover test using failover_test() method 2. Replace the placeholder code with the actual code
3. Monitor test progress using get_vpg_test_status() 3. Each step has hints and examples to help you
4. Stop the test using stop_vpg_test() method when requested 4. If you get stuck, check the solution file in the solution/ directory
The script should: WHAT IS A FAILOVER TEST?
- Find the VPG by name and verify it exists - **Failover Test**: Tests if your VMs can be successfully started at the recovery site
- Start a failover test with default settings - It creates test VMs at the peer site to verify everything works
- Monitor the test progress and status - The test VMs are isolated and don't affect production
- Allow stopping the test when requested - You can stop the test at any time to clean up the test VMs
USAGE EXAMPLE:
python failover.py --vpg-name "My-VPG"
""" """
import sys import sys
@@ -37,159 +46,219 @@ import urllib3
# Suppress SSL warnings # Suppress SSL warnings
urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning) urllib3.disable_warnings(urllib3.exceptions.InsecureRequestWarning)
# Add prerequisites to Python path # Add prerequisites to Python path (this helps Python find your config file)
prerequisites_path = Path(__file__).parent.parent.parent.parent / "prerequisites" prerequisites_path = Path(__file__).parent.parent.parent.parent / "prerequisites"
sys.path.append(str(prerequisites_path)) sys.path.append(str(prerequisites_path))
# Import the SDK modules # Import the Zerto SDK - this gives us the ZVMLClient class
from zvml import ZVMLClient from zvml import ZVMLClient
# Import configuration # Import your configuration settings
try: try:
from config import ( from config import (
ZVM_HOST, ZVM_HOST, # Your ZVM IP address (e.g., "192.168.1.100")
ZVM_PORT, ZVM_PORT, # Usually 443 for HTTPS
ZVM_SSL_VERIFY, ZVM_SSL_VERIFY, # True/False for SSL certificate verification
CLIENT_ID, CLIENT_ID, # Your Keycloak client ID (e.g., "my-api-client")
CLIENT_SECRET CLIENT_SECRET # Your Keycloak client secret
) )
except ImportError: except ImportError:
print("Error: Please copy config.example.py to config.py and update with your values") print("❌ ERROR: Configuration file not found!")
print("Please copy config.example.py to config.py and update with your values")
print("Expected path:", prerequisites_path / "config.py") print("Expected path:", prerequisites_path / "config.py")
sys.exit(1) sys.exit(1)
def parse_arguments(): def parse_arguments():
"""Parse command line arguments.""" """
# TODO: Implement argument parsing Parse command line arguments.
# Required argument:
# --vpg-name: Name of the VPG to test TODO: Implement argument parsing
pass HINT: Use this syntax:
parser = argparse.ArgumentParser(description='Perform failover test on a VPG')
parser.add_argument('--vpg-name', required=True,
help='Name of the VPG to test')
return parser.parse_args()
EXPLANATION:
- argparse helps you get command line arguments
- --vpg-name: Name of the VPG to test (required)
"""
pass # ← REPLACE WITH YOUR CODE
def find_vpg_by_name(client, vpg_name): def find_vpg_by_name(client, vpg_name):
""" """
Find a VPG by its name using get_vpgs() method. Find a VPG by its name.
Args: TODO: Implement the function to find a VPG by name
client: ZVMLClient instance HINT: Use this syntax:
vpg_name: Name of the VPG to find vpg = client.vpgs.list_vpgs(vpg_name=vpg_name)
return vpg if vpg else None
Returns: EXPLANATION:
dict: VPG object if found, None otherwise - client.vpgs.list_vpgs() gets VPGs with a specific name
- Returns the VPG if found, None if not found
TODO: Implement the function to:
1. Call client.vpgs.get_vpgs() to get all VPGs
2. Find the VPG with matching name
3. Log the VPG details if found
4. Return the VPG object or None
""" """
pass pass # ← REPLACE WITH YOUR CODE
def start_failover_test(client, vpg_name): def start_failover_test(client, vpg_name):
""" """
Start a failover test for the specified VPG using failover_test() method. Start a failover test for the specified VPG.
Args: TODO: Implement the function to start a failover test
client: ZVMLClient instance HINT: Use this syntax:
vpg_name: Name of the VPG to test response = client.vpgs.failover_test(
vpg_name=vpg_name,
sync=True # Wait for the test to start
)
return response
Returns: EXPLANATION:
str: Test identifier (task_id) - client.vpgs.failover_test() starts a failover test
- sync=True means wait for the test to start before returning
TODO: Implement the function to: - Returns the response from the API
1. Call client.vpgs.failover_test() with sync=True
2. Log the test initiation
3. Return the task_id
""" """
pass pass # ← REPLACE WITH YOUR CODE
def monitor_test_progress(client, vpg_name, test_id): def monitor_test_progress(client, vpg_name, test_id):
""" """
Monitor the progress of a failover test using get_vpg_test_status(). Monitor the progress of a failover test.
Args: TODO: Implement the function to monitor test progress
client: ZVMLClient instance HINT: Use this syntax:
vpg_name: Name of the VPG test_status = client.vpgs.get_vpg_test_status(vpg_name, test_id)
test_id: Test identifier (task_id) status = test_status.get('Status')
progress = test_status.get('Progress', 0)
Returns: logging.info(f"Test status: {status} (Progress: {progress}%)")
bool: True if test completed successfully, False otherwise
TODO: Implement the function to: if status == 'Succeeded':
1. Call client.vpgs.get_vpg_test_status() to get test status return True
2. Log the status and progress elif status in ['Failed', 'Stopped']:
3. Return True for 'Succeeded', False for 'Failed' or 'Stopped' return False
4. Return False if test is still running
return False # Test is still running
EXPLANATION:
- client.vpgs.get_vpg_test_status() gets the current test status
- Returns True if test succeeded, False if failed/stopped/still running
""" """
pass pass # ← REPLACE WITH YOUR CODE
def stop_failover_test(client, vpg_name, test_id): def stop_failover_test(client, vpg_name):
""" """
Stop a running failover test using stop_vpg_test() method. Stop a running failover test.
Args: TODO: Implement the function to stop a failover test
client: ZVMLClient instance HINT: Use this syntax:
vpg_name: Name of the VPG response = client.vpgs.stop_failover_test(vpg_name=vpg_name)
test_id: Test identifier (task_id)
TODO: Implement the function to: EXPLANATION:
1. Call client.vpgs.stop_vpg_test() with sync=True - client.vpgs.stop_failover_test() stops the running test
2. Wait for the stop operation to complete - This cleans up the test VMs at the recovery site
3. Log the stop operation status
""" """
pass pass # ← REPLACE WITH YOUR CODE
def main(): def main():
""" """
Main function to demonstrate failover testing. Main function - this is where your code goes!
Follow the step-by-step instructions below.
TODO: Implement the following steps:
1. Parse command line arguments for VPG name
2. Create ZVMLClient instance
3. Find the VPG by name using find_vpg_by_name()
4. Start failover test using start_failover_test()
5. Monitor test progress and handle stop request:
- Monitor progress using monitor_test_progress()
- If test completes successfully, exit
- If user requests to stop, call stop_failover_test()
""" """
# Set up logging # Set up logging so you can see what's happening
logging.basicConfig( logging.basicConfig(
level=logging.INFO, level=logging.INFO,
format='%(asctime)s - %(levelname)s - %(message)s' format='%(asctime)s - %(levelname)s - %(message)s'
) )
print("🚀 Starting Zerto Failover Testing Exercise")
print("=" * 50)
try: try:
# TODO: Step 1: Parse command line arguments # ========================================
# STEP 1: Parse command line arguments
# ========================================
print("\n📝 STEP 1: Parsing command line arguments...")
print("You need to call the parse_arguments() function you created above.")
# TODO: Add code to parse arguments
# HINT: Use this syntax:
# args = parse_arguments() # args = parse_arguments()
#
# EXPLANATION:
# This gets the VPG name from command line
# TODO: Step 2: Create ZVMLClient instance # ← ADD YOUR CODE HERE
# client = ZVMLClient(...)
# TODO: Step 3: Find the VPG # ========================================
# STEP 2: Create ZVMLClient instance
# ========================================
print("\n📝 STEP 2: Creating ZVMLClient...")
print("This is the same as previous exercises.")
# TODO: Add code to create ZVMLClient
# HINT: Use this syntax:
# client = ZVMLClient(
# zvm_address=ZVM_HOST,
# client_id=CLIENT_ID,
# client_secret=CLIENT_SECRET,
# verify_certificate=ZVM_SSL_VERIFY
# )
# ← ADD YOUR CODE HERE
# ========================================
# STEP 3: Find the VPG
# ========================================
print("\n📝 STEP 3: Finding the VPG...")
print("You need to find the VPG by its name.")
# TODO: Add code to find VPG
# HINT: Use this syntax:
# vpg = find_vpg_by_name(client, args.vpg_name) # vpg = find_vpg_by_name(client, args.vpg_name)
# if not vpg: # if not vpg:
# logging.error(f"VPG '{args.vpg_name}' not found!") # logging.error(f"VPG '{args.vpg_name}' not found!")
# sys.exit(1) # sys.exit(1)
# TODO: Step 4: Start failover test
# test_id = start_failover_test(client, args.vpg_name)
# TODO: Step 5: Monitor test progress and handle stop request
# while True:
# success = monitor_test_progress(client, args.vpg_name, test_id)
# if success:
# logging.info("Test completed successfully")
# break
# #
# # Check if user wants to stop the test # EXPLANATION:
# response = input("\nWould you like to stop the test? (yes/no): ").lower() # This checks if the VPG exists before trying to test it
# if response in ['yes', 'y']:
# stop_failover_test(client, args.vpg_name, test_id) # ← ADD YOUR CODE HERE
# break
# ========================================
# STEP 4: Start failover test
# ========================================
print("\n📝 STEP 4: Starting failover test...")
print("You need to start a failover test on the VPG.")
# TODO: Add code to start failover test
# HINT: Use this syntax:
# response = start_failover_test(client, args.vpg_name)
# #
# time.sleep(10) # Wait before next status check # EXPLANATION:
# This starts the failover test and waits for it to begin
# ← ADD YOUR CODE HERE
# ========================================
# STEP 5: Handle test stop request
# ========================================
print("\n📝 STEP 5: Handling test stop request...")
print("You can optionally stop the test.")
# TODO: Add code for interactive test stopping
# HINT: Use this syntax:
# response = input("\nWould you like to stop the test? (yes/no): ").lower()
# if response in ['yes', 'y']:
# stop_failover_test(client, args.vpg_name)
#
# EXPLANATION:
# This asks the user if they want to stop the test and cleans up if yes
# ← ADD YOUR CODE HERE
except Exception as e: except Exception as e:
# This catches any errors that might occur
print(f"\n❌ ERROR: Something went wrong!")
print(f"Error details: {str(e)}")
logging.error(f"Failover test failed: {str(e)}") logging.error(f"Failover test failed: {str(e)}")
sys.exit(1) sys.exit(1)