Skip to main content

Google Cloud Migration Center — Lab Guide

📖 Configuration Guide

This lab guide walks you through discovering, analysing, and planning a cloud migration using Google Cloud Migration Center and the Migration Center module. You will connect to a pre-configured Windows VM running the MC Discovery Client (MCDCv6), register it against the Migration Center project that Terraform has already initialised, configure SSH-based discovery of Debian Linux target VMs, review the discovered inventory alongside AWS EC2 data, and generate and explore a TCO cost optimisation report.

The module automates every infrastructure and Migration Center configuration step. You complete the Google OAuth login in MCDCv6, run the discovery scan, and then generate a report from the console once the asset inventory is fully populated — ensuring the report reflects real data.


Table of Contents

  1. Overview
  2. Architecture
  3. Prerequisites
  4. Lab Setup
  5. Exercise 1 — Connect to the Windows VM via RDP
  6. Exercise 2 — Launch MCDCv6 and Complete Google Login
  7. Exercise 3 — Configure SSH Credentials for Linux VM Discovery
  8. Exercise 4 — Run the Discovery Scan and Review Linux Assets
  9. Exercise 5 — Review AWS Sample Data and All Assets
  10. Exercise 6 — Explore Asset Groups
  11. Exercise 7 — Explore Migration Preferences
  12. Exercise 8 — View the TCO Report
  13. Cleanup
  14. Reference

1. Overview

What Is Google Cloud Migration Center?

Google Cloud Migration Center is Google Cloud's free, unified platform for discovering, assessing, and planning the migration of workloads from on-premises data centres or other cloud environments. It aggregates data from multiple discovery sources — agent-based scans (via the MC Discovery Client), agentless network discovery, VMware vCenter integration, and manual CSV imports from AWS, Azure, or on-premises tools — and produces inventory reports, dependency maps, and total cost of ownership (TCO) projections.

Regional commitment: When Migration Center is first initialised for a project (via the initializeConfig API call or from the Cloud Console), you select a GCP region where all assessment data will be stored. This choice is permanent — you cannot change the region without creating a new project. The module locks in the region specified in the region variable (default us-central1).

Use Cases

Use CaseDescription
Data centre inventoryAutomatically discover and catalogue all VMs across heterogeneous environments using agent-based scanning, agentless methods, VMware vCenter integration, or CSV import
Cloud cost modellingGenerate TCO projections comparing current infrastructure costs against GCP machine types, commitment plans, and licensing models
Right-sizingIdentify over-provisioned VMs and recommend appropriately sized GCP machine types based on actual utilisation data collected over time
Multi-cloud assessmentImport AWS (EC2), Azure, or on-premises inventory (RVTools, manual CSV) into a single unified inventory alongside live-scanned data
Dependency analysisMap network connections between VMs to identify inter-VM dependencies, enabling informed migration wave sequencing
Migration wave planningGroup assets into logical waves based on dependency analysis, OS type, business unit, or criticality, then model cost scenarios per wave
Fitness assessmentEvaluate workloads for GCP compatibility and identify any re-platforming considerations before committing to migration

What This Lab Automates

StepAutomated by TerraformManual Step Required
Initialise Migration Center serviceYes — initializeConfig REST API callNone
Register MCDCv6 discovery sourceYes — REST API sourcesNone
Import AWS EC2 inventoryConditional — runs only when aws_access_key_id is provided; queries real EC2 instancesIf no credentials: manually import the pre-staged sample CSV zip in Exercise 5
Create asset groupsNoYou create these in Exercise 6
Create preference setsNoYou create these in Exercise 7
Generate TCO reportNo — requires fully populated inventoryYou generate this in Exercise 8
Install MCDCv6 on Windows VMYes — PowerShell startup scriptNone
Pre-stage AWS sample CSV zipYes — startup script downloads to Downloads\vm-aws-import-files\None
Google OAuth login in MCDCv6No — requires browser-based loginYou complete this in Exercise 2
Configure SSH credential in MCDCv6NoYou complete this in Exercise 3
Configure IP scan rangeNoYou complete this in Exercise 4

2. Architecture

┌──────────────────────────────────────────────────────────────────────────────┐
│ Google Cloud Project │
│ │
│ ┌────────────────────────────────────────────────────────────────────────┐ │
│ │ VPC Network (auto-mode, migcenter-{id}-vpc) │ │
│ │ │ │
│ │ ┌──────────────────────────────┐ ┌──────────────────────────────┐ │ │
│ │ │ Windows Server 2022 VM │ │ Debian 12 Linux VMs │ │ │
│ │ │ migcenter-{id}-winvm01 │ │ migcenter-{id}-linvm-1 │ │ │
│ │ │ e2-medium │ │ migcenter-{id}-linvm-2 │ │ │
│ │ │ • MCDCv6 pre-installed │ │ migcenter-{id}-linvm-3 │ │ │
│ │ │ • Chrome pre-installed │ │ e2-medium × 3 │ │ │
│ │ │ • RDP enabled (port 3389) │ │ • migrationcenter user │ │ │
│ │ │ • User: migrationcenter │ │ • SSH key auth enabled │ │ │
│ │ └──────────────────────────────┘ └──────────────────────────────┘ │ │
│ │ │ ↑ │ │
│ │ MCDCv6 SSH scan discovers via │ │
│ │ └────────────────────────────┘ │ │
│ │ │ │
│ │ Firewall: allow-rdp, allow-ssh, allow-icmp, allow-internal, http │ │
│ └────────────────────────────────────────────────────────────────────────┘ │
│ │
│ ┌────────────────────────────────────────────────────────────────────────┐ │
│ │ Cloud Storage (migcenter-{id}-mc-keys) │ │
│ │ • lab-ssh-key.pem (RSA 4096 private key for Linux VM SSH access) │ │
│ └────────────────────────────────────────────────────────────────────────┘ │
│ │
│ ┌────────────────────────────────────────────────────────────────────────┐ │
│ │ Migration Center (migrationcenter.googleapis.com) │ │
│ │ │ │
│ │ Discovery Source: migcenter-{id}-mc-source (SOURCE_TYPE_DISCOVERY_CLIENT) │ │
│ │ ↓ MCDCv6 scan results (after manual OAuth + scan) │ │
│ │ ↓ EC2 import (real AWS data, if credentials given) │ │
│ │ Asset Inventory: Debian Linux VMs + AWS VMs (real or sample data) │ │
│ │ │ │
│ │ Groups, Preferences, Reports: ← created as hands-on lab exercises │ │
│ └────────────────────────────────────────────────────────────────────────┘ │
│ │
└──────────────────────────────────────────────────────────────────────────────┘

