Learnomancer is a PHP CLI for provisioning and tearing down Percona training environments in AWS. It creates VPCs, launches EC2 instances for classes, generates Ansible inventory, and SSH config files.
The CLI entry point is ./bin/learnomancer, built on CakePHP Console.
$ ./bin/learnomancer
Available Commands:
ansible-config Generate an Ansible configuration file for a given class
create-class Create a new class, including the VPC, instances, and Ansible configuration
create-instances Create, or add, new instances to a existing class
create-vpc Create a VPC for a new class
drop-class Drop an existing class, including the VPC, instances, and related resources
drop-instances Drop instances from an existing class
drop-vpc Drop the VPC for an existing class
list-amis List available AMIs for a given region
list-instances List currently running instances for an existing class
list-vpcs List currently existing VPCs for a given region
ssh-config Generate an SSH config file for an existing class
summary Output summary of a given class, including the class dashboard, and SSH info
sync-dynamo Sync instance information to DynamoDB (rarely needed)
vpc-config Rebuild the local Learnomancer config for a given class (rarely needed)- Install requirements, and clone or update local repo
- Login to AWS via SSO, if Key/Secret not previously configured
- Create a class. See 'create-class' subcommand below.
- Execute
ansible-playbookagainst the class inventory - Get class dashboard URL. See 'summary' subcommand below.
- PHP 8.5+
- Composer
- AWS CLI configured with credentials that can manage EC2, VPC, and DynamoDB
- Ansible (for provisioning hosts after inventory is generated)
brew install php@8.5 composer ansible
git clone https://github.com/percona/training-aws
cd training-aws
composer installEnsure php is in your PATH:
$ php -v
PHP 8.5.3 (cli) (built: Feb 10 2026 18:25:51) (NTS)
Copyright (c) The PHP Group
Built by Homebrew
Zend Engine v4.5.3, Copyright (c) Zend Technologies
with Zend OPcache v8.5.3, Copyright (c), by Zend TechnologiesConfigure ~/.aws/credentials (or equivalent via environment / SSO):
[default]
aws_access_key_id = ...
aws_secret_access_key = ...You can also use aws sso login
./bin/learnomancer
./bin/learnomancer list-amis --helpUse a short client slug (e.g. ACME, TREK) as the class suffix. Resources are named like Percona-Training-{slug}. Pick an AWS region close to the students (e.g. us-west-2, eu-west-1).
List Percona Training AMIs in a region.
./bin/learnomancer list-amis <region>Usage:
learnomancer list_amis [-h] <region>
Options:
--help, -h Display this help.
Arguments:
region The region to list from$ ./bin/learnomancer list-amis us-west-2
========== Listing AMIs in 'us-west-2' ==========
+--------------------------------+-----------------------+
| Name | AMI Id |
+--------------------------------+-----------------------+
| Percona-Training-20260301-AMI | ami-0abc123def4567890 |
| Percona-Training-20260115-AMI | ami-0fedcba9876543210 |
+--------------------------------+-----------------------+List running instances for a class slug in a region.
./bin/learnomancer list-instances <slug> <region>List currently running instances for an existing class
Usage:
learnomancer list_instances [-h] <slug> <region>
Options:
--help, -h Display this help.
Arguments:
slug The slug/suffix for the class
region The region to list from$ ./bin/learnomancer list-instances ACME us-west-2
========== Listing instances for 'ACME' in 'us-west-2' ==========
+---------------------+--------------------------------------+----------------+
| InstanceId | Hostname | PublicIpAddress|
+---------------------+--------------------------------------+----------------+
| i-0a1b2c3d4e5f67890 | Percona-Training-ACME-db1-T1 | 54.200.10.1 |
| i-0f9e8d7c6b5a43210 | Percona-Training-ACME-db2-T1 | 54.200.10.2 |
+---------------------+--------------------------------------+----------------+List VPCs in a region
./bin/learnomancer list-vpcs <region>Usage:
learnomancer list_vpcs [-h] <region>
Options:
--help, -h Display this help.
Arguments:
region The region to list from$ ./bin/learnomancer list-vpcs us-west-2
========== Listing VPCs in 'us-west-2' ==========
+------------------------+----------------------------+
| VpcId | Name |
+------------------------+----------------------------+
| vpc-0abc123def4567890 | Percona-Training-ACME-VPC |
+------------------------+----------------------------+Create a VPC including subnet, gateway, route table, and security groups.
./bin/learnomancer create-vpc <slug> <region>Usage:
learnomancer create_vpc [-h] [-r] <slug> <region>
Options:
--help, -h Display this help.
Arguments:
slug The slug/suffix for the class
region The region to list from$ ./bin/learnomancer create-vpc ACME us-west-2
- No VPC Id in config file. Searching by name 'Percona-Training-ACME-VPC'...
- VPC 'Percona-Training-ACME-VPC' not found. Creating new VPC...
-- VPC Percona-Training-ACME-VPC (vpc-0abc123def4567890) created in us-west-2
- Checking VPC (vpc-0abc123def4567890) status...
-- VPC 'Percona-Training-ACME-VPC' is OK
...Tear down the VPC and related networking for a class.
./bin/learnomancer drop-vpc <slug> <region>Usage:
learnomancer drop_vpc [-h] <slug> <region>
Options:
--help, -h Display this help.
Arguments:
slug The slug/suffix for the class
region The region to list from$ ./bin/learnomancer drop-vpc ACME us-west-2
- Dropping VPC for 'ACME' in 'us-west-2'...
-- Detaching and deleting internet gateway...
-- Deleting subnet, route table, security group...
-- Deleting VPC vpc-0abc123def4567890
- DoneLaunch (or add) EC2 instances into an existing class.
Use this command to create/launch new instances for a class. There are several machine types to select from. You can select a single type, or combine several types separated by comma.
Types:
- db1: A regular PS 8.4 MySQL server with sample data
- db2: A blank instance. Typically used as a replica of db1.
- app: An instance with sysbench, and helper scripts for generating load
- mysql1, mysql2, mysql3: Regular PS 8.4 with sample data in S->R/R configuration. Used in the PXC, and GR classes
- mongodb: Regular PS MongoDb server
Aliases:
- pxc: This is a combination alias for 4 types: "app,mysql1,mysql2,mysql3"
- gr: Also a combination alias for 4 types: "app,mysql1,mysql2,mysql3"
./bin/learnomancer create-instances [-i <ami>] [-o <offset>] <slug> <region> <count> <machinetype[,machinetype...]>Usage:
learnomancer create_instances [-i ami-xxxxxx] [-h] [-o 0] <slug> <region> <count> <db1|db2|app|mysql1|mysql2|mysql3|pxc|gr|node1|node2|node3|node4|mongodb>
Options:
--ami, -i The AMI to use. Use list-amis to get available AMIs
--help, -h Display this help.
--offset, -o Offset the team counter by this amount. Useful when adding
more instances to an existing class.
Arguments:
slug The slug/suffix for the class
region The region to create into
count The number of teams to create
machinetype The machine type to create, related to the class
(choices:
db1|db2|app|mysql1|mysql2|mysql3|pxc|gr|node1|node2|node3|node4|mongodb)
(separator: ",")
# First pick the most recent date-based AMI
$ ./bin/learnomancer list-amis us-west-2
# Launch 9 teams of db1+db2 for ACME Co, MySQL Operations class
$ ./bin/learnomancer create-instances ACME us-west-2 9 db1,db2 -i ami-0abc123def4567890
# Later: add 2 more teams (offset past the existing 9)
$ ./bin/learnomancer create-instances -o 9 ACME us-west-2 2 db1,db2 -i ami-0abc123def4567890Terminate all instances for a class slug (does not drop the VPC).
./bin/learnomancer drop-instances <slug> <region>Usage:
learnomancer drop_instances [-h] <slug> <region>
Options:
--help, -h Display this help.
Arguments:
slug The slug/suffix for the class
region The region to list from$ ./bin/learnomancer drop-instances ACME us-west-2
- Found 18 instances for 'ACME' in 'us-west-2'
Continue? (y/n)
y
- Terminating instances...
- DonePrimary command: create VPC, and launch instances for a known class type.
Available Classes, which should match slide material:
- MySQL: mysql-ops, mysql-dev, pxc, gr, proxysql, mysql-k8s
- MongoDB: mongo-ops, mongo-dev, mongo-k8s
- PostgreSQL: pg-ops, pg-dev, pg-k8s
./bin/learnomancer create-class <class> <slug> <region> <count> <ami>Usage:
learnomancer create_class [-h] <mysql-ops|pxc|gr|proxysql|mysql-k8s|mongo-ops|mongo-dev|mongo-k8s|pg-ops|pg-dev|pg-k8s> <slug> <region> <count> <ami>
Options:
--help, -h Display this help.
Arguments:
class The name of the class. Use -h for full list. (choices:
mysql-ops|pxc|gr|proxysql|mysql-k8s|mongo-ops|mongo-dev|mongo-k8s|pg-ops|pg-dev|pg-k8s)
slug The slug/suffix for the class
region The region to create into
count The number of teams to create
ami The AMI to use. Use list-amis to get a list default:
"ami-xxxxxx"
# List AMIs for region
$ ./bin/learnomancer list-amis us-west-2
# PostgreSQL Developers class for Skynet Inc, with 4 students:
$ ./bin/learnomancer create-class pg-dev SKY us-east-2 4 ami-0abc123def4567890
# MySQL Operations class for Acme Corp, with 9 students:
$ ./bin/learnomancer create-class mysql-ops ACME us-west-1 9 ami-0abc123def4567890Use this command to drop an existing class based on slug and region.
./bin/learnomancer drop-class <slug> <region>Usage:
learnomancer drop_class [-h] <slug> <region>
Options:
--help, -h Display this help.
Arguments:
slug The slug/suffix for the class
region The region to create into
./bin/learnomancer drop-class ACME us-west-2Generate Ansible inventory for a class. Print to stdout, or save with -o.
./bin/learnomancer ansible-config [-o] <slug> <region>Usage:
learnomancer ansible_config [-h] [-o] <slug> <region>
Options:
--help, -h Display this help.
--output, -o Save output to file
Arguments:
slug The slug/suffix for the class
region The region to list from$ ./bin/learnomancer ansible-config -o ACME us-west-2
# Writes inventory file for the class to 'ansible_ACME'
# Use the ansible inventory config to prepare instances after creating the class
$ ansible-playbook -i ansible_acme hosts.ymlGenerate SSH Host entries file for class instances. Print to stdout, or save with -o. This file is typically only for the instructor in order to more quickly connect to a student's instance.
./bin/learnomancer ssh-config [-o] <slug> <region>Usage:
learnomancer ssh_config [-h] [-o] <slug> <region>
Options:
--help, -h Display this help.
--output, -o Save output to file
Arguments:
slug The slug/suffix for the class
region The region to list from$ ./bin/learnomancer ssh-config ACME us-west-2
Host Percona-Training-ACME-db1-T1 db1-T1
HostName 54.200.10.1
User rocky
IdentityFile Percona-Training.key
StrictHostKeyChecking no
ForwardAgent yes
$ ./bin/learnomancer ssh-config -o ACME us-west-2
# Writes ssh_ACME
# Now, you can easily connect to a student's instance for troubleshooting/assistance
$ ssh -F ssh_ACME db2-T3
Print the student dashboard URL, and connection reminders for a class. Share the dashboard URL with the students, and assign the team numbers at the beginning of one of the class sections.
./bin/learnomancer summary <class-slug>Usage:
learnomancer summary [-h] <slug>
Options:
--help, -h Display this help.
Arguments:
slug The slug/suffix for the class$ ./bin/learnomancer summary ACME
=================================================================
TRAINING ENVIRONMENT READY
=================================================================
Server IP Dashboard: http://percona-training.s3-website-us-east-1.amazonaws.com/?tag=ACME
SSH Username: ec2-user (or 'rocky' depending on the class)
SSH Key Download: See link at the bottom of the Server IP Dashboard.
Note: If the dashboard does not load immediately, please wait a minute for DynamoDB to sync.
=================================================================Push instance IP / team metadata to the DynamoDB table, used by the dashboard. (rarely needed, as this sync is normally done during instance creation)
./bin/learnomancer sync-dynamo <slug> <region>Usage:
learnomancer sync_dynamo [-h] <slug> <region>
Options:
--help, -h Display this help.
Arguments:
slug The slug/suffix for the class
region The region to list from$ ./bin/learnomancer sync-dynamo ACME us-west-2
- Found 18 instances to sync
-- Added db1 to team 1
-- Added db2 to team 1
...Rebuild the local class config file from an existing VPC (rarely needed).
./bin/learnomancer vpc-config <slug> <region>Usage:
learnomancer vpc_config [-h] <slug> <region>
Options:
--help, -h Display this help.
Arguments:
slug The slug/suffix for the class
region The region to rebuild the config for$ ./bin/learnomancer vpc-config ACME us-west-2
Config rebuilt for 'ACME' in 'us-west-2' with VPC 'Percona-Training-ACME-VPC' (vpc-0abc123def4567890)| Path | Purpose |
|---|---|
bin/learnomancer |
CLI entry point (CommandRunner + Application) |
src/Application.php |
Registers console commands |
src/AwsClient.php |
EC2 / VPC AWS SDK wrapper |
src/DynamoDbClient.php |
DynamoDB AWS SDK wrapper |
src/LearnomancerConfig.php |
Local .config-*.cnf persistence |
src/Command/ |
One CakePHP command class per sub-command |
src/Command/Helper/ |
Console output helpers |
config/learnomancer.php |
Application configuration |
hosts.yml, roles/ |
Ansible provisioning |
packer/ |
AMI build templates |
This project is a CakePHP Console application, not a full CakePHP web app. The sub-commands extend Cake\Console\BaseCommand, define arguments/options in buildOptionParser(), and implement execute(). New sub-commands should:
- Add a dedicated class under
src/Command/ - Register it in
src/Application.php($commands->add('my-command', ...)) - Keep AWS logic in
AwsClient.php, orDynamoDbClient.phprather than in the command when possible
Static analysis runs at level 10 on src/ (see phpstan.neon). Helpers under src/Command/Helper/ are excluded, as they are 3rd party.
composer stanPrefer fixing real types (narrow nullable CLI args, accurate @return array shapes) over ignores or casts.
Code style is enforced with PHP_CodeSniffer using PSR-12 / CakePHP ruleset customizations (phpcs.xml).
composer cs-check # report violations
composer cs-fix # auto-fix where possiblecomposer lint # PHP parallel-lint (syntax)- Fork and branch from
main - Implement the change with matching style
- Run
composer stanandcomposer cs-checklocally - Open a PR against
main
See CONTRIBUTING.md for bug reports, enhancements, and community notes.