Last active
November 26, 2022 19:54
-
-
Save jthurteau/3c3d8e15208d93c0cf28cc2148c91b0b to your computer and use it in GitHub Desktop.
Vagrant with MrRogers
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
## | |
# Helps Manage Puppetized RHEL Vagrants | |
# https://puppet.com/docs/puppet/5.5/ | |
# https://access.redhat.com/documentation/en-us/red_hat_enterprise_linux/7/ https://www.linux.ncsu.edu/rhel-unc-system/ | |
# https://www.vagrantup.com/docs/ | |
# | |
# You do not need Ruby on the guest for this module, | |
# you should not need Ruby installed on the guest aside from the runtime Vagrant uses | |
# https://gist.github.com/jthurteau/3c3d8e15208d93c0cf28cc2148c91b0b | |
# | |
module MrRogers | |
extend self | |
@tabs = ' ' | |
@manifest_stack = '' | |
@manifests_path = 'puppet/manifests' | |
@manifest_build_file = 'default-dynamic.pp' | |
@built_manifest_token = 'puppet made this' | |
@facts_file = '.puppet_facts' #relative to vagrant, not puppet | |
@puppet_facts = nil | |
@ppp = [] | |
@realm = nil | |
@rhel_org = '' | |
@realm_key = '' | |
@rhel_repo = '' | |
@realhostname = nil | |
@realdomain = nil | |
@collections_requested = false | |
@collection_source = [:rhel, :centos, :remi][2] | |
@when_to_chill = ['never', 'always'][1] | |
@when_to_reregister = ['never', 'always'][0] | |
@when_to_install_sc = ['once', 'never'][0] | |
@when_to_nano_enforce = 'once' | |
#TODO make the puppet modules/versions configurable | |
def self.init(stack, path, build) | |
@manifest_stack = stack | |
@manifests_path = path | |
@manifest_build_file = build | |
begin | |
# NOTE - an empty YAML file equates to nil, | |
# the facts_file must be an explicit empty hash {} if it has no value-keys | |
@puppet_facts = YAML.load_file(@facts_file) | |
rescue SystemCallError => e | |
print "#{@tabs}Warning: puppet facts not available (this is a critical error on up, reload, provision, or resume)\n\r" | |
end | |
@manifest_stack.split('-').each { |a| @ppp.push(a) } | |
end | |
def self.set_realm(new_realm, org, key, repo) | |
@realm = new_realm | |
@rhel_org = org | |
@realm_key = key | |
@rhel_repo = repo | |
end | |
#TODO this should probably be an instance (per app/machine) method | |
def self.box(box, config) | |
config.vm.box = @realm ? 'generic/rhel7' : 'centos/7' | |
config.vm.define ("#{box}-" + (@realm ? 'realm' : 'nomad')) do # |machine| | |
# only used in multi-machine builds | |
end | |
end | |
def self.passthrough_host(config) | |
fqdn = Socket.gethostbyname(Socket.gethostname).first.split('.') | |
hostname = fqdn.shift.downcase | |
domain = fqdn.join('.').downcase | |
public_ips = Socket.ip_address_list.reject{|i| !i.ipv4? || i.ipv4_loopback? || i.ipv4_multicast? || i.ipv4_private? } | |
ip = public_ips.any? ? public_ips.first&.ip_address : nil | |
realfqdn = ip ? (Resolv.getname ip).split('.') : nil | |
@realhostname = realfqdn ? realfqdn.shift.downcase : hostname | |
@realdomain = realfqdn ? realfqdn.join('.').downcase : domain | |
config.trigger.before [:up, :provision, :reload] do |trigger| | |
trigger.info = "Harvesting Host FQDN" | |
trigger.ruby do |env, machine| | |
if (!ip) | |
Socket.ip_address_list.map{ |i| print(i.inspect + "\n\r")} | |
print("#{@tabs}No public IPv4 detected, known IPs: \n\r"); | |
end | |
print "#{@tabs}host fqdn detected as #{@realhostname} + #{@realdomain}" + (ip ? " (#{ip})" : '') + "\n\r" | |
end | |
end | |
config.vm.provision "set_hostname", type: :shell, inline: <<-SHELL | |
hostnamectl set-hostname #{@realhostname} | |
SHELL | |
if (@realm) | |
config.vm.provision "setup_domain", type: :shell, inline: <<-SHELL | |
if [ ! -e /etc/hosts ] || ! grep -q "needed for realm-puppet management" /etc/hosts | |
then | |
echo " " >> /etc/hosts | |
echo "## The line below is needed for realm-puppet management" >> /etc/hosts | |
echo "#{ip} #{@realhostname}.#{@realdomain} #{@realhostname}" >> /etc/hosts | |
echo " " >> /etc/hosts | |
fi | |
SHELL | |
end | |
end | |
def self.register(config) | |
self.passthrough_host(config) if (!@realhostname) | |
if (@realm) | |
config.vm.provision "rhel_setup", type: :shell, inline: <<-SHELL | |
yum install #{@rhel_repo} -y | |
if [[ $(subscription-manager identity) =~ "org ID: #{@rhel_org}" ]] | |
then | |
echo "RHEL already registered" | |
else | |
subscription-manager register --org="#{@rhel_org}" --activationkey="#{@realm_key}" | |
fi | |
SHELL | |
registration_update_inline = <<-SHELL | |
yum install http://rhn200cap.unity.ncsu.edu/pub/katello-ca-consumer-latest.noarch.rpm -y | |
if [[ $(subscription-manager identity) =~ "org ID: #{@rhel_org}" ]] | |
then | |
echo "Unregistering RHEL" | |
subscription-manager unregister | |
else | |
echo "RHEL not registered" | |
fi | |
subscription-manager register --org="#{@rhel_org}" --activationkey="#{@realm_key}" | |
subscription-manager clean | |
yum clean all | |
yum update -y | |
SHELL | |
else | |
config.vm.provision "centos_setup", type: :shell, inline: <<-SHELL | |
yum groups install "Development Tools" -y | |
SHELL | |
registration_update_inline = <<-SHELL | |
echo Unavailable in nomad mode | |
SHELL | |
end | |
config.vm.provision "registration_update", type: :shell, run: @when_to_reregister do |s| | |
s.inline = registration_update_inline | |
end | |
end | |
def self.add_collections(config, source = nil) | |
@collection_source = source if source | |
@collections_requested = true | |
if (@realm) | |
software_collections_inline = <<-SHELL | |
echo Inclusing the software_collections... | |
echo (currently broken) | |
# subscription-manager repos --enable rhel-server-rhscl-7-rpms | |
# subscription-manager repos --enable rhel-7-server-optional-rpms | |
SHELL | |
elsif ( @collection_source == :centos ) | |
software_collections_inline = <<-SHELL | |
yum install centos-release-scl -y | |
yum update -y | |
SHELL | |
elsif ( @collection_source == :remi ) | |
software_collections_inline = <<-SHELL | |
yum install http://rpms.remirepo.net/enterprise/remi-release-7.rpm -y | |
yum update -y | |
SHELL | |
else | |
software_collections_inline = <<-SHELL | |
echo no valid software collection specified (requested '#{source}') | |
SHELL | |
end | |
config.vm.provision "software_collections", type: :shell, run: @when_to_install_sc do |s| | |
s.inline = software_collections_inline | |
end | |
end | |
def self.puppetize(config, options = '') | |
MrRogers::add_collections(config) if (!@collections_requested) | |
config.trigger.before [:up, :provision, :reload, :resume] do |trigger| | |
trigger.info = "Checking, are Strings Attached?" | |
trigger.ruby do |env, machine| | |
if (!@puppet_facts) | |
print "#{@tabs}Error: Unable to load puppet facts. Exiting...\n\r" | |
exit(1) | |
end | |
print "#{@tabs}loaded facts from #{@facts_file}\n\r" | |
ldm_path = "#{@manifests_path}/#{@manifest_build_file}" | |
if !File.file?(ldm_path) | |
ldm_file = File.new(ldm_path, 'w+') | |
ldm_file.write("# #{@built_manifest_token}") | |
else | |
ldm_file = File.new(ldm_path, 'a+') | |
ldm_file.rewind | |
if (!ldm_file.readline.start_with?("# #{@built_manifest_token}")) | |
ldm_file.close | |
ldm_file = nil | |
print "#{@tabs}proceeding with manually written #{@manifest_build_file} \n\r" | |
end | |
end | |
if (ldm_file) | |
print "#{@tabs}building #{@manifest_build_file} \n\r" | |
ldm_file.truncate(ldm_file.pos + 1) | |
ppp_final = ['global'] + @ppp + ['override'] | |
ppp_final.each do |pp| | |
if (File.file?("#{@manifests_path}/#{pp}.pp")) | |
print "#{@tabs} adding \"#{pp}\" manifest to #{@manifest_build_file}\n\r" | |
ldm_file.write("\n\r# from #{pp}.pp \n\r"); | |
ldm_file.write(File.read("#{@manifests_path}/#{pp}.pp")) | |
else | |
print "#{@tabs} no \"#{pp}\" manifest available for #{@manifest_build_file}\n\r" | |
end | |
end | |
ldm_file.close | |
end | |
end | |
end | |
config.vm.provision "puppet_prep", type: :shell, inline: <<-SHELL | |
# rpm -ivh https://yum.puppetlabs.com/puppetlabs-release-el-7.noarch.rpm | |
rpm -Uvh https://yum.puppetlabs.com/puppet5/puppet5-release-el-7.noarch.rpm | |
yum install epel-release puppet -y | |
yum update -y | |
if [ ! -e /usr/bin/puppet ] | |
then | |
echo "linking puppet binary..." | |
ln -s /opt/puppetlabs/bin/puppet /usr/bin/puppet | |
fi | |
# # puppet 3.8 compat "supported" | |
# puppet module install puppetlabs-postgresql --version 4.9.0 | |
# puppet module install puppetlabs-apache --version 1.11.1 | |
# puppet module install puppetlabs-mysql --version 3.11.0 | |
# puppet module install puppetlabs-vcsrepo --version 1.5.0 | |
# # puppet 3.8 compat approved | |
# puppet module install puppet-python --version 2.2.2 | |
# puppet 5.5 compat supported | |
puppet module install puppetlabs-postgresql --version 5.12.0 | |
puppet module install puppetlabs-apache --version 4.0.0 | |
puppet module install puppetlabs-mysql --version 8.0.0 | |
puppet module install puppetlabs-vcsrepo --version 2.4.0 | |
# puppet 5.5 compat approved | |
puppet module install puppet-python --version 2.2.2 | |
puppet config set strict_variables true --section main | |
SHELL | |
config.vm.provision :puppet do |puppet| | |
puppet.manifests_path = @manifests_path | |
puppet.manifest_file = @manifest_build_file | |
puppet.options = options | |
puppet.facter = @puppet_facts | |
end | |
config.vm.provision "puppet-reset", type: :shell, run: 'never' do |s| | |
s.inline = <<-SHELL | |
puppet module uninstall puppetlabs-postgresql | |
puppet module uninstall puppetlabs-apache | |
puppet module uninstall puppetlabs-mysql | |
puppet module uninstall puppet-python | |
puppet module uninstall puppetlabs-vcsrepo | |
SHELL | |
end | |
end | |
def self.nano_please(config) | |
config.vm.provision "nano_setup", type: :shell do |s| | |
s.inline = <<-SHELL | |
yum install nano -y | |
SHELL | |
end | |
config.vm.provision "nano_make_default", type: :shell, run: @when_to_nano_enforce do |s| | |
s.inline = <<-SHELL | |
if [ ! -e ~/.bashrc ] || ! grep -q "set nano as the default editor" ~/.bashrc | |
then | |
echo " " >> ~/.bashrc | |
echo "## The (2) lines below set nano as the default editor" >> ~/.bashrc | |
echo "export EDITOR='nano'" >> ~/.bashrc | |
echo "export VISUAL='nano'" >> ~/.bashrc | |
echo " " >> ~/.bashrc | |
fi | |
SHELL | |
s.privileged = false | |
end | |
end | |
def self.os_friendly(config) | |
if Vagrant::Util::Platform.windows? | |
self.windows_host_friendly(config) | |
end | |
end | |
def self.windows_host_friendly(config) | |
config.vm.provision "windows_support", type: :shell do |s| | |
s.inline = <<-SHELL | |
if [ ! -e ~/.bashrc ] || ! grep -q "poor detection of vagrant windows host" ~/.bashrc | |
then | |
echo " " >> ~/.bashrc | |
echo "## The (2) lines below fix poor detection of vagrant windows host" >> ~/.bashrc | |
echo "stty sane" >> ~/.bashrc | |
echo "export TERM=linux" >> ~/.bashrc | |
echo " " >> ~/.bashrc | |
fi | |
SHELL | |
s.privileged = false | |
end | |
end | |
def self.add_helpers(config, additional = []) | |
additional.each do |a| | |
case a | |
when 'nano' | |
self.nano_please(config) | |
when 'os' | |
self.os_friendly(config) | |
else | |
print "#{tabs}unknown helper: #{a}" | |
end | |
end | |
config.vm.provision "reminders", type: :shell, run: 'always' do |s| | |
s.inline = <<-SHELL | |
echo To activate post-startup tasks on the guest VM use: vagrant up --provision-with start | |
SHELL | |
end | |
config.vm.provision "chill", type: :shell, run: @when_to_chill do |s| | |
s.inline = <<-SHELL | |
echo Toning down SELinux... | |
setenforce Permissive | |
systemctl stop firewalld.service | |
SHELL | |
end | |
config.vm.provision "start", type: :shell, run: 'never' do |s| | |
s.inline = <<-SHELL | |
echo Starting Services... | |
systemctl start httpd.service | |
SHELL | |
end | |
config.vm.provision "stop", type: :shell, run: 'never' do |s| | |
s.inline = <<-SHELL | |
echo Stopping Services... | |
systemctl stop httpd.service | |
SHELL | |
end | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
# -*- mode: ruby -*- | |
# vi: set ft=ruby : | |
require 'resolv' | |
require_relative 'puppet/mr_rogers' | |
# project settings | |
app_name = 'APPLICATION_NAME_HERE' | |
org_name = 'ORG_NAME_HERE' | |
realm_mode = false | |
puppet_stack = "#{org_name}-apache-php-#{app_name}" | |
log_to = ['console', 'file'][0] | |
# rhel settings (used in realm_mode) | |
realm_key = 'KEY_HERE' | |
rhel_org = 'RHEL_ORG_HERE' | |
rhel_repo = 'REPO_URL_HERE' | |
# vagrant/puppet specific preferences | |
vagrant_guest_path = '/vagrant' | |
logtime = DateTime.now.strftime('%Y-%m-%d-%H-%M-%S') | |
logfile = "#{vagrant_guest_path}/puppet/local-dev.puppet-provision-#{logtime}.log.json" | |
log_to = logfile if ('file' == log_to) | |
MrRogers::init(puppet_stack, 'puppet/manifests', 'local-dev.pp') | |
MrRogers::set_realm(org_name, rhel_org, realm_key, rhel_repo) if realm_mode | |
#MrRogers::version('5') #TODO manage puppet repo and module versions based on puppet version | |
Vagrant.configure('2') do |config| | |
MrRogers::box("#{app_name}-#{org_name}", config) | |
# Disable automatic box update checking. If you disable this, then | |
# boxes will only be checked for updates when the user runs | |
# `vagrant box outdated`. This is not recommended. | |
# config.vm.box_check_update = false | |
# Forwarded port mapping | |
config.vm.network 'forwarded_port', guest: 80, host: 8080, host_ip: '127.0.0.1' | |
config.vm.network 'forwarded_port', guest: 8001, host: 8081, host_ip: '127.0.0.1' | |
config.vm.synced_folder '.', vagrant_guest_path, owner: 'vagrant', group: 'vagrant', type: 'virtualbox' | |
# Provider-specific configuration so you can fine-tune various | |
# backing providers for Vagrant. These expose provider-specific options. | |
config.vm.provider 'virtualbox' do |vb| | |
# Display the VirtualBox GUI when booting the machine | |
vb.gui = false | |
vb.memory = "1024" | |
end | |
# provisioners | |
MrRogers::register(config) | |
MrRogers::puppetize(config, "--verbose --debug --logdest #{log_to}") | |
# this is where custom provisioning typically happens | |
MrRogers::add_helpers(config, ['nano','os']) #optional (provisioners to manage apache, tone down selinux, etc.) | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment