Decided to finally have a look at “puppet”.

When I initially had issues with Puppet I also looked at “Chef” but my issues with Chef were that it needs a damn site more resources to run plus to download the main chef server component you have to go through a registration page… and while I have no issues with that in itself that is not something that can be automated… so in line with my philosophy for my home lab which is instances must be able to be thrown-up/torn-down on demand or discarded, Chef is in the discarded bucket for now.

Anyway, my initial issues with Puppet were that the repos seemed to be out of sync or shipping conflicting packages. I’m happy to say that has been resolved and installing Puppet from the repos is now a totally hands off experience for me so I will stick with that.

While I do not have enough servers of similar types to use it as a deployment tool for server builds I believe it could be useful for specific tasks, such as ensuring every server has the same set of nagios/nrpe monitoring scripts… rather my my rather ad-hoc method of remembering to push push out new scripts when nrpe reports they are missing :-).

There is a lot of walk throughs on setting up a puppet master server out on the web, mainly for Ubuntu but a few for CentOS as well.

As my setup is mainly Fedora based and I am only looking into it rather than commiting to it as a solution I decided to use a test environment easily able to be rebuilt as needed; in this case my OpenStack home lab environment.

My deployment is a throw-up/tear-down solution for testing (after all that is what cloud instances are for) in my OpenStack test lab using a simple heat template; allowing me to create all the servers with one openstack command and to delete all the servers simply by deleting the stack from the dashboard. The deployment heat template creates a “puppet” server and a “agenttest” server.

After deploying the heat pattern I have a working “puppet” host running puppetserver with the agenttest server registered with it. The agent can register as I configured the puppetserver to automatically accept agent cert registration requests so there is no need for any manual intervention to accept a certificate (as that would defeat the point of automatically deploying the stack in a hands off way using heat patterns).

[root@puppet ~]# puppet cert list --all
+ "agenttest.mdickinson.dyndns.org" (SHA256) 4D:23:9E:97:77:7C:13:4D:CA:00:42:3B:8F:1A:A6:AB:26:35:A5:B4:D0:FC:B0:A5:3C:08:A2:F1:E7:55:36:FA
+ "puppet.mdickinson.dyndns.org"    (SHA256) 71:84:87:19:DF:90:F7:52:14:67:F2:FE:FA:C1:0A:E4:1B:33:DC:27:E3:41:8B:0D:0D:0E:0D:AB:20:50:88:82 (alt names: "DNS:puppet", "DNS:puppet.mdickinson.dyndns.org")
[root@puppet ~]# 

If you want to use the heat pattern you will need to note

  • change the keypair to one you use
  • change the network names to ones you use
  • change the image name from CentOS-7-x86_64-GenericCloud-1704.qcow2 to whatever you called your copy of the CentOS7 cloud image
  • change the availability_zone used for both servers, most users would use the default “nova” but for my home lab I had to create a custom availability zone to ensure I always had resources available
  • the custom flavor centos7-puppet-min is a minimum of 3Gb memory, 3Gb swap, 8Gb root disk (centos7 cloud image needs 8Gb root disk)
  • the custom flavor centos7-min is a minimum of 1Gb memory, 3Gb swap, 8Gb root disk (centos7 cloud image needs 8Gb root disk)
  • in each instance definition I hard code the address of my external router (192.168.1.1) as an addition to the resolv.conf file so the instances can resolve internet addresses for the package installs, if you are not in a ‘home lab’ you will need to change that in both server instances

My OpenStack lab environment is currently OpenStack Ocata version, installed from the RDO repository via packstack with the main customisation being additional compute nodes. All the nodes are running CentOS7.

