PyYAML在SSH公钥中插入额外换行的问题排查求助
I’ve run into this exact issue before when generating Ansible vars files from database-stored SSH keys—PyYAML has a habit of breaking long strings (like SSH public keys) into multiple lines, especially right before the email portion, which messes up Ansible’s ability to parse the key correctly. Let’s break down why this happens and how to fix it.
Why This Happens
PyYAML’s default serialization behavior automatically wraps strings that exceed a default length (around 80 characters) using folded block style (>) or inserting line breaks. For SSH public keys—single-line strings ending with an email address—this often results in a line break right before the @ symbol, splitting the key into two lines that Ansible doesn’t recognize as a valid public key.
Solution 1: Force Plain Scalar Output (Most Reliable)
The best way to ensure your SSH key stays as a single unbroken line is to tell PyYAML to treat it as a plain scalar string, which overrides its automatic wrapping logic. You’ll need to use the PlainScalarString class from PyYAML’s scalarstring module:
import yaml from yaml.scalarstring import PlainScalarString # Initialize your base dictionary yamldict = { "users": [] } # Example data pulled from MySQL (replace with your actual DB fetch logic) username = "user" full_name = "User McUserface" email = "user@example.com" ssh_pubkey = "ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQD3F6tyPEFEzV0LX3X8BsXdMsQz1x2cEikKDEY0aIj41qgxMCP/iteneqXSIFZBp5vizPvaoIR3Um9xK7PGoW8giupGn+EPuxIA4cDM4vzOqOkiMPhz5XK0whEjkVzTo4+S0puvDZuwIsdiW9mxhJc7tgBNL0cYlWSYVkz4G/fslNfRPW5mYAM49f4fhtxPb5ok4Q2Lg9dPKVHO/Bgeu5woMc7RY0p1ej6D4CKFE6lymSDJpW0YHX/wqE9+cfEauh7xZcG0q9t2ta6F6fmX0agvpFyZo8aFbXeUBr7osSCJNgvavWbM/06niWrOvYX2xwWdhXmXSrbX8ZbabVohBK41 user@example.com" # Add user data, wrapping the SSH key in PlainScalarString to preserve line structure yamldict["users"].append({ "username": username, "name": full_name, "email": email, "ssh_public_key": PlainScalarString(ssh_pubkey) }) # Dump to YAML with settings that preserve your desired structure with open("ansible_users.yml", "w") as f: yaml.dump( yamldict, f, default_flow_style=False, # Keeps nested structures as readable block style sort_keys=False, # Preserves the order of your dictionary keys allow_unicode=True # Handles any special characters in names/emails correctly )
Solution 2: Increase Line Width (Quick Fix)
If you don’t want to import extra modules, you can tell PyYAML to use a much larger line width, so it won’t wrap the SSH key string. This works for most cases, though it’s less reliable if you have extremely long keys:
import yaml yamldict = { "users": [] } # ... (same user data setup as above) with open("ansible_users.yml", "w") as f: yaml.dump( yamldict, f, default_flow_style=False, sort_keys=False, width=10000 # Set to a value larger than any possible SSH key length )
Verify the Output
After running either solution, check your generated YAML file—your SSH public key should appear as a single line, like this:
users: - username: user name: User McUserface email: user@example.com ssh_public_key: ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQD3F6tyPEFEzV0LX3X8BsXdMsQz1x2cEikKDEY0aIj41qgxMCP/iteneqXSIFZBp5vizPvaoIR3Um9xK7PGoW8giupGn+EPuxIA4cDM4vzOqOkiMPhz5XK0whEjkVzTo4+S0puvDZuwIsdiW9mxhJc7tgBNL0cYlWSYVkz4G/fslNfRPW5mYAM49f4fhtxPb5ok4Q2Lg9dPKVHO/Bgeu5woMc7RY0p1ej6D4CKFE6lymSDJpW0YHX/wqE9+cfEauh7xZcG0q9t2ta6F6fmX0agvpFyZo8aFbXeUBr7osSCJNgvavWbM/06niWrOvYX2xwWdhXmXSrbX8ZbabVohBK41 user@example.com
No more line breaks in the key, and Ansible will parse it correctly.
内容的提问来源于stack exchange,提问作者jasondewitt