Module variable wiring:

Migration_Center
region = "us-central1" → All resources in this region
zone = "us-central1-a" → Compute Engine zone
linux_vm_count = 3 → 3 Debian Linux scan targets
create_windows_vm = true → Windows MCDCv6 host
initialize_migration_center = true → Initialise MC service + register discovery source
aws_access_key_id = "<key>" → (Optional) bootstrap creds → scoped IAM user + EC2 import
mc_discovery_client_name = "mc-discovery-client" → Source name entered in MCDCv6 during login

3. Prerequisites

Required Tools

ToolMinimum VersionInstall
gcloud CLI480.0.0Install guide
RDP clientAnyWindows Remote Desktop, Microsoft Remote Desktop (macOS), Remmina (Linux)
Web browserAnyFor Migration Center Cloud Console
curl / jqAnySystem package manager

GCP Permissions

roles/owner  (or)
roles/migrationcenter.admin
roles/compute.admin
roles/storage.admin
roles/iam.serviceAccountAdmin

GCP APIs Required

The module enables these APIs automatically:

migrationcenter.googleapis.com
compute.googleapis.com
storage.googleapis.com
cloudresourcemanager.googleapis.com
iam.googleapis.com
iamcredentials.googleapis.com

Environment Variables

Set these in your terminal before running lab commands:

export PROJECT_ID="your-gcp-project-id"
export REGION="us-central1"
export ZONE="us-central1-a"

gcloud config set project "${PROJECT_ID}"
gcloud config set compute/region "${REGION}"
gcloud config set compute/zone "${ZONE}"

After deployment, set these from the Terraform outputs:

export WINDOWS_VM=$(gcloud compute instances list \
--filter="name~migcenter AND name~winvm" \
--format="value(name)" \
--project="${PROJECT_ID}")

export SSH_KEY_BUCKET=$(gcloud storage buckets list \
--filter="name~migcenter AND name~mc-keys" \
--format="value(name)" \
--project="${PROJECT_ID}")

4. Lab Setup

4.1 Deploy via RAD UI

Deploy the Migration Center module via the RAD UI. In the variable form, set:

VariableValueNotes
project_idyour-gcp-project-idRequired
regionus-central1GCP region for all resources
zoneus-central1-aGCP zone for Compute Engine VMs
linux_vm_count3Number of Debian Linux scan targets
initialize_migration_centertrueAuto-initialise MC service and register discovery source
aws_access_key_id(optional)Bootstrap AWS credentials — module creates scoped IAM user and imports EC2 inventory
aws_secret_access_key(optional)AWS Secret Key corresponding to the Access Key ID
mc_discovery_client_namemc-discovery-clientSource name to enter in MCDCv6

Click Deploy and wait for provisioning to complete.

Note: Terraform provisioning takes approximately 5–8 minutes. The Windows VM startup script (MCDCv6 install + Chrome download) runs in the background after the VM boots and takes an additional 3–5 minutes. Wait for the startup script to finish before starting Exercise 2.

What this provisions: A VPC with firewall rules, a Windows Server 2022 VM with MCDCv6 pre-installed, three Debian 12 Linux VMs, a Cloud Storage bucket containing an SSH private key, and a fully configured Migration Center environment including a registered discovery source, AWS EC2 inventory import (if credentials provided), pre-created asset groups, and migration preference sets. TCO report generation is a manual step performed after discovery.

4.2 Retrieve Deployment Outputs

After deployment, note the Terraform outputs from the RAD UI, or retrieve them via gcloud:

Windows VM external IP:

gcloud compute instances list \
--filter="name~migcenter AND name~winvm" \
--project="${PROJECT_ID}" \
--format="table(name, zone, status, networkInterfaces[0].accessConfigs[0].natIP)"

Linux VM internal IPs:

gcloud compute instances list \
--filter="name~migcenter AND name~linvm" \
--project="${PROJECT_ID}" \
--format="table(name, zone, networkInterfaces[0].networkIP)"

SSH key bucket name:

gcloud storage buckets list \
--filter="name~migcenter" \
--project="${PROJECT_ID}" \
--format="value(name)"

REST API — list all module Compute instances:

curl -s \
"https://compute.googleapis.com/compute/v1/projects/${PROJECT_ID}/aggregated/instances" \
-H "Authorization: Bearer $(gcloud auth print-access-token)" \
| jq '.items | to_entries[] | .value.instances[]? | select(.name | test("migcenter")) | {name, status, internalIP: .networkInterfaces[0].networkIP, externalIP: .networkInterfaces[0].accessConfigs[0]?.natIP}'

Exercise 1 — Connect to the Windows VM via RDP

Objective

Connect to the Windows Server 2022 VM via RDP using the pre-created migrationcenter lab user, and verify that MCDCv6 and Chrome are installed and ready.

Step 1.1 — Get the Windows VM External IP

gcloud:

gcloud compute instances describe "${WINDOWS_VM}" \
--zone="${ZONE}" \
--project="${PROJECT_ID}" \
--format="value(networkInterfaces[0].accessConfigs[0].natIP)"

REST API:

curl -s \
"https://compute.googleapis.com/compute/v1/projects/${PROJECT_ID}/zones/${ZONE}/instances/${WINDOWS_VM}" \
-H "Authorization: Bearer $(gcloud auth print-access-token)" \
| jq '{name, status, externalIP: .networkInterfaces[0].accessConfigs[0].natIP}'

Step 1.2 — Connect via RDP

Open your RDP client and connect with these credentials:

Host:     <windows-vm-external-ip>:3389
Username: migrationcenter
Password: m1grat10nc#nt#r

