This document provides context for AI coding assistants working with this repository.
Name: os_migrate.vmware_migration_kit
Version: 2.2.0
License: Apache-2.0
Repository: https://github.com/os-migrate/vmware-migration-kit
This is an Ansible collection for migrating virtual machines from VMware (ESXi/vCenter) to OpenStack clouds. It uses a hybrid architecture combining:
- Ansible roles & playbooks for orchestration and workflow management
- Go binaries for high-performance migration operations (compiled to native executables)
- Python wrappers for Ansible module interface compatibility
vmware-migration-kit/
├── galaxy.yml # Ansible collection metadata (source of truth for version)
├── Makefile # Build automation (containers, tests, binaries)
├── go.mod / go.sum # Go module dependencies
├── playbooks/ # Main entry point playbooks
│ ├── migration.yml # Primary NBDKit-based migration
│ ├── migration_v2v.yml # Virt-v2v workflow
│ └── ...
├── roles/
│ ├── prelude/ # Setup and validation
│ ├── conversion_host/ # OpenStack conversion host deployment
│ ├── export_metadata/ # VMware metadata extraction
│ ├── convert_metadata/ # Metadata transformation (VMware → OpenStack)
│ └── import_workloads/ # VM import and disk migration
├── plugins/
│ ├── modules/ # Ansible modules (Python wrappers + Go binaries)
│ │ ├── *.py # Python wrapper files (DOCUMENTATION, thin interface)
│ │ ├── migrate # Compiled Go binary (no extension)
│ │ ├── create_server # Compiled Go binary
│ │ └── src/ # Go source code (not shipped in collection)
│ │ ├── migrate/
│ │ │ └── migrate.go
│ │ ├── create_server/
│ │ │ └── create_server.go
│ │ └── ...
│ └── module_utils/ # Shared utilities
│ ├── vmware/ # govmomi vCenter/ESXi integration
│ ├── openstack/ # Gophercloud OpenStack integration
│ ├── nbdkit/ # NBD server management
│ ├── logger/ # Structured logging (logrus)
│ ├── ansible/ # Ansible module interface helpers
│ ├── connectivity/ # Network connectivity checks
│ └── utils.go # Common utilities
├── tests/
│ ├── unit/ # Go unit tests (*_test.go)
│ ├── integration/ # Ansible integration tests
│ └── sanity/ # Ansible sanity ignore files
├── scripts/
│ └── build.sh # Containerized Go build script
└── aee/ # Ansible Execution Environment config
┌─────────────────────────────────────────────────────────────────┐
│ Ansible Controller │
│ ┌──────────────┐ ┌──────────────┐ ┌──────────────┐ │
│ │ playbooks/ │ │ roles/ │ │ vars.yaml │ │
│ └──────┬───────┘ └──────┬───────┘ └──────────────┘ │
│ │ │ │
│ └────────┬────────┘ │
│ ▼ │
│ ┌───────────────────────────────────────────────────────────┐ │
│ │ plugins/modules/*.py (wrappers) │ │
│ │ (DOCUMENTATION + argument passing to Go binaries) │ │
│ └─────────────────────────┬─────────────────────────────────┘ │
│ ▼ │
│ ┌───────────────────────────────────────────────────────────┐ │
│ │ plugins/modules/<binary> (Go executables) │ │
│ │ migrate | create_server | flavor_info | ... │ │
│ └─────────────────────────┬─────────────────────────────────┘ │
│ │ │
└────────────────────────────┼────────────────────────────────────┘
▼
┌────────────────────────────────────────────────────────────────┐
│ Conversion Host (OpenStack VM) │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ nbdkit │ │ virt-v2v │ │ virtio-win │ │
│ │ server │ │ (optional) │ │ (Windows) │ │
│ └──────┬──────┘ └─────────────┘ └─────────────┘ │
│ │ │
│ ┌────┴────┐ │
│ │ NBD/VDDK│────────────────────────────────────────────────┼──► VMware ESXi/vCenter
│ └─────────┘ │ (port 902/TCP)
│ │ │
│ ┌────┴────┐ │
│ │ Cinder │────────────────────────────────────────────────┼──► OpenStack APIs
│ └─────────┘ │
└────────────────────────────────────────────────────────────────┘
Go modules follow a consistent pattern:
// plugins/modules/src/<module_name>/<module_name>.go
package main
import (
"vmware-migration-kit/plugins/module_utils/ansible"
// ... other module_utils imports
)
type ModuleArgs struct {
// Ansible module arguments (JSON unmarshaled)
FieldName string `json:"field_name"`
}
func main() {
var response ansible.Response
// 1. Read args file from os.Args[1]
// 2. Unmarshal JSON into ModuleArgs
// 3. Validate required fields with ansible.RequireField()
// 4. Execute business logic
// 5. Return with ansible.ExitJson() or ansible.FailJson()
}| Target | Description |
|---|---|
make binaries |
Build all Go modules in container (CentOS Stream 9) |
make build |
Build complete Ansible collection tarball |
make clean-binaries |
Remove compiled binaries from plugins/modules/ |
make install |
Build and install collection with dependencies |
make tests |
Run all tests (pytest, ansible-lint, sanity, golangci-lint) |
make test-pytest |
Python unit tests |
make test-ansible-lint |
Ansible linting |
make test-ansible-sanity |
Ansible module validation |
make test-golangci-lint |
Go code quality (golangci-lint v2) |
- Binaries are built inside a container (Podman/Docker with CentOS Stream 9)
- Uses
go build -ldflags="-s -w"for smaller binaries - UPX compression applied when available
- Output binaries placed in
plugins/modules/<module_name>(no file extension) plugins/modules/src/is excluded from the built collection (seegalaxy.ymlbuild_ignore)
# Full containerized build
make binaries
# Or manually with container
podman run --rm -v $(pwd):/code/ quay.io/centos/centos:stream9 /code/scripts/build.sh- Create directory:
plugins/modules/src/my_module/ - Implement
my_module.gofollowing the pattern above - Create Python wrapper:
plugins/modules/my_module.pywith DOCUMENTATION, EXAMPLES, RETURN - Run
make binariesto compile - Add sanity exclusions in
tests/sanity/ignore-2.*.txtif needed (for binary files) - Run
make teststo validate
- Edit
.gofiles inplugins/modules/src/<module>/orplugins/module_utils/ - Run
make binariesto recompile - Run
make test-golangci-lintto check code quality - Run Go unit tests:
go test ./tests/unit/...
# All tests
make tests
# Individual test suites
make test-pytest # Python tests (tests/test_*.py)
make test-golangci-lint # Go linting
make test-ansible-sanity # Ansible validation
make test-ansible-lint # Ansible best practices
# Go unit tests directly (requires local Go toolchain)
go test -v ./tests/unit/...- License header: Apache 2.0 with Red Hat copyright on all
.gofiles - Package naming: Module main packages use
package main; utilities use descriptive names - Imports: Group stdlib, then external, then internal (
vmware-migration-kit/...) - Error handling: Return errors up the chain; log with
logger.Log.Infof() - Ansible interface: Use
ansible.RequireField(),ansible.DefaultIfEmpty(),ansible.ExitJson(),ansible.FailJson() - JSON tags: Use
json:"snake_case"for struct fields
- Wrappers only: Python files in
plugins/modules/are thin wrappers; business logic is in Go - DOCUMENTATION: Full Ansible module documentation in docstring
- Python 2.7 compatibility: No f-strings; use
from __future__ importfor metaclass boilerplate
- Variable naming:
snake_casewith descriptive prefixes (e.g.,import_workloads_*,os_migrate_vmw_*) - Role structure: Follow standard
defaults/main.yml,tasks/main.yml,meta/main.ymllayout - Idempotency: Check state before making changes; support repeated runs
- NBDKit (Default): Uses nbdkit with VDDK plugin for streaming disks to Cinder volumes
- Virt-v2v: Traditional conversion with guest OS modification
- CBT (Change Block Tracking): Two-phase migration for near-zero downtime
# Phase 1 - Initial sync (VM keeps running)
import_workloads_cbt_sync: true
import_workloads_cutover: false
# Phase 2 - Final cutover (VM stopped, delta sync)
import_workloads_cbt_sync: false
import_workloads_cutover: trueCinder volumes store migration state in metadata:
osm: "true"- Managed by os-migratechangeID: "<CBT-ID>"- VMware CBT change identifierconverted: "true/false"- V2V conversion status
| Direction | Port | Purpose |
|---|---|---|
| Conversion Host → vCenter | 443/TCP | Authentication, management |
| Conversion Host → ESXi | 902/TCP | NFC/NBD disk access |
| Conversion Host → OpenStack | Various | API endpoints |
| Ansible Controller → Conversion Host | 22/TCP | SSH management |
| Internal | 10809/TCP | NBDKit server (localhost) |
- ✅ Edit
.gosource files inplugins/modules/src/orplugins/module_utils/ - ✅ Run
make binariesafter any Go code changes - ✅ Keep
galaxy.ymlversion in sync withCHANGELOG.md - ✅ Add Apache 2.0 license headers to new Go files
- ✅ Use existing
module_utilspackages for VMware/OpenStack/logging - ✅ Follow the established Ansible module pattern (ModuleArgs → validation → logic → Response)
- ✅ Add sanity ignore entries for new binary modules
- ❌ Edit binary files (
plugins/modules/migrate, etc.) - they're compiled artifacts - ❌ Assume local Go toolchain - use
make binariesfor reproducible builds - ❌ Add Python business logic - put it in Go modules instead
- ❌ Use f-strings in Python (breaks Python 2.7 compatibility for sanity tests)
- ❌ Modify files in
build_ignorepaths expecting them to ship in collection
The authoritative version is in galaxy.yml. When updating:
- Update
versioningalaxy.yml - Add entry to
CHANGELOG.md - Tag release with
v<version>(e.g.,v2.2.0)
github.com/gophercloud/gophercloud/v2- OpenStack SDKgithub.com/vmware/govmomi- VMware vSphere SDKgithub.com/sirupsen/logrus- Structured logginglibguestfs.org/libnbd- NBD client library
vmware.vmware>= 2.4.0vmware.vmware_rest>= 4.9.0
- nbdkit with VDDK plugin
- virt-v2v (optional, for conversion workflow)
- virtio-win >= 1.40 (Windows migrations)
- CentOS Stream 10 or RHEL 9.5+ recommended
- Conversion Host:
/tmp/osm-nbdkit-<vm-name>-<random-id>.log - Ansible Controller:
<os_migrate_vmw_data_dir>/<vm-name>/migration.log
import_workloads_debug: true# Build and install locally
make install
# Run migration
ansible-playbook -i inventory.yml os_migrate.vmware_migration_kit.migration -e @vars.yaml
# Check migration logs on conversion host
tail -f /tmp/osm-nbdkit-*.log
# Install from Galaxy
ansible-galaxy collection install os_migrate.vmware_migration_kit
# Run Go tests directly
go test -v ./tests/unit/...
# Lint Go code
make test-golangci-lint- Documentation: https://os-migrate.github.io/documentation/
- Issues: https://github.com/os-migrate/vmware-migration-kit/issues
- Demo: https://www.youtube.com/watch?v=XnEQ8WVGW64
- Architecture Diagrams:
doc/*.svg