The heat template is run simply by (a user with heat_admin authority of course) “openstack stack create –template puppet_master_centos7.yaml puppet_testing” which will create a stack named puppet_testing with the following resources

  • create a custom security group to be used by the instances
  • create a “puppet” server on my tenant internal network and
    • install packages I always need for network troubleshooting
    • assign a password of “password” to root for troubleshooting from the console (bad I know)
    • install the puppetserver packages
    • make lots of customisations, including to automatically accept cert requests
    • start the puppetserver
    • assign a floating ip-address to the instance, also primarily for troubleshooting (for getting into it without the console)
  • create a “agentest” server on my tenant internal network and
    • install packages I always need for network troubleshooting
    • assign a password of “password” to root for troubleshooting from the console (bad I know)
    • install the puppet-agent packages
    • ensure the puppet-agent is running
    • change sshd configuration to allow root to login directly, also for troubleshooting so from the “puppet” instance I can login to the agent instance via the internal tenant network without having to copy ssh keys onto the puppet instance

And you have a running and working puppetserver instance to play with with running agent server to test rules against.

When you are done with it just use the dashboard Project/Orchestration/Stacks screen to delete the stack, and all instances and the decurity group will be deleted, and the floating ip released.

Anyway, the template

[root@region1server1 heat_stacks(keystone_mark)]# cat puppet_master_centos7.yaml
heat_template_version: 2016-10-14

description: >
  Install a puppet master server and agent server,
  Custom Flavor notes, CentOS7 cloud image needs a minimum 8Gb disk image for each instance,
  puppetserver instance needs at least 3Gb memory and 3Gb swap,
  agent needs 1Gb memory 2Gb swap,
  the floating ip on puppet server is not recomended but I find it usefull to get into the test stack quickly bypassing a normal tenant gateway server.

parameters:
  key_name:
    type: string
    label: Key Name
    description: Name of key-pair to be used for compute instance
    default: marks-keypair-ocata
  root_password:
    type: string
    label: Root User Password
    description: Password to be used for root user
    hidden: true
    default: password
    constraints:
      - length: { min: 6, max: 8 }
        description: Password length must be between 6 and 8 characters.
      - allowed_pattern: "[a-zA-Z0-9]+"
        description: Password must consist of characters and numbers only.
  net:
    description: name of network used to launch instance.
    type: string
    default: tenant-mark-10-0-3-0
  subnet:
    description: name of subnet within network used to launch instance.
    type: string
    default: tenant-mark-10-0-3-0-subnet1
  public_network:
    description: name of the public network to associate floating ip from.
    type: string
    default: ext-net-192-flat