Tip: On macOS use Microsoft Remote Desktop. On Linux use Remmina or FreeRDP:

xfreerdp /u:migrationcenter /p:'m1grat10nc#nt#r' /v:&lt;external-ip>:3389 /dynamic-resolution

If RDP fails to connect: The Windows startup script may still be running. Wait 3–5 minutes after the Terraform deployment completes and try again. You can check startup progress from your local machine:

gcloud compute instances get-serial-port-output "${WINDOWS_VM}" \
--zone="${ZONE}" --project="${PROJECT_ID}" | tail -20

Step 1.3 — Verify MCDCv6 Is Installed

Once inside the Windows VM:

  1. Click Start and look for Migration Center Discovery Client in the program list, or check C:\Program Files\Google\MCDCv6\
  2. Verify that Google Chrome is installed (required for the OAuth login flow in Exercise 2)
  3. Open File Explorer → navigate to C:\Users\migrationcenter\Downloads\ to confirm the vm-aws-import-files folder is present (pre-staged by the startup script)

Step 1.4 — Test Connectivity to Linux VMs

From the Windows VM, open PowerShell and test SSH port reachability to the Linux VMs. Use the internal IPs from the linux_vm_internal_ips Terraform output:

# Replace with actual IP from Terraform output linux_vm_internal_ips
Test-NetConnection -ComputerName 10.128.0.2 -Port 22
Test-NetConnection -ComputerName 10.128.0.3 -Port 22
Test-NetConnection -ComputerName 10.128.0.4 -Port 22

Expected: TcpTestSucceeded: True for each VM — they are on the same VPC and the firewall allows internal traffic including SSH.


Exercise 2 — Launch MCDCv6 and Complete Google Login

Objective

Launch the MC Discovery Client, authenticate with a Google account, and register this Discovery Client against the Migration Center source that Terraform pre-created.

Step 2.1 — Launch MCDCv6

On the Windows VM:

  1. Open Start → search for and launch Migration Center Discovery Client
  2. MCDCv6 opens using Google Chrome (the application uses a browser-based UI)

Step 2.2 — Sign In with Google

On the MCDCv6 welcome screen:

  1. Click Sign in with Google
  2. Chrome opens a Google OAuth consent screen
  3. Sign in with a Google account that has Migration Center Admin access to the lab project
  4. Grant the requested permissions and return to the MCDCv6 window

Note: This is the one step that cannot be automated — the MCDCv6 OAuth flow requires an interactive browser session to authenticate the discovery client against your GCP project. All other Migration Center setup steps are handled by Terraform.

Step 2.3 — Select the GCP Project

After signing in, MCDCv6 asks you to choose a GCP project:

  1. Select the lab project from the dropdown (matching the project_id in your Terraform deployment)
  2. Click Next

Step 2.4 — Enter the Discovery Client Name

MCDCv6 asks you to enter a discovery client name — this name must exactly match the source ID that Terraform already registered in Migration Center:

  1. In the Add a discovery client name field, enter the value from the Terraform output mc_discovery_client_name. The default value is: mc-discovery-client
  2. Click Next

Important: The name must match exactly (case-sensitive). Terraform created a source with this name in Migration Center. If the names don't match, MCDCv6 creates a new unregistered source and scan results will not appear in the expected source.

Step 2.5 — Verify the Dashboard Appears

After completing login, MCDCv6 shows its main dashboard. Confirm:

  • The project name shown matches your lab project
  • The discovery client name matches mc-discovery-client
  • The connection status shows Connected or Ready

Exercise 3 — Configure SSH Credentials for Linux VM Discovery

Objective

Download the SSH private key from Cloud Storage, add it to MCDCv6 as a named credential, and prepare the discovery client to authenticate against the Linux target VMs.

Step 3.1 — Download the SSH Private Key from GCS

The SSH private key was generated by Terraform using the tls_private_key resource and stored in Cloud Storage. Download it from inside the Windows VM using Chrome or PowerShell.

Option A — Cloud Console (recommended from the Windows VM):

Open Chrome and navigate to:

https://console.cloud.google.com/storage/browser/<bucket-name-from-terraform-output>

Click lab-ssh-key.pem → click Download. The file saves to C:\Users\migrationcenter\Downloads\.

Option B — PowerShell (from the Windows VM):

# Authenticate to GCP (use your lab Google account)
gcloud auth login

# Download the key (replace BUCKET_NAME with the ssh_key_bucket_name output)
$bucketName = "BUCKET_NAME"
gsutil cp "gs://$bucketName/lab-ssh-key.pem" "$env:USERPROFILE\Downloads\lab-ssh-key.pem"

gcloud (from your local machine, to inspect the bucket):

gcloud storage ls "gs://${SSH_KEY_BUCKET}/" --project="${PROJECT_ID}"

REST API — list objects in the SSH key bucket:

curl -s \
"https://storage.googleapis.com/storage/v1/b/${SSH_KEY_BUCKET}/o" \
-H "Authorization: Bearer $(gcloud auth print-access-token)" \
| jq '.items[] | {name, selfLink, size}'

Step 3.2 — Add the SSH Key as a Credential in MCDCv6

In the MCDCv6 dashboard:

  1. Click Credentials in the left navigation pane
  2. Click Add Credential
  3. Configure the credential:
    • Credential type: SSH private key
    • Credential name: Lab-key
    • Username for this key: migrationcenter ← from Terraform output ssh_key_user
    • Private key file: click Browse and select lab-ssh-key.pem from Downloads
  4. Click Save

Step 3.3 — Verify the Credential Is Saved

Back on the Credentials page, confirm Lab-key appears in the list. The status may show Not tested until a scan is run — this is expected.


Exercise 4 — Run the Discovery Scan and Review Linux Assets

Objective

Configure MCDCv6 with the Linux VM subnet scan range, run a discovery collection, and verify that the Linux VMs appear in the Migration Center asset inventory.

Step 4.1 — Determine the IP Scan Range

Use the Linux VM internal IPs from the Terraform output linux_vm_internal_ips to determine the scan range. The IPs are consecutive in the auto-mode VPC subnet.

From your local machine:

