Convert Puppet manifests to Ansible playbooks and roles
Project description
p2a — Puppet to Ansible Converter
Convert Puppet manifests, modules, and entire codebases into production-ready Ansible.
- 100% Local Execution
Install
git clone https://github.com/pavelux00x/puppet-to-ansible.git
cd puppet-to-ansible
pip install -e .
Usage
# Single manifest → playbook
p2a convert nginx.pp -o output/
# Full module → role
p2a convert-module modules/nginx/ -o roles/
# Entire control repo → Ansible project
p2a convert-all /etc/puppet/ -o ansible-project/
# ERB template → Jinja2
p2a convert-erb templates/nginx.conf.erb
# Hiera data only
p2a convert-hiera hieradata/ -o inventory/
# Analyse Puppetfile → Galaxy collection mapping
p2a analyze-puppetfile Puppetfile
Examples
Package + Service + notify
Input:
package { 'nginx': ensure => installed }
file { '/etc/nginx/nginx.conf':
content => template('nginx/nginx.conf.erb'),
notify => Service['nginx'],
}
service { 'nginx':
ensure => running,
enable => true,
}
Output (output/nginx.yml):
- name: nginx
hosts: all
become: true
tasks:
- name: Install nginx
ansible.builtin.package:
name: nginx
state: present
- name: Configure /etc/nginx/nginx.conf
ansible.builtin.template:
src: nginx.conf.j2
dest: /etc/nginx/nginx.conf
notify: Restart nginx
- name: Ensure nginx is running and enabled
ansible.builtin.service:
name: nginx
state: started
enabled: true
handlers:
- name: Restart nginx
ansible.builtin.service:
name: nginx
state: restarted
Class with Hiera parameters → role
Input (modules/nginx/manifests/init.pp):
class nginx (
Integer $port = lookup('nginx::port', Integer, 'first', 80),
String $user = lookup('nginx::user', String, 'first', 'www-data'),
) {
package { 'nginx': ensure => installed }
file { '/etc/nginx/nginx.conf':
content => template('nginx/nginx.conf.erb'),
notify => Service['nginx'],
}
service { 'nginx': ensure => running, enable => true }
}
p2a convert-module modules/nginx/ --hiera hiera.yaml -o roles/
Output:
roles/nginx/
├── tasks/
│ ├── main.yml # include_tasks for each class
│ └── nginx.yml # package, template, service tasks
├── handlers/main.yml # Restart nginx
├── templates/
│ └── nginx.conf.j2 # ERB → Jinja2
└── defaults/main.yml # nginx_port: 80, nginx_user: www-data
Full control repo
p2a convert-all /etc/puppet/ -o ansible-project/
ansible-project/
├── site.yml # From site.pp node definitions
├── requirements.yml # Galaxy collections needed
├── roles/
│ ├── nginx/
│ ├── mysql/
│ └── monitoring/
└── inventory/
├── hosts.yml # From site.pp node definitions
├── group_vars/
│ ├── all.yml # From hieradata/common.yaml
│ └── webserver.yml # From hieradata/roles/webserver.yaml
└── host_vars/
└── web01.example.com.yml
What gets converted
| Puppet | Ansible |
|---|---|
package |
ansible.builtin.package (or apt/yum if provider set) |
service |
ansible.builtin.service (or systemd if provider set) |
file (content) |
ansible.builtin.copy |
file (template source) |
ansible.builtin.template |
file (directory/link/absent) |
ansible.builtin.file |
file_line |
ansible.builtin.lineinfile |
exec |
ansible.builtin.command (or shell if pipe/redirect) |
exec (refreshonly) |
handler |
cron |
ansible.builtin.cron |
user / group |
ansible.builtin.user / group |
mount |
ansible.posix.mount |
host |
ansible.builtin.lineinfile → /etc/hosts |
ssh_authorized_key |
ansible.posix.authorized_key |
yumrepo |
ansible.builtin.yum_repository |
apt::source |
ansible.builtin.apt_repository |
selboolean |
ansible.posix.seboolean |
firewall |
ansible.posix.firewalld or community.general.ufw |
augeas |
lineinfile / ini_file / xml depending on context |
ini_setting |
community.general.ini_file |
concat / concat::fragment |
ansible.builtin.assemble + copy to staging dir |
tidy |
ansible.builtin.find + ansible.builtin.file |
sysctl |
ansible.posix.sysctl |
mysql::db |
community.mysql.mysql_db |
notify (resource) |
ansible.builtin.debug |
| ERB templates | Jinja2 (variables, loops, conditionals, Ruby method → filter) |
Hiera lookup() / hiera() |
Resolved at conversion time; unresolved → Ansible var |
params.pp pattern |
defaults/main.yml |
notify / subscribe |
notify: + handler |
What needs manual work
- Exported resources (
@@resource,<<| |>>) — no Ansible equivalent; p2a generates a TODO task with suggestions - Custom resource types / providers (
lib/puppet/type/) — rewrite as Python Ansible modules - Custom facts (
lib/facter/) — rewrite as Ansible custom facts (facts.d/) - Class inheritance (
inherits) — p2a warns and includes the parent; vars need manual merge - Regex node definitions — inventory entries must be added manually
concat— requiresansible.builtin.assemble; review fragment ordering after conversion
Anything p2a can't convert produces a # TODO task with the original Puppet code. The output is always valid YAML.
Puppet 3 support
Pass --puppet-version 3 for legacy codebases that use $::osfamily, hiera(), hiera_array(), import, and the params.pp pattern:
p2a convert-all /etc/puppet/ --puppet-version 3 -o output/
Parser resilience
p2a is designed to handle real-world Puppet code, which is often imperfect:
- Stray trailing
}— manifests with an extra closing brace after the class body are automatically recovered. p2a strips the trailing}and re-parses, emitting a warning. The conversion continues normally. - Graceful degradation — any resource or construct that cannot be automatically converted produces a
# TODOtask with the original Puppet code instead of crashing. The output is always syntactically valid YAML.
Development
# Tests (200 tests)
pytest
# Lint
ruff check src/ tests/
ruff format src/ tests/
# Add a new resource converter
/add-converter
License
MIT
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file puppet_to_ansible-0.1.2.tar.gz.
File metadata
- Download URL: puppet_to_ansible-0.1.2.tar.gz
- Upload date:
- Size: 92.5 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
d44a95c9cbf1b02abce180a0a86726241c606fe6990d80f79ea5750a6c516074
|
|
| MD5 |
63e0f5e6bb3f6ce848b37af34b20fdb4
|
|
| BLAKE2b-256 |
46c303bba85279f23c1c055e712930441914ee306e8f2eb77fa4313be30c8604
|
File details
Details for the file puppet_to_ansible-0.1.2-py3-none-any.whl.
File metadata
- Download URL: puppet_to_ansible-0.1.2-py3-none-any.whl
- Upload date:
- Size: 107.3 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.12.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
5ef7a8062ea53247b05ea1b4d4b9cfdd4d0c4707ec7b41604abbd4294195228d
|
|
| MD5 |
4e34e8a384434029dd7cc37ce0869671
|
|
| BLAKE2b-256 |
4b0374aaf951de38da4b2c4862be8d7e7f524fe8c3cce074fbc68152f3b6ef34
|