resources:
  puppet-server:
    type: OS::Nova::Server
    properties:
      name: puppet
      key_name: { get_param: key_name }
      image: CentOS-7-x86_64-GenericCloud-1704.qcow2
      flavor: centos7-puppet-min
      security_groups: [{ get_resource: puppet_security_group }]
      availability_zone: compute-pool
      networks: 
        - network: { get_param: net }
      user_data: 
         str_replace:
            template: |
              #!/bin/bash
              echo "Customising system image..."
              # For troubleshooting use a known password for console login
              echo "$ROOTPSWD" | passwd root --stdin
              timedatectl set-timezone Pacific/Auckland
              wc_notify --data-binary '{"status": "SUCCESS"}'
              #
              echo "nameserver 192.168.1.1" >> /etc/resolv.conf
              sync
              yum -y install telnet iputils psmisc
              sync
              #
              # enable the puppetlabs repo and install puppetserver
              rpm -ivh https://yum.puppetlabs.com/puppetlabs-release-pc1-el-7.noarch.rpm
              yum -y install puppetserver
              #
              # In a VM with 3Gb memory and two cores the puppetserver takes a long
              # time to start and generate its key; the startup will fail and loop
              # trying to start and being killed by systemd forever unless the startup
              # timeout values are changed. They must be changed in two configuration
              # files as systemd will use the lowest of either value set.
              # Also change puppetserver memory allocation from 2Gb to 1Gb
              cp /etc/sysconfig/puppetserver /tmp/puppetserver_sysconfig
              cat /tmp/puppetserver_sysconfig | sed -e's/-Xms2g -Xmx2g/-Xms1g -Xmx1g/' | sed -e's/START_TIMEOUT=300/START_TIMEOUT=1200/' > /etc/sysconfig/puppetserver
              cp /usr/lib/systemd/system/puppetserver.service /tmp
              cat /tmp/puppetserver.service | sed -e's/TimeoutStartSec=300/TimeoutStartSec=1200/' > /usr/lib/systemd/system/puppetserver.service
              cp /etc/puppetlabs/puppetserver/conf.d/puppetserver.conf /tmp
              # there are issues with letting legacy auth remain defaulted to true
              cat /tmp/puppetserver.conf | sed -e's/#use-legacy-auth-conf: false/use-legacy-auth-conf: false/' > /etc/puppetlabs/puppetserver/conf.d/puppetserver.conf
              systemctl daemon-reload
              #
              # create an empty default manifest file
              touch /etc/puppetlabs/code/environments/production/manifests/site.pp
              #
              # try and resolve timeout issues
              # MID added, makes no difference but documented as making no change
              echo "# MID added" >> /etc/puppetlabs/puppet/puppet.conf
              echo "http_connect_timeout = 2m" >> /etc/puppetlabs/puppet/puppet.conf
              echo "http_read_timeout = 5h" >> /etc/puppetlabs/puppet/puppet.conf
              echo "filetimeout = 5m" >> /etc/puppetlabs/puppet/puppet.conf
              # Normally you would not autosign, but should make testing easier
              echo "autosign = true" >> /etc/puppetlabs/puppet/puppet.conf
              #
              # puppet command is not in path until logoff/logon, add for next three commands
              export PATH=$PATH:/opt/puppetlabs/bin/puppet
              puppet resource package hiera ensure=installed
              puppet resource package facter ensure=installed
              puppet resource package rubygem-json ensure=installed
              #
              # Start puppetserver, during startup it will generate its ssl cert
              systemctl enable puppetserver
              #
              # systemctl start puppetserver    WAIT, DO NOT START IT YET
              # KNOWN BUG: https://tickets.puppetlabs.com/browse/SERVER-248
              #            that there is no intention of fixing
              # If ipv6 is enabled puppet will only listen on ipv6... centOS7 enables
              # ipv6 be default, even if the interface network-scripts/ifcfg-xxx has
              # ipv6init="no". Disable ipv6 in order to use puppet if you have any
              # agents that use ipv4
              echo "net.ipv6.conf.all.disable_ipv6 = 1" >> /etc/sysctl.conf
              sysctl -p
              #
              # Now it should start OK
              systemctl start puppetserver
              #
              logger "End of puppetserver cloud init scripted install"
              echo "...end of install"
              exit 0
              # ... done
            params: 
              $ROOTPSWD: { get_param: root_password }
  floating_ip:
    type: OS::Neutron::FloatingIP
    properties:
      floating_network: {get_param: public_network}
  association:
    type: OS::Neutron::FloatingIPAssociation
    properties:
      floatingip_id: { get_resource: floating_ip }
      port_id: {get_attr: [puppet-server, addresses, {get_param: net}, 0, port]}

  puppet-agent-test:
    type: OS::Nova::Server
    properties:
      name: agenttest
      key_name: { get_param: key_name }
      image: CentOS-7-x86_64-GenericCloud-1704.qcow2
      flavor: centos7-min
      security_groups: [{ get_resource: puppet_security_group }]
      availability_zone: compute-pool
      networks: 
        - network: { get_param: net }
      user_data: 
         str_replace:
            template: |
              #!/bin/bash
              echo "Customising system image..."
              # For troubleshooting use a known password for console login
              echo "$ROOTPSWD" | passwd root --stdin
              timedatectl set-timezone Pacific/Auckland
              wc_notify --data-binary '{"status": "SUCCESS"}'
              #
              # Servers with only private ips I allow password logins
              # (or all the ssh keys would have to be copied to all servers
              # in the private network that might want to logon to this server).
              cd /etc/ssh
              cat sshd_config | sed -e 's/PasswordAuthentication no/PasswordAuthentication yes/' > sshd_config.new
              mv sshd_config sshd_config.old
              mv sshd_config.new sshd_config
              chmod 644 sshd_config
              service sshd restart
              # Additional nameserver for resolving external download sites on first install boot
              echo "nameserver 192.168.1.1" >> /etc/resolv.conf
              sync
              yum -y install telnet iputils psmisc
              sync
              #
              # It takes along time for the puppet master to install packages and configure itself.
              # As soon as the agent starts it will send a cert request to the puppet server,
              # we must wait until the 'puppet' server has been fully configured as part of the stack build
              # before we start the agent that will immediately try to connect to it to elimate 
              # the puppet server being available as the cause of the idletimeout errors seen in
              # puppet server logs.
              echo "*** Agent startup is delaying for 20mins to allow puppet master to fully configure ***"
              logger "*** Agent startup is delaying for 20mins to allow puppet master to fully configure ***"
              sleep 20m
              #
              # Then install the puppet agent packages
              rpm -ivh https://yum.puppetlabs.com/puppetlabs-release-pc1-el-7.noarch.rpm
              yum -y install puppet-agent
              # to resolve timeout issues
              echo "http_read_timeout = 5h" >> /etc/puppetlabs/puppet/puppet.conf
              /opt/puppetlabs/bin/puppet resource service puppet ensure=running enable=true
              #
              echo "use 'puppet cert list' and 'puppet cert sign' on the puppet server to register this agent"
              echo "this agent will have generated the cert request to the pupper server when the agent started."
              echo "...end of install"
              exit 0
              # ... done
            params: 
              $ROOTPSWD: { get_param: root_password }

  puppet_security_group:
      type: OS::Neutron::SecurityGroup
      properties:
        description: Ports needed for a puppet master server.
        name: puppet-security-group
        rules: [
          {remote_ip_prefix: 0.0.0.0/0,
          protocol: tcp,
          port_range_min: 22,
          port_range_max: 22},
          {remote_ip_prefix: 0.0.0.0/0,
          protocol: tcp,
          port_range_min: 80,
          port_range_max: 80},
          {remote_ip_prefix: 0.0.0.0/0,
          protocol: tcp,
          port_range_min: 443,
          port_range_max: 443},
          {remote_ip_prefix: 0.0.0.0/0,
          protocol: tcp,
          port_range_min: 8140,
          port_range_max: 8140},
          {remote_ip_prefix: 0.0.0.0/0,
          protocol: icmp}]

outputs:
  instance_private_ip_puppet:
    description: Private IP address of puppet server
    value: { get_attr: [puppet-server, networks, {get_param: net}, 0] }
  instance_public_ip_puppet:
    description: Public IP address of agent server
    value: { get_attr: [puppet-server, networks, {get_param: net}, 1] }
  instance_keypair:
    description: SSH Key-Pair to be used to access the instances
    value: { get_param: key_name }
  instance_rootpw:
    description: Root password for both servers
    value: { get_param: root_password }
  instance_private_ip_testagent:
    description: Private IP address of puppetagent test server
    value: { get_attr: [puppet-agent-test, networks, {get_param: net}, 0] }

About mark

At work, been working on Tandems for around 30yrs (programming + sysadmin), plus AIX and Solaris sysadmin also thrown in during the last 20yrs; also about 5yrs on MVS (mainly operations and automation but also smp/e work). At home I have been using linux for decades. Programming background is commercially in TAL/COBOL/SCOBOL/C(Tandem); 370 assembler(MVS); C, perl and shell scripting in *nix; and Microsoft Macro Assembler(windows).
This entry was posted in OpenStack, Unix. Bookmark the permalink.