gcloud compute instances list \
--filter="name~migcenter AND name~linvm" \
--project="${PROJECT_ID}" \
--format="value(networkInterfaces[0].networkIP)" \
| sort

For example, if the output is:

10.128.0.2
10.128.0.3
10.128.0.4

Use scan range:

  • Start IP: 10.128.0.1
  • End IP: 10.128.0.10

REST API — list Linux VM IPs:

curl -s \
"https://compute.googleapis.com/compute/v1/projects/${PROJECT_ID}/zones/${ZONE}/instances" \
-H "Authorization: Bearer $(gcloud auth print-access-token)" \
| jq '.items[] | select(.name | test("linvm")) | {name, ip: .networkInterfaces[0].networkIP}'

Step 4.2 — Configure a New Collection Source

In MCDCv6:

  1. Click Data Sources in the left navigation
  2. Click Add Data Source
  3. Select Linux/Windows as the source type
  4. Click Next

Step 4.3 — Configure the IP Scan Range and Credential

In the data source configuration form:

  1. Enter the Start IP and End IP for the scan range (from Step 4.1)
  2. Leave port settings at default (SSH port 22)
  3. From the Credentials dropdown, select Lab-key
  4. Click Save

Step 4.4 — Start the Discovery Collection

  1. On the Data Sources page, click Collect or Run Now on your newly created source
  2. Watch the Collection Status — it transitions from PendingRunningCompleted
  3. Scans typically complete within 2–5 minutes for 3 VMs

If a VM shows "Access Denied": Confirm the migrationcenter user exists on the Linux VM and the Lab-key credential uses exactly the username migrationcenter. Check the Troubleshooting section for further steps.

Step 4.5 — Verify Assets in Migration Center

After the collection completes, open the Migration Center Console and verify the Linux VMs appear:

Cloud Console:

https://console.cloud.google.com/migration/center?project=<PROJECT_ID>

Click AssetsVirtual Machines → look for the three migcenter-*-linvm-* VMs.

REST API — list all assets:

curl -s \
"https://migrationcenter.googleapis.com/v1/projects/${PROJECT_ID}/locations/${REGION}/assets" \
-H "Authorization: Bearer $(gcloud auth print-access-token)" \
| jq '.assets[] | {name, machineName: .machineDetails.machineName, os: .machineDetails.guestOsDetails.osName, source: .sources[0]}'

Click on one Linux VM to explore its full detail profile — OS version, kernel, CPU/memory capacity, installed packages, running processes, and open network ports collected by MCDCv6.

Performance data and right-sizing accuracy: The single scan you just ran captures a point-in-time snapshot of CPU and memory utilisation. In a real assessment engagement, MCDCv6 is typically left running for 2–4 weeks with scheduled recurring scans to build a utilisation history. Migration Center uses this history to produce statistically-grounded right-sizing recommendations — peak utilisation from a single scan often understates actual workload demand, leading to under-provisioned GCP machine type suggestions. For the purposes of this lab, a single scan is sufficient to populate the inventory and generate a TCO report.

Step 4.6 — Explore Network Connections (Dependency Mapping)

MCDCv6 also records the active network connections on each scanned VM — which ports are listening and which remote IPs have established connections. This data underpins Migration Center's dependency analysis capability, which identifies inter-VM communication patterns for migration wave planning.

In the asset detail view, click the Open ports tab to see the listening TCP/UDP ports and the process bound to each. In a multi-tier application environment, this view reveals which VMs are fronting web traffic, which are database servers, and which VMs depend on each other — critical information for grouping assets into coherent migration waves rather than migrating them one by one and breaking application connectivity.


Exercise 5 — Review AWS Data and All Assets

Objective

Understand the AWS inventory data in Migration Center alongside the live Linux VM scan results. Depending on whether AWS credentials were provided at deployment time, this data arrives via automatic import or manual upload.

Step 5.1 — Check Whether the AWS Import Job Ran Automatically

If aws_access_key_id was provided during deployment, Terraform queried your AWS EC2 inventory and submitted an import job to Migration Center.

Cloud Console: Navigate to Migration Center → Data Sources and look for an import job. The status should show Completed (or Completed with warnings if any optional fields were absent from the generated CSV).

REST API — list import jobs:

curl -s \
"https://migrationcenter.googleapis.com/v1/projects/${PROJECT_ID}/locations/${REGION}/importJobs" \
-H "Authorization: Bearer $(gcloud auth print-access-token)" \
| jq '.importJobs[] | {displayName, state, createTime}'

If no import jobs appear, proceed to Step 5.1a to manually import the pre-staged sample data.

Step 5.1a — Manually Import Sample CSV Data (if no AWS credentials were provided)

The Windows VM startup script pre-staged a sample AWS CSV export to C:\Users\migrationcenter\Downloads\vm-aws-import-files\. This folder contains four CSV files (vmInfo.csv, diskInfo.csv, tagInfo.csv, perfInfo.csv) representing a simulated AWS VM inventory that you can import manually.

From the Windows VM — Cloud Console:

  1. Open Chrome and navigate to the Migration Center console for your project
  2. Click Data Sources → Add source
  3. Select Uploads
  4. Give the source a name (e.g. aws-sample-import)
  5. Under File format, select AWS VM export
  6. Click Upload files and select all CSV files from C:\Users\migrationcenter\Downloads\vm-aws-import-files\
  7. Click Import and wait for the job to complete

REST API — alternative approach via the Windows VM PowerShell or your local machine:

TOKEN=$(gcloud auth print-access-token)

# Create a new import job
IMPORT_JOB_ID="manual-aws-import-$(date +%s)"
curl -s -X POST \
"https://migrationcenter.googleapis.com/v1/projects/${PROJECT_ID}/locations/${REGION}/importJobs?importJobId=${IMPORT_JOB_ID}" \
-H "Authorization: Bearer ${TOKEN}" \
-H "Content-Type: application/json" \
-d "{\"displayName\": \"aws-sample-import\", \"assetSource\": \"projects/${PROJECT_ID}/locations/${REGION}/sources/${MC_SOURCE_ID}\"}" \
| jq '{name, state}'

