VMWare Template initialization If you want to create a fresh template you just create a new VM and install it.

When you’re done with it you stop the VM and turn it into a template.

In order to make it able to customize hostname / network etc … you just have to create some policies in VMware :

Click menu > Policies and Profiles

Then in VM customization you create a new one for Linux (Target guest OS : Linux).

Then you just go on in the wizard to make the change you want to enable.

Template creation There is few steps to make your template working with VM customization and cloud-init :

yum update 
yum -y install open-vm-tools perl cloud-init 

Then edit the cloud-init config :

cat << EOF > /etc/cloud/cloud.cfg
cloud_init_modules:
 - disk_setup
 - migrator
 - bootcmd
 - write-files
 - growpart
 - resizefs
 - set_hostname
 - update_hostname
 - update_etc_hosts
 - rsyslog
 - users-groups
 - ssh
cloud_config_modules:
 - mounts
 - locale
 - set-passwords
 - rh_subscription
 - yum-add-repo
 - package-update-upgrade-install
 - timezone
 - puppet
 - chef
 - salt-minion
 - mcollective
 - disable-ec2-metadata
 - runcmd
cloud_final_modules:
 - rightscale_userdata
 - scripts-per-once
 - scripts-per-boot
 - scripts-per-instance
 - scripts-user
 - ssh-authkey-fingerprints
 - keys-to-console
 - phone-home
 - final-message
 - power-state-change
system_info:
  distro: rhel
  paths:
    cloud_dir: /var/lib/cloud
    templates_dir: /etc/cloud/templates
  ssh_svcname: sshd
# vim:syntax=yaml
EOF

Then add some configs for our personal requirements :

cat << EOF > /etc/cloud/cloud.cfg.d/01_network.cfg
network:
  config: disabled
EOF

This is disabling the network config by cloud-init because it’ll be done by vmtools.

datasource_list: [NoCloud]
datasource:
  NoCloud:
    seedfrom: http://puppet.domain.local/userdata/
This is saying cloud-init to look for userdata in foreman.

Then you add a cleaning script to make the template like a new VM :

cat > ~/clean.sh <<EOF
#!/bin/bash

# stop logging services
/usr/bin/systemctl stop rsyslog
/usr/bin/systemctl stop auditd

# remove old kernels
# /bin/package-cleanup -oldkernels -count=1

#clean yum cache
/usr/bin/yum clean all

#force logrotate to shrink logspace and remove old logs as well as truncate logs
/usr/sbin/logrotate -f /etc/logrotate.conf
/bin/rm -f /var/log/*-???????? /var/log/*.gz
/bin/rm -f /var/log/dmesg.old
/bin/rm -rf /var/log/anaconda
/bin/cat /dev/null > /var/log/audit/audit.log
/bin/cat /dev/null > /var/log/wtmp
/bin/cat /dev/null > /var/log/lastlog
/bin/cat /dev/null > /var/log/grubby

#remove udev hardware rules
/bin/rm -f /etc/udev/rules.d/70*

#remove uuid from ifcfg scripts
/bin/cat > /etc/sysconfig/network-scripts/ifcfg-ens192 <<EOM
DEVICE=ens192
ONBOOT=yes
EOM

#remove SSH host keys
/bin/rm -f /etc/ssh/*key*

#remove root users shell history
/bin/rm -f ~root/.bash_history
unset HISTFILE

#remove root users SSH history
/bin/rm -rf ~root/.ssh/known_hosts
EOF

Then just run it : bash /root/clean.sh

Finally poweroff : systemctl poweroff

And turn it to a template.

Template modification All our VMs are vmware based.

There is one template which is used to deploy new VMs : ol7_template_cloudinit

This template can be modified by turning it to a VM (do a backup if you’re unsure). By default this VM will not have any network.

So just edit :

NAME=ens192
GATEWAY=192.168.1.254
DNS1=192.168.1.254
DEVICE=ens192
NETMASK=24
IPADDR=192.168.1.11

Then run : systemctl restart network

if you do ip a you should see it up.

Then you can do you modifications.

Do not forget at the end to run : /root/clean.sh

Poweroff and then turn it back to a template.

Foreman Foreman can manage template customization to vmware via the vmware tools.

VMware tools userdata In foreman go to Hosts > Provisioning templates

Create a new one with content :

# Template for VMWare customization via open-vm-tools
identity:
  LinuxPrep:
    domain: <%= @host.domain %>
    hostName: <%= @host.shortname %>
    hwClockUTC: true
globalIPSettings:
  dnsSuffixList: [<%= @host.domain %>]
  <%- @host.interfaces.each do |interface| -%>
  <%- next unless interface.subnet -%>
  dnsServerList: [<%= interface.subnet.dns_primary %>, <%= interface.subnet.dns_secondary %>]
  <%- end -%>
nicSettingMap:
<%- @host.interfaces.each do |interface| -%>
<%- next unless interface.subnet -%>
  - adapter:
      dnsDomain: <%= interface.domain %>
      dnsServerList: [<%= interface.subnet.dns_primary %>, <%= interface.subnet.dns_secondary %>]
      gateway: [<%= interface.subnet.gateway %>]
      ip: <%= interface.ip %>
      subnetMask: <%= interface.subnet.mask %>
<%- end -%>

In Type tab you choose User Data template.

In Association tab choose your OS.

Then Submit.

Cloud init In foreman go to Hosts > Provisioning templates.

Create a new one with this kind of content :

#cloud-config
hostname: <%= @host.name %>
fqdn: <%= @host %>
manage_etc_hosts: true
users: {}
runcmd:
- touch ~/cloud-init

yum_repos:
    # The name of the repository
    puppet:
        # Any repository configuration options
        # See: man yum.conf
        #
        # This one is required!
        baseurl: http://yum.puppetlabs.com/puppet6/el/7/$basearch
        enabled: 1
        failovermethod: priority
        gpgcheck: true
        gpgkey: file:///etc/pki/rpm-gpg/RPM-GPG-KEY-puppet6-release
        name: Puppet 6 Repository el 7 - $basearch
puppet:
 conf_file: '/etc/puppetlabs/puppet/puppet.conf'
 ssl_dir: '/etc/puppetlabs/puppet/ssl'
 conf:
   agent:
     server: "puppet.domain.local"
     # certname supports substitutions at runtime:
     #   %i: instanceid 
     #       Example: i-0123456
     #   %f: fqdn of the machine
     #       Example: ip-X-Y-Z.cloud.internal
     #
     # NB: the certname will automatically be lowercased as required by puppet
     certname: "%f"
   # ca_cert is a special case. It won't be added to puppet.conf.
   # It holds the puppetmaster certificate in pem format. 
   # It should be a multi-line string (using the | yaml notation for 
   # multi-line strings).
   # The puppetmaster certificate is located in 
   # /var/lib/puppet/ssl/ca/ca_crt.pem on the puppetmaster host.
   #

package_upgrade: true

phone_home:
  url: <%= foreman_url('built') %>
  post: []
tries: 10

You can add more there is some examples there : https://cloudinit.readthedocs.io/en/latest/topics/examples.html

In Type tab set cloud-init template.

In association select you OS.

Then submit.

To make your templates default for your OS go in Hosts > Operating systems. Click on the one you want to use (OracleLinux 7.7 for example). Go to Templates tab choose your cloud-init template and user-data templates and then submit.