Skip to main content

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.

Python License

  • 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 — requires ansible.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 # TODO task 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


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

puppet_to_ansible-0.1.1.tar.gz (90.1 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

puppet_to_ansible-0.1.1-py3-none-any.whl (104.5 kB view details)

Uploaded Python 3

File details

Details for the file puppet_to_ansible-0.1.1.tar.gz.

File metadata

  • Download URL: puppet_to_ansible-0.1.1.tar.gz
  • Upload date:
  • Size: 90.1 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/6.2.0 CPython/3.12.3

File hashes

Hashes for puppet_to_ansible-0.1.1.tar.gz
Algorithm Hash digest
SHA256 92efdcc1241b97acad671d0885f59ce41389b52ab8e4a8fa37a160c60fc7797c
MD5 ab3ab1c6e50d7d96b780655e580aa28b
BLAKE2b-256 7421344d05f372aaa097c09a97a92bb3ba39eaf5031ebfb380ea65651da34d5d

See more details on using hashes here.

File details

Details for the file puppet_to_ansible-0.1.1-py3-none-any.whl.

File metadata

File hashes

Hashes for puppet_to_ansible-0.1.1-py3-none-any.whl
Algorithm Hash digest
SHA256 86411ec654b66c2ee90d4ffcd037fac007ac9f7c7f417a315c65a5084aef852b
MD5 0da73839abae147356dcc08c1afc7f88
BLAKE2b-256 4ddf0439df8e157537d19b6e6d352c7c2d28f89a7a5d3894f8c4484be0d919a2

See more details on using hashes here.

Supported by

AWS Cloud computing and Security Sponsor Datadog Monitoring Depot Continuous Integration Fastly CDN Google Download Analytics Pingdom Monitoring Sentry Error logging StatusPage Status page