# Upload each CSV file
for FILE in vmInfo diskInfo tagInfo perfInfo; do
curl -s -X POST \
"https://migrationcenter.googleapis.com/v1/projects/${PROJECT_ID}/locations/${REGION}/importJobs/${IMPORT_JOB_ID}/importDataFiles?importDataFileId=${FILE}" \
-H "Authorization: Bearer ${TOKEN}" \
-H "Content-Type: text/csv" \
--data-binary "@${FILE}.csv" \
| jq '{name, state}'
done

# Validate and run
curl -s -X POST \
"https://migrationcenter.googleapis.com/v1/projects/${PROJECT_ID}/locations/${REGION}/importJobs/${IMPORT_JOB_ID}:validate" \
-H "Authorization: Bearer ${TOKEN}" -H "Content-Type: application/json" -d '{}'
sleep 30
curl -s -X POST \
"https://migrationcenter.googleapis.com/v1/projects/${PROJECT_ID}/locations/${REGION}/importJobs/${IMPORT_JOB_ID}:run" \
-H "Authorization: Bearer ${TOKEN}" -H "Content-Type: application/json" -d '{}'

Step 5.2 — Explore the Full Asset Inventory

In Migration Center → AssetsVirtual Machines. You should now see:

  • 3 Debian Linux VMs — discovered by MCDCv6 scan (your lab VMs, rich with OS and process data)
  • AWS VMs — from the CSV import (real EC2 instances or the sample dataset), with hardware profile and tag data but no guest-OS-level detail (no package lists, no running processes)

This contrast illustrates a key Migration Center concept: depth of inventory data varies by discovery method. Agent-based scanning (MCDCv6) provides comprehensive guest OS data including installed software and open ports; CSV import provides hardware inventory and tags but no live OS insight.

Use the search and filter controls to explore:

  • Filter by OS type: Compare the Windows/Linux AWS VMs against the Debian scan targets
  • Filter by source: Distinguish MCDCv6 scan results from the CSV import source
  • Sort by CPU or memory: Identify the highest-resource VMs in the inventory

Step 5.3 — View an Individual Asset's Detail

Click on any asset to open its detail view and explore the available tabs:

TabWhat You'll See
AttributesCPU cores, RAM, total disk capacity, OS version, kernel
Installed softwareApplication list collected from the guest OS
Open portsActive network ports discovered during the scan
PerformanceCPU and memory utilisation history (if performance data was collected)

REST API — get details for a specific asset:

# List assets and extract the first one's resource name
ASSET_NAME=$(curl -s \
"https://migrationcenter.googleapis.com/v1/projects/${PROJECT_ID}/locations/${REGION}/assets?pageSize=1" \
-H "Authorization: Bearer $(gcloud auth print-access-token)" \
| jq -r '.assets[0].name')

# Fetch the full asset detail
curl -s \
"https://migrationcenter.googleapis.com/v1/${ASSET_NAME}" \
-H "Authorization: Bearer $(gcloud auth print-access-token)" \
| jq '{name, machineDetails, performanceSamples: (.performanceSamples | length)}'

Exercise 6 — Create Asset Groups

Objective

Create three asset groups that organise the discovered inventory into logical sets, then add assets to each group. Groups are required inputs when generating a TCO report in Exercise 8.

Set your deployment ID in the shell before starting:

export DEPLOYMENT_ID="<your-deployment-id>"   # from Terraform output deployment_id

Step 6.1 — Create Groups via REST API

TOKEN=$(gcloud auth print-access-token)

create_group() {
local GROUP_ID="$1"
local DISPLAY_NAME="$2"
curl -s -X POST \
"https://migrationcenter.googleapis.com/v1/projects/${PROJECT_ID}/locations/${REGION}/groups?groupId=${GROUP_ID}" \
-H "Authorization: Bearer ${TOKEN}" \
-H "Content-Type: application/json" \
-d "{\"displayName\": \"${DISPLAY_NAME}\"}" \
| jq '{name, displayName}'
}

create_group "migcenter-${DEPLOYMENT_ID}-all-assets" "All Assets"
create_group "migcenter-${DEPLOYMENT_ID}-windows-only" "windows-only"
create_group "migcenter-${DEPLOYMENT_ID}-linux-only" "linux-only"

Cloud Console alternative: Navigate to Migration Center → GroupsCreate group, enter the display name, and click Create.

Step 6.2 — Verify Groups Were Created

curl -s \
"https://migrationcenter.googleapis.com/v1/projects/${PROJECT_ID}/locations/${REGION}/groups" \
-H "Authorization: Bearer $(gcloud auth print-access-token)" \
| jq '.groups[] | {displayName, name: (.name | split("/") | last)}'

You should see three groups: All Assets, windows-only, linux-only.

Step 6.3 — Add Assets to Groups

In Migration Center → Assets, select one or more VMs by checking their checkboxes, then click Add to group and select the appropriate group. Repeat for each group.

REST API — add an asset to a group:

TOKEN=$(gcloud auth print-access-token)
GROUP_ID="migcenter-${DEPLOYMENT_ID}-all-assets"
ASSET_RESOURCE="projects/${PROJECT_ID}/locations/${REGION}/assets/<asset-id>"

curl -s -X POST \
"https://migrationcenter.googleapis.com/v1/projects/${PROJECT_ID}/locations/${REGION}/groups/${GROUP_ID}:addAssets" \
-H "Authorization: Bearer ${TOKEN}" \
-H "Content-Type: application/json" \
-d "{\"assets\": [{\"asset\": \"${ASSET_RESOURCE}\"}]}" \
| jq '{done}'

REST API — list assets in a group:

curl -s \
"https://migrationcenter.googleapis.com/v1/projects/${PROJECT_ID}/locations/${REGION}/groups/migcenter-${DEPLOYMENT_ID}-linux-only/assets" \
-H "Authorization: Bearer $(gcloud auth print-access-token)" \
| jq '.assets[].name'

Exercise 7 — Create Migration Preference Sets

Objective

Create two migration preference sets that model different cost optimisation strategies. These preference sets are paired with asset groups when generating the TCO report in Exercise 8.

Step 7.1 — Understand the Two Strategies

