Merge branch 'develop' into neoloc/grafana

This commit is contained in:
2024-06-01 14:47:06 +10:00
250 changed files with 6676 additions and 876 deletions
-27
View File
@@ -1,27 +0,0 @@
# frozen_string_literal: true
# arpa_fact.rb
require 'facter'
Facter.add(:arpa) do
setcode do
arpa_info = {}
Facter.value(:networking)['interfaces'].each do |interface_name, values|
next unless values.key?('ip')
ip_address = values['ip']
reversed_ip_parts = ip_address.split('.').reverse
addr = "#{reversed_ip_parts.join('.')}.in-addr.arpa"
trimmed_ip_parts = reversed_ip_parts[1..]
zone = "#{trimmed_ip_parts.join('.')}.in-addr.arpa"
arpa_info[interface_name] = {
'zone' => zone,
'addr' => addr
}
end
arpa_info
end
end
-14
View File
@@ -1,14 +0,0 @@
# frozen_string_literal: true
# create an enc_role_path fact from enc_role, to be used by hiera.yaml
#
# roles::infra::dns::resolver becomes roles/infra/dns/resolver
Facter.add(:enc_role_path) do
setcode do
enc_role = Facter.value(:enc_role)
if enc_role
enc_role_path = enc_role.gsub('::', '/')
enc_role_path
end
end
end
@@ -1,15 +0,0 @@
# frozen_string_literal: true
# split the enc_role fact into different tiers
#
# e.g.
# enc_role_tier2: roles::infra::dns::resolver -> infra
Facter.add(:enc_role_tier1) do
setcode do
role = Facter.value(:enc_role)
if role
parts = role.split('::')
parts[1] if parts.size > 1
end
end
end
@@ -1,14 +0,0 @@
# frozen_string_literal: true
# split the enc_role fact into different tiers
# e.g.
# enc_role_tier2: roles::infra::dns::resolver -> dns
Facter.add(:enc_role_tier2) do
setcode do
role = Facter.value(:enc_role)
if role
parts = role.split('::')
parts[2] if parts.size > 2
end
end
end
@@ -1,14 +0,0 @@
# frozen_string_literal: true
# split the enc_role fact into different tiers
# e.g.
# enc_role_tier3: roles::infra::dns::resolver -> resolver
Facter.add(:enc_role_tier3) do
setcode do
role = Facter.value(:enc_role)
if role
parts = role.split('::')
parts[3] if parts.size > 3
end
end
end
@@ -1,11 +0,0 @@
# frozen_string_literal: true
# create a boolean for when the mariadb service is active
require 'English'
Facter.add('mariadb_active') do
setcode do
system('systemctl is-active --quiet mariadb')
$CHILD_STATUS.exitstatus.zero?
end
end
@@ -1,22 +0,0 @@
# frozen_string_literal: true
# check if the /etc/my.cnf.d/server.cnf file exists,
# open it and search for the 'datadir =' option
# store the datadir value as this fact
require 'facter'
Facter.add('mariadb_datapath') do
setcode do
if File.exist?('/etc/my.cnf.d/server.cnf')
datadir = nil
File.foreach('/etc/my.cnf.d/server.cnf') do |line|
match = line.match(/^\s*datadir\s*=\s*(.+)\s*$/)
if match
datadir = match[1].strip
break
end
end
datadir
end
end
end
@@ -1,16 +0,0 @@
# frozen_string_literal: true
# check if the mariadb server exists
# check if the mariadb_datapath fact exists, else set /var/lib/mysql as the datapath
# check if the galera grastate.dat file exists, identifying if galera is boostrapped
require 'facter'
if system('systemctl is-active --quiet mariadb')
Facter.add('mariadb_galera_active') do
setcode do
mariadb_datapath = Facter.value(:mariadb_datapath) || '/var/lib/mysql'
File.exist?("#{mariadb_datapath}/grastate.dat")
end
end
end
@@ -1,8 +0,0 @@
# frozen_string_literal: true
# create boolean for if mariadb is installed based of the default service file
Facter.add('mariadb_installed') do
setcode do
File.exist?('/usr/lib/systemd/system/mariadb.service')
end
end
-21
View File
@@ -1,21 +0,0 @@
# frozen_string_literal: true
# skip if mysql isnt installed or active
if system('which mysql > /dev/null 2>&1') && system('systemctl is-active --quiet mariadb')
# export mysql wsrep status
wsrep_status = `mysql -e "SHOW STATUS LIKE 'wsrep%';"`
# loop over the output
wsrep_status.each_line do |line|
# skip the line unless it starts with 'wsrep_'
next unless line.match(/^wsrep_/)
key, value = line.split("\t")
Facter.add("mysql_#{key.strip}") do
setcode do
value.strip
end
end
end
end
+9 -8
View File
@@ -1,15 +1,16 @@
# create the sysadmin user
class profiles::accounts::sysadmin(
String $password,
Array[String] $sshkeys = [],
){
profiles::base::account {'sysadmin':
username => 'sysadmin',
uid => 1000,
gid => 1000,
groups => ['wheel'],
sshkeys => $sshkeys,
sudo_rules => ['sysadmin ALL=(ALL) NOPASSWD:ALL'],
password => '',
ignore_pass => true,
username => 'sysadmin',
uid => 1000,
gid => 1000,
groups => ['adm', 'admins', 'systemd-journal'],
sshkeys => $sshkeys,
sudo_rules => ['sysadmin ALL=(ALL) NOPASSWD:ALL'],
password => $password,
require => Group['admins'],
}
}
+1 -11
View File
@@ -30,27 +30,17 @@ class profiles::apt::puppet7 (
Array[String] $managed_repos,
String $mirror,
String $repo,
String $dist,
) {
$codename = $facts['os']['distro']['codename']
if 'puppet7' in $managed_repos {
$puppet_source = "${mirror}/${repo}-release-${dist}.deb"
# Install the puppet release using dpkg
package { "${repo}-${dist}":
ensure => installed,
name => "${repo}-release",
provider => dpkg,
source => $puppet_source,
}
# deb http://apt.puppet.com bullseye puppet7
apt::source { 'puppet7':
location => $mirror,
repos => $repo,
release => $dist,
release => $codename,
include => {
'src' => false,
'deb' => true,
+53 -44
View File
@@ -3,55 +3,64 @@ class profiles::base (
Array $puppet_servers,
) {
case $facts['os']['family'] {
'RedHat': {
include profiles::yum::global
include profiles::firewall::firewalld
# run a limited set of classes on the first run aimed at bootstrapping the new node
if $facts['firstrun'] {
include profiles::firstrun::init
}else{
# install the vault ca first
include profiles::pki::vaultca
# manage the puppet agent
include profiles::puppet::agent
# manage puppet clients
if ! member($puppet_servers, $trusted['certname']) {
include profiles::puppet::client
}
'Debian': {
include profiles::apt::global
# include the base profiles
include profiles::base::repos
include profiles::packages
include profiles::base::facts
include profiles::base::motd
include profiles::base::scripts
include profiles::base::hosts
include profiles::base::groups
include profiles::base::root
include profiles::accounts::sysadmin
include profiles::ntp::client
include profiles::dns::base
include profiles::pki::vault
include profiles::cloudinit::init
include profiles::metrics::default
include profiles::helpers::node_lookup
include profiles::consul::client
# include the python class
class { 'python':
manage_python_package => true,
manage_venv_package => true,
manage_pip_package => true,
use_epel => false,
}
default: {
fail("Unsupported OS family ${facts['os']['family']}")
# all hosts will have sudo applied
class { 'sudo':
secure_path => '/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin:/opt/puppetlabs/bin'
}
}
# manage the puppet agent
include profiles::puppet::agent
# manage virtualised guest agents
if $::facts['is_virtual'] and $::facts['dmi']['manufacturer'] == 'QEMU' {
include profiles::qemu::agent
}
# manage puppet clients
if ! member($puppet_servers, $trusted['certname']) {
include profiles::puppet::client
}
# include classes from hiera
lookup('hiera_classes', Array[String], 'unique').include
# include the base profiles
include profiles::packages::base
include profiles::base::facts
include profiles::base::motd
include profiles::base::scripts
include profiles::base::hosts
include profiles::accounts::sysadmin
include profiles::ntp::client
include profiles::dns::base
include profiles::cloudinit::init
include profiles::metrics::default
include profiles::helpers::node_lookup
# include the python class
class { 'python':
manage_python_package => true,
manage_venv_package => true,
manage_pip_package => true,
use_epel => false,
}
# all hosts will have sudo applied
class { 'sudo':
secure_path => '/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/sbin:/usr/local/bin:/opt/puppetlabs/bin'
}
# manage virtualised guest agents
if $::facts['is_virtual'] and $::facts['dmi']['manufacturer'] == 'QEMU' {
include profiles::qemu::agent
# specifc ordering constraints
Class['profiles::pki::vaultca']
-> Class['profiles::base::repos']
-> Class['profiles::packages']
}
}
+2 -1
View File
@@ -11,6 +11,7 @@
#
class profiles::base::datavol (
Enum['present', 'absent'] $ensure = 'present',
Enum['present', 'absent', 'mounted'] $mountstate = 'mounted',
Enum['ext2', 'ext3', 'ext4', 'xfs', 'btrfs'] $fstype = 'xfs',
String $vg = 'datavg',
String $pv = '/dev/vdb',
@@ -63,7 +64,7 @@ class profiles::base::datavol (
# Ensure the logical volume is mounted at the desired location
mount { $mount:
ensure => $ensure,
ensure => $mountstate,
device => "/dev/${vg}/${lv}",
fstype => $fstype,
options => $mount_options.join(','),
+19 -9
View File
@@ -12,18 +12,28 @@ class profiles::base::facts {
mode => '0755',
}
# facts to create
# cleanup old facts files
$fact_list = [ 'enc_role', 'enc_env' ]
# Manage the external fact file with content from the template
$fact_list.each | String $item | {
file { "${facts_d_path}/${item}.txt":
ensure => file,
owner => 'root',
group => 'root',
mode => '0644',
content => template("profiles/base/facts/${item}.erb"),
require => File[$facts_d_path],
ensure => absent,
}
}
# ensure the path to the custom store exists
file { '/root/.cache':
ensure => directory,
owner => 'root',
group => 'root',
mode => '0750',
}
# create the file that will be read
file { '/root/.cache/custom_facts.yaml':
ensure => file,
owner => 'root',
group => 'root',
mode => '0644',
content => template('profiles/base/facts/custom_facts.yaml.erb'),
}
}
+12
View File
@@ -0,0 +1,12 @@
# profiles::base::groups
# simple group management
class profiles::base::groups (
Hash $local = {},
) {
$local.each |$group, $data| {
group { $group:
name => $group,
* => $data,
}
}
}
+2
View File
@@ -7,6 +7,8 @@ class profiles::base::motd (
String $nic = $facts['networking']['primary'],
String $os_name = $facts['os']['name'],
String $os_release = $facts['os']['release']['full'],
String $location = "${facts['country']}-${facts['region']}",
String $env = $facts['environment'],
) {
# Use the regsubst function to remove the 'roles::' prefix from the role name
+16
View File
@@ -0,0 +1,16 @@
# profiles::base::repos
class profiles::base::repos {
# manage package repositories
case $facts['os']['family'] {
'RedHat': {
include profiles::yum::global
include profiles::firewall::firewalld
}
'Debian': {
include profiles::apt::global
}
default: {
fail("Unsupported OS family ${facts['os']['family']}")
}
}
}
+13
View File
@@ -0,0 +1,13 @@
# manage the root user
class profiles::base::root {
# TODO
# for now, add some root directories
file {'/root/.config':
ensure => directory,
owner => 'root',
group => 'root',
mode => '0600',
}
}
+77
View File
@@ -0,0 +1,77 @@
# profiles::cobbler::config
class profiles::cobbler::config {
include profiles::cobbler::params
$default_password_crypted = $profiles::cobbler::params::default_password_crypted
$httpd_ssl_certificate = $profiles::cobbler::params::httpd_ssl_certificate
$httpd_ssl_privatekey = $profiles::cobbler::params::httpd_ssl_privatekey
$pxe_just_once = $profiles::cobbler::params::pxe_just_once
$is_cobbler_master = $profiles::cobbler::params::is_cobbler_master
$service_cname = $profiles::cobbler::params::service_cname
$next_server = $profiles::cobbler::params::next_server
$server = $profiles::cobbler::params::server
# manage the cobbler settings file
file { '/etc/cobbler/settings.yaml':
ensure => 'file',
content => template('profiles/cobbler/settings.yaml.erb'),
group => 'apache',
owner => 'root',
mode => '0640',
require => Package['cobbler'],
notify => Service['cobblerd'],
}
# manage the debmirror config to meet cobbler requirements
file { '/etc/debmirror.conf':
ensure => 'file',
content => template('profiles/cobbler/debmirror.conf.erb'),
group => 'root',
owner => 'root',
mode => '0644',
require => Package['debmirror'],
}
# manage the httpd ssl configuration
file { '/etc/httpd/conf.d/ssl.conf':
ensure => 'file',
content => template('profiles/cobbler/httpd_ssl.conf.erb'),
group => 'root',
owner => 'root',
mode => '0644',
require => Package['httpd'],
notify => Service['httpd'],
}
# fix permissions in /var/lib/cobbler/web.ss
file {'/var/lib/cobbler/web.ss':
ensure => 'file',
group => 'root',
owner => 'apache',
mode => '0660',
require => Package['cobbler'],
notify => Service['cobblerd'],
}
# manage the main ipxe menu script
file { '/var/lib/tftpboot/main.ipxe':
ensure => 'file',
content => template('profiles/cobbler/main.ipxe.erb'),
owner => 'root',
group => 'root',
mode => '0644',
require => Package['cobbler'],
}
# export cnames for cobbler
if $is_cobbler_master {
profiles::dns::record { "${::facts['networking']['fqdn']}_${service_cname}_CNAME":
value => $::facts['networking']['hostname'],
type => 'CNAME',
record => "${service_cname}.",
zone => $::facts['networking']['domain'],
order => 10,
}
}
}
+17
View File
@@ -0,0 +1,17 @@
# profiles::cobbler::init
class profiles::cobbler::init (
) {
# wait for enc_role to be populated, needed for hieradata to match
if $facts['enc_role'] == 'roles::infra::cobbler::server' {
include profiles::cobbler::config
include profiles::cobbler::install
include profiles::cobbler::ipxebins
include profiles::cobbler::selinux
include profiles::cobbler::service
Class['profiles::cobbler::install']
-> Class['profiles::cobbler::config']
-> Class['profiles::cobbler::ipxebins']
-> Class['profiles::cobbler::selinux']
}
}
@@ -0,0 +1,34 @@
# profiles::cobbler::install
class profiles::cobbler::install {
include profiles::cobbler::params
$packages = $profiles::cobbler::params::packages
ensure_packages($packages, { ensure => 'present' })
# move the /var/www/cobbler directory to /data/cobbler
if ! $facts['cobbler_var_www_islink'] and ! $facts['cobbler_data_exists'] {
exec {'move_cobbler_data':
command => 'mv /var/www/cobbler /data/cobbler',
onlyif => 'test -d /var/www/cobbler',
path => ['/bin', '/usr/bin'],
before => Service['cobblerd'],
}
file { '/var/www/cobbler':
ensure => 'link',
target => '/data/cobbler',
require => Exec['move_cobbler_data'],
before => Service['httpd'],
notify => Service['httpd'],
}
}
if ! $facts['cobbler_var_www_exists'] and $facts['cobbler_data_exists'] {
file { '/var/www/cobbler':
ensure => 'link',
target => '/data/cobbler',
before => Service['httpd'],
notify => Service['httpd'],
}
}
}
@@ -0,0 +1,48 @@
# profiles::cobbler::ipxebins
class profiles::cobbler::ipxebins {
include profiles::cobbler::params
# download the custom undionly.kpxe file
# https://gist.github.com/rikka0w0/50895b82cbec8a3a1e8c7707479824c1
exec { 'download_undionly_kpxe':
command => 'wget -O /var/lib/tftpboot/undionly.kpxe http://repos.main.unkin.net/unkin/8/x86_64/os/Archives/undionly.kpxe',
path => ['/bin', '/usr/bin'],
creates => '/var/lib/tftpboot/undionly.kpxe',
}
# set correct permissions ipxe boot image to tftpboot
file { '/var/lib/tftpboot/undionly.kpxe':
ensure => 'file',
owner => 'root',
group => 'root',
mode => '0644',
require => [
Package['ipxe-bootimgs'],
Package['cobbler'],
Exec['download_undionly_kpxe']
],
}
# download the custom ipxe.efi file
# https://gist.github.com/rikka0w0/50895b82cbec8a3a1e8c7707479824c1
exec { 'download_ipxe_efi':
command => 'wget -O /var/lib/tftpboot/ipxe.efi http://repos.main.unkin.net/unkin/8/x86_64/os/Archives/ipxe.efi',
path => ['/bin', '/usr/bin'],
creates => '/var/lib/tftpboot/ipxe.efi',
}
# set correct permissions ipxe boot image to tftpboot
file { '/var/lib/tftpboot/ipxe.efi':
ensure => 'file',
owner => 'root',
group => 'root',
mode => '0644',
require => [
Package['ipxe-bootimgs'],
Package['cobbler'],
Exec['download_ipxe_efi']
],
}
}
+25
View File
@@ -0,0 +1,25 @@
# profiles::cobbler::params
class profiles::cobbler::params (
Stdlib::Absolutepath $httpd_ssl_certificate = '/etc/pki/tls/vault/certificate.crt',
Stdlib::Absolutepath $httpd_ssl_privatekey = '/etc/pki/tls/vault/private.key',
Stdlib::Absolutepath $tftpboot_path = '/var/lib/tftpboot/boot',
Stdlib::Fqdn $service_cname = $facts['networking']['fqdn'],
String $default_password_crypted = 'changeme',
String $server = $::facts['networking']['ip'],
String $next_server = $::facts['networking']['ip'],
Boolean $pxe_just_once = true,
Boolean $is_cobbler_master = false,
Array $packages = [
'cobbler',
'cobbler3.2-web',
'httpd',
'syslinux',
'dnf-plugins-core',
'debmirror',
'pykickstart',
'fence-agents',
'selinux-policy-devel',
'ipxe-bootimgs',
]
){
}
@@ -0,0 +1,48 @@
# profiles::cobbler::selinux
class profiles::cobbler::selinux inherits profiles::cobbler::params {
include profiles::cobbler::params
$tftpboot_path = $profiles::cobbler::params::tftpboot_path
# manage selinux requirements for cobbler
if $::facts['os']['selinux']['config_mode'] == 'enforcing' {
$enable_sebooleans = [
'httpd_can_network_connect_cobbler',
'httpd_serve_cobbler_files',
'cobbler_can_network_connect'
]
$enable_sebooleans.each |$bool| {
selboolean { $bool:
value => on,
persistent => true,
}
}
selinux::fcontext { $tftpboot_path:
ensure => 'present',
seltype => 'cobbler_var_lib_t',
pathspec => "${tftpboot_path}(/.*)?",
}
selinux::fcontext { '/data/cobbler':
ensure => 'present',
seltype => 'cobbler_var_lib_t',
pathspec => '/data/cobbler(/.*)?',
}
exec { "restorecon_${tftpboot_path}":
path => ['/bin', '/usr/bin', '/sbin', '/usr/sbin'],
command => "restorecon -Rv ${tftpboot_path}",
refreshonly => true,
subscribe => Selinux::Fcontext[$tftpboot_path],
}
exec { 'restorecon_/data/cobbler':
path => ['/bin', '/usr/bin', '/sbin', '/usr/sbin'],
command => 'restorecon -Rv /data/cobbler',
refreshonly => true,
subscribe => Selinux::Fcontext['/data/cobbler'],
}
}
}
@@ -0,0 +1,17 @@
# profiles::cobbler::service
class profiles::cobbler::service inherits profiles::cobbler::params {
# ensure cobblerd is running
service {'cobblerd':
ensure => 'running',
enable => true,
require => File['/etc/cobbler/settings.yaml'],
}
# ensure httpd is running
service {'httpd':
ensure => 'running',
enable => true,
require => File['/etc/httpd/conf.d/ssl.conf'],
}
}
+87
View File
@@ -0,0 +1,87 @@
# profiles::consul::client
class profiles::consul::client (
String $secret_id_salt = '',
Stdlib::Fqdn $consul_hostname = 'consul.service.consul',
Enum['http','https'] $consul_protocol = 'http',
Stdlib::Port $consul_port = 8500,
String $consul_api_token = lookup('profiles::consul::server::acl_tokens_initial_management'),
Boolean $members_lookup = false,
String $members_role = undef,
Array $consul_servers = [],
Stdlib::Absolutepath $data_dir = '/opt/consul',
Array[Hash] $node_rules = [],
) {
if $facts['enc_role'] != $members_role {
# set a datacentre/cluster name
$consul_cluster = "${::facts['country']}-${::facts['region']}"
# if lookup is enabled, find all the hosts in the specified role and create the servers_array
if $members_lookup {
# check that the role is also set
unless !($members_role == undef) {
fail("members_role must be provided for ${title} when members_lookup is True")
}
# if it is, find hosts, sort them so they dont cause changes every run
$servers_array = sort(query_nodes("enc_role='${members_role}' and region='${::facts['region']}'", 'networking.fqdn'))
# else use provided array from params
}else{
$servers_array = $consul_servers
}
# deploy the consul agent
class { 'consul':
config_hash => {
'data_dir' => $data_dir,
'datacenter' => $consul_cluster,
'log_level' => 'INFO',
'node_name' => $facts['networking']['fqdn'],
'retry_join' => $servers_array,
'bind_addr' => $::facts['networking']['ip'],
'advertise_addr' => $::facts['networking']['ip'],
'acl' => {
tokens => {
default => fqdn_uuid("${facts['networking']['fqdn']}-${secret_id_salt}")
}
}
},
}
}
# Create ACL policy that allows nodes to update themselves and read others
consul_policy { $facts['networking']['hostname']:
description => "${facts['networking']['fqdn']} puppet-generated-policy",
rules => $node_rules,
acl_api_token => $consul_api_token,
hostname => $consul_hostname,
protocol => $consul_protocol,
port => $consul_port,
}
consul_token { $facts['networking']['hostname']:
accessor_id => fqdn_uuid($facts['networking']['fqdn']),
description => "${facts['networking']['fqdn']} puppet-generated-token",
policies_by_name => [$facts['networking']['hostname']],
acl_api_token => $consul_api_token,
secret_id => fqdn_uuid("${facts['networking']['fqdn']}-${secret_id_salt}"),
hostname => $consul_hostname,
protocol => $consul_protocol,
port => $consul_port,
}
# ensure the consul token is saved for the root user
file {'/root/.config/consul_node_token':
ensure => file,
owner => 'root',
group => 'root',
mode => '0600',
content => Sensitive(fqdn_uuid("${facts['networking']['fqdn']}-${secret_id_salt}")),
require => File['/root/.config'],
}
}
@@ -0,0 +1,23 @@
# profiles::consul::policies
class profiles::consul::policies (
String $root_api_token = lookup('profiles::consul::server::acl_tokens_initial_management'),
) {
consul_policy { 'node_editor':
description => 'Policy to read/write all nodes puppet-generated-policy',
rules => [
{
'resource' => 'node',
'segment' => '',
'disposition' => 'write'
},
{
'resource' => 'node',
'segment' => '',
'disposition' => 'read'
}
],
acl_api_token => $root_api_token,
hostname => $facts['networking']['ip'],
}
}
@@ -0,0 +1,14 @@
# profile::consul::prepared_query
class profiles::consul::prepared_query (
String $root_api_token = lookup('profiles::consul::server::acl_tokens_initial_management'),
Hash $rules = {},
) {
$rules.each | $rule, $data | {
consul_prepared_query { $rule:
acl_api_token => $root_api_token,
hostname => $facts['networking']['ip'],
* => $data,
}
}
}
+158
View File
@@ -0,0 +1,158 @@
# profiles::consul::server
class profiles::consul::server (
Variant[
Undef,
String
] $gossip_key = undef,
Variant[
Undef,
String
] $primary_datacenter = undef,
Hash $acl = {},
Hash $ports = {},
Hash $addresses = {},
Boolean $members_lookup = false,
String $members_role = undef,
Array $consul_servers = [],
Boolean $enable_ui = true,
Boolean $enable_ui_config = true,
Boolean $manage_repo = false,
String $package_ensure = 'latest',
String $package_name = 'consul',
Integer $bootstrap_count = 1,
String $domain = 'consul',
Integer $raft_multiplier = 1,
Enum[
'allow',
'deny',
'extend-cache',
'async-cache'
] $acl_down_policy = 'extend-cache',
Enum[
'allow',
'deny'
] $acl_default_policy = 'deny',
Enum[
'url',
'package',
'docker',
'none'
] $install_method = 'package',
Stdlib::IP::Address $client_addr = '0.0.0.0',
Stdlib::Absolutepath $data_dir = '/opt/consul',
Stdlib::Absolutepath $bin_dir = '/usr/bin',
Boolean $disable_remote_exec = true,
Boolean $disable_update_check = true,
Boolean $join_remote_regions = false,
Array[String] $remote_regions = [],
) {
# wait for all attributes to be ready
if $facts['enc_role'] == $members_role {
# set a datacentre/cluster name
$consul_cluster = "${::facts['country']}-${::facts['region']}"
# if lookup is enabled, find all the hosts in the specified role and create the servers_array
if $members_lookup {
# check that the role is also set
unless !($members_role == undef) {
fail("members_role must be provided for ${title} when members_lookup is True")
}
# if it is, find hosts, sort them so they dont cause changes every run
$servers_array = sort(query_nodes("enc_role='${members_role}' and region='${::facts['region']}'", 'networking.fqdn'))
if $join_remote_regions {
# get all nodes in the members_role for each other region
$region_to_servers = $remote_regions.reduce({}) |$memo, $region| {
$servers = sort(query_nodes("enc_role='${members_role}' and region='${region}'", 'networking.fqdn'))
$memo + { $region => $servers }
}
# sort and flatten the regions into a single array of fqdns
$remote_servers_array = sort(flatten($region_to_servers.values))
} else {
# else just send an empty array
$remote_servers_array = []
}
# else use provided array from params
}else{
$servers_array = $consul_servers
}
# if $data_dir starts with /data, ensure the data mount exists
if ($data_dir.stdlib::start_with('/data') and $::facts['mountpoints']['/data']) or ! $data_dir.stdlib::start_with('/data') {
# install consul
class { 'consul':
install_method => $install_method,
manage_repo => $manage_repo,
package_name => $package_name,
package_ensure => $package_ensure,
bin_dir => $bin_dir,
config_hash => {
'primary_datacenter' => $primary_datacenter,
'acl' => $acl,
'ports' => $ports,
'addresses' => $addresses,
'disable_remote_exec' => $disable_remote_exec,
'disable_update_check' => $disable_update_check,
'domain' => $domain,
'bootstrap_expect' => $bootstrap_count,
'client_addr' => '0.0.0.0',
'data_dir' => $data_dir,
'datacenter' => $consul_cluster,
'log_level' => 'INFO',
'node_name' => $::facts['networking']['fqdn'],
'server' => true,
'ui' => $enable_ui,
'ui_config' => { 'enabled' => $enable_ui_config },
'performance' => { 'raft_multiplier' => $raft_multiplier },
'bind_addr' => $::facts['networking']['ip'],
'advertise_addr' => $::facts['networking']['ip'],
'retry_join' => $servers_array,
'retry_join_wan' => $remote_servers_array,
},
}
}
}
# consul before extra services
if defined(Class['consul']) {
# include nginx, policies and tokens
include profiles::nginx::simpleproxy
include profiles::consul::policies
include profiles::consul::tokens
include profiles::consul::prepared_query
# get the dns port from the $ports hash, otherwise use the default
$dns_port = pick($ports['dns'], 8600)
# install dnsmasq
package { 'dnsmasq':
ensure => installed,
}
# create the 10-consul.conf file
file { '/etc/dnsmasq.d/10-consul.conf':
ensure => file,
owner => 'root',
group => 'root',
mode => '0644',
content => "server=/${domain}/${::facts['networking']['ip']}#${dns_port}\n",
require => Package['dnsmasq'],
notify => Service['dnsmasq'],
}
# ensure dnsmasq service is running and enabled at boot
service { 'dnsmasq':
ensure => running,
enable => true,
subscribe => File['/etc/dnsmasq.d/10-consul.conf'], # Restart dnsmasq if the consul config changes
}
}
}
+13
View File
@@ -0,0 +1,13 @@
# profiles::consul::tokens
class profiles::consul::tokens (
String $root_api_token = lookup('profiles::consul::server::acl_tokens_initial_management'),
){
consul_token { 'node_editor':
accessor_id => lookup('profiles::consul::token::node_editor::accessor_id'),
policies_by_name => ['node_editor'],
acl_api_token => $root_api_token,
secret_id => lookup('profiles::consul::token::node_editor::secret_id'),
hostname => $facts['networking']['ip'],
}
}
+12 -1
View File
@@ -8,7 +8,9 @@ class profiles::defaults {
}
Package {
ensure => present,
ensure => present,
require => Class['profiles::base::repos']
}
File {
@@ -27,4 +29,13 @@ class profiles::defaults {
ensure => present,
shell => '/bin/bash',
}
Yumrepo {
ensure => 'present',
enabled => 1,
gpgcheck => 1,
mirrorlist => 'absent',
require => Class['profiles::pki::vaultca'],
notify => Exec['dnf_makecache'],
}
}
+39
View File
@@ -0,0 +1,39 @@
# profiles::dhcp::server
class profiles::dhcp::server (
Array[Stdlib::Host] $ntpservers = [
'0.au.pool.ntp.org',
'1.au.pool.ntp.org',
'2.au.pool.ntp.org',
'3.au.pool.ntp.org'
],
Array[String] $interfaces = ['eth0'],
Integer $default_lease_time = 86400,
Array[String] $globaloptions = [],
Hash $pools = {},
Hash $classes = {},
){
if $facts['enc_role'] == 'roles::infra::dhcp::server' {
class { 'dhcp':
service_ensure => running,
interfaces => $interfaces,
ntpservers => $ntpservers,
default_lease_time => $default_lease_time,
globaloptions => $globaloptions
}
# if pools, import them
$pools.each | $name, $data | {
dhcp::pool { $name:
* => $data,
}
}
# if classes, import them
$classes.each | $name, $data | {
dhcp::dhcp_class { $name:
* => $data,
}
}
}
}
+17 -6
View File
@@ -3,13 +3,24 @@ class profiles::dns::base (
String $ns_role = undef,
Array $search = [],
Array $nameservers = ['8.8.8.8', '1.1.1.1'],
Enum[
'all',
'region',
'country'
] $use_ns = 'all',
){
# install bind_utils
include bind::updater
# if ns_role is set, find all hosts matching that enc_role
if $ns_role == undef {
$nameserver_array = $nameservers
}else{
$nameserver_array = query_nodes("enc_role='${ns_role}'", 'networking.ip')
$nameserver_array = $ns_role ? {
undef => $nameservers,
default => $use_ns ? {
'all' => query_nodes("enc_role='${ns_role}'", 'networking.ip'),
'region' => query_nodes("enc_role='${ns_role}' and region=${facts['region']}", 'networking.ip'),
'country' => query_nodes("enc_role='${ns_role}' and country=${facts['country']}", 'networking.ip'),
}
}
# if search is undef, fallback to domainname from facts
@@ -21,8 +32,8 @@ class profiles::dns::base (
# include resolvconf class
class { 'profiles::dns::resolvconf':
nameservers => $nameserver_array,
search_domains => $search_array,
nameservers => sort($nameserver_array),
search_domains => sort($search_array),
}
# export dns records for client
+20 -2
View File
@@ -1,6 +1,5 @@
# profiles::dns::master authoritative service
class profiles::dns::master (
Array[String] $nameservers,
Stdlib::AbsolutePath $basedir,
Hash $acls = {},
Hash $zones = {},
@@ -13,8 +12,27 @@ class profiles::dns::master (
String $owner = 'root',
String $group = 'named',
Boolean $dnssec = false,
Variant[String, Undef] $ns_role = undef,
Enum['all', 'region', 'country'] $use_ns = 'all',
){
# if ns_role is set, find all hosts matching that enc_role, otherwise use the current host
$nameservers_array = $ns_role ? {
undef => [$facts['networking']['fqdn']],
default => $use_ns ? {
'all' => query_nodes("enc_role='${ns_role}'", 'networking.fqdn'),
'region' => query_nodes("enc_role='${ns_role}' and region=${facts['region']}", 'networking.fqdn'),
'country' => query_nodes("enc_role='${ns_role}' and country=${facts['country']}", 'networking.fqdn'),
}
}
# if nameservers is empty, use the current host, otherwise use nameservers_array as nameservers
$nameservers = empty($nameservers_array) ? {
true => [$facts['networking']['fqdn']],
false => $nameservers_array,
default => [$facts['networking']['fqdn']],
}
class {'profiles::dns::server':
acls => $acls,
zones => $zones,
@@ -37,7 +55,7 @@ class profiles::dns::master (
profiles::dns::zone { $name:
zone => $data['domain'],
basedir => $basedir,
nameservers => $nameservers,
nameservers => sort($nameservers),
owner => $owner,
group => $group,
before => Bind::Zone[$name]
+12
View File
@@ -0,0 +1,12 @@
# profiles::edgecache::init
class profiles::edgecache::init {
if $facts['enc_role'] == 'roles::infra::storage::edgecache' {
include profiles::edgecache::nginx
include profiles::edgecache::selinux
Class['profiles::edgecache::nginx']
-> Class['profiles::edgecache::selinux']
}
}
+129
View File
@@ -0,0 +1,129 @@
# profiles::edgecache::nginx
class profiles::edgecache::nginx {
include profiles::edgecache::params
$data_root = $profiles::edgecache::params::data_root
$nginx_vhost = $profiles::edgecache::params::nginx_vhost
$nginx_aliases = $profiles::edgecache::params::nginx_aliases
$nginx_port = $profiles::edgecache::params::nginx_port
$nginx_ssl_port = $profiles::edgecache::params::nginx_ssl_port
$nginx_listen_mode = $profiles::edgecache::params::nginx_listen_mode
$nginx_cert_type = $profiles::edgecache::params::nginx_cert_type
$nginx_resolvers_enable = $profiles::edgecache::params::nginx_resolvers_enable
$nginx_resolvers_ipv4only = $profiles::edgecache::params::nginx_resolvers_ipv4only
# select the certificates to use based on cert type
case $nginx_cert_type {
'puppet': {
$selected_ssl_cert = "/etc/pki/tls/puppet/${facts['networking']['fqdn']}.crt"
$selected_ssl_key = "/etc/pki/tls/puppet/${facts['networking']['fqdn']}.key"
}
'vault': {
$selected_ssl_cert = '/etc/pki/tls/vault/certificate.crt'
$selected_ssl_key = '/etc/pki/tls/vault/private.key'
}
default: {
# enum param prevents this ever being reached
}
}
# set variables based on the listen_mode
case $nginx_listen_mode {
'http': {
$enable_ssl = false
$ssl_cert = undef
$ssl_key = undef
$listen_port = $nginx_port
$listen_ssl_port = undef
$extras_hash = {}
}
'https': {
$enable_ssl = true
$ssl_cert = $selected_ssl_cert
$ssl_key = $selected_ssl_key
$listen_port = $nginx_ssl_port
$listen_ssl_port = $nginx_ssl_port
$extras_hash = {
'subscribe' => [File[$ssl_cert], File[$ssl_key]],
}
}
'both': {
$enable_ssl = true
$ssl_cert = $selected_ssl_cert
$ssl_key = $selected_ssl_key
$listen_port = $nginx_port
$listen_ssl_port = $nginx_ssl_port
$extras_hash = {
'subscribe' => [File[$ssl_cert], File[$ssl_key]],
}
}
default: {
# enum param prevents this ever being reached
}
}
if $nginx_resolvers_ipv4only and $nginx_resolvers_enable {
$resolvers = $facts['nameservers'].join(' ')
file { '/etc/nginx/conf.d/resolvers.conf':
ensure => file,
content => "resolver ${resolvers} ipv4=on;\n",
}
}
# set the server_names
$server_names = unique([$facts['networking']['fqdn'], $nginx_vhost] + $nginx_aliases)
# define the default parameters for the nginx server
$defaults = {
'listen_port' => $listen_port,
'server_name' => $server_names,
'use_default_location' => true,
'access_log' => "/var/log/nginx/${nginx_vhost}_access.log",
'error_log' => "/var/log/nginx/${nginx_vhost}_error.log",
'www_root' => "${data_root}/pub",
'autoindex' => 'on',
'ssl' => $enable_ssl,
'ssl_cert' => $ssl_cert,
'ssl_key' => $ssl_key,
'ssl_port' => $listen_ssl_port,
}
# ensure the requires directories exist
$profiles::edgecache::params::directories.each |$name,$data| {
file { $name:
ensure => 'directory',
before => Class['nginx'],
mode => '0775',
* => $data,
}
}
# merge the hashes conditionally
$nginx_parameters = merge($defaults, $extras_hash)
# manage the nginx class
class { 'nginx':
proxy_cache_path => {
"${data_root}/cache" => 'cache:128m',
},
proxy_cache_levels => '1:2',
proxy_cache_keys_zone => 'cache:128m',
proxy_cache_max_size => '30000m',
proxy_cache_inactive => '60d',
proxy_temp_path => "${data_root}/cache_tmp",
}
# create the nginx vhost with the merged parameters
create_resources('nginx::resource::server', { $nginx_vhost => $nginx_parameters })
# create location mirrors
$profiles::edgecache::params::mirrors.each |$name, $data| {
nginx::resource::location { "${nginx_vhost}_${name}":
server => $nginx_vhost,
ssl => true,
ssl_only => false,
* => $data,
}
}
}
@@ -0,0 +1,15 @@
# profiles::edgecache::params
class profiles::edgecache::params (
Stdlib::Absolutepath $data_root = '/data/edgecache',
Stdlib::Fqdn $nginx_vhost = $facts['networking']['fqdn'],
Array[Stdlib::Host] $nginx_aliases = [],
Stdlib::Port $nginx_port = 80,
Stdlib::Port $nginx_ssl_port = 443,
Enum['http','https','both'] $nginx_listen_mode = 'http',
Enum['puppet', 'vault'] $nginx_cert_type = 'vault',
Boolean $nginx_resolvers_enable = false,
Boolean $nginx_resolvers_ipv4only = false,
Hash $directories = {},
Hash $mirrors = {},
){
}
@@ -0,0 +1,56 @@
# profiles::edgecache::selinux
class profiles::edgecache::selinux {
include profiles::edgecache::params
$data_root = $profiles::edgecache::params::data_root
if $::facts['os']['selinux']['config_mode'] == 'enforcing' {
# set httpd_sys_content_t to all files under the www_root
selinux::fcontext { "${data_root}/pub":
ensure => 'present',
seltype => 'httpd_sys_content_t',
pathspec => "${data_root}/pub(/.*)?",
}
# set httpd_sys_rw_content_t to all files under the cache_root
selinux::fcontext { "${data_root}/cache":
ensure => 'present',
seltype => 'httpd_sys_rw_content_t',
pathspec => "${data_root}/cache(/.*)?",
}
selinux::fcontext { "${data_root}/cache_tmp":
ensure => 'present',
seltype => 'httpd_sys_rw_content_t',
pathspec => "${data_root}/cache_tmp(/.*)?",
}
# make sure we can connect to other hosts
selboolean { 'httpd_can_network_connect':
persistent => true,
value => 'on',
}
exec { "restorecon_${data_root}/pub":
path => ['/bin', '/usr/bin', '/sbin', '/usr/sbin'],
command => "restorecon -Rv ${data_root}/pub",
refreshonly => true,
subscribe => Selinux::Fcontext["${data_root}/pub"],
}
exec { "restorecon_${data_root}/cache":
path => ['/bin', '/usr/bin', '/sbin', '/usr/sbin'],
command => "restorecon -Rv ${data_root}/cache",
refreshonly => true,
subscribe => Selinux::Fcontext["${data_root}/cache"],
}
exec { "restorecon_${data_root}/cache_tmp":
path => ['/bin', '/usr/bin', '/sbin', '/usr/sbin'],
command => "restorecon -Rv ${data_root}/cache_tmp",
refreshonly => true,
subscribe => Selinux::Fcontext["${data_root}/cache_tmp"],
}
}
}
@@ -0,0 +1,19 @@
# profiles::firstrun::complete
class profiles::firstrun::complete {
file { '/root/.cache':
ensure => 'directory',
owner => 'root',
group => 'root',
mode => '0750',
}
file {'/root/.cache/puppet_firstrun_complete':
ensure => 'file',
owner => 'root',
group => 'root',
mode => '0750',
content => 'firstrun completed',
require => File['/root/.cache'],
}
}
+20
View File
@@ -0,0 +1,20 @@
# profiles::firstrun::init
class profiles::firstrun::init {
# include the required CA certificates
include profiles::pki::vaultca
# fast install packages on the first run
include profiles::base::repos
include profiles::firstrun::packages
# mark the firstrun as done
include profiles::firstrun::complete
Class['profiles::defaults']
-> Class['profiles::pki::vaultca']
-> Class['profiles::base::repos']
-> Class['profiles::firstrun::packages']
-> Class['profiles::firstrun::complete']
}
@@ -0,0 +1,27 @@
# profiles::firstrun::packages
class profiles::firstrun::packages {
# include the correct package repositories, define the install_packages exec
case $facts['os']['family'] {
'RedHat': {
include profiles::yum::global
$install_command = 'dnf install -y'
}
'Debian': {
include profiles::apt::global
$install_command = 'apt-get install -y'
}
default: {
fail("Unsupported OS family ${facts['os']['family']}")
}
}
# get all the packages to install, and convert into a space separated list
$packages = hiera_array('profiles::packages::install', [])
$package_list = $packages.join(' ')
# install all the packages
exec { 'install_packages':
command => "${install_command} ${package_list}",
path => ['/bin', '/usr/bin'],
}
}
+55
View File
@@ -0,0 +1,55 @@
# profiles::gitea::init
class profiles::gitea::init (
String $mysql_pass = '',
String $lfs_jwt_secret = '',
) {
include profiles::nginx::simpleproxy
class { 'gitea':
ensure => '1.22.0',
checksum => 'a31086f073cb9592d28611394b2de3655db515d961e4fdcf5b549cb40753ef3d',
custom_configuration => {
'' => {
'APP_NAME' => 'Gitea',
'RUN_USER' => 'git',
'RUN_MODE' => 'prod',
},
'repository' => {
'ROOT' => '/data/gitea/repos',
'FORCE_PRIVATE' => false,
'MAX_CREATION_LIMIT' => -1,
'DISABLE_HTTP_GIT' => false,
'DEFAULT_BRANCH' => 'main',
'DEFAULT_PRIVATE' => 'last',
},
'ui' => {
'SHOW_USER_EMAIL' => false,
},
'server' => {
'PROTOCOL' => 'http',
'DOMAIN' => 'git.query.consul',
'ROOT_URL' => 'https://git.query.consul',
'HTTP_ADDR' => '0.0.0.0',
'HTTP_PORT' => 3000,
'START_SSH_SERVER' => false,
'SSH_DOMAIN' => 'git.query.consul',
'SSH_PORT' => 2222,
'SSH_LISTEN_HOST' => '0.0.0.0',
'OFFLINE_MODE' => true,
'APP_DATA_PATH' => '/var/lib/gitea/data',
'SSH_LISTEN_PORT' => 22,
},
'database' => {
'DB_TYPE' => 'mysql',
'HOST' => 'mariadb-prod.service.au-syd1.consul:3306',
'NAME' => 'gitea',
'USER' => 'gitea',
'PASSWD' => Sensitive($mysql_pass),
'SSL_MODE' => 'disable',
'PATH' => '/var/lib/gitea/data/gitea.db',
'LOG_SQL' => false,
},
}
}
}
@@ -0,0 +1,19 @@
# profiles::haproxy::backends
class profiles::haproxy::backends {
# set location_environment
$location_environment = "${facts['country']}-${facts['region']}-${facts['environment']}"
# for each backend:
$backends = lookup('profiles::haproxy::backends', Hash, 'deep', {})
$backends.each |$backend, $data| {
# create backend
haproxy::backend { $backend:
* => $data,
}
# collect exported resources
$tag = "${backend}_${location_environment}"
Haproxy::Balancermember <<| tag == $tag |>>
}
}
@@ -0,0 +1,19 @@
# profiles::haproxy::balancemember
define profiles::haproxy::balancemember (
String $service,
Array[Stdlib::Port] $ports,
Array $options = ['check'],
) {
$location_environment = "${facts['country']}-${facts['region']}-${facts['environment']}"
$balancemember_tag = "${service}_${location_environment}"
@@haproxy::balancermember { $title:
listening_service => $service,
ports => $ports,
server_names => $facts['networking']['hostname'],
ipaddresses => $facts['networking']['ip'],
options => $options,
tag => $balancemember_tag,
}
}
@@ -0,0 +1,18 @@
# profiles::haproxy::certlist
class profiles::haproxy::certlist (
Boolean $enabled = true,
Stdlib::Absolutepath $path = '/etc/haproxy/certificate.list',
Array[Stdlib::Absolutepath] $certificates = []
) {
if $enabled {
file { $path:
ensure => 'file',
owner => 'root',
group => 'root',
mode => '0600',
content => template('profiles/haproxy/certificate.list.erb')
}
}
}
+27
View File
@@ -0,0 +1,27 @@
# profiles::haproxy::dns
class profiles::haproxy::dns (
Array[Stdlib::Fqdn] $cnames = [],
Integer $order = 10,
){
# create an A record for each load balancer in a region
$location_environment = "${facts['country']}-${facts['region']}-${facts['environment']}"
profiles::dns::record { "${facts['networking']['fqdn']}_${location_environment}-halb_A":
value => $::facts['networking']['ip'],
type => 'A',
record => "${location_environment}-halb",
zone => $::facts['networking']['domain'],
order => $order,
}
# export cnames for haproxy applications
$cnames.each |$cname| {
profiles::dns::record { "${::facts['networking']['fqdn']}_${cname}_CNAME":
value => "${location_environment}-halb",
type => 'CNAME',
record => "${cname}.",
zone => $::facts['networking']['domain'],
order => $order,
}
}
}
@@ -0,0 +1,14 @@
# profiles::haproxy::frontends
class profiles::haproxy::frontends {
# for each frontend:
$frontends = lookup('profiles::haproxy::frontends', Hash, 'deep', {})
$frontends.each |$frontend, $data| {
# create frontends
haproxy::frontend { $frontend:
* => $data,
}
}
}
@@ -0,0 +1,19 @@
# profiles::haproxy::listeners
class profiles::haproxy::listeners {
# set location_environment
$location_environment = "${facts['country']}-${facts['region']}-${facts['environment']}"
# for each listener:
$listeners = lookup('profiles::haproxy::listeners', Hash, 'deep', {})
$listeners.each |$listen, $data| {
# create listener
haproxy::listen { $listen:
* => $data,
}
# collect exported resources
$tag = "${listen}_${location_environment}"
Haproxy::Balancermember <<| tag == $tag |>>
}
}
@@ -0,0 +1,19 @@
# the default status listener
class profiles::haproxy::ls_stats (
Stdlib::IP::Address $bind_addr = $facts['networking']['ip'],
Stdlib::Port $bind_port = 9090,
Array $bind_opts = [],
String $user = 'admin',
String $pass = 'admin',
) {
haproxy::listen { 'stats':
bind => { "${bind_addr}:${bind_port}" => $bind_opts },
options => {
'mode' => 'http',
'stats' => [
'uri /',
"auth ${user}:${pass}",
],
},
}
}
@@ -0,0 +1,13 @@
# profiles::haproxy::mappings
class profiles::haproxy::mappings {
# for each mapping:
$mappings = lookup('profiles::haproxy::mappings')
$mappings.each |$mapping, $data| {
# create mapping
haproxy::mapfile { $mapping:
* => $data,
}
}
}
@@ -0,0 +1,32 @@
# profiles::haproxy::selinux
class profiles::haproxy::selinux (
Array[String] $sebooleans = [],
Array[Stdlib::Port] $ports = [],
) {
# manage enforcing mode
include profiles::selinux::setenforce
# manage selinux requirements for haproxy
if $::facts['os']['selinux']['config_mode'] == 'enforcing' {
# set context for ports
$ports.each |$port| {
selinux::port { "haproxy_port_${port}":
ensure => 'present',
seltype => 'http_port_t',
protocol => 'tcp',
port => $port,
}
}
# enable sebooleans
$sebooleans.each |$bool| {
selboolean { $bool:
value => on,
persistent => true,
}
}
}
}
+63
View File
@@ -0,0 +1,63 @@
# configure a haproxy server
class profiles::haproxy::server (
Hash $globals = {},
Hash $defaults = {},
){
# default global/defaults arrays
$global_options = {
'log' => "${facts['networking']['ip']} local0",
'chroot' => '/var/lib/haproxy',
'pidfile' => '/var/run/haproxy.pid',
'maxconn' => '4000',
'user' => 'haproxy',
'group' => 'haproxy',
'daemon' => '',
'stats' => 'socket /var/lib/haproxy/stats',
}
$default_options = {
'log' => 'global',
'stats' => 'enable',
'option' => ['redispatch'],
'retries' => '3',
'timeout' => [
'http-request 10s',
'queue 1m',
'connect 10s',
'client 1m',
'server 1m',
'check 10s',
],
'maxconn' => '8000',
}
# merge the default globals/defaults with those provided as params
$merged_global_options = merge($global_options, $globals)
$merged_default_options = merge($default_options, $defaults)
# wait until enc_role matches haproxy enc_role
if $facts['enc_role'] == 'roles::infra::halb::haproxy' {
# manage selinux
include profiles::haproxy::selinux
# create the haproxy service/instance
class { 'haproxy':
global_options => $merged_global_options,
defaults_options => $merged_default_options,
require => Class['profiles::haproxy::selinux']
}
include profiles::haproxy::certlist # manage the certificate list file
include profiles::haproxy::mappings # manage the domain to backend mappings
include profiles::haproxy::ls_stats # default status listener
include profiles::haproxy::dns # manage dns for haproxy
include profiles::haproxy::frontends # create frontends
include profiles::haproxy::backends # create backends
include profiles::haproxy::listeners # create listeners
Class['profiles::haproxy::certlist']
-> Class['profiles::haproxy::dns']
-> Class['profiles::haproxy::mappings']
}
}
@@ -0,0 +1,77 @@
# profiles::helpers::certmanager
#
# wrapper class for python, pip and venv
class profiles::helpers::certmanager (
String $script_name = 'certmanager',
Stdlib::AbsolutePath $base_path = "/opt/${script_name}",
Stdlib::AbsolutePath $venv_path = "${base_path}/venv",
Stdlib::AbsolutePath $config_path = "${base_path}/config.yaml",
Hash $vault_config = {},
String $owner = 'root',
String $group = 'root',
Boolean $systempkgs = false,
String $version = 'system',
Array[String[1]] $packages = ['requests', 'pyyaml'],
){
if $::facts['python3_version'] {
$python_version = $version ? {
'system' => $::facts['python3_version'],
default => $version,
}
# ensure the base_path exists
file { $base_path:
ensure => directory,
mode => '0755',
owner => $owner,
group => $group,
}
# create a venv
python::pyvenv { $venv_path :
ensure => present,
version => $python_version,
systempkgs => $systempkgs,
venv_dir => $venv_path,
owner => $owner,
group => $group,
require => File[$base_path],
}
# install the required pip packages
$packages.each |String $package| {
python::pip { "${venv_path}_${package}":
ensure => present,
pkgname => $package,
virtualenv => $venv_path,
}
}
# create the script from a template
file { "${base_path}/${script_name}":
ensure => file,
mode => '0755',
content => template("profiles/helpers/${script_name}.erb"),
require => Python::Pyvenv[$venv_path],
}
# create the config from a template
file { $config_path:
ensure => file,
mode => '0660',
owner => 'puppet',
group => 'root',
content => Sensitive(template("profiles/helpers/${script_name}_config.yaml.erb")),
require => Python::Pyvenv[$venv_path],
}
# create symbolic link in $PATH
file { "/usr/local/bin/${script_name}":
ensure => 'link',
target => "${base_path}/${script_name}",
require => File["${base_path}/${script_name}"],
}
}
}
+46 -37
View File
@@ -12,45 +12,54 @@ class profiles::helpers::node_lookup (
Array[String[1]] $packages = ['requests'],
){
# ensure the base_path exists
file { $base_path:
ensure => directory,
mode => '0755',
owner => $owner,
group => $group,
}
# create a venv
python::pyvenv { $venv_path :
ensure => present,
version => $version,
systempkgs => $systempkgs,
venv_dir => $venv_path,
owner => $owner,
group => $group,
require => File[$base_path],
}
if $::facts['python3_version'] {
# install the required pip packages
$packages.each |String $package| {
python::pip { "${venv_path}_${package}":
$python_version = $version ? {
'system' => $::facts['python3_version'],
default => $version,
}
# ensure the base_path exists
file { $base_path:
ensure => directory,
mode => '0755',
owner => $owner,
group => $group,
}
# create a venv
python::pyvenv { $venv_path :
ensure => present,
pkgname => $package,
virtualenv => $venv_path,
version => $python_version,
systempkgs => $systempkgs,
venv_dir => $venv_path,
owner => $owner,
group => $group,
require => File[$base_path],
}
# install the required pip packages
$packages.each |String $package| {
python::pip { "${venv_path}_${package}":
ensure => present,
pkgname => $package,
virtualenv => $venv_path,
}
}
# create the script from a template
file { "${base_path}/${script_name}":
ensure => file,
mode => '0755',
content => template("profiles/helpers/${script_name}.erb"),
require => Python::Pyvenv[$venv_path],
}
# create symbolic link in $PATH
file { "/usr/local/bin/${script_name}":
ensure => 'link',
target => "${base_path}/${script_name}",
require => File["${base_path}/${script_name}"],
}
}
# create the script from a template
file { "${base_path}/${script_name}":
ensure => file,
mode => '0755',
content => template("profiles/helpers/${script_name}.erb"),
require => Python::Pyvenv[$venv_path],
}
# create symbolic link in $PATH
file { "/usr/local/bin/${script_name}":
ensure => 'link',
target => "${base_path}/${script_name}",
require => File["${base_path}/${script_name}"],
}
}
+208
View File
@@ -0,0 +1,208 @@
# profiles::minio::server
class profiles::minio::server (
String $minio_root_user,
String $minio_root_pass,
Array $minio_opts = [],
Boolean $minio_members_lookup = false,
String $minio_members_role = undef,
Integer $minio_members = undef,
Array $minio_servers = [],
String $minio_storage_class = 'EC:2',
String $version = 'RELEASE.2023-12-20T01-00-02Z',
String $checksum = '09fafaf399885b4912bafda6fa03fc4ccbc39ec45e17239677217317915d6aeb',
String $checksum_type = 'sha256',
String $owner = 'minio',
String $group = 'minio',
Stdlib::Fqdn $url_domain = $::facts['networking']['domain'],
Enum['http', 'https'] $url_scheme = 'http',
Array[String[0]] $blockdev = [],
Stdlib::Port $listen_port = 9000,
Stdlib::IP::Address $listen_addr = $::facts['networking']['ip'],
Stdlib::AbsolutePath $datadir = '/data/minio',
Stdlib::AbsolutePath $confdir = '/etc/minio',
Stdlib::AbsolutePath $homedir = '/var/lib/minio',
Stdlib::AbsolutePath $bindir = '/opt/minio',
Optional[Enum['puppet']] $cert_type = 'puppet',
) {
# create the region string
$minio_region = "${::facts['country']}-${::facts['region']}"
# count the block devices
$blockdev_count = count($blockdev)
# create minio static facts, which are used by pre-compile facts
file { "${lookup('facts_path')}/minio_facts.yaml":
ensure => file,
content => template('profiles/minio/minio_facts.yaml.erb'),
}
# create the user if its not yet initialised, if it is initialised, let the minio::server class manage
# manage the resource. This is done so that the user/group exist before attempting to create the data-
# directories.
if ! $::facts['minio_user_exists'] {
class {'minio::server::user':
manage_user => true,
manage_group => true,
manage_home => true,
owner => $owner,
group => $group,
home => $homedir,
}
}
# create the datadir
if ! $::facts['minio_datadirs_initialised'] {
# create the datadir root
exec { "mkdir_p_${datadir}":
command => "mkdir -p '${datadir}'",
unless => "test -d '${datadir}'",
path => '/bin:/usr/bin',
}
# create te datavol's if blockdev's are listed
$blockdev.each |Integer $index, String $device| {
$id = $index + 1
profiles::storage::datavol {"${::facts['networking']['fqdn']}_${device}":
fstype => 'xfs',
vg => "minio_vg${id}",
pv => $device,
lv => "store${id}",
owner => $owner,
group => $group,
mount => "${datadir}/store${id}",
require => Exec["mkdir_p_${datadir}"],
}
}
}
# copy puppet certs to /etc/pki/tls/puppet
include profiles::pki::puppetcerts
# create the cert configuration hash
if $cert_type == 'puppet' {
$cert_conf = {
'source_path' => '/etc/pki/tls/puppet',
'source_cert_name' => $::facts['networking']['fqdn'],
'source_key_name' => $::facts['networking']['fqdn'],
}
}
# if lookup is enabled, find all the hosts in the specified role and create the servers_array
if $minio_members_lookup {
# check that the role is also set
unless !($minio_members_role == undef) {
fail("minio_members_role must be provided for ${title} when minio_members_lookup is True")
}
# if it is, find hosts, sort them so they dont cause changes every run
#$servers_array = sort(query_nodes("enc_role='${minio_members_role}'", 'networking.fqdn'))
$servers_array = sort(query_nodes("enc_role='${minio_members_role}' and minio_region='${minio_region}'", 'networking.fqdn'))
# else use provided array from params
}else{
$servers_array = $minio_servers
}
# iterate through the servers_array and find the nodeid for each host
$servers_array.each |Integer $index, String $server| {
$id = $index + 1
if $::facts['networking']['fqdn'] == $server {
$nodeid = $id
if $::facts['minio_pool'] != undef {
# create a cname which is used to create a sequential group of names for distributed minio pool
profiles::dns::record { "${minio_region}-${::facts['minio_pool']}-${nodeid}.${::facts['networking']['domain']}_CNAME":
value => $::facts['networking']['hostname'],
type => 'CNAME',
record => "${minio_region}-${::facts['minio_pool']}-${nodeid}.${::facts['networking']['domain']}.",
zone => $::facts['networking']['domain'],
order => 10,
}
}
}
}
# wait until all expected servers in the pool have reported into puppet
if count($servers_array) == $::facts['minio_members'] and $::facts['minio_pool'] != undef {
# if datadirs and user have been initialised, prepare configuration.
if $::facts['minio_datadirs_initialised'] and $::facts['minio_user_exists'] {
# join the minio_opts
$options = join($minio_opts, ' ')
# create vars for $deployment_definition, others used below are params
$url_location = "${minio_region}-${::facts['minio_pool']}"
$url_servers = "1...${count($servers_array)}"
# create the deployment definition line
# >= 1 : https://au-somewhere-1-pool1-{1...5}.example.domain/var/minio/store{1...4}
# == 1 : https://au-somewhere-1-pool1-{1...5}.example.domain/var/minio/store1
# else : https://au-somewhere-1-pool1-{1...5}.example.domain/var/minio
if $blockdev_count >= 1 {
$deployment_definition = "${url_scheme}://${url_location}-{${url_servers}}.${url_domain}:${listen_port}${datadir}/store{1...${blockdev_count}}"
}elsif $blockdev_count == 1 {
$deployment_definition = "${url_scheme}://${url_location}-{${url_servers}}.${url_domain}:${listen_port}${datadir}/store1"
}else{
$deployment_definition = "${url_scheme}://${url_location}-{${url_servers}}.${url_domain}:${listen_port}${datadir}"
}
# create the configuration hash
$configuration = {
'MINIO_ROOT_USER' => $minio_root_user,
'MINIO_ROOT_PASSWORD' => $minio_root_pass.unwrap,
'MINIO_REGION_NAME' => $minio_region,
'MINIO_OPTS' => "\'${options}\'",
'MINIO_DEPLOYMENT_DEFINITION' => $deployment_definition,
'MINIO_STORAGE_CLASS_STANDARD' => $minio_storage_class,
}
}
}
# check all the expected DNS CNAME records do not exist
$all_dns_exist = $::facts['minio_pool_dns'].all |String $cname, Boolean $exists| { $exists }
# create the minio server if all dns records exist
if $all_dns_exist {
class { 'minio::server::install':
package_ensure => 'present',
owner => $owner,
group => $group,
base_url => 'https://dl.minio.io/server/minio/release',
version => $version,
checksum => $checksum,
checksum_type => $checksum_type,
configuration_directory => $confdir,
installation_directory => $bindir,
storage_root => $datadir,
listen_ip => $listen_addr,
listen_port => $listen_port,
manage_service => true,
service_template => 'profiles/minio/minio.service.erb',
service_provider => 'systemd',
cert_directory => "${confdir}/certs",
custom_configuration_file_path => '/etc/default/minio',
}
class { 'minio::server::config':
owner => $owner,
group => $group,
configuration_directory => $confdir,
installation_directory => $bindir,
storage_root => $datadir,
configuration => $configuration,
custom_configuration_file_path => '/etc/default/minio',
require => Class['Minio::Server::Install'],
}
class { 'minio::server::service':
manage_service => true,
service_provider => 'systemd',
service_ensure => 'running',
require => Class['Minio::Server::Config'],
}
}
}
@@ -0,0 +1,116 @@
# profiles::nginx:simpleproxy
#
# only one simpleproxy per host, for anything more advanced, use nginx class
class profiles::nginx::simpleproxy (
Stdlib::Fqdn $nginx_vhost = 'localhost',
Array[Stdlib::Host] $nginx_aliases = [],
Stdlib::Port $nginx_port = 80,
Stdlib::Port $nginx_ssl_port = 443,
Enum['http','https','both'] $nginx_listen_mode = 'https',
Enum['puppet', 'vault'] $nginx_cert_type = 'vault',
Enum['http','https'] $proxy_scheme = 'http',
Stdlib::Port $proxy_port = 80,
Stdlib::Host $proxy_host = $facts['networking']['ip'],
String $proxy_path = '/',
) {
# if nginx_version isnt set, install nginx
if ! $facts['nginx_version'] {
package {'nginx':
ensure => 'present',
}
# else, configure simple proxy
}else{
# build the proxyurl from proxy_* variables
$proxyurl = "${proxy_scheme}://${proxy_host}:${proxy_port}${proxy_path}"
# set the server_names
$server_names = unique([$facts['networking']['fqdn'], $nginx_vhost] + $nginx_aliases)
# select the certificates to use based on cert type
case $nginx_cert_type {
'puppet': {
$selected_ssl_cert = "/etc/pki/tls/puppet/${facts['networking']['fqdn']}.crt"
$selected_ssl_key = "/etc/pki/tls/puppet/${facts['networking']['fqdn']}.key"
}
'vault': {
$selected_ssl_cert = '/etc/pki/tls/vault/certificate.crt'
$selected_ssl_key = '/etc/pki/tls/vault/private.key'
}
default: {
# enum param prevents this ever being reached
}
}
# set variables based on the listen_mode
case $nginx_listen_mode {
'http': {
$enable_ssl = false
$ssl_cert = undef
$ssl_key = undef
$listen_port = $nginx_port
$listen_ssl_port = undef
$extras_hash = {}
}
'https': {
$enable_ssl = true
$ssl_cert = $selected_ssl_cert
$ssl_key = $selected_ssl_key
$listen_port = $nginx_ssl_port
$listen_ssl_port = $nginx_ssl_port
$extras_hash = {
'subscribe' => [File[$ssl_cert], File[$ssl_key]],
}
}
'both': {
$enable_ssl = true
$ssl_cert = $selected_ssl_cert
$ssl_key = $selected_ssl_key
$listen_port = $nginx_port
$listen_ssl_port = $nginx_ssl_port
$extras_hash = {
'subscribe' => [File[$ssl_cert], File[$ssl_key]],
}
}
default: {
# enum param prevents this ever being reached
}
}
# define the default parameters for the nginx server
$defaults = {
'listen_port' => $listen_port,
'server_name' => $server_names,
'use_default_location' => true,
'access_log' => "/var/log/nginx/${nginx_vhost}_access.log",
'error_log' => "/var/log/nginx/${nginx_vhost}_error.log",
'autoindex' => 'on',
'ssl' => $enable_ssl,
'ssl_cert' => $ssl_cert,
'ssl_key' => $ssl_key,
'ssl_port' => $listen_ssl_port,
'proxy' => $proxyurl,
}
# merge the hashes conditionally
$nginx_parameters = merge($defaults, $extras_hash)
# manage the nginx class
include 'nginx'
# create the nginx vhost with the merged parameters
create_resources('nginx::resource::server', { $nginx_vhost => $nginx_parameters })
# manage selinux
if $::facts['os']['selinux']['config_mode'] == 'enforcing' {
# make sure nginx can reverse proxy
selboolean { 'httpd_can_network_connect':
persistent => true,
value => 'on',
}
}
}
}
+14 -7
View File
@@ -11,6 +11,11 @@ class profiles::ntp::client (
'running',
'stopped'
] $wait_ensure = 'running',
Enum[
'all',
'region',
'country'
] $use_ntp = 'all',
Boolean $client_only = true,
) {
@@ -18,23 +23,25 @@ class profiles::ntp::client (
# through the profiles::ntp::server class.
if $client_only {
# if ntp_role is set, find all hosts matching that enc_role
if $ntp_role == undef {
$ntpserver_array = $peers
}else{
$ntpserver_array = query_nodes("enc_role='${ntp_role}'", 'networking.fqdn')
$ntpserver_array = $ntp_role ? {
undef => $peers,
default => $use_ntp ? {
'all' => query_nodes("enc_role='${ntp_role}'", 'networking.fqdn'),
'region' => query_nodes("enc_role='${ntp_role}' and region=${facts['region']}", 'networking.fqdn'),
'country' => query_nodes("enc_role='${ntp_role}' and country=${facts['country']}", 'networking.fqdn'),
}
}
# Define the client configuration based on OS family
if $facts['os']['family'] == 'RedHat' {
class { 'chrony':
servers => $ntpserver_array,
servers => sort($ntpserver_array),
wait_enable => $wait_enable,
wait_ensure => $wait_ensure,
}
} else {
class { 'chrony':
servers => $ntpserver_array,
servers => sort($ntpserver_array),
}
}
}
+20
View File
@@ -0,0 +1,20 @@
# profiles::ovirt::node
class profiles::ovirt::node {
# Define the DNF modules to be enabled
$dnf_modules_to_enable = {
'javapackages-tools' => { 'ensure' => 'latest' },
'pki-deps' => { 'ensure' => 'latest' },
'postgresql' => { 'ensure' => '12' },
'mod_auth_openidc' => { 'ensure' => '2.3' },
'nodejs' => { 'ensure' => '14' },
}
# Enable the DNF modules
create_resources(
'package',
$dnf_modules_to_enable, {
provider => dnfmodule,
enable_only => true
}
)
}
+23
View File
@@ -0,0 +1,23 @@
# This class manages the installation of packages for the base profile
#
# Parameters:
# - $install: An array of package names to be installed
# - $remove: An array of package names to be removed
#
class profiles::packages (
Array $install = [],
Array $install_exclude = [],
Array $remove = [],
Array $remove_exclude = [],
) {
# Filter out excluded packages
$install_real = $install.filter |$item| { !$install_exclude.any |$exclude_item| { $exclude_item == $item } }
$remove_real = $remove.filter |$item| { !$remove_exclude.any |$exclude_item| { $exclude_item == $item } }
# Ensure packages to install are installed
ensure_packages($install_real, {'ensure' => 'present'})
# Ensure packages to remove are absent
ensure_packages($remove_real, {'ensure' => 'absent'})
}
-21
View File
@@ -1,21 +0,0 @@
# This class manages the installation of packages for the base profile
#
# Parameters:
# - $add: An array of package names to be installed
# - $remove: An array of package names to be removed
#
class profiles::packages::base (
Array $add = [],
Array $remove = [],
) {
# Ensure packages to add are installed
ensure_packages($add, {'ensure' => 'present'})
# Ensure packages to remove are absent
$remove.each |String $package| {
package { $package:
ensure => 'absent',
}
}
}
-11
View File
@@ -1,11 +0,0 @@
# installs git related packages
#
class profiles::packages::git (
Array[String] $packages = lookup('profiles::packages::git', Array, 'first', ['git']),
) {
$packages.each |String $package| {
package { $package:
ensure => installed,
}
}
}
@@ -1,11 +0,0 @@
# installs reposync related packages
#
class profiles::packages::reposync (
Array[String] $packages = lookup('profiles::packages::reposync', Array, 'first', ['createrepo']),
) {
$packages.each |String $package| {
package { $package:
ensure => installed,
}
}
}
@@ -1,11 +0,0 @@
# installs selinux related packages
#
class profiles::packages::selinux (
Array[String] $packages = lookup('profiles::packages::selinux', Array, 'first', ['policycoreutils']),
) {
$packages.each |String $package| {
package { $package:
ensure => installed,
}
}
}
@@ -0,0 +1,42 @@
# profiles::pki::puppetcerts
class profiles::pki::puppetcerts {
# Define the directory
file { '/etc/pki/tls/puppet':
ensure => 'directory',
owner => 'root',
group => 'root',
mode => '0755',
}
# Copy the CA certificate
file { '/etc/pki/tls/puppet/ca.pem':
ensure => 'file',
owner => 'root',
group => 'root',
mode => '0644',
source => '/etc/puppetlabs/puppet/ssl/certs/ca.pem',
require => File['/etc/pki/tls/puppet'],
}
# Copy the private key
file { "/etc/pki/tls/puppet/${facts['networking']['fqdn']}.key":
ensure => 'file',
owner => 'root',
group => 'root',
mode => '0644',
source => "/etc/puppetlabs/puppet/ssl/private_keys/${facts['networking']['fqdn']}.pem",
require => File['/etc/pki/tls/puppet'],
}
# Copy the certificate
$cert = "/etc/puppetlabs/puppet/ssl/certs/${facts['networking']['fqdn']}.pem"
file { "/etc/pki/tls/puppet/${facts['networking']['fqdn']}.crt":
ensure => 'file',
owner => 'root',
group => 'root',
mode => '0644',
source => "/etc/puppetlabs/puppet/ssl/certs/${facts['networking']['fqdn']}.pem",
require => File['/etc/pki/tls/puppet'],
}
}
+141
View File
@@ -0,0 +1,141 @@
# profiles::pki::vault
class profiles::pki::vault (
Optional[Array[Stdlib::Host]] $alt_names = [],
Optional[Array[Stdlib::IP::Address]] $ip_sans = [],
){
# validate and prepare additional alt_names, if any
$default_alt_names = [$::facts['networking']['hostname'], $::facts['networking']['fqdn']]
$effective_alt_names = $alt_names ? {
[] => $default_alt_names,
default => concat($default_alt_names, $alt_names),
}
# validate and prepare additional ip_sans, if any
$default_ip_sans = ['127.0.0.1', $::facts['networking']['ip']]
$effective_ip_sans = $ip_sans ? {
[] => $default_ip_sans,
default => concat($default_ip_sans, $ip_sans),
}
# path for the alt names file
$base_path = '/etc/pki/tls/vault'
$alt_names_file = "${base_path}/alt_names"
# ensure the base directory exists
file { '/etc/pki':
ensure => directory,
owner => 'root',
group => 'root',
mode => '0755',
}
file { '/etc/pki/tls':
ensure => directory,
owner => 'root',
group => 'root',
mode => '0755',
require => File['/etc/pki']
}
file { $base_path:
ensure => directory,
owner => 'root',
group => 'root',
mode => '0755',
require => File['/etc/pki/tls']
}
# alt_names_file contents
$alt_names_content = concat($effective_alt_names, $effective_ip_sans)
# manage the alt names file
file { $alt_names_file:
ensure => file,
owner => 'root',
group => 'root',
mode => '0644',
content => join($alt_names_content, "\n"),
require => File[$base_path]
}
# compare the sorted arrays of altnames from disk (fact) vs what is intended (this run)
$alt_names_match = sort($::facts['vault_cert_altnames']) == sort($alt_names_content)
# only renew certificate if its expiring or the alt names have changed
if $::facts['vault_cert_expiring'] or ! $alt_names_match {
# certificate variables
$common_name = $::facts['networking']['fqdn']
$valid_days = 90
# prepare alt_names and ip_sans arguments conditionally
$alt_names_string = $effective_alt_names.empty() ? {
true => '',
default => join($effective_alt_names, ','),
}
$ip_sans_string = $effective_ip_sans.empty() ? {
true => '',
default => join($effective_ip_sans, ','),
}
# certmanager arguments
$cmd = '/usr/local/bin/certmanager'
$alt_names_arg = '--alt-names'
$ip_sans_arg = '--ip-sans'
$expiry_days_arg = '--expiry-days'
# call the script with generate(), capturing json output
$json_output = generate(
$cmd,
$common_name,
$alt_names_arg,
$alt_names_string,
$ip_sans_arg,
$ip_sans_string,
$expiry_days_arg,
$valid_days,
'--json'
)
$cert_data = parsejson($json_output)
# manage certificate file resources based on script output
$certificate_files = {
"${base_path}/certificate.crt" => $cert_data['certificate'],
"${base_path}/private.key" => $cert_data['private_key'],
"${base_path}/full_chain.crt" => $cert_data['full_chain'],
"${base_path}/ca_certificate.crt" => $cert_data['ca_certificate'],
"${base_path}/certificate.pem" => "${cert_data['certificate']}\n${cert_data['private_key']}",
}
# manage each file resources
$certificate_files.each |$file_path, $content| {
file { $file_path:
ensure => file,
content => $content,
owner => 'root',
group => 'root',
mode => '0644',
require => File[$base_path],
}
}
}else{
# manage each file resources, but dont change the content
$certificate_files = [
"${base_path}/certificate.crt",
"${base_path}/private.key",
"${base_path}/full_chain.crt",
"${base_path}/ca_certificate.crt",
"${base_path}/certificate.pem"
]
$certificate_files.each |$file_path| {
file { $file_path:
ensure => file,
owner => 'root',
group => 'root',
mode => '0644',
require => File[$base_path],
}
}
}
}
+37
View File
@@ -0,0 +1,37 @@
# ensure the ca certificate for vault is installed everywhere
class profiles::pki::vaultca {
$root_cacert = 'vaultcaroot.pem'
# Define the target path based on the operating system
case $facts['os']['family'] {
'RedHat': {
$ca_cert_target_path = "/etc/pki/ca-trust/source/anchors/${root_cacert}"
$update_ca_cert_command = 'update-ca-trust extract'
}
'Debian': {
$ca_cert_target_path = "/usr/local/share/ca-certificates/${root_cacert}"
$update_ca_cert_command = 'update-ca-certificates'
}
default: {
fail("Unsupported operating system: ${facts['os']['family']}")
}
}
# Ensure the CA certificate is present and contains the content from the template
file { $ca_cert_target_path:
ensure => file,
owner => 'root',
group => 'root',
mode => '0644',
content => template('profiles/pki/vaultcaroot.pem.erb'),
notify => Exec['update_ca_trust_store'],
}
# Execute the system command to update the CA trust store
exec { 'update_ca_trust_store':
command => $update_ca_cert_command,
path => ['/bin', '/usr/bin', 'sbin', '/usr/sbin'],
refreshonly => true,
require => File[$ca_cert_target_path],
}
}
+50
View File
@@ -0,0 +1,50 @@
# profiles::proxmox::ceph
class profiles::proxmox::ceph {
# include params class
include profiles::proxmox::params
# localise some vars
$network = $profiles::proxmox::params::pve_ceph_network
$size = $profiles::proxmox::params::pve_ceph_size
$min_size = $profiles::proxmox::params::pve_ceph_minsize
# install ceph if it is enabled
if $profiles::proxmox::params::pve_ceph_install {
# initialise the cluster, but only on the clusterinit node and only if its not already initialised
if $profiles::proxmox::params::pve_clusterinit_master and ! $facts['pve_ceph_initialised']{
exec { 'pveceph_init':
command => "/usr/bin/pveceph init --network ${network} --size ${size} --min_size ${min_size}",
user => 'root',
}
}
if $facts['pve_ceph_initialised'] {
# create monitors
if $profiles::proxmox::params::pve_ceph_mon {
# only when its not already a monitor
if ! $facts['is_pveceph_mon'] {
exec { 'pveceph_mon':
command => '/usr/bin/pveceph mon create',
user => 'root',
}
}
}
# create managers
if $profiles::proxmox::params::pve_ceph_mgr {
# only when its not already a manager
if ! $facts['is_pveceph_mgr'] {
exec { 'pveceph_mgr':
command => '/usr/bin/pveceph mgr create',
user => 'root',
}
}
}
}
}
}
@@ -0,0 +1,41 @@
# profiles::proxmox::clusterinit
class profiles::proxmox::clusterinit {
# include params class
include profiles::proxmox::params
# localise some vars
$clusterinit_master = $profiles::proxmox::params::pve_clusterinit_master
$clustername = $profiles::proxmox::params::pve_cluster
$membersrole = $profiles::proxmox::params::pve_members_role
# if this is the cluster master
if $clusterinit_master {
# and its not a member of a cluster yet
if ! $facts['pve_cluster_member'] {
# initialise a cluster
exec {'pve_init_cluster':
command => "/usr/bin/pvecm create ${clustername}",
unless => 'pvecm status',
timeout => 60,
}
}
}
$servers_array = sort(query_nodes(
"enc_role='${membersrole}' and country='${facts['country']}' and region='${facts['region']}'",
'networking.fqdn'
))
if ! $profiles::proxmox::params::pve_clusterinit_master {
if !empty($servers_array) {
notify { "Cluster ${profiles::proxmox::params::pve_cluster} detected, proceeding to join...":
}
} else {
notify { "No cluster flag found for ${profiles::proxmox::params::pve_cluster}, not attempting to join":
}
}
}
}
@@ -0,0 +1,74 @@
# profiles::proxmox::clusterjoin
class profiles::proxmox::clusterjoin {
# include params class
include profiles::proxmox::params
# localise some vars
$clusterinit_master = $profiles::proxmox::params::pve_clusterinit_master
$clustername = $profiles::proxmox::params::pve_cluster
$membersrole = $profiles::proxmox::params::pve_members_role
$root_password = $profiles::proxmox::params::root_password
# query puppetdb for list of cluster members
$members_array = sort(query_nodes(
"enc_role='${membersrole}' and \
country='${facts['country']}' and \
region='${facts['region']}' and \
pve_cluster.cluster_name='${clustername}'",
'networking.fqdn'
))
# check if the pve kernerl is running
if $facts['kernelrelease'] == $profiles::proxmox::params::pve_kernel_release {
# if this is the cluster master
if $clusterinit_master {
# there are no cluster members in puppetdb
if empty($members_array) {
# and this host isnt already in a cluster by itself
if ! $facts['pve_cluster'] {
# initialise a cluster
exec {'pve_init_cluster':
command => "/usr/bin/pvecm create ${clustername}",
unless => 'pvecm status',
timeout => 60,
}
}
}
}
# for non-masters
if ! $clusterinit_master {
# if there are already members of the cluster
if !empty($members_array) {
# and this host isnt already in a cluster
if ! $facts['pve_cluster'] {
# create an expect script to join the cluster
file { '/usr/local/bin/join_pvecluster.expect':
ensure => file,
owner => 'root',
mode => '0755',
content => template('profiles/proxmox/join_pvecluster.erb'),
}
exec { 'pve_join_cluster':
command => "/usr/local/bin/join_pvecluster.expect '${root_password.unwrap}' '${members_array[0]}'",
require => [File['/usr/local/bin/join_pvecluster.expect'], Package['expect']],
unless => "/usr/bin/pvesh nodes | grep -q '${facts['networking']['hostname']}'",
user => 'root',
}
}
} else {
notify { "No initialised cluster found for ${clustername}, not attempting to join":
}
}
}
}
}
+19
View File
@@ -0,0 +1,19 @@
# profiles::proxmox::config
class profiles::proxmox::config {
# include params class
include profiles::proxmox::params
# localise some vars
$clusterinit_master = $profiles::proxmox::params::pve_clusterinit_master
# create pve_facts file
file {'/opt/puppetlabs/facter/facts.d/pve_facts.yaml':
ensure => 'file',
owner => 'root',
group => 'root',
mode => '0600',
content => template('profiles/proxmox/pve_facts.yaml.erb')
}
}
+17
View File
@@ -0,0 +1,17 @@
# proxmox::
class profiles::proxmox::init {
#include profiles::proxmox::params
include profiles::proxmox::repos
include profiles::proxmox::install
include profiles::proxmox::clusterjoin
include profiles::proxmox::ceph
include profiles::proxmox::config
include profiles::proxmox::weblb
Class['profiles::proxmox::repos']
-> Class['profiles::proxmox::install']
-> Class['profiles::proxmox::clusterjoin']
-> Class['profiles::proxmox::ceph']
-> Class['profiles::proxmox::config']
}
@@ -0,0 +1,58 @@
# profiles::proxmox::install
class profiles::proxmox::install {
# include params class
include profiles::proxmox::params
# install the pve kernel
package { 'proxmox-default-kernel':
ensure => $profiles::proxmox::params::pve_kernel_version,
notify => Reboot['after_run'],
require => Apt::Source['proxmox'],
}
# reboot into the new kernel
reboot { 'after_run':
apply => finished,
}
if $facts['kernelrelease'] == $profiles::proxmox::params::pve_kernel_release {
# install pve
ensure_packages($profiles::proxmox::params::pve_packages_install, { ensure => 'present', require => Apt::Source['proxmox']})
# remove the old linux kernel metapackage
ensure_packages($profiles::proxmox::params::pve_packages_remove, { ensure => 'absent' })
# install ceph package if requested
if $profiles::proxmox::params::pve_ceph_install {
ensure_packages($profiles::proxmox::params::pve_packages_ceph, { ensure => 'present', require => Apt::Source['ceph'] })
}
# cleanup the old kernel packages
exec { 'remove-linux-kernel-packages':
command => '/usr/bin/apt-get purge -y $(/usr/bin/dpkg --list | /bin/grep "linux-image-6.1" | /usr/bin/awk \'{ print $2 }\')',
onlyif => '/usr/bin/dpkg --list | /bin/grep -q "linux-image-6.1"',
path => ['/usr/bin', '/bin', '/sbin'],
refreshonly => true,
}
# update grup
exec { 'update-grub':
command => '/usr/sbin/update-grub',
path => ['/usr/bin', '/bin', '/sbin'],
refreshonly => true,
}
# update grub after removing kernel packages only
Exec['remove-linux-kernel-packages'] ~> Exec['update-grub']
# prepare for SDN
file_line { 'source-network-interfaces-d':
path => '/etc/network/interfaces',
line => 'source /etc/network/interfaces.d/*',
match => '^source /etc/network/interfaces.d/\*$',
append_on_no_match => true,
}
}
}
+44
View File
@@ -0,0 +1,44 @@
# profiles::proxmox::params
class profiles::proxmox::params (
Sensitive[String] $root_password = Sensitive(lookup('profiles::accounts::root::password')),
String $pve_members_role = 'roles::infra::proxmox::node',
String $pve_kernel_version = '1.0.1',
String $pve_kernel_release = '6.5.13-5-pve',
String $pve_cluster = "${::facts['country']}-${::facts['region']}",
Boolean $pve_clusterinit_master = false,
Boolean $pve_ceph_repos = false,
Boolean $pve_ceph_install = false,
Boolean $pve_ceph_mon = false,
Boolean $pve_ceph_mgr = false,
Boolean $pve_ceph_osd = false,
String $pve_ceph_release = 'quincy',
Integer $pve_ceph_size = 3,
Integer $pve_ceph_minsize = 2,
Variant[
Undef,
Stdlib::IP::Address::V4::CIDR
] $pve_ceph_network = undef,
Array $pve_packages_install = [
'proxmox-ve',
'postfix',
'open-iscsi',
'frr-pythontools',
'ksm-control-daemon'
],
Array $pve_packages_remove = [
'os-prober',
'linux-image-amd64'
],
Array $pve_packages_ceph = [
'ceph',
'ceph-common',
'ceph-fuse',
'ceph-mds',
'ceph-volume',
'gdisk',
'nvme-cli'
],
Stdlib::Port $pve_webport = 8006,
){
}
+37
View File
@@ -0,0 +1,37 @@
# profiles::proxmox::repos
class profiles::proxmox::repos {
# include params class
include profiles::proxmox::params
$codename = $facts['os']['distro']['codename']
exec { 'download-proxmox-gpg-key':
command => "/usr/bin/wget https://enterprise.proxmox.com/debian/proxmox-release-${codename}.gpg -O /etc/apt/trusted.gpg.d/proxmox-release-${codename}.gpg",
creates => "/etc/apt/trusted.gpg.d/proxmox-release-${codename}.gpg",
path => ['/usr/bin', '/bin'],
require => File['/etc/apt/trusted.gpg.d/'],
}
file { '/etc/apt/trusted.gpg.d/':
ensure => 'directory',
}
apt::source { 'proxmox':
location => 'http://download.proxmox.com/debian/pve',
repos => 'pve-no-subscription',
include => {
src => false,
},
}
if $profiles::proxmox::params::pve_ceph_repos {
apt::source { 'ceph':
location => "http://download.proxmox.com/debian/ceph-${profiles::proxmox::params::pve_ceph_release}",
repos => 'no-subscription',
include => {
src => false,
},
}
}
}
+33
View File
@@ -0,0 +1,33 @@
# profiles::proxmox::weblb
class profiles::proxmox::weblb {
# include params class
include profiles::proxmox::params
# export haproxy balancemember
profiles::haproxy::balancemember { "${facts['networking']['fqdn']}_${profiles::proxmox::params::pve_webport}}":
service => "be_${facts['country']}${facts['region']}pve_web",
ports => [$profiles::proxmox::params::pve_webport],
options => [
"cookie ${facts['networking']['hostname']}",
'ssl',
'verify none',
'check',
'inter 2s',
'rise 3',
'fall 2',
]
}
profiles::haproxy::balancemember { "${facts['networking']['fqdn']}_${profiles::proxmox::params::pve_webport}_api2}":
service => "be_${facts['country']}${facts['region']}pve_api",
ports => [$profiles::proxmox::params::pve_webport],
options => [
'ssl',
'verify none',
'check',
'inter 2s',
'rise 3',
'fall 2',
]
}
}
+23 -8
View File
@@ -4,11 +4,6 @@ class profiles::puppet::agent (
String $puppet_version = 'latest',
) {
# Ensure the puppet-agent package is installed and locked to a specific version
package { 'puppet-agent':
ensure => $puppet_version,
}
# if puppet-version is anything other than latest, set a versionlock
$puppet_versionlock_ensure = $puppet_version ? {
'latest' => 'absent',
@@ -18,9 +13,29 @@ class profiles::puppet::agent (
'latest' => undef,
default => $puppet_version,
}
yum::versionlock{'puppet-agent':
ensure => $puppet_versionlock_ensure,
version => $puppet_versionlock_version,
case $facts['os']['family'] {
'RedHat': {
# Ensure the puppet-agent package is installed and locked to a specific version
package { 'puppet-agent':
ensure => $puppet_version,
require => Yumrepo['puppet'],
}
# versionlock puppet-agent
yum::versionlock{'puppet-agent':
ensure => $puppet_versionlock_ensure,
version => $puppet_versionlock_version,
}
}
'Debian': {
# Ensure the puppet-agent package is installed and locked to a specific version
package { 'puppet-agent':
ensure => $puppet_version,
require => Class['profiles::apt::puppet7'],
}
}
default: {}
}
# Ensure the puppet service is running
@@ -4,35 +4,6 @@
# based on specified subnet ranges and domain patterns.
# It is useful in environments where nodes are dynamically provisioned and
# require automatic certificate signing without manual intervention.
#
# Parameters:
# - `subnet_ranges`: An array of IP subnet ranges in CIDR notation.
# Nodes with IP addresses within these ranges will have their
# certificates autosigned.
# Default: []
# Example: ['198.18.17.0/24']
#
# - `domains`: An array of domain patterns.
# Nodes with hostnames matching these patterns will have their
# certificates autosigned.
# Default: []
# Example: ['*.main.unkin.net', '*.secondary.unkin.net']
#
# - `nodes`: An array of specific node names.
# Nodes with hostnames matching these will have their
# certificates autosigned.
# Default: []
# Example: ['somenode.main.unkin.net', 'othernode.secondary.unkin.net']
# Usage:
#
# To include this class with custom parameters:
# class { 'profiles::puppet::autosign':
# subnet_ranges => ['198.18.17.0/24', '198.18.18.0/24'],
# domains => ['*.main.unkin.net', '*.dev.unkin.net'],
# nodes => ['somenode.main.unkin.net', 'othernode.dev.unkin.net'],
# }
#
# Alternatively, configure subnet ranges and domains through Hiera.
class profiles::puppet::autosign (
Array[Stdlib::IP::Address::V4::CIDR] $subnet_ranges = [],
Array[String[1]] $domains = [],
+16 -9
View File
@@ -4,7 +4,7 @@
#
# site/profile/manifests/puppet/client.pp
class profiles::puppet::client (
String $dns_alt_names = $trusted['certname'],
Array $dns_alt_names = [$trusted['certname']],
String $server = 'puppetmaster',
String $ca_server = 'puppetca',
String $environment = 'develop',
@@ -14,14 +14,21 @@ class profiles::puppet::client (
Boolean $usecacheonfailure = false,
) {
# Assuming you want to manage puppet.conf with this profile
file { '/etc/puppetlabs/puppet/puppet.conf':
ensure => 'present',
content => template('profiles/puppet/client/puppet.conf.erb'),
owner => 'root',
group => 'root',
mode => '0644',
notify => Service['puppet'],
# dont manage puppet.conf if this is a puppetmaster
if $facts['enc_role'] != 'roles::infra::puppet::master' {
$dns_alt_names_string = join(sort($dns_alt_names), ',')
# Assuming you want to manage puppet.conf with this profile
file { '/etc/puppetlabs/puppet/puppet.conf':
ensure => 'present',
content => template('profiles/puppet/client/puppet.conf.erb'),
owner => 'root',
group => 'root',
mode => '0644',
notify => Service['puppet'],
}
}
}
@@ -0,0 +1,76 @@
# Class: profiles::puppet::cobbler_enc
#
# This will deploy the cobbler-enc tool for puppetmasters
#
# wrapper class for python, pip and venv
class profiles::puppet::cobbler_enc (
Stdlib::Host $cobbler_hostname,
Enum['http','https'] $cobbler_scheme = 'https',
String $script_name = 'cobbler-enc',
Stdlib::AbsolutePath $base_path = "/opt/${script_name}",
Stdlib::AbsolutePath $venv_path = "${base_path}/venv",
String $owner = 'root',
String $group = 'root',
Boolean $systempkgs = false,
String $version = 'system',
Array[String[1]] $packages = ['sys','requests','pyyaml'],
Stdlib::AbsolutePath $trusted_ca_cert = '/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem'
){
# set the cobbler url, required for the erb template
$cobbler_base_url = "${cobbler_scheme}://${cobbler_hostname}"
if $::facts['python3_version'] {
$python_version = $version ? {
'system' => $::facts['python3_version'],
default => $version,
}
# ensure the base_path exists
file { $base_path:
ensure => directory,
mode => '0755',
owner => $owner,
group => $group,
}
# create a venv
python::pyvenv { $venv_path :
ensure => present,
version => $python_version,
systempkgs => $systempkgs,
venv_dir => $venv_path,
owner => $owner,
group => $group,
require => File[$base_path],
}
# install the required pip packages
$packages.each |String $package| {
python::pip { "${venv_path}_${package}":
ensure => present,
pkgname => $package,
virtualenv => $venv_path,
}
}
# create the script from a template
file { "${base_path}/${script_name}":
ensure => file,
mode => '0755',
content => template("profiles/puppet/server/${script_name}.erb"),
require => [
Python::Pyvenv[$venv_path],
Package['python3.11']
],
}
# create symbolic link in $PATH
file { "/usr/local/bin/${script_name}":
ensure => 'link',
target => "${base_path}/${script_name}",
require => File["${base_path}/${script_name}"],
}
}
}
-31
View File
@@ -4,43 +4,12 @@
# systemd service and timer to keep the repository updated every minute.
# The Git package is installed if not present, and the repository at the given
# location will always reflect the state of the remote Git repository.
#
# Parameters:
# - enc_repo: The URL of the Git repository to clone.
#
# Actions:
# - Ensures the Git package is installed.
# - Ensures the /opt/puppetlabs/enc directory is a clone of the given Git repository.
# - Creates a helper script '/opt/puppetlabs/bin/git_update' for updating the Git repository.
# - Creates a systemd service and timer that runs the git update script every minute.
#
# Usage:
# Directly include the class in your node definitions or classify your nodes
# using an ENC or Hiera.
# Example:
# node 'puppet.example.com' {
# class { 'profiles::puppet::enc':
# enc_repo => 'https://github.com/user/repo.git',
# }
# }
#
# Requirements:
# - The 'puppet-vcsrepo' module should be installed on your puppetmaster.
# - The 'puppet-systemd' module should be installed on your puppetmaster.
# - '/opt/puppetlabs/bin/' directory must exist and be writable.
# - Puppet master must have access to the specified Git URL.
#
# Limitations:
# This is designed to work on Unix-like systems only.
#
class profiles::puppet::enc (
String $repo,
String $release = 'master',
Boolean $force = false,
) {
include profiles::packages::git
vcsrepo { '/opt/puppetlabs/enc':
ensure => latest,
provider => git,
+41
View File
@@ -0,0 +1,41 @@
# profiles::puppet::eyaml
class profiles::puppet::eyaml (
String $privatekey = '',
String $publickey = '',
) {
# create the /var/lib/puppet/keys directory
file { '/var/lib/puppet':
ensure => 'directory',
owner => 'puppet',
group => 'root',
mode => '0755',
}
file { '/var/lib/puppet/keys':
ensure => 'directory',
owner => 'puppet',
group => 'root',
mode => '0755',
require => File['/var/lib/puppet']
}
# manage the eyaml private key
file { '/var/lib/puppet/keys/private_key.pkcs7.pem':
ensure => 'file',
owner => 'puppet',
group => 'root',
mode => '0400',
content => Sensitive($privatekey),
before => Service['puppetserver'],
require => File['/var/lib/puppet/keys'],
}
# manage the eyaml private key
file { '/var/lib/puppet/keys/public_key.pkcs7.pem':
ensure => 'file',
owner => 'puppet',
group => 'root',
mode => '0400',
content => Sensitive($publickey),
before => Service['puppetserver'],
require => File['/var/lib/puppet/keys'],
}
}
+1 -28
View File
@@ -5,40 +5,12 @@
# The latest release of g10k is downloaded from GitHub and placed into '/opt/puppetlabs/bin'.
# Additionally, it creates a helper script to easily run g10k with the appropriate configuration.
# It also creates a systemd service and timer that runs the g10k script every minute.
#
# Parameters: None
#
# Actions:
# - Downloads the latest g10k release from GitHub.
# - Extracts the download and places the executable in '/opt/puppetlabs/bin'.
# - Creates a helper script '/opt/puppetlabs/bin/puppet-g10k' for easy usage of g10k.
# - Creates a systemd service and timer that runs the g10k script every minute.
#
# Usage:
# Directly including the class in your node definitions or classify your nodes
# using an ENC or Hiera.
# Example:
# node 'puppet.example.com' {
# include profiles::puppet::g10k
# }
#
# Requirements:
# - The 'puppet-archive' module should be installed in your puppetmaster.
# - The 'puppet-systemd' module should be installed on your puppetmaster.
# - '/opt/puppetlabs/bin/' directory must exist and be writable.
# - Puppet master must have access to the GitHub URL.
#
# Limitations:
# This is designed to work on Unix-like systems only.
class profiles::puppet::g10k (
String $bin_path,
String $cfg_path,
String $environments_path,
String $default_environment,
){
package { 'unzip':
ensure => installed,
}
archive { '/tmp/g10k.zip':
ensure => present,
@@ -47,6 +19,7 @@ class profiles::puppet::g10k (
extract_path => '/opt/puppetlabs/bin',
creates => '/opt/puppetlabs/bin/g10k',
cleanup => true,
require => Package['unzip']
}
file { '/opt/puppetlabs/bin/puppet-g10k':
+12
View File
@@ -0,0 +1,12 @@
# profiles::puppet::gems
class profiles::puppet::gems (
Array $puppet = [],
){
# install puppetmaster gems
$puppet.each | $pgem | {
package { $pgem:
ensure => installed,
provider => 'puppet_gem',
}
}
}
+42 -4
View File
@@ -8,7 +8,7 @@ class profiles::puppet::puppetboard (
Integer $reports_count = 40,
Boolean $offline_mode = true,
String $default_environment = '*',
String $puppetdb_host = lookup('profiles::puppet::puppetdb::puppetdb_host'),
String $puppetdb_host = lookup('puppetdbapi'),
Stdlib::AbsolutePath $basedir = '/opt/puppetboard',
Stdlib::Absolutepath $virtualenv_dir = "${basedir}/venv",
Stdlib::Absolutepath $settings_file = "${basedir}/settings.py",
@@ -18,8 +18,9 @@ class profiles::puppet::puppetboard (
String $gunicorn_bind_prefix = 'http://',
Integer $gunicorn_workers = 1,
Integer $gunicorn_threads = 4,
String $nginx_vhost = 'puppetboard.main.unkin.net',
Integer $nginx_port = 80,
Stdlib::Port $nginx_port = 80,
Stdlib::Host $nginx_vhost = 'puppetboard.main.unkin.net',
Array[Stdlib::Host] $nginx_aliases = [],
#String[1] $secret_key = "${fqdn_rand_string(32)}",
) {
@@ -98,10 +99,12 @@ class profiles::puppet::puppetboard (
# ensure the nginx service is managed
class { 'nginx': }
$nginx_server_names = unique([$nginx_vhost] + $nginx_aliases)
# create the nginx vhost
nginx::resource::server { $nginx_vhost:
listen_port => $nginx_port,
server_name => [$nginx_vhost],
server_name => $nginx_server_names,
proxy => "${gunicorn_bind_prefix}${gunicorn_bind}",
proxy_set_header => [
'Host $http_host',
@@ -120,4 +123,39 @@ class profiles::puppet::puppetboard (
server => $nginx_vhost,
location_alias => "${virtualenv_dir}/lib/python${python_version}/site-packages/puppetboard/static",
}
# export haproxy balancemember
profiles::haproxy::balancemember { "${facts['networking']['fqdn']}_${nginx_port}}":
service => 'be_puppetboard',
ports => [$nginx_port],
options => [
"cookie ${facts['networking']['hostname']}",
'check',
'inter 2s',
'rise 3',
'fall 2',
]
}
#@@haproxy::balancermember { "${facts['networking']['fqdn']}_${nginx_port}}":
# listening_service => 'be_puppetboard',
# ports => [$nginx_port],
# server_names => $facts['networking']['hostname'],
# ipaddresses => $facts['networking']['ip'],
# options => [
# "cookie ${facts['networking']['hostname']}",
# 'check',
# 'inter 2s',
# 'rise 3',
# 'fall 2',
# ]
#}
# if selinux is defined, manage it
if $::facts['os']['selinux']['config_mode'] == 'enforcing' {
# call the nginx selinux class
class { 'profiles::selinux::nginx':
require => Class['Nginx'],
}
}
}
@@ -0,0 +1,56 @@
# Class: profiles::puppet::puppetca
#
# This class manages Puppet CA
class profiles::puppet::puppetca (
Boolean $allow_subject_alt_names = false,
Boolean $allow_authorization_extensions = false,
Boolean $enable_infra_crl = false,
Boolean $is_puppetca = false,
) {
# manage the ca.cfg file
file { '/etc/puppetlabs/puppetserver/conf.d/ca.conf':
ensure => 'file',
owner => 'root',
group => 'root',
mode => '0644',
content => template('profiles/puppet/puppet_ca.cfg.erb'),
notify => Service['puppetserver'],
}
# manage the crl file
if $is_puppetca {
# export the puppet crl.pem
@@file { '/etc/puppetlabs/puppet/ssl/crl.pem':
ensure => file,
content => file('/etc/puppetlabs/puppet/ssl/crl.pem'),
tag => 'crl_pem_export',
}
}else{
# import the puppet crl.pem
File <<| tag == 'crl_pem_export' |>> {
require => Service['puppetserver'],
}
}
# register the PuppetCA service with consul
if $is_puppetca {
consul::service { 'puppetca':
service_name => 'puppetca',
tags => ['ca', 'puppet', 'ssl'],
address => $facts['networking']['ip'],
port => 8140,
checks => [
{
id => 'puppetca_https_check',
name => 'PuppetCA HTTPS Check',
http => "https://${facts['networking']['fqdn']}:8140/status/v1/simple",
method => 'GET',
tls_skip_verify => true,
interval => '10s',
timeout => '1s',
}
],
}
}
}
+38 -14
View File
@@ -1,21 +1,45 @@
# configure the puppetdb api service
class profiles::puppet::puppetdb_api (
String $postgres_host = lookup('profiles::puppet::puppetdb::postgres_host'),
String $postgres_host = lookup('puppetdbsql'),
String $listen_address = $facts['networking']['ip'],
Stdlib::Absolutepath $java_bin = '/usr/bin/java',
Hash $java_args = {},
) {
class { 'puppetdb::server':
database_host => $postgres_host,
manage_firewall => false,
ssl_listen_address => $listen_address,
listen_address => $listen_address,
# wait for enc_role to match the required role
if $facts['enc_role'] == 'roles::infra::puppetdb::api' {
class { 'java':
package => 'java-11-openjdk-devel',
before => Class['puppetdb::server'],
}
class { 'puppetdb::server':
database_host => $postgres_host,
manage_firewall => false,
ssl_listen_address => $listen_address,
listen_address => $listen_address,
java_bin => $java_bin,
java_args => $java_args,
}
contain ::puppetdb::server
class { 'prometheus::puppetdb_exporter':
puppetdb_url => "http://${listen_address}:8080/pdb/query",
export_scrape_job => true,
}
# export haproxy balancemember
profiles::haproxy::balancemember { "${facts['networking']['fqdn']}_8080":
service => 'be_puppetdbapi',
ports => [8080],
options => [
"cookie ${facts['networking']['hostname']}",
'check',
'inter 2s',
'rise 3',
'fall 2',
]
}
}
contain ::puppetdb::server
class { 'prometheus::puppetdb_exporter':
puppetdb_url => "http://${listen_address}:8080/pdb/query",
export_scrape_job => true,
}
}
@@ -1,6 +1,6 @@
# configure the puppetdb sql service
class profiles::puppet::puppetdb_sql (
String $puppetdb_host = lookup('profiles::puppet::puppetdb::puppetdb_host'),
String $puppetdb_host = lookup('puppetdbsql'),
String $listen_address = $facts['networking']['ip'],
) {
@@ -24,4 +24,12 @@ class profiles::puppet::puppetdb_sql (
contain ::puppetdb::database::postgresql
# create the postgresql::server::config_entry resources
$pg_config_entries = lookup('postgresql_config_entries', Hash[String, Data], 'hash', {})
$pg_config_entries.each |String $key, Data $value| {
postgresql::server::config_entry { $key:
ensure => 'present',
value => $value,
}
}
}
+28 -54
View File
@@ -2,63 +2,37 @@
#
# This class manages the puppetmaster using the ghoneycutt-puppet module.
# It manages the server settings in the puppet.conf file.
#
# Parameters: None
#
# Actions:
# - Sets up the server, main, agent, and master sections in the puppet.conf file
#
# Usage:
# Directly include the class in your node definitions or classify your nodes
# using an ENC or Hiera.
# Example:
# node 'puppet.example.com' {
# include profiles::puppet::puppetmaster
# }
#
# Requirements:
# - The 'ghoneycutt/puppet' module should be installed in your Puppet master.
# - Puppet master must have access to the necessary directories.
#
# Limitations:
# This is designed to work on Unix-like systems.
class profiles::puppet::puppetmaster (
String $puppetdb_host = lookup('profiles::puppet::puppetdb::puppetdb_host'),
Optional[Stdlib::Fqdn] $puppetdb_host = lookup('puppetdbapi', Optional[Stdlib::Fqdn], 'first', undef),
) {
include profiles::puppet::r10k
include profiles::puppet::g10k
include profiles::puppet::enc
include profiles::puppet::autosign
class { 'puppetdb::master::config':
puppetdb_server => $puppetdb_host,
manage_storeconfigs => false,
if $facts['enc_role'] == 'roles::infra::puppet::master' {
include profiles::puppet::r10k
include profiles::puppet::g10k
include profiles::puppet::enc
include profiles::puppet::cobbler_enc
include profiles::puppet::autosign
include profiles::puppet::gems
include profiles::helpers::certmanager
include profiles::puppet::server
include profiles::puppet::puppetca
include profiles::puppet::eyaml
class { 'puppetdb::master::config':
puppetdb_server => $puppetdb_host,
manage_storeconfigs => false,
}
Package['puppetserver']
-> Class['profiles::puppet::gems']
-> Class['profiles::puppet::r10k']
-> Class['profiles::puppet::g10k']
-> Class['profiles::puppet::enc']
-> Class['profiles::puppet::cobbler_enc']
-> Class['profiles::puppet::autosign']
-> Class['puppetdb::master::config']
-> Class['profiles::puppet::server']
}
class { 'profiles::puppet::server':
vardir => '/opt/puppetlabs/server/data/puppetserver',
logdir => '/var/log/puppetlabs/puppetserver',
rundir => '/var/run/puppetlabs/puppetserver',
pidfile => '/var/run/puppetlabs/puppetserver/puppetserver.pid',
codedir => '/etc/puppetlabs/code',
dns_alt_names => [
'prodinf01n01.main.unkin.net',
'puppet.main.unkin.net',
'puppetca.main.unkin.net',
'puppetmaster.main.unkin.net',
'puppet',
'puppetca',
'puppetmaster',
],
server => 'prodinf01n01.main.unkin.net',
node_terminus => 'exec',
external_nodes => '/opt/puppetlabs/bin/enc',
autosign => '/etc/puppetlabs/puppet/autosign.conf',
default_manifest => '/etc/puppetlabs/code/environments/develop/manifests',
default_environment => 'develop',
storeconfigs => true,
storeconfigs_backend => 'puppetdb',
reports => 'puppetdb',
usecacheonfailure => false,
}
}
-31
View File
@@ -4,41 +4,10 @@
# systemd service and timer to keep the repository updated every minute.
# The Git package is installed if not present, and the repository at the given
# location will always reflect the state of the remote Git repository.
#
# Parameters:
# - r10k_repo: The URL of the Git repository to clone.
#
# Actions:
# - Ensures the Git package is installed.
# - Ensures the /etc/puppetlabs/r10k directory is a clone of the given Git repository.
# - Creates a helper script '/opt/puppetlabs/bin/puppet-r10k' for updating the Git repository.
# - Creates a systemd service and timer that runs the git update script every minute.
#
# Usage:
# Directly include the class in your node definitions or classify your nodes
# using an enc or Hiera.
# Example:
# node 'puppet.example.com' {
# class { 'profiles::puppet::r10k':
# r10k_repo => 'https://github.com/user/repo.git',
# }
# }
#
# Requirements:
# - The 'puppet-vcsrepo' module should be installed on your puppetmaster.
# - The 'puppet-systemd' module should be installed on your puppetmaster.
# - '/opt/puppetlabs/bin/' directory must exist and be writable.
# - Puppet master must have access to the specified Git URL.
#
# Limitations:
# This is designed to work on Unix-like systems only.
#
class profiles::puppet::r10k (
String $r10k_repo,
){
include profiles::packages::git
vcsrepo { '/etc/puppetlabs/r10k':
ensure => latest,
provider => git,
+35 -32
View File
@@ -1,36 +1,33 @@
# Class: profiles::puppet::server
#
# This class manages Puppet server's configuration and service.
#
# Parameters:
# vardir - Directory path for variable data.
# logdir - Directory path for logs.
# rundir - Directory path for run-time data.
# pidfile - File path for the PID file.
# codedir - Directory path for code data.
# dns_alt_names - Array of alternate DNS names for the server.
# server - Server's name.
# node_terminus - Node terminus.
# external_nodes - Path to the external node classifier script.
# autosign - Path to the autosign script.
#
class profiles::puppet::server (
String $vardir,
String $logdir,
String $rundir,
String $pidfile,
String $codedir,
Array[String[1]] $dns_alt_names,
String $server,
String $node_terminus,
String $external_nodes,
String $autosign,
String $default_manifest,
String $default_environment,
Boolean $storeconfigs,
String $storeconfigs_backend,
String $reports,
Boolean $usecacheonfailure,
Stdlib::Absolutepath $vardir = '/opt/puppetlabs/server/data/puppetserver',
Stdlib::Absolutepath $logdir = '/var/log/puppetlabs/puppetserver',
Stdlib::Absolutepath $rundir = '/var/run/puppetlabs/puppetserver',
Stdlib::Absolutepath $pidfile = '/var/run/puppetlabs/puppetserver/puppetserver.pid',
Stdlib::Absolutepath $codedir = '/etc/puppetlabs/code',
Array[String] $dns_alt_names = [
$facts['networking']['fqdn'],
$facts['networking']['hostname'],
],
Stdlib::Fqdn $agent_server = 'puppetmaster',
Stdlib::Fqdn $report_server = $agent_server,
Stdlib::Fqdn $ca_server = 'puppetca',
String $node_terminus = 'exec',
String $external_nodes = '/opt/cobbler-enc/cobbler-enc',
String $default_environment = 'develop',
String $environment = 'develop',
Stdlib::Absolutepath $autosign = '/etc/puppetlabs/puppet/autosign.conf',
Stdlib::Absolutepath $default_manifest = "${codedir}/environments/${default_environment}/manifests",
String $reports = 'puppetdb',
Boolean $storeconfigs = true,
String $storeconfigs_backend = 'puppetdb',
Boolean $usecacheonfailure = false,
Boolean $report = true,
Integer $runinterval = 1800,
Integer $runtimeout = 3600,
Boolean $show_diff = true,
) {
file { '/etc/puppetlabs/puppet/puppet.conf':
@@ -44,8 +41,15 @@ class profiles::puppet::server (
'rundir' => $rundir,
'pidfile' => $pidfile,
'codedir' => $codedir,
'dns_alt_names' => join($dns_alt_names, ','),
'server' => $server,
'dns_alt_names' => join(sort($dns_alt_names), ','),
'server' => $agent_server,
'ca_server' => $ca_server,
'environment' => $environment,
'report' => $report,
'runinterval' => $runinterval,
'runtimeout' => $runtimeout,
'show_diff' => $show_diff,
'report_server' => $report_server,
'node_terminus' => $node_terminus,
'external_nodes' => $external_nodes,
'autosign' => $autosign,
@@ -66,4 +70,3 @@ class profiles::puppet::server (
hasrestart => true,
}
}
@@ -10,7 +10,7 @@ class profiles::reposync::autosyncer (
group => 'root',
mode => '0755',
content => template('profiles/reposync/autosyncer.erb'),
require => Class['profiles::packages::reposync'],
require => Package['createrepo'],
}
# daily autosyncr service/timer
+1 -1
View File
@@ -4,7 +4,7 @@ define profiles::reposync::repos (
String $description,
String $osname,
String $release,
Stdlib::HTTPUrl $gpgkey,
Stdlib::Filesource $gpgkey,
String $arch = 'x86_64',
String $repo_owner = 'root',
String $repo_group = 'root',
+7 -5
View File
@@ -1,7 +1,6 @@
# setup a reposync syncer
class profiles::reposync::syncer {
include profiles::packages::reposync
include profiles::reposync::autosyncer
include profiles::reposync::autopromoter
include profiles::reposync::webserver
@@ -14,10 +13,13 @@ class profiles::reposync::syncer {
mode => '0755',
}
file { '/etc/reposync/conf.d':
ensure => directory,
owner => 'root',
group => 'root',
mode => '0755',
ensure => directory,
owner => 'root',
group => 'root',
mode => '0755',
purge => true,
recurse => true,
force => true,
}
# get a list of repos as a hash, and iterate through them
+124 -16
View File
@@ -1,23 +1,120 @@
# setup a reposync webserver
class profiles::reposync::webserver (
String $www_root = '/data/repos/snap',
String $cache_root = '/data/repos/cache',
String $nginx_vhost = 'repos.main.unkin.net',
Integer $nginx_port = 80,
Stdlib::Port $nginx_port = 80,
Stdlib::Port $nginx_ssl_port = 443,
Boolean $favicon = true,
Boolean $selinux = true,
Enum['http','https','both'] $nginx_listen_mode = 'http',
Enum['puppet', 'vault'] $nginx_cert_type = 'vault'
) {
class { 'nginx': }
# select the certificates to use based on cert type
case $nginx_cert_type {
'puppet': {
$selected_ssl_cert = "/etc/pki/tls/puppet/${facts['networking']['fqdn']}.crt"
$selected_ssl_key = "/etc/pki/tls/puppet/${facts['networking']['fqdn']}.key"
}
'vault': {
$selected_ssl_cert = '/etc/pki/tls/vault/certificate.crt'
$selected_ssl_key = '/etc/pki/tls/vault/private.key'
}
default: {
# enum param prevents this ever being reached
}
}
# create the nginx vhost
nginx::resource::server { $nginx_vhost:
listen_port => $nginx_port,
server_name => [$nginx_vhost],
use_default_location => true,
access_log => "/var/log/nginx/${nginx_vhost}_access.log",
error_log => "/var/log/nginx/${nginx_vhost}_error.log",
www_root => $www_root,
autoindex => 'on',
# set variables based on the listen_mode
case $nginx_listen_mode {
'http': {
$enable_ssl = false
$ssl_cert = undef
$ssl_key = undef
$listen_port = $nginx_port
$listen_ssl_port = undef
$extras_hash = {}
}
'https': {
$enable_ssl = true
$ssl_cert = $selected_ssl_cert
$ssl_key = $selected_ssl_key
$listen_port = $nginx_ssl_port
$listen_ssl_port = $nginx_ssl_port
$extras_hash = {
'subscribe' => [File[$ssl_cert], File[$ssl_key]],
}
}
'both': {
$enable_ssl = true
$ssl_cert = $selected_ssl_cert
$ssl_key = $selected_ssl_key
$listen_port = $nginx_port
$listen_ssl_port = $nginx_ssl_port
$extras_hash = {
'subscribe' => [File[$ssl_cert], File[$ssl_key]],
}
}
default: {
# enum param prevents this ever being reached
}
}
# define the default parameters for the nginx server
$defaults = {
'listen_port' => $listen_port,
'server_name' => [$nginx_vhost],
'use_default_location' => true,
'access_log' => "/var/log/nginx/${nginx_vhost}_access.log",
'error_log' => "/var/log/nginx/${nginx_vhost}_error.log",
'www_root' => $www_root,
'autoindex' => 'on',
'ssl' => $enable_ssl,
'ssl_cert' => $ssl_cert,
'ssl_key' => $ssl_key,
'ssl_port' => $listen_ssl_port,
}
# merge the hashes conditionally
$nginx_parameters = merge($defaults, $extras_hash)
# manage the nginx class
class { 'nginx':
proxy_cache_path => {
"${cache_root}/debian" => 'debian:128m',
},
proxy_cache_levels => '1:2',
proxy_cache_keys_zone => 'debian:128m',
proxy_cache_max_size => '30000m',
proxy_cache_inactive => '60d',
proxy_temp_path => "${cache_root}/tmp",
}
# create the nginx vhost with the merged parameters
create_resources('nginx::resource::server', { $nginx_vhost => $nginx_parameters })
# cache debian packages from upstream
nginx::resource::location { "${nginx_vhost}-debian":
ensure => present,
ssl => true,
ssl_only => false,
location => '/debian',
server => $nginx_vhost,
proxy => 'http://mirror.gsl.icu/debian',
}
nginx::resource::location { "${nginx_vhost}-debian_pool":
ensure => present,
ssl => true,
ssl_only => false,
location => '/debian/pool',
server => $nginx_vhost,
proxy => 'http://mirror.gsl.icu/debian/pool',
proxy_cache => 'debian',
proxy_cache_valid => [
'200 302 1440h',
'404 1m'
],
}
if $favicon {
@@ -39,10 +136,7 @@ class profiles::reposync::webserver (
order => 10,
}
if $selinux {
# include packages that are required
include profiles::packages::selinux
if $::facts['os']['selinux']['config_mode'] == 'enforcing' {
# set httpd_sys_content_t to all files under the www_root
selinux::fcontext { $www_root:
@@ -51,6 +145,13 @@ class profiles::reposync::webserver (
pathspec => "${www_root}(/.*)?",
}
# set httpd_sys_rw_content_t to all files under the cache_root
selinux::fcontext { $cache_root:
ensure => 'present',
seltype => 'httpd_sys_rw_content_t',
pathspec => "${cache_root}(/.*)?",
}
# make sure we can connect to port 80
selboolean { 'httpd_can_network_connect':
persistent => true,
@@ -63,5 +164,12 @@ class profiles::reposync::webserver (
refreshonly => true,
subscribe => Selinux::Fcontext[$www_root],
}
exec { "restorecon_${cache_root}":
path => ['/bin', '/usr/bin', '/sbin', '/usr/sbin'],
command => "restorecon -Rv ${cache_root}",
refreshonly => true,
subscribe => Selinux::Fcontext[$cache_root],
}
}
}
@@ -7,8 +7,6 @@ class profiles::selinux::mysqld (
Boolean $selinuxuser_mysql_connect_enabled = true,
String $selinux_mode = 'enforcing',
){
# include packages that are required
include profiles::packages::selinux
# setenforce
class { 'profiles::selinux::setenforce':
+20
View File
@@ -0,0 +1,20 @@
# profiles::selinux::nginx
# selinux settings for nginx
class profiles::selinux::nginx (
Boolean $persistent = true,
Boolean $httpd_can_network_connect = true,
String $selinux_mode = 'enforcing',
){
# setenforce
class { 'profiles::selinux::setenforce':
mode => $selinux_mode,
}
# make sure we can connect to network resources
selboolean { 'httpd_can_network_connect':
persistent => $persistent,
value => $httpd_can_network_connect,
}
}
@@ -3,7 +3,8 @@ class profiles::selinux::setenforce (
Enum['enforcing', 'permissive', 'disabled'] $mode = 'enforcing',
) {
class { 'selinux':
mode => $mode,
mode => $mode,
require => Package['policycoreutils']
}
}
+6 -5
View File
@@ -30,7 +30,6 @@ class profiles::sql::galera_member (
Boolean $package_manage = true,
String $package_name = 'mariadb-server',
Boolean $epel_needed = false,
Boolean $selinux = true,
Boolean $manage_repo = true,
) {
@@ -48,7 +47,7 @@ class profiles::sql::galera_member (
}
# if it is, find hosts, sort them so they dont cause changes every run
$servers_array = sort(query_nodes("enc_role='${galera_members_role}'", 'networking.fqdn'))
$servers_array = sort(query_nodes("enc_role='${galera_members_role}' and region='${facts['region']}'", 'networking.fqdn'))
# else use provided array from params
}else{
@@ -59,10 +58,10 @@ class profiles::sql::galera_member (
if length($servers_array) >= 3 {
# if selinux is defined, manage it
if $selinux {
if $::facts['os']['selinux']['config_mode'] == 'enforcing' {
# set permissive on first run, as we need mariadb installed/started at a custom path before adding fcontext
if $::facts['mariadb_acti'] { $selinux_mode = 'enforcing' }else{ $selinux_mode = 'permissive' }
if $::facts['mariadb_active'] { $selinux_mode = 'enforcing' }else{ $selinux_mode = 'permissive' }
# call the mysqld selinux class
class { 'profiles::selinux::mysqld':
@@ -104,7 +103,8 @@ class profiles::sql::galera_member (
'binlog_format' => 'ROW',
'default-storage-engine' => 'innodb',
'query_cache_size' => '0',
'query_cache_type' => '0'
'query_cache_type' => '0',
'bind-address' => $local_ip,
}
}
$default_override_options_galera = {
@@ -212,4 +212,5 @@ class profiles::sql::galera_member (
}else{
notice("${title} requires the servers_array to have 3 or more, currently it is ${length($servers_array)}.")
}
}
@@ -0,0 +1,75 @@
# profiles::storage::datavol
#
# This define manages the creation of a logical volume using the `lvm::volume` definition.
#
# Parameters:
# $ensure - Ensure whether the logical volume is present or not. Defaults to 'present'.
# $vg - Volume group name. No default.
# $pv - Physical volume, typically the disk or partition device path. No default.
# $fstype - Filesystem type for the logical volume. Defaults to 'ext3'.
# $size - Size of the logical volume. undef = 100%FREE. Changing $size to cause a resize.
#
define profiles::storage::datavol (
Enum['present', 'absent'] $ensure = 'present',
Enum['ext2', 'ext3', 'ext4', 'xfs', 'btrfs'] $fstype = 'xfs',
String $vg = 'datavg',
String $pv = '/dev/vdb',
String $lv = 'data',
String $owner = 'root',
String $group = 'root',
Stdlib::Filemode $mode = '0755',
Stdlib::Absolutepath $mount = '/data',
Optional[Variant[Pattern[/^\d+(M|G|T|P)$/], Integer]] $size = undef,
Array[Enum[
'defaults', 'ro', 'rw', 'sync', 'async',
'noatime', 'nodiratime', 'noexec', 'nosuid',
'nodev', 'remount', 'auto', 'noauto'
]] $mount_options = ['noatime', 'nodiratime'],
) {
# Ensure the physical volume exists
physical_volume { $pv:
ensure => $ensure,
before => Volume_group[$vg],
}
# Ensure the volume group exists
volume_group { $vg:
ensure => $ensure,
physical_volumes => [$pv],
before => Logical_volume[$lv],
}
# Ensure the logical volume exists
logical_volume { $lv:
ensure => $ensure,
volume_group => $vg,
size => $size,
before => Filesystem["/dev/${vg}/${lv}"],
}
# Ensure the filesystem is created on the logical volume
filesystem { "/dev/${vg}/${lv}":
ensure => $ensure,
fs_type => $fstype,
require => Logical_volume[$lv],
before => Mount[$mount],
}
# Ensure the mountpath exists
file { $mount:
ensure => directory,
owner => $owner,
group => $group,
mode => $mode,
}
# Ensure the logical volume is mounted at the desired location
mount { $mount:
ensure => $ensure,
device => "/dev/${vg}/${lv}",
fstype => $fstype,
options => $mount_options.join(','),
require => Filesystem["/dev/${vg}/${lv}"],
}
}

Some files were not shown because too many files have changed in this diff Show More