Preference SetMachine SeriesSizing StrategyCommitmentBest For
aggressive-optimization-3-year-commitN2, N2DAggressive — shrinks to actual observed peak utilisation3-year CUD (~57% discount on N2)Stable, predictable workloads where right-sizing risk is low
moderate-optimization-1-year-commitC2, C2D + SSDModerate — keeps 20–30% headroom above observed peak1-year CUDVariable or spiky workloads where over-sizing avoidance is critical

Why two strategies? Right-sizing based on a short observation window risks under-provisioning production workloads. Presenting both an aggressive and a moderate estimate in a business case gives stakeholders a cost range: the aggressive figure shows the theoretical minimum if all VMs are perfectly right-sized; the moderate figure is a safer planning number. In practice, most migrations land somewhere between the two as teams gain confidence in workload characterisation.

Machine series choice: N2/N2D are cost-optimised general-purpose machines suited to most workloads. C2/C2D are compute-optimised with higher per-core performance but at a higher base price — they are more appropriate for CPU-intensive workloads. The SSD disk type in the moderate preset adds cost but is realistic for database and I/O-sensitive workloads.

Step 7.2 — Create Preference Sets via REST API

TOKEN=$(gcloud auth print-access-token)

echo "Creating aggressive-optimization-3-year-commit..."
curl -s -X POST \
"https://migrationcenter.googleapis.com/v1/projects/${PROJECT_ID}/locations/${REGION}/preferenceSets?preferenceSetId=migcenter-${DEPLOYMENT_ID}-aggressive-3yr" \
-H "Authorization: Bearer ${TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"displayName": "aggressive-optimization-3-year-commit",
"virtualMachinePreferences": {
"targetProduct": "COMPUTE_MIGRATION_TARGET_PRODUCT_COMPUTE_ENGINE",
"computeEnginePreferences": {
"machinePreferences": {
"allowedMachineSeries": [{"code": "n2"}, {"code": "n2d"}]
},
"licenseType": "LICENSE_TYPE_DEFAULT"
},
"sizingOptimizationStrategy": "SIZING_OPTIMIZATION_STRATEGY_AGGRESSIVE",
"commitmentPlan": "COMMITMENT_PLAN_THREE_YEAR"
}
}' | jq '{name, displayName}'

echo "Creating moderate-optimization-1-year-commit..."
curl -s -X POST \
"https://migrationcenter.googleapis.com/v1/projects/${PROJECT_ID}/locations/${REGION}/preferenceSets?preferenceSetId=migcenter-${DEPLOYMENT_ID}-moderate-1yr" \
-H "Authorization: Bearer ${TOKEN}" \
-H "Content-Type: application/json" \
-d '{
"displayName": "moderate-optimization-1-year-commit",
"virtualMachinePreferences": {
"targetProduct": "COMPUTE_MIGRATION_TARGET_PRODUCT_COMPUTE_ENGINE",
"computeEnginePreferences": {
"machinePreferences": {
"allowedMachineSeries": [{"code": "c2"}, {"code": "c2d"}]
},
"licenseType": "LICENSE_TYPE_DEFAULT",
"persistentDiskType": "PERSISTENT_DISK_TYPE_SSD"
},
"sizingOptimizationStrategy": "SIZING_OPTIMIZATION_STRATEGY_MODERATE",
"commitmentPlan": "COMMITMENT_PLAN_ONE_YEAR"
}
}' | jq '{name, displayName}'

Cloud Console alternative: Navigate to Migration Center → Migration preferencesCreate preference set and fill in the machine series, sizing strategy, and commitment plan fields.

Step 7.3 — Verify Preference Sets

curl -s \
"https://migrationcenter.googleapis.com/v1/projects/${PROJECT_ID}/locations/${REGION}/preferenceSets" \
-H "Authorization: Bearer $(gcloud auth print-access-token)" \
| jq '.preferenceSets[] | {
displayName,
sizingStrategy: .virtualMachinePreferences.sizingOptimizationStrategy,
commitmentPlan: .virtualMachinePreferences.commitmentPlan
}'

Exercise 8 — Generate and View the TCO Report

Objective

Create a report configuration, trigger TCO report generation, and explore how Migration Center projects GCP costs for each asset group under both preference scenarios. This exercise is intentionally performed after the MCDCv6 scan so the report reflects the full asset inventory.

Why now? Generating a report at deploy time would produce an incomplete snapshot because MCDCv6 discovery data arrives only after the manual OAuth login and scan in Exercises 2–4. The asset groups and preference sets were pre-created by Terraform — you only need to trigger the report itself.

Step 8.1 — Create a Report Configuration

A report configuration defines which groups and preference sets to compare. Create one via the Cloud Console or the REST API.

Cloud Console:

  1. Navigate to Migration Center → Reports
  2. Click Create report
  3. Give it a display name (e.g. lab-tco-report)
  4. Under Groups and preferences, add the following assignments:
GroupPreference set
All Assets (migcenter-<id>-all-assets)aggressive-3yr (migcenter-<id>-aggressive-3yr)
windows-only (migcenter-<id>-windows-only)moderate-1yr (migcenter-<id>-moderate-1yr)
linux-only (migcenter-<id>-linux-only)moderate-1yr (migcenter-<id>-moderate-1yr)
  1. Click Create — Migration Center generates the report (allow up to 5 minutes)

REST API — create report config and trigger report:

DEPLOYMENT_ID="<your-deployment-id>"   # from Terraform output deployment_id

REPORT_CONFIG_ID="migcenter-${DEPLOYMENT_ID}-report-config"

# Create the report configuration
curl -s -X POST \
"https://migrationcenter.googleapis.com/v1/projects/${PROJECT_ID}/locations/${REGION}/reportConfigs?reportConfigId=${REPORT_CONFIG_ID}" \
-H "Authorization: Bearer $(gcloud auth print-access-token)" \
-H "Content-Type: application/json" \
-d "{
\"displayName\": \"lab-report-config\",
\"groupPreferencesetAssignments\": [
{
\"group\": \"projects/${PROJECT_ID}/locations/${REGION}/groups/migcenter-${DEPLOYMENT_ID}-all-assets\",
\"preferenceSet\": \"projects/${PROJECT_ID}/locations/${REGION}/preferenceSets/migcenter-${DEPLOYMENT_ID}-aggressive-3yr\"
},
{
\"group\": \"projects/${PROJECT_ID}/locations/${REGION}/groups/migcenter-${DEPLOYMENT_ID}-windows-only\",
\"preferenceSet\": \"projects/${PROJECT_ID}/locations/${REGION}/preferenceSets/migcenter-${DEPLOYMENT_ID}-moderate-1yr\"
},
{
\"group\": \"projects/${PROJECT_ID}/locations/${REGION}/groups/migcenter-${DEPLOYMENT_ID}-linux-only\",
\"preferenceSet\": \"projects/${PROJECT_ID}/locations/${REGION}/preferenceSets/migcenter-${DEPLOYMENT_ID}-moderate-1yr\"
}
]
}" | jq '{name, displayName}'
# Generate a TCO report from the config
curl -s -X POST \
"https://migrationcenter.googleapis.com/v1/projects/${PROJECT_ID}/locations/${REGION}/reportConfigs/${REPORT_CONFIG_ID}/reports?reportId=migcenter-${DEPLOYMENT_ID}-tco" \
-H "Authorization: Bearer $(gcloud auth print-access-token)" \
-H "Content-Type: application/json" \
-d '{
"displayName": "lab-tco-report",
"type": "TOTAL_COST_OF_OWNERSHIP"
}' | jq '{name, displayName, state}'

Step 8.2 — Wait for the Report to Complete

Report generation typically takes 2–5 minutes. Poll the status:

curl -s \
"https://migrationcenter.googleapis.com/v1/projects/${PROJECT_ID}/locations/${REGION}/reportConfigs/${REPORT_CONFIG_ID}/reports" \
-H "Authorization: Bearer $(gcloud auth print-access-token)" \
| jq '.reports[] | {displayName, state, createTime}'

Wait until state shows SUCCEEDED.

Step 8.3 — Explore the Report Summary

Open Migration Center → Reports in the Cloud Console and click on lab-tco-report.

On the overview page, review:

  1. Total estimated monthly GCP cost — combined projection across all groups
  2. Cost breakdown by group — All Assets vs. windows-only vs. linux-only sections
  3. Preference set comparison — side-by-side aggressive-3yr vs. moderate-1yr cost estimates

Step 8.4 — Explore the Detailed Report

Click View report to open the detailed breakdown:

TabWhat You'll See
AssetsPer-VM cost estimates with recommended machine types, grouped by the asset group each VM belongs to
MachinesRecommended GCP machine type and vCPU/RAM for each VM based on the preference set's sizing strategy
StorageEstimated persistent disk costs based on discovered disk capacity and the preference set's disk type
LicensesWindows licence cost modelling — compares Google-provided licences against BYOL (Bring Your Own Licence)

Key observations to make:

  • Compare the per-VM machine type recommendations between the aggressive and moderate scenarios. Notice how the aggressive strategy maps VMs to smaller machine types (lower vCPU/RAM) based on observed peak utilisation, while the moderate strategy suggests larger types with headroom.
  • Look at the Licenses tab for any Windows VMs. Migration Center distinguishes between Google-provided Windows licences (included in the VM price) and BYOL — for enterprises with existing Microsoft volume agreements, BYOL can significantly reduce the per-VM cost estimate.
  • Notice that VMs from the CSV import have less precise recommendations than MCDCv6-scanned VMs, because the import data includes disk and hardware specs but no utilisation history.

Step 8.5 — Generate a Second Report Variation (Optional)

Repeat the generation step with a different report ID to compare results after further discovery data arrives:

curl -s -X POST \
"https://migrationcenter.googleapis.com/v1/projects/${PROJECT_ID}/locations/${REGION}/reportConfigs/${REPORT_CONFIG_ID}/reports?reportId=migcenter-${DEPLOYMENT_ID}-tco-v2" \
-H "Authorization: Bearer $(gcloud auth print-access-token)" \
-H "Content-Type: application/json" \
-d '{
"displayName": "lab-tco-report-v2",
"type": "TOTAL_COST_OF_OWNERSHIP"
}'

The new report appears in Migration Center → Reports within 5 minutes.


13. Cleanup

Return to the RAD UI and click Undeploy on the Migration Center deployment. This removes the VPC network, Windows VM, Linux VMs, Cloud Storage bucket, and associated firewall rules.

Note: Migration Center resources — discovery sources, import jobs, asset groups, preference sets, and reports — are created via REST API calls and are not tracked in Terraform state. Terraform destroy does not delete them. These resources must be removed manually via the Cloud Console or the REST API.

Manual Cleanup — Migration Center Resources

Delete asset groups:

for GROUP_SUFFIX in all-assets windows-only linux-only; do
GROUP_ID="migcenter-<deployment-id>-${GROUP_SUFFIX}"
curl -s -X DELETE \
"https://migrationcenter.googleapis.com/v1/projects/${PROJECT_ID}/locations/${REGION}/groups/${GROUP_ID}" \
-H "Authorization: Bearer $(gcloud auth print-access-token)"
echo "Deleted group: ${GROUP_ID}"
done

Delete preference sets:

for PREF_SUFFIX in aggressive-3yr moderate-1yr; do
PREF_ID="migcenter-<deployment-id>-${PREF_SUFFIX}"
curl -s -X DELETE \
"https://migrationcenter.googleapis.com/v1/projects/${PROJECT_ID}/locations/${REGION}/preferenceSets/${PREF_ID}" \
-H "Authorization: Bearer $(gcloud auth print-access-token)"
echo "Deleted preference set: ${PREF_ID}"
done

Delete report config (also deletes its associated reports):

REPORT_CONFIG=$(curl -s \
"https://migrationcenter.googleapis.com/v1/projects/${PROJECT_ID}/locations/${REGION}/reportConfigs" \
-H "Authorization: Bearer $(gcloud auth print-access-token)" \
| jq -r '.reportConfigs[0].name')

curl -s -X DELETE \
"https://migrationcenter.googleapis.com/v1/${REPORT_CONFIG}" \
-H "Authorization: Bearer $(gcloud auth print-access-token)"

Delete discovery source:

SOURCE_ID="migcenter-<deployment-id>-mc-source"
curl -s -X DELETE \
"https://migrationcenter.googleapis.com/v1/projects/${PROJECT_ID}/locations/${REGION}/sources/${SOURCE_ID}" \
-H "Authorization: Bearer $(gcloud auth print-access-token)"

Delete Compute resources (if Terraform undeploy fails):

# Delete Windows VM
gcloud compute instances delete "${WINDOWS_VM}" \
--zone="${ZONE}" --project="${PROJECT_ID}" --quiet

# Delete Linux VMs
gcloud compute instances list \
--filter="name~migcenter AND name~linvm" \
--project="${PROJECT_ID}" \
--format="value(name,zone)" | while IFS=$'\t' read -r name zone; do
gcloud compute instances delete "${name}" --zone="${zone}" --project="${PROJECT_ID}" --quiet
done

# Delete VPC (firewall rules are deleted automatically with the VPC)
VPC_NAME=$(gcloud compute networks list \
--filter="name~migcenter" --project="${PROJECT_ID}" --format="value(name)")
gcloud compute networks delete "${VPC_NAME}" --project="${PROJECT_ID}" --quiet

14. Reference

Key Module Variables

VariableTypeDefaultDescription
project_idstringGCP project ID (required)
regionstringus-central1GCP region for all resources
zonestringus-central1-aGCP zone for Compute Engine VMs
linux_vm_countnumber3Number of Debian Linux scan target VMs
create_windows_vmbooltrueDeploy Windows Server 2022 VM with MCDCv6
windows_vm_machine_typestringe2-mediumWindows VM machine type
windows_vm_boot_disk_size_gbnumber50Windows VM boot disk size in GB
linux_vm_machine_typestringe2-mediumLinux VM machine type
initialize_migration_centerbooltrueAuto-initialise MC service and register discovery source
aws_access_key_idstring""Bootstrap AWS credentials — module creates scoped IAM user and imports EC2 inventory
aws_secret_access_keystring""AWS Secret Key corresponding to the Access Key ID
aws_regionstringus-east-1AWS region for EC2 discovery
mc_discovery_client_namestringmc-discovery-clientMCDCv6 source name

Terraform Outputs

OutputDescription
deployment_idUnique deployment suffix appended to all resource names
project_idGCP project ID
windows_vm_nameWindows VM name
windows_vm_external_ipExternal IP — use for RDP (user: migrationcenter, pass: m1grat10nc#nt#r)
linux_vm_namesList of Linux target VM names
linux_vm_internal_ipsList of Linux VM internal IPs — use to set MCDCv6 scan range
ssh_key_bucket_nameGCS bucket containing lab-ssh-key.pem
ssh_key_userLinux SSH username: migrationcenter
mc_discovery_client_nameSource name to enter in MCDCv6 login
migration_center_urlDirect URL to Migration Center console for this project
mc_source_idMigration Center discovery source resource ID
vpc_nameVPC network name

Troubleshooting

IssueLikely CauseResolution
RDP cannot connectWindows startup script still runningWait 3–5 min after Terraform completes; check serial port output
MCDCv6 OAuth failsGoogle account lacks MC Admin roleGrant roles/migrationcenter.admin to the login account
MCDCv6 source name mismatchEntered wrong nameMust exactly match mc_discovery_client_name output
SSH scan shows "Access Denied"Wrong SSH key or usernameUse migrationcenter user and lab-ssh-key.pem key
Linux VMs not discoveredIP range too narrowEnsure range covers all IPs from linux_vm_internal_ips output
AWS import job pending/failedAPI propagation delayCheck job state via REST API; may take up to 10 min
TCO report still generatingReports take up to 5 min after triggeringRefresh Migration Center → Reports; poll via REST API until state = SUCCEEDED
prevent_destroy blocks destroyExpected lifecycle policyDelete resources manually via the Cloud Console or contact platform support

Useful Commands Reference

# List all Migration Center assets
curl -s \
"https://migrationcenter.googleapis.com/v1/projects/${PROJECT_ID}/locations/${REGION}/assets" \
-H "Authorization: Bearer $(gcloud auth print-access-token)" \
| jq '.assets[] | {name: (.name | split("/") | last), os: .machineDetails.guestOsDetails.osName}'

# List all import jobs and their states
curl -s \
"https://migrationcenter.googleapis.com/v1/projects/${PROJECT_ID}/locations/${REGION}/importJobs" \
-H "Authorization: Bearer $(gcloud auth print-access-token)" \
| jq '.importJobs[] | {displayName, state}'

# List all asset groups
curl -s \
"https://migrationcenter.googleapis.com/v1/projects/${PROJECT_ID}/locations/${REGION}/groups" \
-H "Authorization: Bearer $(gcloud auth print-access-token)" \
| jq '.groups[] | {displayName, name: (.name | split("/") | last)}'

# List all preference sets
curl -s \
"https://migrationcenter.googleapis.com/v1/projects/${PROJECT_ID}/locations/${REGION}/preferenceSets" \
-H "Authorization: Bearer $(gcloud auth print-access-token)" \
| jq '.preferenceSets[] | {displayName}'

# Windows VM external IP
gcloud compute instances list \
--filter="name~migcenter AND name~winvm" \
--project="${PROJECT_ID}" \
--format="value(networkInterfaces[0].accessConfigs[0].natIP)"

# Linux VM internal IPs
gcloud compute instances list \
--filter="name~migcenter AND name~linvm" \
--project="${PROJECT_ID}" \
--format="table(name, networkInterfaces[0].networkIP)"

# Check Windows VM startup script status (serial port output)
gcloud compute instances get-serial-port-output "${WINDOWS_VM}" \
--zone="${ZONE}" --project="${PROJECT_ID}" | tail -30

# Verify GCP APIs are enabled
gcloud services list \
--filter="config.name~migrationcenter OR config.name~compute OR config.name~storage" \
--project="${PROJECT_ID}" \
--format="table(config.name, state)"

Further Reading