From 5f1be2380c98f2f338adb8e4174db8b66135aa07 Mon Sep 17 00:00:00 2001 From: Charles Wyble Date: Sat, 9 Dec 2017 12:48:51 -0600 Subject: [PATCH] migration and cleanup from legacy repos --- CMDB/snmp/.svn/all-wcprops | 29 + CMDB/snmp/.svn/entries | 164 +++++ .../prop-base/centos-snmpd.options.svn-base | 5 + .../text-base/centos-snmpd.options.svn-base | 3 + .../text-base/debian-default-snmpd.svn-base | 22 + .../.svn/text-base/setup-snmp.sh.svn-base | 62 ++ CMDB/snmp/.svn/text-base/snmpd.conf.svn-base | 10 + CMDB/snmp/centos-snmpd.options | 3 + CMDB/snmp/debian-default-snmpd | 22 + CMDB/snmp/distro | 70 ++ CMDB/snmp/setup-snmp.sh | 32 + CMDB/snmp/snmpd.conf | 10 + CMDB/subnets | 35 + CMDB/zenossScan.sh | 5 + README | 5 +- TODO.TXT | 70 ++ bare-metal/interfaces-fnfDedi | 293 ++++++++ bare-metal/interfaces-tsysDedi | 169 +++++ lab/LICENSE | 674 ++++++++++++++++++ lab/README | 0 lab/README.md | 31 + lab/docs/Joes-logical | 80 +++ lab/docs/Joes-logical.png | Bin 0 -> 63670 bytes lab/docs/Lab-physical | 126 ++++ lab/docs/LabLogical-Backbone | 59 ++ lab/docs/LabLogical-Backbone.png | Bin 0 -> 36514 bytes lab/docs/LabLogical-Devices | 103 +++ lab/docs/LabLogical-Devices.png | Bin 0 -> 63635 bytes lab/vagrant/Vagrantfile | 88 +++ .../docker/thefnf/freeradius/Dockerfile | 6 + lab/vagrant/docker/thefnf/freeside/Dockerfile | 55 ++ lab/vagrant/docker/thefnf/freeside/Makefile | 468 ++++++++++++ lab/vagrant/docker/thefnf/odoo/Dockerfile | 13 + .../docker/thefnf/odoo/openerp_serverrc | 62 ++ .../ovh/shared-router/shorewall/conntrack | 53 ++ .../ovh/shared-router/shorewall/interfaces | 13 + mtpconfigs/ovh/shared-router/shorewall/masq | 19 + mtpconfigs/ovh/shared-router/shorewall/params | 28 + mtpconfigs/ovh/shared-router/shorewall/policy | 20 + mtpconfigs/ovh/shared-router/shorewall/rules | 113 +++ .../shared-router/shorewall/shorewall.conf | 274 +++++++ mtpconfigs/ovh/shared-router/shorewall/zones | 14 + rubix/Monitoring/mibs/LM-SENSORS-MIB | 230 ++++++ rundeck/auslab | 30 + rundeck/ovh | 35 + rundeck/satx | 20 + rundeck/sshConfig | 99 +++ slack/bin/distro | 257 +++++++ slack/bin/slackInstall.sh | 60 ++ slack/dist/Makefile | 39 + slack/dist/Makefile.common | 27 + slack/dist/Slack.pm | 371 ++++++++++ slack/dist/slack | 329 +++++++++ slack/dist/slack-diff | 514 +++++++++++++ slack/dist/slack-getroles | 161 +++++ slack/dist/slack-installfiles | 149 ++++ slack/dist/slack-rolediff | 146 ++++ slack/dist/slack-runscript | 111 +++ slack/dist/slack-runscript.orig | 111 +++ slack/dist/slack-stage | 278 ++++++++ slack/dist/slack-sync | 169 +++++ slack/dist/slack.conf | 0 slack/env/SlackConfig-prod.config | 6 + slack/env/SlackSSH-prod.config | 4 + slack/env/SlackSSH-prod.key | 27 + slack/env/SlackSSH-prod.key.pub | 1 + slack/slackDist.tar.gz | Bin 0 -> 16474 bytes 67 files changed, 6481 insertions(+), 1 deletion(-) create mode 100755 CMDB/snmp/.svn/all-wcprops create mode 100755 CMDB/snmp/.svn/entries create mode 100755 CMDB/snmp/.svn/prop-base/centos-snmpd.options.svn-base create mode 100755 CMDB/snmp/.svn/text-base/centos-snmpd.options.svn-base create mode 100755 CMDB/snmp/.svn/text-base/debian-default-snmpd.svn-base create mode 100755 CMDB/snmp/.svn/text-base/setup-snmp.sh.svn-base create mode 100755 CMDB/snmp/.svn/text-base/snmpd.conf.svn-base create mode 100755 CMDB/snmp/centos-snmpd.options create mode 100755 CMDB/snmp/debian-default-snmpd create mode 100755 CMDB/snmp/distro create mode 100755 CMDB/snmp/setup-snmp.sh create mode 100755 CMDB/snmp/snmpd.conf create mode 100755 CMDB/subnets create mode 100755 CMDB/zenossScan.sh mode change 100644 => 100755 README create mode 100755 TODO.TXT create mode 100755 bare-metal/interfaces-fnfDedi create mode 100644 bare-metal/interfaces-tsysDedi create mode 100755 lab/LICENSE create mode 100755 lab/README create mode 100755 lab/README.md create mode 100755 lab/docs/Joes-logical create mode 100755 lab/docs/Joes-logical.png create mode 100755 lab/docs/Lab-physical create mode 100755 lab/docs/LabLogical-Backbone create mode 100755 lab/docs/LabLogical-Backbone.png create mode 100755 lab/docs/LabLogical-Devices create mode 100755 lab/docs/LabLogical-Devices.png create mode 100755 lab/vagrant/Vagrantfile create mode 100755 lab/vagrant/docker/thefnf/freeradius/Dockerfile create mode 100755 lab/vagrant/docker/thefnf/freeside/Dockerfile create mode 100755 lab/vagrant/docker/thefnf/freeside/Makefile create mode 100755 lab/vagrant/docker/thefnf/odoo/Dockerfile create mode 100755 lab/vagrant/docker/thefnf/odoo/openerp_serverrc create mode 100755 mtpconfigs/ovh/shared-router/shorewall/conntrack create mode 100755 mtpconfigs/ovh/shared-router/shorewall/interfaces create mode 100755 mtpconfigs/ovh/shared-router/shorewall/masq create mode 100755 mtpconfigs/ovh/shared-router/shorewall/params create mode 100755 mtpconfigs/ovh/shared-router/shorewall/policy create mode 100755 mtpconfigs/ovh/shared-router/shorewall/rules create mode 100755 mtpconfigs/ovh/shared-router/shorewall/shorewall.conf create mode 100755 mtpconfigs/ovh/shared-router/shorewall/zones create mode 100755 rubix/Monitoring/mibs/LM-SENSORS-MIB create mode 100644 rundeck/auslab create mode 100644 rundeck/ovh create mode 100644 rundeck/satx create mode 100755 rundeck/sshConfig create mode 100755 slack/bin/distro create mode 100755 slack/bin/slackInstall.sh create mode 100755 slack/dist/Makefile create mode 100755 slack/dist/Makefile.common create mode 100755 slack/dist/Slack.pm create mode 100755 slack/dist/slack create mode 100755 slack/dist/slack-diff create mode 100755 slack/dist/slack-getroles create mode 100755 slack/dist/slack-installfiles create mode 100755 slack/dist/slack-rolediff create mode 100755 slack/dist/slack-runscript create mode 100755 slack/dist/slack-runscript.orig create mode 100755 slack/dist/slack-stage create mode 100755 slack/dist/slack-sync create mode 100755 slack/dist/slack.conf create mode 100644 slack/env/SlackConfig-prod.config create mode 100644 slack/env/SlackSSH-prod.config create mode 100644 slack/env/SlackSSH-prod.key create mode 100644 slack/env/SlackSSH-prod.key.pub create mode 100755 slack/slackDist.tar.gz diff --git a/CMDB/snmp/.svn/all-wcprops b/CMDB/snmp/.svn/all-wcprops new file mode 100755 index 0000000..1b48647 --- /dev/null +++ b/CMDB/snmp/.svn/all-wcprops @@ -0,0 +1,29 @@ +K 25 +svn:wc:ra_dav:version-url +V 57 +/rg0103/pdesubversion-tpqaslack/!svn/ver/366/scripts/snmp +END +debian-default-snmpd +K 25 +svn:wc:ra_dav:version-url +V 78 +/rg0103/pdesubversion-tpqaslack/!svn/ver/315/scripts/snmp/debian-default-snmpd +END +centos-snmpd.options +K 25 +svn:wc:ra_dav:version-url +V 78 +/rg0103/pdesubversion-tpqaslack/!svn/ver/359/scripts/snmp/centos-snmpd.options +END +setup-snmp.sh +K 25 +svn:wc:ra_dav:version-url +V 71 +/rg0103/pdesubversion-tpqaslack/!svn/ver/366/scripts/snmp/setup-snmp.sh +END +snmpd.conf +K 25 +svn:wc:ra_dav:version-url +V 68 +/rg0103/pdesubversion-tpqaslack/!svn/ver/276/scripts/snmp/snmpd.conf +END diff --git a/CMDB/snmp/.svn/entries b/CMDB/snmp/.svn/entries new file mode 100755 index 0000000..a657701 --- /dev/null +++ b/CMDB/snmp/.svn/entries @@ -0,0 +1,164 @@ +10 + +dir +440 +https://svn01.atlanta.hp.com/rg0103/pdesubversion-tpqaslack/scripts/snmp +https://svn01.atlanta.hp.com/rg0103/pdesubversion-tpqaslack + + + +2013-10-30T20:33:11.769859Z +366 +wyble@hp.com + + + + + + + + + + + + + + +92b00a8e-620f-4ac7-abd2-c9ef5b6c269b + +debian-default-snmpd +file + + + + +2013-12-10T21:18:03.480402Z +536542d8470261eb1971bd3bb35adf68 +2013-10-02T16:57:28.319476Z +315 +wyble@hp.com + + + + + + + + + + + + + + + + + + + + + +723 + +centos-snmpd.options +file + + + + +2013-12-10T21:18:03.487402Z +40233436f1b04129a231dba3a5225762 +2013-10-25T19:11:31.312453Z +359 +wyble@hp.com +has-props + + + + + + + + + + + + + + + + + + + + +135 + +setup-snmp.sh +file + + + + +2013-12-10T21:18:03.492402Z +dde4ae53ae1e316b551dbc386ac30e9b +2013-10-30T20:33:11.769859Z +366 +wyble@hp.com + + + + + + + + + + + + + + + + + + + + + +1350 + +snmpd.conf +file + + + + +2013-12-10T21:18:03.496402Z +88b7c51014dbd12d784982d41c3ae7e7 +2013-09-17T18:44:43.972099Z +276 +wyble@hp.com + + + + + + + + + + + + + + + + + + + + + +474 + diff --git a/CMDB/snmp/.svn/prop-base/centos-snmpd.options.svn-base b/CMDB/snmp/.svn/prop-base/centos-snmpd.options.svn-base new file mode 100755 index 0000000..869ac71 --- /dev/null +++ b/CMDB/snmp/.svn/prop-base/centos-snmpd.options.svn-base @@ -0,0 +1,5 @@ +K 14 +svn:executable +V 1 +* +END diff --git a/CMDB/snmp/.svn/text-base/centos-snmpd.options.svn-base b/CMDB/snmp/.svn/text-base/centos-snmpd.options.svn-base new file mode 100755 index 0000000..58fd07c --- /dev/null +++ b/CMDB/snmp/.svn/text-base/centos-snmpd.options.svn-base @@ -0,0 +1,3 @@ +# snmpd command line options +OPTIONS="-Lsd -Lf /dev/null -p /var/run/snmpd.pid" +#OPTIONS="-Lsd -Lf /dev/null -p /var/run/snmpd.pid -a" diff --git a/CMDB/snmp/.svn/text-base/debian-default-snmpd.svn-base b/CMDB/snmp/.svn/text-base/debian-default-snmpd.svn-base new file mode 100755 index 0000000..14f2b86 --- /dev/null +++ b/CMDB/snmp/.svn/text-base/debian-default-snmpd.svn-base @@ -0,0 +1,22 @@ +# This file controls the activity of snmpd and snmptrapd + +# Don't load any MIBs by default. +# You might comment this lines once you have the MIBs downloaded. +export MIBS= + +# snmpd control (yes means start daemon). +SNMPDRUN=yes + +# snmpd options (use syslog, close stdin/out/err). +SNMPDOPTS='-Lsd -Lf /dev/null -u snmp -g snmp -I -smux -p /var/run/snmpd.pid' + +# snmptrapd control (yes means start daemon). As of net-snmp version +# 5.0, master agentx support must be enabled in snmpd before snmptrapd +# can be run. See snmpd.conf(5) for how to do this. +TRAPDRUN=no + +# snmptrapd options (use syslog). +TRAPDOPTS='-Lsd -p /var/run/snmptrapd.pid' + +# create symlink on Debian legacy location to official RFC path +SNMPDCOMPAT=yes diff --git a/CMDB/snmp/.svn/text-base/setup-snmp.sh.svn-base b/CMDB/snmp/.svn/text-base/setup-snmp.sh.svn-base new file mode 100755 index 0000000..508d1ab --- /dev/null +++ b/CMDB/snmp/.svn/text-base/setup-snmp.sh.svn-base @@ -0,0 +1,62 @@ +#!/bin/bash +#A script to setup snmp on redhat/debian systems + + + +centos_snmp() +#Install SNMP on a cent box +{ +#Fix yum.conf +wget -O /etc/yum/yum.conf http://slack-master.tplab.tippingpoint.com/yum.conf + + +#Install snmpd +yum -y install net-snmp + +#Install observium bits +wget -O /usr/bin/distro http://www.observium.org/svn/observer/trunk/scripts/distro +chmod 755 /usr/bin/distro + +#Pull down snmpd configuration files +wget -O /etc/snmp/snmpd.conf http://slack-master.tplab.tippingpoint.com/snmp/snmpd.conf +wget -O /etc/sysconfig/snmpd.options http://slack-master.tplab.tippingpoint.com/snmp/centos-snmpd.options + +#Restart snmpd +/etc/init.d/snmpd restart + +chkconfig snmpd on +} + + +debian_snmp() +#Install snmp on a debian box +{ +#Install snmpd +apt-get -y install snmpd + +#Install observium bits +wget -O /usr/bin/distro http://www.observium.org/svn/observer/trunk/scripts/distro +chmod 755 /usr/bin/distro + +#Pull down snmpd configuration files +wget -O /etc/default/snmpd http://slack-master.tplab.tippingpoint.com/snmp/debian-default-snmpd.conf +wget -O /etc/snmp/snmpd.conf http://slack-master.tplab.tippingpoint.com/snmp/snmpd.conf + +#Restart snmpd +/etc/init.d/snmpd restart + +chkconfig snmpd on +} + + +DIST=$(lsb_release -d) + +if [ $(echo $DIST | grep Ubuntu -c) -eq 1 ]; +then +debian_snmp +fi + +if [ $(echo $DIST | grep Centos -c) -eq 1 ]; +then +centos_snmp +fi diff --git a/CMDB/snmp/.svn/text-base/snmpd.conf.svn-base b/CMDB/snmp/.svn/text-base/snmpd.conf.svn-base new file mode 100755 index 0000000..41b2cf3 --- /dev/null +++ b/CMDB/snmp/.svn/text-base/snmpd.conf.svn-base @@ -0,0 +1,10 @@ +com2sec readonly default mng-actua1 +group MyROGroup v1 readonly +group MyROGroup v2c readonly +group MyROGroup usm readonly +view all included .1 80 +access MyROGroup "" any noauth exact all none none +syslocation Austin TX USA +syscontact esplabsupport@hp.com +#This line allows Observium to detect the host OS if the distro script is installed +extend .1.3.6.1.4.1.2021.7890.1 distro /usr/bin/distro diff --git a/CMDB/snmp/centos-snmpd.options b/CMDB/snmp/centos-snmpd.options new file mode 100755 index 0000000..58fd07c --- /dev/null +++ b/CMDB/snmp/centos-snmpd.options @@ -0,0 +1,3 @@ +# snmpd command line options +OPTIONS="-Lsd -Lf /dev/null -p /var/run/snmpd.pid" +#OPTIONS="-Lsd -Lf /dev/null -p /var/run/snmpd.pid -a" diff --git a/CMDB/snmp/debian-default-snmpd b/CMDB/snmp/debian-default-snmpd new file mode 100755 index 0000000..d20bb04 --- /dev/null +++ b/CMDB/snmp/debian-default-snmpd @@ -0,0 +1,22 @@ +# This file controls the activity of snmpd and snmptrapd + +# Don't load any MIBs by default. +# You might comment this lines once you have the MIBs downloaded. +export MIBS= + +# snmpd control (yes means start daemon). +SNMPDRUN=yes + +# snmpd options (use syslog, close stdin/out/err). +SNMPDOPTS='-LS4d -Lf /dev/null -u snmp -g snmp -I -smux -p /var/run/snmpd.pid' + +# snmptrapd control (yes means start daemon). As of net-snmp version +# 5.0, master agentx support must be enabled in snmpd before snmptrapd +# can be run. See snmpd.conf(5) for how to do this. +TRAPDRUN=no + +# snmptrapd options (use syslog). +TRAPDOPTS='-Lsd -p /var/run/snmptrapd.pid' + +# create symlink on Debian legacy location to official RFC path +SNMPDCOMPAT=yes diff --git a/CMDB/snmp/distro b/CMDB/snmp/distro new file mode 100755 index 0000000..f4bed4b --- /dev/null +++ b/CMDB/snmp/distro @@ -0,0 +1,70 @@ +#!/bin/sh +# Detects which OS and if it is Linux then it will detect which Linux Distribution. + +OS=`uname -s` +REV=`uname -r` +MACH=`uname -m` + +if [ "${OS}" = "SunOS" ] ; then + OS=Solaris + ARCH=`uname -p` + OSSTR="${OS} ${REV}(${ARCH} `uname -v`)" +elif [ "${OS}" = "AIX" ] ; then + OSSTR="${OS} `oslevel` (`oslevel -r`)" +elif [ "${OS}" = "Linux" ] ; then + KERNEL=`uname -r` + if [ -f /etc/redhat-release ] ; then + DIST=$(cat /etc/redhat-release | awk '{print $1}') + if [ "${DIST}" = "CentOS" ]; then + DIST="CentOS" + elif [ "${DIST}" = "Mandriva" ]; then + DIST="Mandriva" + PSEUDONAME=`cat /etc/mandriva-release | sed s/.*\(// | sed s/\)//` + REV=`cat /etc/mandriva-release | sed s/.*release\ // | sed s/\ .*//` + elif [ "${DIST}" = "Fedora" ]; then + DIST="Fedora" + else + DIST="RedHat" + fi + + PSEUDONAME=`cat /etc/redhat-release | sed s/.*\(// | sed s/\)//` + REV=`cat /etc/redhat-release | sed s/.*release\ // | sed s/\ .*//` + elif [ -f /etc/SuSE-release ] ; then + DIST=`cat /etc/SuSE-release | tr "\n" ' '| sed s/VERSION.*//` + REV=`cat /etc/SuSE-release | tr "\n" ' ' | sed s/.*=\ //` + elif [ -f /etc/mandrake-release ] ; then + DIST='Mandrake' + PSEUDONAME=`cat /etc/mandrake-release | sed s/.*\(// | sed s/\)//` + REV=`cat /etc/mandrake-release | sed s/.*release\ // | sed s/\ .*//` + elif [ -f /etc/debian_version ] ; then + if [ -f /etc/mailcleaner/etc/mailcleaner/version.def ] ; then + DIST="MailCleaner" + REV=`cat /etc/mailcleaner/etc/mailcleaner/version.def` + else + DIST="Debian `cat /etc/debian_version`" + REV="" + fi + fi + + if [ -f /etc/UnitedLinux-release ] ; then + DIST="${DIST}[`cat /etc/UnitedLinux-release | tr "\n" ' ' | sed s/VERSION.*//`]" + fi + + if [ -f /etc/lsb-release ] ; then + LSB_DIST="`cat /etc/lsb-release | grep DISTRIB_ID | cut -d "=" -f2`" + LSB_REV="`cat /etc/lsb-release | grep DISTRIB_RELEASE | cut -d "=" -f2`" + if [ "$LSB_DIST" != "" ] ; then + DIST=$LSB_DIST + REV=$LSB_REV + fi + fi + +# OSSTR="${OS} ${DIST} ${REV}(${PSEUDONAME} ${KERNEL} ${MACH})" + OSSTR="${DIST} ${REV}" +elif [ "${OS}" = "Darwin" ] ; then + if [ -f /usr/bin/sw_vers ] ; then + OSSTR=`/usr/bin/sw_vers|grep -v Build|sed 's/^.*:.//'| tr "\n" ' '` + fi +fi + +echo ${OSSTR} diff --git a/CMDB/snmp/setup-snmp.sh b/CMDB/snmp/setup-snmp.sh new file mode 100755 index 0000000..48b55eb --- /dev/null +++ b/CMDB/snmp/setup-snmp.sh @@ -0,0 +1,32 @@ +#!/bin/bash +#Install script for snmp on all Linux systems + +if [ -f /etc/apt/sources.list ]; +then +#Install observium bits +chmod 755 /usr/bin/distro +#Pull down snmpd configuration files +wget -O /etc/default/snmpd http://txn04-slack-master.tplab.tippingpoint.com/sysmgmt/snmp/debian-default-snmpd +wget -O /etc/snmp/snmpd.conf http://txn04-slack-master.tplab.tippingpoint.com/sysmgmt/snmp/snmpd.conf +#Restart snmpd +/etc/init.d/snmpd restart + + + + +elif [ -f /etc/yum.conf ]; +then +#Fix yum.conf +wget -O /etc/yum/yum.conf http://fezzik.tplab.tippingpoint.com/yum.conf +#Install snmpd +yum -y install net-snmp +#Install observium bits +curl --silent http://txn04-slack-master.tplab.tippingpoint.com/sysmgmt/snmp/distro > /usr/bin/distro +chmod 755 /usr/bin/distro +#Pull down snmpd configuration files +wget -O /etc/snmp/snmpd.conf http://txn04-slack-master.tplab.tippingpoint.com/sysmgmt/snmp/snmpd.conf +wget -O /etc/sysconfig/snmpd.options http://txn04-slack-master.tplab.tippingpoint.com/sysmgmt/snmp/centos-snmpd.options +#Restart snmpd +/etc/init.d/snmpd restart +chkconfig snmpd on +fi diff --git a/CMDB/snmp/snmpd.conf b/CMDB/snmp/snmpd.conf new file mode 100755 index 0000000..ec1c8b3 --- /dev/null +++ b/CMDB/snmp/snmpd.conf @@ -0,0 +1,10 @@ +com2sec readonly default mng-actua1 +group MyROGroup v1 readonly +group MyROGroup v2c readonly +group MyROGroup usm readonly +view all included .1 80 +access MyROGroup "" any noauth exact all none none +syslocation Austin TX USA +syscontact techops-alerts@turnsys.com +#This line allows Observium to detect the host OS if the distro script is installed +extend .1.3.6.1.4.1.2021.7890.1 distro /usr/bin/distro diff --git a/CMDB/subnets b/CMDB/subnets new file mode 100755 index 0000000..3077989 --- /dev/null +++ b/CMDB/subnets @@ -0,0 +1,35 @@ +10.253.0.0/24 +10.253.1.0/24 +10.253.2.0/24 +10.253.3.0/24 +10.253.4.0/24 +10.253.5.0/24 +10.253.6.0/24 +10.253.7.0/24 +10.253.8.0/24 +10.253.9.0/24 +10.251.0.0/24 +10.251.1.0/24 +10.251.2.0/24 +10.251.3.0/24 +10.251.4.0/24 +10.251.5.0/24 +10.251.6.0/24 +10.251.7.0/24 +10.251.8.0/24 +10.251.9.0/24 +10.251.10.0/24 +10.251.11.0/24 +10.251.12.0/24 +10.251.13.0/24 +10.251.30.0/24 +10.251.31.0/24 +10.251.32.0/24 +10.251.33.0/24 +10.251.34.0/24 +10.251.35.0/24 +10.251.36.0/24 +10.251.37.0/24 +10.251.38.0/24 +10.251.39.0/24 +10.251.40.0/24 diff --git a/CMDB/zenossScan.sh b/CMDB/zenossScan.sh new file mode 100755 index 0000000..5b87ff7 --- /dev/null +++ b/CMDB/zenossScan.sh @@ -0,0 +1,5 @@ +#!/bin/bash +for subnet in $(cat subnets); do +zendisc run --now --monitor localhost --deviceclass /Discovered --parallel 8 --net $subnet +done + diff --git a/README b/README old mode 100644 new mode 100755 index 802992c..7e19a31 --- a/README +++ b/README @@ -1 +1,4 @@ -Hello world + +System stuff. + +More details added later, till then figure it the fuck out yourself! diff --git a/TODO.TXT b/TODO.TXT new file mode 100755 index 0000000..c5e97e9 --- /dev/null +++ b/TODO.TXT @@ -0,0 +1,70 @@ +############################################################# +Core services (BLM/S backups, logging, monitoring, security) +############################################################# + + + +#### +1) Logging backend +#### + +Setup stratum 1/2 NTP at SATX +Setup stratum 2 NTP at OVH +Fix time zones everywhere to CST +Setup security onion + + +6) Backups and storage +* Audit overall backup strategy + + Finish setup of ZFS at satx + ZFS caching +Before cache usb: +root@ausprod-linsrv:~/envmon/temper-python# ls /dev/disk/by-id/ +ata-HL-DT-ST_DVD+_-RW_GSA-H73N ata-WDC_WD10JMVW-11AJGS3_WD-WX51AB339130 ata-WDC_WD10JMVW-11AJGS3_WD-WX61A759LES4-part1 wwn-0x50014ee65b4b1bfd +ata-PLDS_DVD-ROM_DH-16D2S ata-WDC_WD10JMVW-11AJGS3_WD-WX51AB339130-part1 wwn-0x50014ee65979b8c3 wwn-0x50014ee65b4b1bfd-part1 +ata-SanDisk_SDSSDRC032G_151115401425 ata-WDC_WD10JMVW-11AJGS3_WD-WX51AB339130-part9 wwn-0x50014ee65979b8c3-part1 wwn-0x5001b44e3ac304d1 +ata-SanDisk_SDSSDRC032G_151115401425-part1 ata-WDC_WD10JMVW-11AJGS3_WD-WX61A759LES4 wwn-0x50014ee65979b8c3-part9 wwn-0x5001b44e3ac304d1-part1 +root@ausprod-linsrv:~/envmon/temper-python# + +After cache usb: +root@ausprod-linsrv:~/envmon/temper-python# ls /dev/disk/by-id +ata-HL-DT-ST_DVD+_-RW_GSA-H73N ata-WDC_WD10JMVW-11AJGS3_WD-WX51AB339130-part1 usb-MONSTER_USB_2.0_621AE5C7-0:0-part1 wwn-0x50014ee65979b8c3-part1 wwn-0x5001b44e3ac304d1-part1 +ata-PLDS_DVD-ROM_DH-16D2S ata-WDC_WD10JMVW-11AJGS3_WD-WX51AB339130-part9 usb-MONSTER_USB_2.0_FBZXXXXXXQJBR-0:0 wwn-0x50014ee65979b8c3-part9 +ata-SanDisk_SDSSDRC032G_151115401425 ata-WDC_WD10JMVW-11AJGS3_WD-WX61A759LES4 usb-MONSTER_USB_2.0_FBZXXXXXXQJBR-0:0-part1 wwn-0x50014ee65b4b1bfd +ata-SanDisk_SDSSDRC032G_151115401425-part1 ata-WDC_WD10JMVW-11AJGS3_WD-WX61A759LES4-part1 usb-MONSTER_USB_2.0_FBZXXXXXXQJBR-0:0-part2 wwn-0x50014ee65b4b1bfd-part1 +ata-WDC_WD10JMVW-11AJGS3_WD-WX51AB339130 usb-MONSTER_USB_2.0_621AE5C7-0:0 wwn-0x50014ee65979b8c3 wwn-0x5001b44e3ac304d1 +r----------------------- + + +Finish technical infrastructure: +Finish backup setup + ovh replication automation to rsync.net + linux lab server + zfs on usb drive + snapshot/replicate to rsync.net + Finalize laptop data cleanup/backup + +Finish monitoring setup + Zenoss + OVH + +Security - full lockdown / baseline +===Pen test=== +http://resources.infosecinstitute.com/pentesting-distributions-and-installer-kits-for-your-raspberry-pi/ + Setup all jimmyraypurser blog post security tools + Setup metasploit/armitage/openvas + Setup warvox + +===Setup PIV using CA=== +https://technet.microsoft.com/en-us/library/ff829847(v=ws.10).aspx +https://www.nsa.gov/ia/programs/suiteb_cryptography/index.shtml +http://sourceforge.net/projects/opensc/files/OpenSC/opensc-0.14.0/ +https://technet.microsoft.com/en-us/library/ +http://blogs.technet.com/b/pki/archive/2012/03/14/hspd-12-logical-access-authentication-and-2008-active-directory-domains-on-download-center.aspx + +https://github.com/dejavusecurity/OutlookPrivacyPlugin +https://blog.josefsson.org/2014/06/23/offline-gnupg-master-key-and-subkeys-on-yubikey-neo-smartcard/ +http://blog.mailgun.com/security-guide-basic-infrastructure-security/ +http://viccuad.me/blog/secure-yourself-part-1-airgapped-computer-and-GPG-smartcards +https://trmm.net/Yubikey \ No newline at end of file diff --git a/bare-metal/interfaces-fnfDedi b/bare-metal/interfaces-fnfDedi new file mode 100755 index 0000000..017978d --- /dev/null +++ b/bare-metal/interfaces-fnfDedi @@ -0,0 +1,293 @@ +#This file is fairly long and complex. Don't change it unless you know what you are doing. +#And if you aren't Charles Wyble, you don't know what your doing in this context. Trust me. + + +# The loopback network interface +auto lo +iface lo inet loopback + + +#First we create the bonded interfaces for high availabilty: + + +########################################################################################### +#First bond here (eth0/1 ha pair) +########################################################################################### + +auto eth0 + allow-bond0 eth0 + +iface eth0 inet manual + bond-master bond0 + +auto eth1 + allow-bond0 eth1 + +iface eth1 inet manual + bond-master bond0 + +auto bond0 +iface bond0 inet manual + post-up ifconfig $IFACE up + pre-down ifconfig $IFACE down + bond-slaves none + bond-mode active-backup + bond-miimon 100 + bond-downdelay 200 + bond-updelay 100 + dns-nameservers 208.67.222.222 208.67.220.220 + +########################################################################################### +#Second bond here (eth2/3 ha pair) +########################################################################################### + +auto eth2 + allow-bond1 eth2 + +iface eth2 inet manual + bond-master bond1 + +auto eth3 + allow-bond1 eth3 + +iface eth3 inet manual + bond-master bond1 + +auto bond1 + +iface bond1 inet manual + post-up ifconfig $IFACE up + pre-down ifconfig $IFACE down + bond-slaves none + bond-mode active-backup + bond-miimon 100 + bond-downdelay 200 + bond-updelay 100 + dns-nameservers 208.67.222.222 208.67.220.220 + +########################################################################################### +#Interface defintions # +########################################################################################### + +########################################################################################### +#Backend MGMT interface (used for overall management network, physical devices) # +########################################################################################### +auto bond0.2 + iface bond0.2 inet manual + post-up ifconfig $IFACE up + pre-down ifconfig $IFACE down + vlan-raw-device bond0 + +auto br2 +iface br2 inet static + address 10.250.2.3 + netmask 255.255.255.0 + gateway 10.250.2.1 + bridge_ports bond0.2 + bridge_stp off + bridge_fd 0 + bridge_maxwait 0 + +########################################################################################### +#Backend FNF interface (used for FNF management network). For now all virtual machines # +########################################################################################### +auto bond0.4 + iface bond0.4 inet manual + post-up ifconfig $IFACE up + pre-down ifconfig $IFACE down + vlan-raw-device bond0 + +auto br4 +iface br4 inet static + address 10.250.4.3 + netmask 255.255.255.0 + gateway 10.250.4.1 + bridge_ports bond0.4 + bridge_stp off + bridge_fd 0 + bridge_maxwait 0 + +########################################################################################### +#Frontend FNF interface (used for internet traffic) # +########################################################################################### +auto bond1.5 + iface bond1.5 inet manual + post-up ifconfig $IFACE up + pre-down ifconfig $IFACE down + vlan-raw-device bond1 + +auto br5 +iface br5 inet static + address 10.250.5.3 + netmask 255.255.255.0 + gateway 10.250.5.1 + bridge_ports bond1.5 + bridge_stp off + bridge_fd 0 + bridge_maxwait 0 + + +########################################################################################### +#Backend infra interface (used for shared infra services like DNS) +########################################################################################### +auto bond0.6 + iface bond0.6 inet manual + post-up ifconfig $IFACE up + pre-down ifconfig $IFACE down + vlan-raw-device bond0 + +auto br6 +iface br6 inet static + address 10.250.6.3 + netmask 255.255.255.0 + gateway 10.250.6.1 + bridge_ports bond0.6 + bridge_stp off + bridge_fd 0 + bridge_maxwait 0 + +########################################################################################### +#Backend www interface (used for www management network) # +########################################################################################### +auto bond0.8 + iface bond0.8 inet manual + post-up ifconfig $IFACE up + pre-down ifconfig $IFACE down + vlan-raw-device bond0 + +auto br8 +iface br8 inet static + address 10.250.8.3 + netmask 255.255.255.0 + gateway 10.250.8.1 + bridge_ports bond0.8 + bridge_stp off + bridge_fd 0 + bridge_maxwait 0 + +########################################################################################### +#Frontend www interface (used for www external network) # +########################################################################################### + +auto bond1.9 + iface bond1.9 inet manual + post-up ifconfig $IFACE up + pre-down ifconfig $IFACE down + vlan-raw-device bond1 + +auto br9 +iface br9 inet static + address 10.250.9.3 + netmask 255.255.255.0 + gateway 10.250.9.1 + bridge_ports bond1.9 + bridge_stp off + bridge_fd 0 + bridge_maxwait 0 + +########################################################################################### +#IMW backend interface # +########################################################################################### + +auto bond0.54 + iface bond0.54 inet manual + post-up ifconfig $IFACE up + pre-down ifconfig $IFACE down + vlan-raw-device bond1 + +auto br54 +iface br54 inet static + address 10.250.54.3 + netmask 255.255.255.0 + gateway 10.250.54.1 + bridge_ports bond0.54 + bridge_stp off + bridge_fd 0 + +########################################################################################### +#AutoTunnel interfaces # +########################################################################################### + +#Management +auto bond0.88 + iface bond0.88 inet manual + post-up ifconfig $IFACE up + pre-down ifconfig $IFACE down + vlan-raw-device bond1 + +auto br88 +iface br88 inet static + address 10.250.88.3 + netmask 255.255.255.0 + gateway 10.250.88.1 + bridge_ports bond0.88 + bridge_stp off + bridge_fd 0 + +#Inline +auto bond0.89 + iface bond0.89 inet manual + post-up ifconfig $IFACE up + pre-down ifconfig $IFACE down + vlan-raw-device bond1 + +auto br89 +iface br89 inet static + address 10.250.89.3 + netmask 255.255.255.0 + gateway 10.250.89.1 + bridge_ports bond0.89 + bridge_stp off + bridge_fd 0 + +#Isolation +auto bond0.90 + iface bond0.90 inet manual + post-up ifconfig $IFACE up + pre-down ifconfig $IFACE down + vlan-raw-device bond1 + +auto br90 +iface br90 inet static + address 10.250.90.3 + netmask 255.255.255.0 + gateway 10.250.90.1 + bridge_ports bond0.90 + bridge_stp off + bridge_fd 0 + +#Registration +auto bond0.91 + iface bond0.91 inet manual + post-up ifconfig $IFACE up + pre-down ifconfig $IFACE down + vlan-raw-device bond1 + +auto br91 +iface br91 inet static + address 10.250.91.3 + netmask 255.255.255.0 + gateway 10.250.91.1 + bridge_ports bond0.91 + bridge_stp off + bridge_fd 0 + +########################################################################################### +#KNEL backend interface # +########################################################################################### + +auto bond0.24 + iface bond0.24 inet manual + post-up ifconfig $IFACE up + pre-down ifconfig $IFACE down + vlan-raw-device bond0 + +auto br24 +iface br24 inet static + address 10.250.24.3 + netmask 255.255.255.0 + gateway 10.250.24.1 + bridge_ports bond0.24 + bridge_stp off + bridge_fd 0 + bridge_maxwait 0 diff --git a/bare-metal/interfaces-tsysDedi b/bare-metal/interfaces-tsysDedi new file mode 100644 index 0000000..d8ff37c --- /dev/null +++ b/bare-metal/interfaces-tsysDedi @@ -0,0 +1,169 @@ +# This file describes the network interfaces available on your system +# and how to activate them. For more information, see interfaces(5). + +# The loopback network interface +auto lo +iface lo inet loopback + +auto eth0 +iface eth0 inet manual + + +########################################################################## +#WAN bridge - non ovs, physical interface +########################################################################## +auto brWan +iface brWan inet static + address 158.69.225.97 + netmask 255.255.255.0 + network 158.69.225.0 + broadcast 158.69.225.255 + gateway 158.69.225.254 + bridge_ports eth0 + bridge_stp off + bridge_fd 0 + bridge_hello 2 + bridge_maxage 12 + +#Routing network +#10.253.0.0/24 + +#No VLAN1 obviously, what do you think this is? A holiday inn? + +########################################################################## +#bare metal net vlan2 goes nowhere just provides isolation +########################################################################## +auto baremetal +allow-ovs baremetal +iface baremetal inet static + address 10.253.44.2 + netmask 255.255.255.0 + ovs_type OVSBridge + ovs_ports vlan2 + +allow-baremetal vlan2 +iface vlan2 inet manual + ovs_bridge baremetal + ovs_type OVSIntPort + ovs_options tag=2 + +########################################################################## +#mgmt net vlan3 +########################################################################## +auto mgmt +allow-ovs mgmt +iface mgmt inet static + address 10.253.3.2 + netmask 255.255.255.0 + ovs_type OVSBridge + ovs_ports vlan3 + +allow-mgmt vlan3 +iface vlan3 inet manual + ovs_bridge mgmt + ovs_type OVSIntPort + ovs_options tag=3 + +########################################################################## +#asn2net net vlan4 +########################################################################## +auto asn2net +allow-ovs asn2net +iface asn2net inet static + address 10.253.4.2 + netmask 255.255.255.0 + ovs_type OVSBridge + ovs_ports vlan4 + +allow-asn2net vlan4 +iface vlan4 inet manual + ovs_bridge asn2net + ovs_type OVSIntPort + ovs_options tag=4 + +########################################################################## +#S2l net vlan5 +########################################################################## +auto s2l +allow-ovs s2l +iface s2l inet static + address 10.253.5.2 + netmask 255.255.255.0 + ovs_type OVSBridge + ovs_ports vlan5 + +allow-s2l vlan5 +iface vlan5 inet manual + ovs_bridge s2l + ovs_type OVSIntPort + ovs_options tag=5 + + +########################################################################## +#rackrental net vlan6 +########################################################################## +auto rackrental +allow-ovs rackrental +iface rackrental inet static + address 10.253.6.2 + netmask 255.255.255.0 + ovs_type OVSBridge + ovs_ports vlan6 + +allow-rackrental vlan6 +iface vlan6 inet manual + ovs_bridge rackrental + ovs_type OVSIntPort + ovs_options tag=6 + + +########################################################################## +#fnf net vlan7 +########################################################################## +auto fnf +allow-ovs fnf +iface fnf inet static + address 10.253.7.2 + netmask 255.255.255.0 + ovs_type OVSBridge + ovs_ports vlan7 + +allow-fnf vlan7 +iface vlan7 inet manual + ovs_bridge fnf + ovs_type OVSIntPort + ovs_options tag=7 + +########################################################################## +#knel net vlan8 +########################################################################## +auto knel +allow-ovs knel +iface knel inet static + address 10.253.8.2 + netmask 255.255.255.0 + ovs_type OVSBridge + ovs_ports vlan8 + +allow-knel vlan8 +iface vlan8 inet manual + ovs_bridge knel + ovs_type OVSIntPort + ovs_options tag=8 + +########################################################################## +#tsys net vlan9 +########################################################################## +auto tsys +allow-ovs tsys +iface tsys inet static + address 10.253.9.2 + netmask 255.255.255.0 + ovs_type OVSBridge + ovs_ports vlan9 + +allow-tsys vlan9 +iface vlan9 inet manual + ovs_bridge tsys + ovs_type OVSIntPort + ovs_options tag=9 diff --git a/lab/LICENSE b/lab/LICENSE new file mode 100755 index 0000000..ef7e7ef --- /dev/null +++ b/lab/LICENSE @@ -0,0 +1,674 @@ +GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + {one line to give the program's name and a brief idea of what it does.} + Copyright (C) {year} {name of author} + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + {project} Copyright (C) {year} {fullname} + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. diff --git a/lab/README b/lab/README new file mode 100755 index 0000000..e69de29 diff --git a/lab/README.md b/lab/README.md new file mode 100755 index 0000000..630f72f --- /dev/null +++ b/lab/README.md @@ -0,0 +1,31 @@ +FNF Lab +======= + + +Introduction +------------ + +This repository contains +* configuration files +* hack notes etc +* helper scripts +* test suites for FreedomStack + +related to the FNF R&D lab. + +FNF R&D Lab overview +-------------------- + +The lab consists of various bits of network gear to support development of the FreedomStack and educating a new generation of "net ninjas". You can +find comprehensive documentation on the lab on the FNF wiki: + +https://commons.thefnf.org/index.php/FNF_Lab + + +File/directory overview +----------------------- + +* lab_aliases is a set of shell aliases for all the lab hosts. Add it to your shell config and have easy access to all lab systems. It needs a couple + tweaks at the top for your FNFLAB username and private SSH keypath. + +* docs is for things not on the wiki. Network and rack diagrams mostly diff --git a/lab/docs/Joes-logical b/lab/docs/Joes-logical new file mode 100755 index 0000000..ec09e18 --- /dev/null +++ b/lab/docs/Joes-logical @@ -0,0 +1,80 @@ +nwdiag { + +//Upstream space (gateways,partner networks etc) + +network "JoesDataCenter Upstream" { + JoesWanGateway [shape = cloud ] address = "96.43.139.113"; + address = "96.43.139.113/28"; +} + +network "Wan edge - public" { + group wan-edge-outside { + wan01-public [shape = cloud ] [ address = "96.43.139.115"]; + wan02-public [shape = cloud ] [ address = "96.43.139.116"]; + } +} + +// Intra network links +JoesWanGateway -- wan01-public; +wan01 -- sw01; + +// Networks under our administrative control. +// Using a standardized scheme of: site name, local vlan, description + +network "Joes - VLAN 2 - Physical Systems" { + address = "10.250.2.0/24"; + + group wan-edge-inside { + wan01 [ address = "10.250.2.x" ] + wan02 [ address = "10.250.2.x" ] + } + + group switches { + sw01 [address = "10.250.2.25"]; + sw02 [address = "10.250.2.75"]; + } + + group lxc-vm-hosts { + vm01 [address = "10.250.2.3"]; + vm02 [address = "10.250.2.5"]; + } + + group zfs-storage-nodes { + stor01 [address = "10.250.2.70"]; + stor02 [address = "10.250.2.75"]; + } + + } + +network "Joes - VLAN 4 - Production Virtual Machines" { + address = "10.250.4.0/24"; + + group www { + lamplb [ address = "10.250.4.38" ]; + lamppublic [ address = "10.250.4.40" ]; + lampenterprise [ address = "10.250.4.37" ]; + chili [ address = "10.250.4.32" ]; + askbot [ address = "10.250.4.72" ]; + gus [ address = "10.250.4.74" ]; + } + + group coreinfra { + dns [ address = "10.250.6.5" ]; + ldap [ address = "10.250.4.54" ]; + autonoc [ address = "10.250.4.39" ]; + sql [ address = "10.250.4.53" ]; + } + + group comms { + mail [ address = "10.250.4.73" ]; + irc [ address = "10.250.4.63" ]; + } + + + } + +//network "FNF KC - Development Virtual Machines - Management network - VLAN(x) { +// +//} + +} diff --git a/lab/docs/Joes-logical.png b/lab/docs/Joes-logical.png new file mode 100755 index 0000000000000000000000000000000000000000..428ce4df58d8316526634ee431c390ee87d46696 GIT binary patch literal 63670 zcmeFZX;@R))&}TTx9%rSK%rHjGF-|+3?di@X2KQ9YY8$G7zP^nLa8UsbLqwD*BvFAxW)UGmfPev_h9p2p0)!;JG2HI{(fxEk-TgfM=R?uM$vOM% zz1G@mz3*Dz7I%u8+8q-{b2nW5^gmADBEdPXL;Qj z@_C-ybiBGc6FSFVuR0N}y6{@h<0gZM_D`R!l7l|kV^|VSkDVgI3MO3S+Dlpy(zb<^ z$?<*yXOvrpW}gc=ov0iF}wk^x))BZcZrS}k%FUMDK@3US6JPPu zG@T*ce3uTLfjYu7ik@n;py8X>WufHs0az687z0zL{*<&2DSVBh3<&l(M01xzInvOC zW;Wil+hUB~$1tSpSYG%1)9wH_U_zpM@Iizl`nGYSfp)pdWnS}HT)wqbE6R~#N9E>s zo)%K*%cG2-t8J@2bvv*?FuPxx+e(s}Xc48P_#?uGrZTA_6v0Z0vMFvKiEAmYz&FO) zMo;dTP)#o2?A7t5%s}zV;*$^9K%9)WQo$P4u&_9LQviKjN>AQ5|5gQj&M|=+T{hRyo5~Igp5) zPL-an^)xT+8y}|yvZ_8D>)DS^Ol)R0@=ds@cC?5DW+{puPTQfEjxkyw7Y2o=c0 zK#cM|pEd9LdezHNwQ->X)apU8|I-V#bErTmhHcJ>wd=R8^6dUB{$y^h8Z5EgGA{eG z4swzjI49}Jk=k$qLSf943OGVKkE}~6MTq@r>&G;1_&f_lu%sNT%E(FuU@^n@$lh8%4}SV zuUTQkaQF+~T5nqhgCPQkpJdcNYbM9aJ8TXoz$4;w&?8ka@e_lUX#>TyK^s4*Etspk zI}l(=CK90)Cr-FF2wDY~U}XmAK=cRH#9)Mle?lO7ypjLxauFO3cXEbAKS*f#baGRV z&-ZJLv;Kh@tRF3$pkPKhWQ6gSGRyv+Ihf;kYWLt4R~L)+TaPHrWS`DBtcjZJGsuTFOp}wa>!fSL zm)5A3B-)o&L81jg4+t*2=%N+sks{JvwHL45PCQ`SY(7S5qeSm-txNuSRbpMmpv_yE z6Szs_%4m}~+9d@SW6wQ3-*5(xSjOCfrh7UA(G!VuPiHo2B38}tJp3e(Kylwi{?VP0 zY$>Y0ML)f~%eu;SJcqz+xi0KDk=j+5+BE<+ui&27_11_V(RI95_WYdwm)0OAiW0?2 z7;fYfd99q*IvE(3UqAEXW`r(`TW&CHbbprA|iGB4mP;QN5x+ZMt&)oH;$bsoPXGp%L<7fvjw&7vQ zImj+x?}Uj7x#ZRopA(%jsnX23_WceI){mVDM;MIo%gcOY03ml2#TY zVA%z23*^f?J+Td=7V$5L5#ICT+>w0Gkp3j{!H;t~ zaaU&WB_$;{Hq4e)$_Q+-PEOrV>Y2+uq0mIi7LN?<`8v`yNYVl3)ZFm+avj*J zKs~jZj^nz4`X9UW3?u4V`i@7k>Y`KBcmLX0_4kO8F^NU+e|+bUF`|G^lW7bcw?OTr z-L0d)K(aS1NKkw&(5!jWUz@p3%{}p2Tx@AR;tY$9U$-z1-gK5R6W>M!{qiW)oV{DM zqGmnIW8rFpWnENl4Ql`??#@pDlI&7Ky zzwvRi*Uk2Y?WYWo4K~$hcby=8$bBHG?wIefk=cZ7?!z`4a6YdpSa$HCOeqATOmY-Tw`I!-06W3pl|M>IYRUaq*7x-BC_2afRYBW8z zCcgi2JSOVTP0rLG%s7X|WR+s4nmwuqt`v`hS0|F+LT>LJIm zPIumJ1{@4`j5?n5Q6g$&XAp_$vARQZx#u4UHy0!g#ISZ>>(PuZ^Kk|^>Szu!(76jz z5lg-ydtVo|DQlnksW~@W%tYkm72ume_yxemq+$iB`gn`rh;4I==v$U35*-V`LlPu( zucI0qepAy?y{>C>7WR8AnZlc_f`J{+K1zB5mobMce%h4EHQCQob0fv}*nnOtEUZ1D z-?{{Cs~Y;;?U#M~#U{VXBJh+tO{yL`<-JrQucp#JCrwuP;@sxz{y5O9(%t=k0JoAo zO6OP8*_p35u;j6(GCk=$pPLp#NNV|A5fwPHHbz z)A^YJd+s9=WD;s&AEzzWY;C2cCkyA_C?XQWv!FQ@_&siJam^FARX4sgQX3y{j?~0X zAZZA0QWzRqMpZsgQ<#uwdNMQNtx1JxNLH{e10U~Jfp1PC^EaW!%bVXuMZF)r5=Dcs zZl&0KDAgV{Ut5QhI_+Ql6NKVqo%FA=7x)A!k)o0_9jqK?{|TOjs4aA#wajm13) z-iQ;79zh2-UyrTb$0at=i2PzE4`sR23D|&Ei)xO|JzrR*TiV`aI`U3SOVF}Vy0!Vg zX_tx%`TvdktGZVSr_*Wx(kSulj%76(rX4*G&$l!ToZU!G0Os%ZU2_XG;lJG5H$X^V zKmToG?|XJb=^@&i zdlQ{~B_{qr<0-OGHdj#fddK<;nuJM}FLD^s26}q@TJLHhp#mQW(c-g!S@Blxnxf zFoAj=={Vl1z%P#uU?nb2F|J%zqg;Vo8!A)q&YU?z2H&>T!{PNoByzA$5wHqR=k0{D ziCVWGRFCi1Y;K8Vm5eJ_43r!kG%d{bR;R#{GcT3-)5QL`gWQ0dn#AJxlR3!zco4S} z{`2IjVPH`Lnhx?TBp?57<+y|BI8AoEY_*ppn-6o4ea~LhV=q>@orww-uNBKV*GaNg zl8gbV7zZ!~pfCV{v+7B_f^Cp7G_>nnT^i{&~TVd}t^2U3@krrnCI*r~0GC7?)u_fos0qdVIp zbQ$O2aDa>!L+TUTd`(N|=jZMI8sKgft*$?fWQ7i$;Njoh_3S3R;S*He;$?}J3#9+{ z+*su6tG(7$00Pg(Sv%O-ji)Ss8e|FEMEw~K%GCkfC>Q*fo4S~ZSYO~UavfrTdT^hLRq=PRBiMYLfOV z6bkKxgarK;k>qY`X3uP#^wXzH(JcW25|h`8zgJZ0*T)qBkhz!`9WC4e(98%Iw(?2? zE4g8?K4ngmOIS3?)T5@W#Zn^Xn{oB*;H$lfg%T_W0Hm^K=b5R=CNc={oy=__ib zV0f)j`SC$j_&Bxl_bB@a<*kZH)@+1D$}=)qb_s`5PGo2pU#GhE0SDW#eDa0bA294D zYpxAf*P{L;PASDHtK70zFEqxkXeeGetY}md_f-?WDBmI0TxgtDhB7^RC0z+%9wv}! zc}&ri+S9Zi2DJVg8ZFICNl6jT3k0yD0d9t2+OZrY8LZoy+qeNE_puu7FPQ$2@xS9a zvX2`Y`bv6qeX#FO^d*y1Y>RcF$}y2Du3h7SE&TB77LM-+lyW$k66I4pyuPxM7`Fcf z*wxaUoE%9`ZZ6updbmv}OVCM=(q(u!pS9*%?Q{}#xnq~yBN?f1)^D=i znGeta_EQG-lSTk@g)NC>OVEVM&%D;4$OJzGZ-uSkvlT-?r~_P)F_}!xl}IGi4SN!# z!W@W1qK4t4SY0o*^0OQGT7$(aizd-1zNYFMmIiKVujA!_z2yTxS&66XJp2z4EjbVq z&vAyt?rs^f%7Fu4#gmPbXmMk>8*jtm$og8PIHwFEG-CmH;#A zX9D#zo0XL`n-p<_zroOGeoPemMBfIN0M8n0vtn?NC=@dfQ4MD_qF@n8uh*78z_B`;~PLO2oI+U8%F0p7hh}` zjb);GT&IMVAYbsY@j&-xEQtR$YVwxrjJh@V`9z=nPNyL$hK%tiF##8vu*&I6rqo$p zCj&|}*|E?GsHZ?E!_b805%jiYUNmPxiWN!~!$jg*_=f~f`ZIf&^j{EAyR>TKz5C(SK zzav>3B5~=UcdqMD7GdH`bz>y6iZmL?6k9|@a}qS0HWyG07H~guX0pwlV+G5eVBNLP z;Yj$O`53k(Pn_J?f|V+OgPUZg_A%FIy*NQDMOC?@iru)6?(1dl3_jo}X9ye$trwymtyR2Xnc&2_xt z4ac}ny>a74le)UP1et}CJYcR2wvgrRc9{sNY@y6DzTQxSkjAFS=F~nY)V9O_PwRq2b&yNQ+f!Qs) z4w(W|p1$a_Vyj^QTOa?Pj!OhyA8cU}n5l>k;_*pBUk*^TKA+F0h(J&opovHP%WN@r zs}UBqAbz+*c0uV+w~Y#ub`1O>8FH{udGl-Je)XuyW-lnpzt!DYU_G6(yCs8fHse~H zU4ggCK>|GQ0&(qc>9Y2zz+cp5n51bssf9MAq(l^5q)_H0larI$Usu?kp}|f9nzfb5 zWI_=5Z-6vJtS*SsI*yO&u@M%3wrw{|!+UP~8kCCTqZ;#EAte(n^3JUq`l-`*IE+3s zegGVf9$aCq3WY-4^mKa$;zO3QADD9<01@v`xFX>2GEWo2YN__K(~+v_A3QrX=UuX! z?DXMVVV~@-XL54K%G@H9?i)GTIItI))joGguxgb97H|hz;Q9|3g}j!jp>MbH`o>lb zYV(HA1*+mSMiv533o=!ZinfVU)X~LaUaNpm>337}^+o`(IAtICT9&Z>kbklX5xXAB zYP1DAI$>~yFu_Hn0<+VWN~N@?G@5c_v{%53hqDskOz~6e^tNIt<@*;Z4{`t4b%HJD zT&g{WBG7bvg9^;hd~H)apI`>1>pJRegbrpU417)ck(dp^I;|TSqI4p0r0N?f$Mq*{ z+eUx}{-_J+6F6j$5u5yZRtvckO6S*o!2<3BV#5th$CbAku;m_(RihZJ8S#zTVS|6Ycv7+<2`(cGZCB0e>o48*38ZP-Vui5q^q^=SC*P7WPHW=^}M4 z&gABTpaIe?bHM78DWw2@tJ1#WF0YU$#PAPkGhn11zN|6Qhj7I^7fNrt-5;DH|Ki0V zg*A+B+yZoW2IQ>}ZBG^vC- zceZvm7r*}orArZ zUBt(Q9y)ts0<$C_3#k|{4o$GGvX?2??&iN9#XH81|2$oFC7Jv;n>0-e!{*{Uug!P1 zYiF|?`Qa@A{XoFHB8N?Vp83WyuW?srl>-bEJA%0#Q!Y2B8#us)tG9cw->)$3ajFZO z-M@_z+;rVDX%p@0fO%P+HqBpwR20Y8MTM{PHJSFX&GEK=V;OKN3tH&;E^=TqO);69 zw&^;y96U9p;$mBV)B1K3xBkz`ucG_E6i7LhzwPCFkXMp$JnuMYsWg7g@}~mNkCE0bid!Hbjw5kQu4lTmTS@j*9lc_o%5hBRQwQR&eJr3jYXxHEns8Z z#?7?H)xS<){P;JPzy>XN|A>OAL+Q=iSR)K05OCEE)2Kogt8_=3J6;C~QrtQmi>N{! z##-RCr~hl3|xNm9pKEzf61ae_H0bCga>3yt@CCI}JA&8U6bF1IcCc zA^1hB(TAoZyYGX8lmc?b3%<4A!X?BLsdTYexZw2{)hf;tCvE~At`&x2; z3Gb<9_;~#5urcldDa-bHWb?HZBBvNFOUlLl>Ot$}m14-B>Z`ahlgyPL3rhx0+cuHb zP$kC&aDDZo+dxU{YZwP)A(afs$~JYH^y_F-io|JkLFCVrLndWS$ko=I!?+>Nc*es4 z^R=WBQ5&K7hnHWgRv^y>{2rhWApTh54&ehcR9O~5?qR)O^wu- z{j4|5)$5W!0FU3tZ7nGQrO&oci(%Y^LFi}Jz<}(=A3i0rjY=JExGGMa?VcFlsGMvR zGGfoM9#fKVgdvqHi27wb=;1P~Ip1VLkP zBgSrkvJLbX2q+qG?0~+8WEs&PCw?94rG3oofo@?@W|ojZzdiT*k2Hig_SQ!u@YsT;U95_2KOX zKxN$JFEx}48p^4pCg8P`q_08)pHl@bBHZobmZ$_c9O-=dQqjc;P;CNH8(B` zMl{X?WcxMCuo0~Ao|8ZG;|8y&%x&oS>PyW2*rbqCGW(D$_guUGyVa#fGzo8EFc-Vb zb;l{h2&GtgO3iRRpSI)!!`dGI2(u$pw@T9l;S3}m06PO@wNWUu;Ra~5znv)_ zIvB;!G#hV`Qx}X7OGXabj%qX!TG3CVQ20VQg(ihJSr`iP`D-6Lp8PY=;!j&9Y9cxz zUIS1Lz+5-72Ve1bEC};(I7i|ex0xXoXk3@cpFF}lex(Xm1GPP!L*ti)al2ns7stb$ zpI9*NF^U_U_mpa|lrv@PdF(hs{Ip{A4G7LX8#NM>it~0mPDq6}q z(A|_v<0q*sjd^AYYcMwd(F_is?c*9%oUm~9%H}lNyznP?ug(~HITXlkFoO6p*{8^X z>oVR(@?srStIR+*z|++OC7Q3BCx!#za5sp(G)b-e14Whhm1cqh?~Ckl0Q$C#hc-O4 zE$|Gnx;+*w3No|_1qIS^iEcBkhE&MXwWnq?LuIz6bYBbR1Pr5!wlTS&^oxYjHIb(N zhH1^#t#%!GwvHbH;t646je%^{%`S&o4(~_T%~+EMBQ`A^r1>{$MdhGY)Rgd_TG3X4 zIgdBnzwN{9AF9mnwUmEtl#60NfpXD4dr&Tdj;rx_aqB^wLBRMrL0jw3$sTDM;dhKG zdIXqGNH#kpwoD!Se-e;4f>KNwUeozjlYQoXpKiHwUyHpIgX#2mEt_Jh#*R7uZB*T< z+s2W$9hw_^)WbqpW;+8`O#1;59XC2oTH7ZbmR~?H$kRVX6%vc|B83A<5stTw(zQaIITDFycZC_@J7h1{ zUeU&CY6=WZRrz0mR&x?+_VOFI@|p9_b&h*^9&{6YK>j^Tz;|8>Z@)9(2TJP2A8*k1 zIjXe}a%qo(QWt!xFUCHVue7nuZ6_1-LBV}lSSJULL9jgv@fhmb+DvJ``fYVk>3 z(4paCkCQPS)q(>IV2{U2&OqQ8{R|6lu}xauf-bTbN?(7VhOzNR%!2B_Dq%T}`NooT zsUe<>-_z}zZ};3#BeIKUk%jSJdRv?(s84Q8kS7pu8hAt9G$5AwrkY$cN z)Db>!Ab%a5^F+`S6TWpN{!BeWpz&K{>{`TI>L-avU$xiH5nlFHLkuHwjNFYhBKI;I zj_C{26p2+?jLf5Tt;Zy&Lr!{eZiX`{y9<}5NvWNo2IRHQGQ}6cVJy=<;^FitH#!<2 z|LBerXVO1YKceLwqueNm$;l=?u8GK2{y{`f8eJzHQ)EUt$ZgDJLE~s?I7SaM=i*e8 z;d|0a^e67KFe=(0hqm(Py$lNto*$7Fnl+FEp>5OFyR5=C=W<{69X>SuyEGxEV#Z{q z{0L{!&DSBxVx0w}cHY)WEm$#t z;p`2+KoZy$Ghd?Mq~SB7tHo?Pm5^XE8GdHo@|*@ zwZbA zeNvuQ?a+!2Pct;%E0Kuzbv$dRf!gaMdIn3p>my8U)|HQ)5e<^Cm#x-%&vY+p!!*~< zkVCDCZni}^c0ur3mDuyE{leA5h?JE)gp%Wf>6dVZ2Eabnru2`>NXPm=GfES_e#C?h zWP;*OH8xsEkhM~C6b%L|@tMj&4aFdz%NtNy(vF~_l@}t=2Ji`mEsNzYtb+-C7qtVC zGCNiYi<_<5Lg(^82+Y@V>3V`M-_{;yOwy;p3(91dU@Noc=38kiyzW=#I6rGe@7DG& znHsNStTd8_@pkVCf$S!G8S|M8g;U}Z7kqFs9F`@T!nSJj4%0OqcS47qehD=AQo?yl z5g+PzSX*tDh0=7lK!aH3* z<&4D=#&7QT}F})8hxmDX2FwV)#1mgswOpRyj0J&@ymlXL-klA1gNl zwjT6iLle_6`rrvqvCnqXLwCm^GCTwfRI`j>`@cQpmi42HR;y?O$H%Sky*U@5q_KOl zg9YX4p*4<&VmCYNuDN{IoMdmb;oz;S?q--|Vf2<-w|K^&;XoUybLk$A=b#yyA@H(d!O{1z zBJ%WS;T_G_UBcXyxX&u7Pi5ct{$)DHq$(k}U}5I*{t~*s)kO_Ds}*;r{LyimhMU8nK$SIULOSj$dfe|S-vvSYd>(Xw-bWq1xf zd9HmA($j!M|6k)KzJ6O)aa<&mA3|$%?^6DD2%A z6H#A3_{|ekfcg?IuM~Oe5Z(p+Rr;icq&@%6%;=`h{6`hQzN+L^L6Zx89RdFj3gwueZ zO0@-!K*L6#YP^&M6FeVWP~Y#gsJxwLL6=Hi zde-UNBC~>p$TPNKjHD$lx-88jWT#Q&gWps4{ltGsq1Bjwoxrs##-PEYLAFRu+NbBB zkAPT|a@%4pNDWOC<mB0Lj6!R< z4MAu1-*_!`>^vV00vxbqLm$JrpMG{Dh*dSM7@(7bf;eW$q^!f2(zTFS%D)orIK#@t z%{!H4hCX)M>)7RV3)-Q%)Rn{XN%=c-ids?So`PwaQ(5a#J<{HeDFF-IeRCn4X;0n8 zN}9*l&l8bma{u#6MME<1Iy_PX<0cktLbc=#Io`KJ7RfN zvZ_5{!1mIS!s@@c>7y(^a=bU#N_%_sYQA}j)L}had14N}zr8iPBHC%+m%ABj6x&Ed zWBVEfp&Tww8}pI2+P*}f6~imZ1314G3W;}xd?Q6BvL!!Ek*!L2v`-2?gVhwCs)&@O zsKhljyls5kVDa)bR`GCgoLaS@u9Hz4nKoZdF-FyJq25Rn2%~sR(+dl8jQaTS${}`X z3Yi+xNL8umiDvU(bviwh3?F``ew+`7Gjh;Tk!haXn`bbQ5~ro_vNKjhEyfOHTlpa- zz!eT7OvOX)h|kW>HI*yc=)vh4m34$Ctcl3_dl7S|MY+&)O0NAV3#*tpW6V3yXB zv}#orI92xxDE&8QQF2LPhQ;5uNL^Cxc*{(xG*Z|WNL)Qu8KvhrROqqG(3{hRDsLfD z+;^hXMwmllac!CM>85#&pZ>-YJ^8u0uR++ZXu{4tL>3w3pYW#>{WCt)oPJYntJh@x zf=ZqBp{AY_aqe9_yt)6H59|KgKhb#m@<)!y83MYI<6flbbcf$c8m4z$z!9Rc?Kh~RT0+F#WZ@Cwky#ZHUwmYT}YvOI$nUM7^G<>+RJ*9p08 z{M`~}Pg@g@r$Hh}>&#hH4EJlcXJ%x%O+jWDI>_{-|&oFvs= zxB{9Q|HYS2Kg_6dzawVm^~;O)!U63116k1AGm(`nxv+#W$_)~qG;0-_^kZpK z(4vEVe6iU;C<5I*M!Tb`H`n_?x=3q*u5l@tVmz1~9ug;I6J5>Bby?Zqne z6+^u_XJ>v;wenr_0U_G*F#TC}C~2R;fZ*A#>De~(nPeho&avH^Lz+khWGtaGh zhu53WPndL6;u;AlKYkbY4UgC6AV>sB321+A{1Ia zG5wjWuWa=WbMMCoZxc#vUsuh+bN-~hX^&Q{A{^+Q!EU0^vlAxXk+`@=%isQp&I%QB zR$pK|MBqGEfh_xb3_uvBN>oc|p4xYis-*EfpGfICy zCZVP$y}9A~;;}O)X>UduCE7;^WGkU0*#o9E;HgO4iw0;7o^P(<%zbCD%{}N^oS_3f z!pHaH)T}3F#i-%fewYGVL+X5%(-5jAZiTgsq(F?Uh$?iHXatsXfUXsCGKk?(b$~s} zGE1IM%C#0+llCnIp=*37)J0d{^b(F)r53UHwT|N*Bl`J}Lx!aRg)(u%S@x~_OI>UG zf@J9XV)2)OmMo5)|9~@#@u804xeN7+-zFjn%757>&NKuh{`Th!-$(;v6BzRtYkhf) zZ;kW!F25kZ_XLC&-+kY4uUA(6cEbXX?g?uz8!#(VBVUA9jMa0ey)4*F^1S28InDT; z<>R%dRiXIY&6j;%GWO<2WwmWvVb#)VSVGpK}OPqck8I z*jf*5)?iW+(fk3oenUCN#~Z&bk_eoGj23PQ|{f$7{yl8eS0~ z*6tx%_@goP${r2*b(;A1y*v)==J0*zGN&%1QnZQPS53dH0Bvg5d>wyjNxSdzm_8t% z1?-%mQ)c_eU#teX-#UpVlPU_`N6KNo>51c2@3#7q0QL(Jsco}4xwpOqF?4G_5kx`|yda+oJ#q}_iJv4mJT(M9$q~B;xD`ZNQwUef<+d@?>?ulxqZ4@11@DNw}v$E=)M>8JVBfv=Nw#9o%h1qr~Z+S^BpKX z?93#)9<^!8*I)MSf>h~tRi?a zEp{?(+`Hw(<#Y8rA@uq?hE;iG?7&QxzcKG{dU1%3CGX0)$dhwPc}s2EI2stKP@a*i zo<7Rq)Y}H+L}o1>o;-d>EcVo{AsOJXm|B)eWqmD@_UT>nUJ4=JF+HMAA`Ta4^$QJ4MLiT!XFMnT8BD}9k^2#O$>iakiYjAX29y{$c zJb~&iTX9l$4@i)|7(IdxPxub=2My#MmU{9xxCH}w4ngftD1BjA`Nan#F;nU# zl_W(eZngo(GsbFQ?Efuc}R&#_apfgRNjs8Jo9O<=-^8sD`ustJCj~VJsV%C%5 z0`n`khfc!VA7sk~4=&jIb`0O}+m}Fw4)CBBPe@{ny<|K(1+f=<2{y5!`3x}X?#geI5se`Q_V)*`-1Ts~7U|k|D|dhXa*Q} zKcF~<>Bqe5m*LxyHBP3H0VgwCw>xQz?zd|?nxNp0K9-zUaS?@)5hKW3$S00xhc&%k zgolZbrR8ZRlzbPxf26g}zO`#H>}zYH>yV}E$rC8>cOR>ApUXbRdpfGLf@*S^@|dR+ zr$1(sR_7uYn2N!a9PZy#OsDpyOz8aJifD=*ejhtg*%pNq5H=Da#ezvQL7qdYT4+s( zfUt)dSu%pz@7?#{iOA#K(Yd4Pcb!W@J{JuEgQ|bz5puGldo6i%MZ1nVDsYqo*P|-=eWW{?u4cs`{(o9n?#s+6?9AKn}7x* zFNih$*a%eW3il4w_L;CdLZDoP+ZSuh{>?UNWg*BH^SgsSZn<`C;Xw4stp->R1I)sy z_=W3~xleq`+$G$v2J$JI=!x=*8ncNNZ`*IV4!Ulm6MkqgX0K<{l(e=#7ja6a{9#Gw z{1ic%P1vjSr>+tdSmp~xAj_0h8H9G-cQJBaJJMI!>!lpAtA#!FF~Cfn!mLbh9UjbJ z6Ez&xp4zOvi3-3bTGlu`&0}OVl+T~64lm7NnVE&b{SxYHSib44cql+L6XUN+ydcOs zp^uS%O>n=c5oRozSwqZdfTjLsoNF+-gO@wsIeW$+is^$|ekGrq`kTz1$*dQn6e|QV zYB>S}m)E$;A7t}N`~qkv-Fr0Vhck?M)v)yi|Grme47@W8MqL;NlbO{T^J$9dh+Z;Z z^CG-#EWE~3$7{P$N!!nmS18rX+t&`?nXT(QETDqQA`%|QE>K(|nX*@ZgRSS2-sIvW zhkG94*79c;ank+W)8?3;Kz_|5{b3_sH;%|CPRLn1=3m?1=Acg&55Aq_lyA@A?a7tl zbC^c88F$w_x#cI2ITOd;X9AAGaJs}~uVR#hXosX#AGWw98*LyPiC+7Qc&DZA;|Ggj z51-2`$CV1Dq8hw86)h`>ULW9@%vQQN`TJl35kkrRyL`S=iBoLxz|djyT;yA&61=L#claP3FORbD6!ok$%O*jYVJpv^Z7Px`EfjLC#@#}^_anr>J$ z#?T_u7Cc;mSv|Hl1W$Vjbd+H`% zH7*Lg*sHh8h+c9*3}%Ll`>=vi&E9rN#1m;BH-J^4VuMVYwNn;3dA1 z{X542V)RmfqVHIfajzBbW}9K%SLjr%7d^sEK54-*u>?yEweEPf&r269wLFmf+&4Qm z0bf1AfjzGt{*c99FTpL59iLK*S_R}r7@0aEI+$^=ZtSSt=(hI3sCkVap45zm@v8B4 z{T0>eZ{gMnsGXoA$+gL_vm$gWNI;LI63y1B79^R^ed!$I$fM>nAyM5d=1_R1+@$!v?JW^_PFSwE*XBdL43b; zR;LwZFor$U_m-PHAD=G^$nRUbFc)6mJKR65iB@M0u5F)wzZOmux1~g3^n?Q;v`cHm zZH&l$8j^R-eu#1*V8`mN`CfVHz6`^Y^&K{yp2Mh|zRBPhD=#_CQXbZtkDDE+07P;_8&z67&{zj6r{_d<*(i4p z2V$}%APx8M>v6z#O z-j`m43VR(debJ3SJAEj7nt@xE;bs;GpC(@YFc6Z3TX?Xj{9sJu3m@qKaPL#@?&@4o z?HKUfXdVR>4x}IFFv2(n65HIIbib^{{bu?~q*A)a=`3W{MEyxE&+3Y&-}9Dv6mnAN znDjP#@s$7AL~>x?yTO{hW%HFQmq6-yl?zyVV7XMYp}VWREqQj${BfwL)&! zcN@Z6(tI6j7+Tfk9pO6-^R;;8j~WL+Y9}0fzKHVBkZ&K9KG7aJ>8HPoAM@67b}_c5 zOqVO^I@WZir#!GOu0cONfuhedS2g4&2K1u;%y^sd>*fKgE0+=;& zr%|Wx7n?boo3WGL?fs^;5^XTluSX07kGwcl&_c}u%wq$CY(6=oeSV@nR`DsOSkH_h zNG#!DO~ps?co#LJG##fykaSPxu&+<-{TFcB@oJxx%<$EisvwwehgcC|ni6R+Hymr3 zn~`baFzO=DE4iPWz-cb(9Jh>ZIBr`|4{)2~UZPIi_aHC4*BxetiGKlJ<_imMTh$vM zu%~=>I@gkRg6^9QXchRb)_19)YYwffuU*g`uMmspxwyg+pZ*lSO>gz=MU38j<#gAN zIT>Uqsr7z_&0P8R;F^#wXgc&JcsYQm<;luO4%-`Mkhlj8Tf5mT-H$VatzEGxtJzD_o%iMSH>m zbtSFE5`wS&C8X%z*}+xn;vWkF7R!p?)$4ar0gQrf$Tj z3YxLUZQt*YJr6|&IkQ&w}8KOaH~c>!oH)+VA3KOm0LNN3s8lKsu0K{JM+zm(#7J2C7B9?W|_? zQUvA*nf#nuzze92cSA>DZk9X^4_l4#=H8%~81w?qw_6maPp94{yg)spI`1^f&~jF* z?+3iS+p2BsPgT?579prqUCh^VI^=#MJj*a$v*+Nyyg_E!$rM_l701qRE4~>!d^7oE z=I6v8J_=49vaP;1$MdvAK0(5Xcb(zH^Z6#j6-1Xhdj0tpyiT>I=l1eiP^eJtkyz==#F2Yftb8($G(|V_Thq!CS$RORbNN33=|98RgTB!a0+>4RczK>F$|I$9~cBsd%7qdT( zomPz8W>h-=)U3*JX0B1TN55x?6yHD%0cD9ewR$@m)teu90pYqcDKI~#X@p5E%FYP% zS4VroE<9Si^j-I}%$8^n@F9R5s~Lj4%%So$Xh-rM)oVW2c%W0=wzPA2Pl&1U;7QPs z{VFBP=u!P0qZfv|B71oja9-nC-oXlStSN)%+c#2AjQ>J>NB8Xud6HA@u~wOdQ8&cr z4Sv}Zm*-e&X(;Rs@qKPBc;VFGmD~5@@^H;gl)dDMiD8a4-nR%^aM2WQPp>q)9CXt! z|FvB@X!V6P6EX}7*CW=O_tIuc{0?PWR8bPn*@{1uX0d(5R*#5ytGUFB>n4wq0x!b1 zi_R~_>ZQXn>}Kwk<{&!9JC63VJQG@Veh569BKGBv02#uMAMR=F-YUZ9CIG9tm2`4P zQoKDsHO`g467Yr^_N&a!9T4MzT2kZ!ww1cJW>!n$*rdTSu5L(fw1#wAS3?_+M=sOn z5D-`|aMR9*3@hV=%)MWC{sJA8q(9$Pek6Y zb-Ztm98z};U$PtKJg8eD=2i^U??k?7NxK`OhWg$)&sk99IfqggU990=1_6y2)!tgm z0B=uFbD)p%GT$}vJjS4vQGu2dZ@v4PA6K^xd0PWPwU)_(cP@^uRGfg|>$-x2atVvF z6E4-2yLcCmV|OEO4dk+;=+TVRf%zpC+10Q)7-M;I(FL~Gp(@G#eM76e=xO-avj|?S zbv3;`$)qPq*Qep0%p|>DJ?U|oQr|%~zs?I}Fth(`O4%jQ6t!3uRw=DlVa2I`L9>wC zpX8t~V@k3NK9&R_LT?R_NcYQXNjiN3Vb2KaP6Nsxh0!JiSJjD#XG43RWEmBBy4{QX-sQ2UTVOsikN&=b z8vc=Zx#wB6h*W#~K&M`6V*PgQT!%+yV$^P? z_~LrqcHZ3TBFLO39cA0ail=jk0$wbpIC`r{GVpC9_gwx-F=^{zh zNu8FI+F@3hKKz z-ex^izt1azcTl}g#IbZzGi)2yV{&sH&ck&ZIZg1O1kk?XyVk(r?vb_L#^k;8I9V@b zz2AwvoUT29d(1wrd=};Yk<$tZeH^lvCk-3No(8^@GQ-7Lj`+NhDsQQZ##8-T%`GzL z+lE>2okj(5arU3j)6c*2s5<%{9w3E3mT9q2IjDZftd=ME?IQmRd+#0Bbk_BYVwpil z6tGYfL11Q3R1i>#0+|s4Goy%%M5JcuQbH)w0!gq8pdit)AfjZ18G4Z#YQhXvstBPa zBq%)r0)!AqJsaY4&hy;+p8LM{oY##$VkmE0`2ESa|6tg z&Z~F>QQk%gPx~zTzK!_P2ABLRySM3G>Ex$1^4J>==eK26D-VUDU66#$bS*%~Xx>wt zrE+l>aNJ>Ec>|C1+fVnu!JTNSO?eY^(WUa6>z=z$B)s@(cY4#4ODTGj2Rm>48oHn1 zq0D%4#@HUPkYu#njpM6FUZZI1WTlI{T%+sRpOzB-u9evb-eD4NMH$!|C zZY+Lr?YKAJ2Gt_9G3qJ^a=Xj_5QIg$1__+qKGP8hKaBgF|LHz>aH3XSphXXCm&G#= z@PMiP1?tV(sd8*~X+^WrPhWXoE}hhVs`pGkTQ2m_r7Q0Is_>8NelqI!wAJQ`UV{9m zdc+Uwy064nUHwJ%FYDeCb&QCg5$1X%@ELbrSR9{gP=o*c?!>+Q7Vl29KE2ppGfBL6 z1E$x!-}C(aNWJGdZQ-dZmyVY{ef8;GctU@9NRP@K`s4bE1i6ccaWh8eL`gIF{y$r1 zIMh$P+OcK0H~Ka0oVfPFtR!vWc4d5eU(~a9SC3uk1pVvau@{Rk8qdYen11wf2rxM` z?{;vp=P1@7$ct@qUF3pviH=0 z^fzsCp1TxX_wXFwQcRiqhhi~70>t`}Uh(;2Pk~|&1dbM*j3&YF@>P&1^cZ7(sG69$ zE?K!#Wp1YjMEK9l#?XIGRKHg?R)lVGrRW~IR6RY(&setDr3lBZAC9mm1&fRtJo#0T z_ehIO`f7M4y^)9dSUgu(Pc+Oq)0~r|_lI1l@kUx8y^18+10d!08WgO!wRU`^zs|Je zLc|UuW~S?C1X40|H)$q3mk8wa+WMzZyLrsiZtARP)OP}IJd{p*eV((798TwL&_~xJ zxii>jn(wrT9a}aUM*))z-lq}Sp8;^k8X@e@X!*Dh(mHhhvC)BJx*6QDy^kV21xF&7 z+j!Y+qzQ<)U#!z3py2fGJz5FVHCQG~@GR;+Aa?NiE`;Y`Ki4Gw>7_&plO3cM*`u?_ zeAQ<2_AWoDjw6NcpP+Z+#WAAsiAg$E2J|#LjV_&|7TH9%-D=IaIpFz1Z6keyG+-TC z7YMdAkNkxFO!Yr}KuXy5L&W{w?c9F%;t)k{`siO{GBb2|knwj{(1P^M_Qkj1J9@DP z2-gha2V_99?K0=BaBOKcvgMs;XF2_wtrtk?0um3(!+5v-iK#~nJ$tZ_rz8w;-eeSA zT(lj$QOHpGJ7x!$b7gw(&h|))!s!Aw3;$DGebF*<6d^sEu8P%$h@U(;a?wBjYWEe4 z>>tIlc?-4}$bjb$C-CzOVjp~$WaOKD9n3xtrgQ*!)v7z2PW&V2D6^$(;6j_bOE}0n z#b@sUM4sK=yxV*Si<@h*y(Fymww0<@k{{vd??{v&ParUAd)&6gCS){BTxF@Wp-N@) zoZALgH?xT3>W!DszczOV$rF``6btTB$W2w1W*_bud%zERsoo3aiv8E4Zu?O3xPTiBcXa;}&@utE`?R`Lfs(#(Sa77R< z6v_d%r2)ZgPj%hT<|BW-4*db4#%$3)E4%NLUW zb?&Ct=lixjap*pOot^c5(JUo;4AiSC^y&Nn8NMG)jxQ~-csEB3{E*Bi&EY{Mt??kr z&c%G?i;Th25i=R^*pRi`y3G-+kiu!}H~xbuCnQ6s_$QFy^f>;eS;?bI{kp~Fh1#?1 zrWhR5VYg(UA2=4w_V?KJrg^_dhaQbI9Ll^N-8WNl7)9_qMZMk#Y$ zY*Fp5VE;*qqJ+g=V0tM=M)Q6I3&jGx>{?k^c?xK`eTirOka~7(Xx?4QtIym60M?fr zf8PD$l*v8q=7SF309A3$+j}0mRQ%JskOP&rH2Q&%wY3>gLo1lu5*j)mbxJRLzsF&t z(wO0SYL9wr{YV2^R$_ih^dzq^n3zqUaCmzE?mssAlQW?fv)#j5{?UdR~dmO#ZejIVZ)0SJ`kEVrT#AVu=o-9t3{9~A-qvJD2n6k2R z8eY~C+MIIq!gZg*SnV*ZXHkot+&`*-2Or!iN&8AkseG}`Xmc2WkM;MTAu*}O|H!3y zbp!qzisV+Q-e++V%7s*1*0Fy?p7GHRCcQ*me;OH^x5zy(i zT73h5uHB2+^S^$cLCS3pB3^+l-dRXyD8o)?mSu(-eTYsCHG8d6!1IZoHEf*V8jcsY z7gC=;c+llGqODE9C;zA}>89XFaI;Ip-ZE!QLHi2zNz44u#Z21(BG?pD+~M~YTXH_{Ejur;PR`P1D>=N|UOB+V|ow;}2Z z=hXzXO(nsZeNH%)92JFYdkez%<&*@3pq@9)Ia*p)xmf!^y<487O-R%>thLPu{=3Ho zRGlwOEz`F1CA~g5NsUyLq=s=*gop|aAq~kJfcTZt+})m^ATDeOWcEpfOmy-CI*_t zx7Z`XA15Ju{5fn^IlR!x(kta!Wy^U=lstL5one=@{I!CfWbCZ{*w~%gv2bvTEywn8 zWTz{JFHiJty`==p=|r)a^yF?XePEUMHLpb@pOE_?=L{@b2zE0rTM)LXmJDh}Zi{pd z3XKhMOG08hfCe-&M?;TJ%rRftVjsAxYP2RVyhnVL>>LR`33QmP?O*pL_bS?{x!#RD zos(KBTBK~grqGDQE4m?`Bj~+;Z3WlOx19(Y;J$Gdkr_E8E@jIQYPt)`A6}~`(ptvV7kG(}8+rPjg5f(3vM& zXjCfdM+OMBAh@}<{uezCcKy|R2{_1j3LCq6Bq3?bdcJO@qfIbHe573-fRG6F`|TIbghaJT@e&^Ofi(hc8yE8=iJE+=GpqVq+s zVxN(xrP;&qY9mO!>8%6f%N>dBst7#-1d>%@^e?xnk4egrI>NB!{V)t*0>_%SS)Qp?5a*=g6MGVhw z(NSU@pp)LfWA%bu`WZM~7WJd}B;W zPVL&w*vp7t(KY(#Hl})4rTd@Jzk4f5jm3gsB0GyZbLx2fL^x-L>;KkuLCBXVlxyAC z-h{e*uq7nSU|*6@TTv-6-s|e)8uHbc?TlPqF^) z7n!!U-qTw*EG;FEPiJ_e1^eqRRgMXx#A~I-Rcq!?J1hus2@&B9h=9-eGQRK5&qb7^ ztpC~-q?+nH#K7!KdGk=(eJ8j4k(HlhwVj}uEBPVyKMPmqs-q`WCs0GUQXAaubJh57 z|52p~m+-q}CHk*H??vXTgjC16BZur*$bx)sBoQNiKMk#LH@|g~_>=4FpJF5HF6&Be zY@E;<_bDN6_==0@X19(kQVK|+A)&K|)EqVOAj7mwKcA4;p(|VW>!j^Pr!Yz9Mb+=5 z&W}moEsH*@Z;*M~(C*M7_9MH~WrSQ>GDDK98!wd)E{7mv{)e-s z)jcBRLnYEKCGM&o!F4?d%sy|v9S!_pz+wGt=vtEZppTs}lo;|k+(_XP;?m9DJy4mp zAl#w2P8#`IP)^0yzA$jE%y?{f8U?e&EsRnl)ptRz41VT?r+_>7sq&OQidC@MT_a96 z6B?wD27NzkdcT`JRw z=2Y~{P>InEt8Fvl>Xz$k#GDNXR=drj$(+{U4f{Jy`WQ@m7)%;FRG1iOYM<2aJUb=1 zLFJ`g+Why|y_k=S_Koci;tJE1dUTvJdM#{9U&N$@O&LRv@Yc|mS(=i|ad&{M97CDz z{2#78Rl8jto{Th1ORpijSg`a~I|d8Ntm|VSvXq}BSIY&LOT$vra^_tlgnCU$kSm#st0kP_5t8=SfNP|Ckc~y8M1`oagh6pk{WR-Fp@!0)0Uuz>;_Jc)ac{vqoY) zK8^JSUGl$;U>3xlciEe%TT((74R{jrw6m%tPyI!9CsmFDP*wR6wK_=`N|~B&GwS`o zv7^eXT{-u8{Fv%&56XCrvr)sKcYdCZE>-WUj;_+VJI}nm=4u@bS6fDNL}X8D_=04% zAvNCLYGEX`?_+i_-&2zSsqD4s)!VKjY0_HLuFqFV{eNP*nb<`g%fDOo+0mFoLGRdG zS<-5cNDt|s%-0S}5AwCNgk85^q*+S@h&l*_i_2k+&HkdA^#;24bf&kZkC#`h@uRw( zpKH>qWB}W9c&7YV{t!u|CT4tBm$T=* z8s;X>ww>YnFGol%yJvTZ@ZwH!9eur5a829?F&SWUKQg3c;-8}f^-2^FsOa;BSW#${ z!M?r(g>zoeqzAbf%Fj|+p1VKS(~SChCzV=P4=VAYd@L&pRh*`VGoO2|KJiY6p9&a# zH2`gXG4X!JulPD_A^sQsUrl6(oTd$RJV`fAIjyfvo$ue5omvpF>_N_c0`2M4;|*)a zUmqzOH5^}5wo6m?^ZVR`syo0KW-i>McO?6R=`!j_Xi(DNOh2?BwP3i=wj3%`suV`M zjCe79IA5bcJHI%7R8}oY{3(5z1KuT@milA(fUy@m*@SeXa*pihR`1est2Wn3#w_8L zb5e~r=egs;*kP(wh@@|VqqYaF{SMr2ZiZt+WxIK+kGZmc?U$}OimFV+U>;8l zWObXBagSIG1W?w%t9p>9Fy|-P+&u5W_nEEgymuNisRb{HW)C-}%7)&ZA?O)e6!^8j zY@H3G5OIGaBps|O4Wug3KAEY{lRMWUr>8Ue-ZtLGrt^iS0^6e44=oVWgE^|`;$)g8WBM2e z)rjt#fU_cr3+Wc-SbPM#we8U%&w?8=X14J)ufZ$cy>&a~(V)WcNYguAHvPt5wG4IP zR-I(DAG_Gt?Pl*|X@zesOwv0UuNRY)8;E$RVA7M*I{v}%zR4biLly-pp%+eX08x@|=(eH4eyeozCf%^I@oXi3CY?)- zzXgUzdXUICok^JQAI|h0IIA;iS}}atGbOCIl&e&=gOCNYocC!e4#@fyvdaM(BPc-E ztuL=W>ZRw@3vy6Zg@YbJMcM9&-5$9h;-Sbq)U!%Q%WjK%=RPl3qfCLy-bK7zVWjH? z9CosTUG^M&pP+)80wKdq-tjSrZZ*!ed^BO_=+KVklE{~k*s%5)77S(u^|JS|_u)K0 z_mFaqkRyqxrJ(ec`ej>*vuo7U825qX0~<>=zi#7sy|*yht}kEXWEtnd{NvM}iow2C zP_*1lf@}&uuZ{IrnRuPC+3s3FT;rPXU6+5~%=5kk#P4Pg?bwTJrb?enB{h12r(*N< z{e$fK<<1cv*mza6CnpD1?x_OvLmnkOAWr!4;51h?cxJV~bF*th!HX<|tecRKL^+t< zIa$!!7z*OR=TeDFxnO!wlAmlYE8qVJ8AfhjxHTycn^rJ|oB-epe8ml)i##s1B>%sXa5Q zc$0izOPD>(l3X|A)^M~GEfDU-bJiWwTOCO7=xA0O>D(1OUvRT2mV~&2?huK_0=N+7 z@;s%j+Jx{2wPwO&!j##{mE{6oru7IHD-o?l^Xq)e1xZGW&s zvoUm@@!h^_Ucg_g9BR%PHMy}&h%Xw9J#KTmUO~% zw#bQ--{p2XMopjhD$VHLOz@e?J+&tZI>^-Dx2BlmZ*>y-mSv_AzCR=t+_JH;@ngV( zK6SA!;QOt?*?4_4F+nmI|kWcJA-B1a>%e)@H)L@;u~LjMTUu*jvg2 z`=?rx6ieX5*o~$FhZ158he3|ib*nda)=5>IFus!Jn08`$%Zo-G%RY|9XlrN~Fu_p_ z=|)J}tBlvL8+da$cp_TJ;}o#jY{i+G87(G<*Me%mY)p5j_j6D}kMfaIF{}yGUJFYv zdngonuGe$5J9C=-v51wKaB08oM;KSrT#ysZx7XcD~g-96dJgt~5P3 zT5;o)4k+Ep?C4!UB(a6BK8}gk zH_$Kl^#NzB^@Gxs_>7DUZ=d7|S>5@<0=h{o54 z8lZRuy%L9W4bgV#YNY!~Yx#!g1L>IkVQ?r}>5#?1)F}NK%lE^Ok6f&9d=+2I6g`Tnf!86i)`Yn=%Gjw0rq;bnzm$px zIVb|{24tENzZtqKSre|=HVV7EeC%OfK6{(aIFP|WXtksU6|3*((3ek`8>Vb zXTAZ~fA%zrwScHT`j|XZ$go)L4m}biUM+VbgctJdnc>YoW^DtguF~B6kRx6WK|AKT z7Z(EN8l|sI!`1#0)@)l>NpOIltRZL1!&v6OgjAJtL zD-~em1os!$3t$z4{zm7R8#)83D3%3mZ)*Q;_V1d&n(|*asyu_L@m0-HU4Tl)h7ikv3vfaffiSp` zE&RAXh0v@(Zg{m-_7+S|RlTuJdf@)bQ~p|Ue0WA-&!^RN)(W68Qm@lRey7|-Pn$xI znp{>MLB3FZ9kbR67p<_=YWLz`0Tfxs`M;UbMwu}|MK-{dL}b+&rCxgqU&PKz%FCD< zZC~`gY4o5j-hH-?Pj*TN^;*yLvUwdh7v69ebYKp5rojZyVl}!j8ttTrC}ww;;W{1q zM(szkK4n5Lz?)Znl+g`|FB8U&FLv6Er%KnEU*tPI68v>=8jlgE3L3;8vE%UQNLEfi z-`w0(M{Orn*pGwD*3)C^t8PaH>xRYy)17>a zI)HegKYD7MMuH1IDPm)14NZM&7U*QBq{J7x*5RPEsdE5p440@cNj{E)NC!g0qq@pL zkhos3y5)<=+15MSV;UPRew|;)DDrn|ehNc0%F%>qvgISP7ZEQqn( zxm2qo#&va#7S*9SAzS`j^+gZ3yO!g@x zx?P9BTLiqXr-yRR;dQeNJp-+S3AQQYL~|!WQyW+x5a#Avw)7Zqo0D+u5gaS1lBb$! zpe8*!W-TVK_Q4CwN>Uxu^*n>p%$$9^J2Q&9N1S>C%j06iP66yUl%?S@xnG8?CAp4Z zsqI0u+RznILok2(3C}Sk?N?u@l{eYclB4Heo`@+;2H)t02jDxLEdMMLsN(1^knb9g z3I&ri+-}^UuQU}OCD0%5c`$p;(x-xaQ0Sq&xl#kk`pJl6fnHu-K{@wmL2|(?XPzqk z{u#;SWO;uu`$sj%JAA24c9oHSrngnntcAT=)%SxHi7(m`{p$6h8(Ff|<=GNRopX+h zlldcbH+@adjI35CI9$k^VffG8I847W49Uebmq!h=by~1-J~@U z`pn;teWy@Z@k{>3Vko6oqKs*}DL=`YB228EGK_BGvbkt|04g;TPLxl#51uUd{Z*36-1lAM-bRD+BQ>t%%;`70ie&TC1@Kdzv{MDPNr?Am zvMehkQaVtz?!5R3{X78Q`cO#5a&o(SvC4Gd#JBM+(5fkD<+28V-SjNI*AVVApiLE&|^nCN3~NDOnn|e;c>oy{4W419qpWscLQ*qCy=S(D7viS8eRMvg54D8 zIlzWwlJZ6w8jAE+WX25L7v#ti+f{P>lftW(HS)V3le6?Eemv!|Who$6zqc{$3FSn` zjQVu9+kd2^f}SCgRjNV`L}?)fXck1WB&7D85Jy|{g` ziaNResa}CDddlAT5o%dEb-uNK$OJDs*ko#%tW0@Bk>tmsz5{fDjMV(xg~L<}j-Nam z1p`vF^6HSx?h{2y^JI0O&(EjZ8#L*MKmM`t4lYh3`=?puk>9{ zKMW_{2a~15M3pN&0m}^jE0QY=ui%Kz&F#t`V{Zx;m!JW(So1EoBR|8AeU29py!3u^bXv2rPn7rpxX}`>3!umS{Ud&tAsMYLI9*S3 zxFtPVo^y8aBTcZh^4=z{?WCqgOhrqDum+dtURey(y2dHv`8+-c5j8Wo!Q$LS^4|Dt#$?<-_(5Ce+Z})^Mg;6!zpryM#`)$_f14ZB=~i?BBGp6 zYIrz9GTJ|Eu|$KtUd?_vu3T_3>&!`7ab-h85YjrxfwbR8&Hb%#P>*nQafBk9=kn#) zp~poItIzEgoXo0umRVal=JB{qrNP66R#-*muS)V0$&=! zhlO|#ti?EN_GP0xa603~x5*E;E$jW-+BR@~IQ8VUCveea>>1aMy^=t=v`I@Dzdm%= z{d+x?k^%_H;qHPzi@voKQ`OX(-8Qa6OQ9(QHT9SBqYWjs#8vicf_tt7?Iot1P`Z#^ z^*1rr<7oseNhWJ6VK^=ymU%>q_@YrM1&4RuY>BatRq&4QEG@nMJ)p8tPw$R|P76@P zUjX_+P58Hf%EoKsmj6!PtMISAQZdU)Lv@&B1WKmxFX35731pa|p(Uwn2AcKHJe(69 zKv((!ky#oHAp*t`^$fApM(Yy|yFhqx$Sb&ZpB0ok*RqwY$v6PAZq)H~>>8anWjmA%e&hVtg3d~M`5TZ7ckN0ma_Vi*RcO%8Y>PlF*2&#d(~`iqjbWR2 zTv9GQ+JM-})r-1DuXmgDDQ)MRwPN;ZIB}k*2885rBWi5l4I5*V*C^T5#8$I=_>la{>&aE;HM$=@wS>v#}oRz`l~{PzM8d!T6q z+R2X2J)scR8&a&2bJK!O#Lc0%D#Ay3fMFyj&-(j);e)f#4S8edwsoH;HEGV>=T=oM zN&*|SW18!@?6*Z*SC5+mjsKFv&_8hQ4qxdN(!cserj42BqGLmugExXsD$HLp-zueP zss~&}^;5?~cJj{y&A;qdK`cHF^ImOF41|@sM%HO`9Gu!52~xH=Af53~|96~n{6~3U zAu(kdml0?g6wJ!!IwFDUU}@>&?d2#beLL<40=1MibD?%F``Ok2jZy%zNIoi?IHi=7 zs?~IzT@TC3oFpFRENuO0>4g#)3%!jTDgFw^ho~64gSGjur$i83z{1FfUCxp^!`$F^5#jH zrq@|k(rl%@rvV;yT2o(BbE4@s^&81)G*Lf+z6#FMHqg-2#t0#zByqwJ+k-tZeT&_O ze7;=3qO5>YK8oU{gpHO+NOz9!O#eGnf16*5`y%<%g4Cxr6WE$q02k4Pt=MTi4<~x} zhO%r@jA{Jk=17|YdlNs*Y2wZ3CKye~p>Nt*T(8JYWTe?eZmPa%=SwcwdA&kCh)e-(fbw(v3LAD+{W268vTMeM4K6kW8I-D>Iq=6TE z@Yc>wr*^t&HBnoKWs0)Z0}f~PBKYQCN$}k*r{|L2@gO(Z+|owRGC9d`^@;nne*Njh zmU^W!x8hLZi_tUOjv8yriuA!4%&l!)$XZgwEzN4ph=33W@_UW=v0KYIN%`Ovx{B$h z$~vu3z#SPrRc6}+PGL?QLs1igAY0}JxIufRkT9@7utJ`mc2A@!$cN}xJjhjX=8%mC ze1g!7zL}0$v&^7aWaX!%`<$>t9o6+N%Zc&;hfjf|c>9s0^Pp~ZCQY8Z62 zBez!NCEBcnsBm+r=r)(OiBSGvZQ#%xaV)YbSIKGW5ykJFBBK08GstCx!v~>2;UZN3{!Dzc{SBz7IKLy8rq8=^?xCYu`7{(-0HBe< zlV#Rb$*zsBl@D>g|9#Bdcriy6E7d8QC`iC`^M6iNlN%;N(i~6osQSFOdnM^NxAhoHN*^xC=RWH}lPY zrG7zG1}N(iMOFhKPTfrr-3zn`ie!!|W&0E~GU(@LeKYDFhgT5AhihJ^m}cgKlMWZK zlwFH=rKx?rwyJ`2EJv8PPyLbZhVt6 zqYS6ysPaEdU@lr~ZE$O#zC~IEH)*bv{xU_pvs(A1k&#WM&iu!@g4oeiUE$#p zEVh^i>WwbCJ`#$;=wt%lTr@K;PD#_*x>?mov-;!X>JvW@d#`SU-SyWb+~%(gGblug zB(jP?(8e{A-%c@VY20&nmOR@?onedRM;qDff4T|-LN)v&>ex!@_+;@l4E^9+7r1N; zyiGi;R~!$qGX9&rY|o_3RBg=`;@Y5%;OcAJ+S^p?{P;8TF?jG$(M8p$j0_8O9aECm zi!!}zC+W@q81sEgn*YG1o4p<7?}Tfw-PrG-o5~p7MqCp)cJ7i?Q>3xbEIp38^$sQtCZF~nZUjcqU^6xm_WB<5`) zXNb7KKe21e7Nn#yl61eS)-+cs71Z=@ylOL_IY(@ErEu~p2@qd=o$0r4KeG{{=!(+R z-VyTSfjhH_iG_*4`DyBwM5Y>c*)^$<4KlU!wKExGVI{PbVRMlvz857Zu<@*LC(=Ft z_KZOIB+B|cSbx=4j#TSaHR7RhK70@Gzzx*z|f(pCiI0yn@#f>SaQ>vOR%?P<-*j$U&Ux$kf0lS+1e2j zMrym)7O1<;4w`(exp?2?8EBPBX1876$xP%WYy0}{WVPeEs1F>bA>)W`w?P50s@TU} zfd4EdRqeZ(lilw#V_gLgYR~V;AAU{m&TR)2&vrwoj$z+(Mex-tY(-=av?kuPBkZ(< z4T%^4{5F%eoXP3C(!=7uSbBku_|9GpE6_joK(*$D#|_u|qAzNOzkoKmJgyYll^}HN zpHZYXw#AlV_FB71EZel4_k~oWZ)X>CrjikQK}xFaQe*ej&DP|^dXV6TbKkzb|>w>=;(!+?D8$m!efIeAf#U5`GYzO(<2AltSvOMfsWo#J~PbjteA{{(c88@uka_^8|= zYrDF+;%R(x3xmOYaH^9b@E4uH+9TL&CslS<|0+f%APQbJ^%?B`YO`ypbtHiz#z>=T zhNSavg58ZF#!>H4G7H{ZlbuwL(C_BFBRCP zvTRer@M(&)RAb27FS)0SakWHn1OkjdAWW|syVYfDCT0+axFpfAE2*%Tsk38@rw^8RM+x5R3n zA*rTd=hufyAbqWrms^hAw&#C>rAx#xSNIvr5G|&D!d*FmsafFNoM-m(U(~6H59mwW za-%^7K>l@gbglrH-9KZdluOHJti+~;`G7r3-!-D89hzpD+g5F^-KQUPgEtUSh0K5$ zy25oVsC3BG75_>X{+6@pG#l-zO~v8SX1!r`GL?}-34wqf4nG!&zdE@mw&&m^4*IY7 zJGf(9T>uIQ_dzz%;UQf(QSgym;6QIcaTs-qx^Az)$?ZuY0J16UdI}CnGz}db7j5V2 zp?Gos3qW}8iAbBoNG@bf*ai{U7s=jS^7;(Ib3a4yJ4o|x!b!r&%hqSUF# z4Z!R~U~;|yr{6-^{VP%BE;_vcy+kR+=K=KZO$2)WoRn0Q%T6kMe3!)n*K3-R*8~1u z;i5B?lau3{rVI!UNi81e(9lq#TM3*Lwd_$j5_rA;?864`8!pY`h}@Lnv6uhP82x!G zfYG0qVD$LjJ&(rQg)5ZU*|bB&;9P=B-#t~E$My>!1RgT!dOUFufV4^dY?oNJ=P9`G zMUn$#Dhj30jD%zJ@`7 zQhZImAyAdg<~Zy3C^d$dm^fbPub>7Rda}^3vi+jrT z{epJiE8cgh=Rx7<;rX5&EMGMp?U6Zoo zOR6xN$6+Icwa5P|LyGtp;aPS2uMX)&V_^37 zNiW-8>RvB3;b)h$C7s7>(CPtrzmz!$kbKiN(}#UVhx7>PJ2ENT@c~&=5G8fLz0n!Z zv6N2Ej$XOPgonZN%RdgS(CVp%t2gcRlEY4UbdcZnJRv*2!mwR41Ogm|L4iDM>BNWL zC2M5y5I zi8zSRSfvK9i#d-Tb`Tsp#sEM*>X%j8MCIP6p%)sE&Xr18Z64&63TxucYxOsZDM^aH z(JKtT3z4UuKu*8e^t5j}VNW$#cUYQ}gyyyAVwT$gMq``0Wx&9WIes-lVTn_KygYj< zchOx56|m62m$$P5TWeHsS$nD@Nw0{6eGzUZ?$N27QsgKEVmuek_JpGZC1Vf+zAGiH zpF10m&dksMCzQXhd$fld{hvYk`(i3x2|F)_oR;fg;?%gP+2FBFn7@hmNoxl_vHF`c zDAoqpPlCXy%mCcn%Uh-(NkyksC8pDR)l^w`^xcZ7gI0;BY4mH8AbonVXC0iOIR6j~ z+lHv+Phi8zKXqp9KOq0!+ulA4gJVPE`yu^zE|+l!E*PjNSraXC0m@=7q8N z>wKEnlb(Z9IjLW+1GQYt*1=KDtzP*N-X~3JHo>_!I`W3<(B_A#gm1^Y;`5COa4)a#dlB5LSN|{Dcb2- z78#~7%LCJ)`^ck@9w)t-@pu*L5?J<7F|7#4X{fNLwvBo`LV0SHURL!5Us;0ae;W1ZPDn8^#t6W#HbIW zx7I$n!uG8hdorQrT<&`GR%rpe1 zI?h>m2Yr<^oCCb(zc>>@oqA(2E>K!(JW<7_5luH&@S=x*%}G@i6I~#pp)bXCo-VXl zT`F-SRa98r^>?{OR++zQCQk`41OR26bfdN2t)<=#8rYiHabc$=eqY>9OVe;bEpUe~ zmG8*3HN_~)c|%uEXc&z8KLA98(Nmezdj6`R{O>o~+uNyElnG-?SGV=GF@_2;e+_{a zX04j};66va)si}S9}xA;diBSNCt``c$9U#V3+Z>(Y>$fl-wP|%g^NmRF<)2tMiBlx z1A+bpv|qzRRWp0J;~;6f#`?WNzvae~D9S++J_N$2T=Mbi3LB^Zn|ce)y;ju?oUAI6 zsWz&QQ_Ft{4CuIfmGq0+fbQD6`+i$tcdH%SrN(Pe5!<+&bA=@|V##;B>sVK#Yp zM;#o{tu|sPf*Fw1l2pp{ByXzX;}8pu&*Y=t^GoyUkfWGzF*Cr8&Ry0WixA*`9pLJH zW3qWUm}Tjiyp*Tn4?h%?wgrufO!%~!WzuRT$%~$Fq-HC91s)o_^9}CB?}sIKj33>m zE&25?ThNVPZj$linA({dvSSaxfzv#=W&(SF?_kxEb?N{^F}5;?Mp8uxfeJRURjJ@x zU?cX`e`6zdV?XB>Zzx9n>gT=Kir>s=9+zP#Qd4vKNhyC~wn;7B*i~KQ+W@tvVQOv( z`&;2LYAItg+&KplsX?@i#8fZv){aa@h-+QSJl2;<{n?3$4%i~>61EwK4KT$eMsXZ+ zogb=CzuNNPX(J_ITi{yh0$#u{ z|5KY;Rzx<)cLM0nRM6K$iw#ldXKoiD!5Nva+<}uyOpIpp(wYC)L=g*Y#+;s8Eg^VU zYm~=-oGfdFve+8hgmCzxW zY5cQ;#qa4=AZbJ(z=fh5i_Fg8*)~#|kj!$3;SBMjl=nj|1?zNW9U29zxKFrFXk|NK z!_P-^9E@~}?^&v?Peb@vk*t+vy$B-YU_Z8CXORMS0iAyd8^hKTv#={c@Nbq5nsIoQ zLr?NKhP(Xj8eklCe^syzF<%yjR#btS|0(-nV471bJk|?~Xd3;V-N$x`IZVQ69z? z`UAQE+Q|z4oUHp?5BZ#&(_(o1WkO_@8evC9itB6fJLFh6y;D~G6lMay?f~*CWIq1< z;#7!vm3V45pQ(nbE|G}S$1UMzFLo!YOm}m|B&-IdI&ZGyhj#!5Ro5;@?rCbXzDN_Z zTp2^IrX3>A7j0sykX)%7xhiC;GKNH0F&F}R04S4_cd)wXrYx*(fVkB20@y2LczSB; zH38WZv4~euxbf)^!0hm3 zPkVPG-8MIf*DHg7g+fyP^vsCItjS_n#Eck@$Tg*o*Fah&XjZYrWZ@8&h2`UK2x)L0 zC5gVSB_bD~Cx|KHJT$8o63M>BbNHuC{+tzp$V@zxm^jys7nSiUx}G!J3v&yr-IG@x zhVpQBq{XS4HW!k4rFe#@!!ms>;&3wd)8ioTU9G1wN)xTlw%4IH)WmpEj;01p z01@%UQ+4ymNyA_VToGn$62rLB60z#pn{RH3f4*6VKoNp*-ekt;U<8f`3`!Z$PdMEg zytDOt5*f3pyJjuIDSf!Q)0@O*NofHstO&xl4F>etrrt!c7K~4rVmlAd(*?CuKQrCU$Na zQYFqw=}nFKS;)kR*y3_PqfgQ8feZc=uR&sj>-{+KxLWU&5nZ+bFZ{8&n}l_(rO&-1 zm-LQ^vlnog*s*KEpNAHEpD^HXJCerQIv+%L-1E5fUaezy8rG?Cvly53zl}<4=lCW# zU%GjQS*V`tmzE(bzM`*58x8QOUeQr8U9d)97W+Z?VOTb`P70NQ2^7? zSkBHCS}y#pB4fycTtdsw1{@?^J}&`2umRyMi2CW`G2R?YNMYuX#J+&Wg*iEh6 zODkZZMb4a zk{}WS6@z7WfMUr1BPB&#&T~HFBPE4ZAJEZ>ZHXO0w-(%$mZI)SOEae<{qV>Pph&tv zji7RIl&7ufaAgD=s!)V_Av!5o3*E8a=x-8M9ipo0A+Ygz|3{LFaIG^2e_pw`)J!tc zxvDlh1)+8{I&9SZhlL%5` z83aoedkvy!d#se%U-*^>+`T?nRZdpzGd&;UOz+Jw-tb`VKv|Tjx z9$rJjj@nf?K=R;6YB(1Z^5(sNQPNdBOBitlAJNZ~L~Zi{=mEf!0`*)1*p~0P|KP7M z`gi^c#?e`F1qa)S@-sT;PEwZEOQd&q_uR(~ysxn{epQ1~bejp_e8(N_6VR-w;M`N? ze5SxeZo`K7@IBVA!p_;aGy#Yh)Q<4O*Gdzcd@7t7Do9IoO zc|lQw-s#2wGcH$^1vi6(*lom-bvw{^Mv$~N_vn3edOXh(rNW#d#xwnNi0|Zt_MT{7 z)dSJ>Tv2hI=FCD<$#omT$eJQTtUs~dOJEmmxPl0!$>4QzHo%^wjsgH#GPzX|<}?3yHXva|)QSe_$m=d{+vls4_(2WjFr) zfsO?|(8NvaWI%?I^ZLMVobTqQ90WA2VmJU@#H;cpBUT3^2LGxUK_s)&=D$!>fz^Vz zGeouSs@Y!Fo1?mo9dTl)Gr9>|pBpOtDrYb9yh#6peg%MVAR&YcEu))_$PGk% z4?np{Gch?KVpVh)RuRSy;q@_a@yv_NUkc&8(Fz_!vIq<#2MJp~Wl57Ik}7%p8&#CU zb?|Q8s7CoDUyi;k=g`bW8Pu$KbPYgweZ!=9V*eB3&!PquOc}aJG6IQa+=LIDmY~l7 z1Nq^K&#jM{=)HgDKKG=UBnYGmqc*GGNal7v6&%nL;Uw2(M+86igxwk{eKlt!s}_O=cqfBOI1= zbfU;y;&%YF;njQ&$inJZ1P`j6cNI~lPf^Bm*B--HVR_rCWOlxXa##x|Cj^`>m@q&z z_mCdQa24H4NCgNwa7t^f-DJu=Yv6XEA|00B`}E-jB52IG4^-bu(n$=-h6SIYF&BFU zG!2?$olsNtrN1$Nscan>>2B+cS1jlVlIfo4tP#1d$z~^BD*!>-#++Y8ZwboS&cure z7UxV_4BXEp%pNVSMab_gLL0iy$O<2!Dy*y?N}Qg+F9)9ob(A7h*ei<5VT=3e!Kr@r zMZO`Xc8_Y4yevif-P62g1F&`zyYJ8&YwNas&0 zT)Zqc&cM;@h)xRgI3VkgUs$n>e$jk}klY$X#gb%J48mmjUHxxPBs^4~=(H>I0>j|C zvm1e{VY?WNDAe>%wC(>xchkq=AUc92s{7?eoj_;J!=su%j#fkuSm_I1CMR;A8B*9btfx+AUe5Rk!cm%5;H(ND14(;DMgJ8O_entLPp0lPZf@4{iOO zp6MZG9h(k0nds}isLDqv-2)BKr;(&BZTas-QT+ub{(JWh9Fsb#gJ^BZ3wH3_9%8IA z2kn~w0*vOZkF&5q0rIyUb&(nORw4V>1WU{JtDu4Ll^I$&+M^0O zF1@m5u{Gf##anUavU8^)vED5^Z<}E;$4~e2l%4BCl+sQR;yeqYOQ73;?yiHGapKz% zJI8dI?ev!|(h*H_q@@G}^$G7D#WG%7@vY)RxrE6`Fwb4q6l~*L!mnceuf14u3|~#1 zkdpe?VZ_wEvH(`|I$W~x5lU(I$E)W{^s*wrrRW~At;q6xy#<4KKaq!#wE?KF{%8~I z&{!~-VBCk%v5_>LCT2Bqr0XEC!a)IhT!iC zS|;nTnfc{GsYo6qbQ{=FUvBZg0+5|IlSo1p`u4!zymtwgi`E`nEmZeHw*TUS$n6C= zsGKjrt~O`wX=>XPt|UD_ghz=5Y^#NX(IXFIW*<#jXwM;fkN7WEh<9UgEb&dtHz5>o z{TwVyG#QmEIOh<7q`RzCx;62L1@dRch`CZ8y2uCYsrxqh zUol+iQ=6KP`r%#8^h9>z2JZCYqsap5JN&d$*JwG^>nCQx6Za-4?h4-Ym1r4jF6dpq z`CI{PzNRQ2%dn&6)EaTHS=_IHA*C&;SF-9NQqKr`@jC2~o{-b~HXGcqqGV#eGV|V* z%R(Th%Eg!&c+9P}7Fr!!MDWS2Cy5Jkml_PV34m=CV<<5;)*t_Wp=2c>*O&*hasC^5 z`&iqB%RES6=kmJ(Bhe=4`6isZFRP8CpJKRoDUCVEUGcNBCtM**B8nR}djYI*^t}MG zA4SRX*Nq0sK$tH-MgxGYfyKvdM`AsO1CulPjE4zwTx~6K%h9U5V$FOrV|RDsNO8pL zWicWsn^U5Rk1|%2diT4yIDROLTZ1;FLb-iHSo){6TqRNdTR=H_vYD+bjD4^6bqsOO zwxd259gk{hYC)`StgHP82rOJcW1e_c_|W88V%uO2LHt)7MO7~Yi&9ehq-wB0)fgyl z)FJLG%i>%fy0ER9Ere${N?W5>VS;cGjPa^O1)c5sK)jHZ%D0DYWn%FqJ?ItDWx-H? zOjH;&w^Rq2Js~&Y8sJrWKxAHim!O6xbIWVCvI1hp5txd2rJU;hE0a$Mh+0eV(3g;X?mNUPWbF#Px%WrcJ{<)|0Cs)sn`)+EHo zx7=Uy^lt7gu{E)?J*PL#i7Y2i^ImM{a8KKrCKsOW;&HMfv0>4KJG7hkJu9x8ED zWiE3*m3le5Ijnbv`2t&-(B3v-I5wM}$KhY@o*6%Mg4N?I-Hcn)rUizGqkQ2bK^JhWanw~8IDgkAb zH+h(&6RDJAP0rgU8F(OIB`3;u0dP1)Gt5YTYut$ZS%UHafIp>+O1$g>j#gqSGOSun z(DlB^kb#N#8rP$Fx$rSv&czV%Me*CoIcpzBBhw^Y$~8#322!{e@Kd>}G1t-26B2av zL=93!rJvj+;JoRDa9Gx72rHY&r5|lCWj!A%R3+TOsLV}B^8>Ko&diXDSr<}zA~bzL z`aa6|bwZkGe1AcL9^Js~^-k&Tw>v_3qXRk%Gf@|9jYtZyQzVUo9uI%loYsjf+gvL! zczc3<>(9Ff)t+UfK0z6(%+OLI1~?`E7o<@YEV$+9d^>&Zo^cs?S+a~AJ zk(#~(c^1s?v-SwH+esdjytQ7a?}!(6CUPOcMR!!e=y(TIAbh(5Q3R~0$2KvbX129sSI7jsd?%^{I{05 z`AR2Hm)x_L-0S45VmWTotd=ub9<9$ny-;yv+YI{+8-)>sI?SXCLVui*g|piw4%529 zn!y%avhKMra!Uc2wlqV{ylqQQ+qx!ztr(&raCU6coMEdqJ;-12R*Crzl3raB&+fR` zuPJ!rw43;F8)6$NNaM%=pqCmPz*X~WR0iU_Oho#HYH&i>7uka2o-T=w8j1bqjXivN zp0x!*m3A#T8+GmMKAiu%cz`hUb9KD0qlWwVo0=Yh`haIeJjbn6N3EY$GAo-fWUvs7>@( z!wg*R?9@?&LY0+KYhxQg|NFIq_Lm34h$qFlm11pQ22cf3oWpy827QPMV&u4ev_GFO z6m`T$w#COQXY`*3?6TWQw@#RCZ*t>J3x{q>`Gm1aIGG)`);O78c4~AUwX^A@R9dP# zF^<&EJ63l_+^~^-`Gqw>IYrHZ@DENe@939!7cRD!p!^ya>U=m~;9opg@3FkcM>+4w zg_D(m%6Sv-x|2}Ai!j_fV}E0f^L;O5jv-SjG52p=$@-#AIY{r`Acg*3K1}UknA&+K zz=XLy#NYlVi!LKGUzR)ZWlIxIFfE*wzn4<4)R4l=?uP6=e~u7gBLea=Ka5474udOR z6>zo~yc5_0@IC#{?PYE<@_x9$@v!p#TW!U)YPUF8B#9(_8xR^K=t0aL+4@-x2NZCS zH$cP-;J!A26~zezSE0$2OKbz(jXIbsx8ott48J*H%uP$#*&SEdxVmG7Vs#^A9_nE3 z7Y(bjH*sf$xF-}+?rI+ewE%_-l=B8f)jhos{B1$#&*Z;QwjQ8f{(fvsmN_U@po_~v zutTb-STlV7#fghWoil#ni)*?9yBmVgGm`Zz2iEhve6J(`au=|K0ZE63{_t|3I;Q33 zjRBEONJ8hpFqxf^_ARS`O?+wCH&od~k z{Uya3Guuvw-N3H?GQ0dL#{(0;M>E>j>Rfd^e)pb*86HX>>2V>b*`v0 z{-S6Iu@GT-4h+(F99CTsTv2;tchwVAP;W2Ri~XBqabseyWJL#Zq(~%~>98v=5fp=% z)U5eylw?8wBrgF$v=)pQGr5znd`|qVBsMEjZWorJf>e~v(GyjLaD#1|@+N;1jb1uK z$jQ%Nw=#DD3gS0(E85&z+eM_XUC7=?*R@TydDgN+8`H0PC@MPq+9>-%%(uBp=%>(a zxKtTG4YTv7Q=}r|xwZoJJWtjux&*-fvyW z!de5GwB|<9UACJI;QeMMEJ^Cl0jouP{H2OpnXQH2svTI-RXdOaN}_`GEH!dU5iy+o zfJ7V6b}NG~_*L9gENHth+%y>%#h^guQUsjig>XgHe>D}q-c;h1EQoE2V@BDbI6Vmu zL3^Y+UazF37S=M;b;{IuYf0!4DoCctSyvdI+Gya2tA1OV)D!m8Ym!cdfG<_C((kB_ zk5mF*+n#VR7?AjyD3AU0r{JrYsX7*o<+M6`#14yYD@?o)`4II21fw<*XLQ%wy$#w; zl?P`F_`N>i@9j_)ve4yNhFU|uo>Y^T*2u}BePAaqsb#m{9Ntb3{Da`cKy4y$K4hs7 z3v8=MK^7qyu>O!+bi6c5sr{`M?pa!uHEP<*w*_Af{wCU#d{6L|Vu`Ax{=wjPARE27 z>2bi{02tvB{F%5}*^*o9CH$bg9wb5lA9wM2*tVRcp>J+o&@eggGB%o3SYPUfZm^V+#L$fjYQc{@RLsrJ zS!uwDdGQMY>4a%aLq zw<3B5WcEJr5r9@gQf=?$a&8<}je~^=5#)Noip3tD%S$%hm1RCO&T8;ECNBCz_=L;g ziuip#sF~2OMn1Fyh$1zs-~>>aL%ZIC`??6eyACyXaf&QzfKEh>#Lz`qFL_o-cC8X` zkvlFbshtmAuWbgomjbud0nWqu1_p)2ddHr;QDM&$^%l+}OQVt6?!#tRd?j%)$>TW@ zNmUpO=Tum?!DYT>9N!5FfZrL#c7|t6xNP}YHf3O++w?V$uI4Ilh)f?5AU5&Q-L#>RA+g^#hK9RIo_n=$AX-ZK4j3R)XfH|_5)z;uRoGsx>83brVERW zbUqFKrVL@Of%EgO^Y$-iSKGoqeC~>r`vk|iLcNy3VmVyTD!%0cYa3#>bq&msFapwwS0EkpFi?_*0jIe--}l{(;2Hxy2TD_w^5ZJ8q-t1ccu z&PCHT)RA2k_%Ur5H;T7VJrqX@Tg8g+p_#Y4K7ISj$083tbDUiT-~&!RAwFfbRKc;W zhGF@Qgx;nbrMOp3@YpA`c{ATHhT^t{!X`Q8wVYsjdgBDLh85x>T4TJ8jsN~5?dk^J zq$awt5w$eYH67Ii&3JN2gS>Q%9Fj0p*$$t{x4G-(i7gIGmnPctaDKw^pmJp%;_9p) zu@O~DABa3J#G<=&s+ltjFiu0RH`4-6v|vo)8s{vq$j#J`=QwWQ&H#Eq3gE%x4KqsZ zO6szoG*<7DUNAYxQ@h?xdJY7ofZL>8={hX#iyzOrHpe2?$IKOM8l+zv!*VK^jD64X zcm@$~ri084h#tZyEuDZbUHV98bOomm*cG{5;M5Nqi!(hA7{~TKBOI??o!T-7;b_}L zquEm|GIGuWdg86XhRB%gW#uaHMHNz;2dTJsDzXs@8p+H2AVQ;m$`*Gf*YyMd?5~f;5 z(5-5uT@fNSE>Jdb7uPs`I!cpIv!j-gIb5RU?&&wJaE#$^8bh0k>=>l zIKIs;E3T2uKS&e}ECe9)hpw>tZ@PN0{#Dcl0{)YycWs$o9Hm2 zVfjNn$$$NY&8ntG`S{^G)~feSej^v<(p@=>HHarmkxuGok_%u#m=s zC1oFp%sTnl3;67`RdXW{LtZ*pR$W*O-P-)jsVuMB4p;QW>+px%H_>Lgg+=WU(Woq8h52vz@sDK=|LZS++MBJ| z?Y{e8Mp_`boAtn)z0(I7)#Tc*c!-}!G(rPAS;H(^?` zkxPA5YBd3!p4WtUD<_x-OsFU*V#RTTv^I)*k+TB~BX-mb%irp9z_oi7p+mwhW1ZcP z@4kCXe?EN&;`HC1*f{q6=jGAL=(PURfhu(T%~>MqY%~LP9!Fn8G|t)8K{E!SVN(c2g=FX>I}gpYs8D{p5{#<&Ubv^u`fhDTu4^N<~@4p>|@X3{|P6F=k4 zf9*9G6ANNV)(AdYip3_VAnpKc-&2fUBpxd&g9DFL@)&vC<+*8jqVioh0Uv#H4kyzj zR3B<$EwI`1!%Kn+A#98h*tW*AIEyYffB11t4HqVhzjN= zE9io;b@Cp75W98yhUNX6-XB`Ia(@4rk5-f1n=4X@Po@z>|XOrx7hZOF0^R_~H_zkp-3zfSL3CJTXZ zHwMB{m<0={jm&tWeTMa>>GEz}mqiovzn=xEK>PmM+vY5G)Y6)nIOl2k#~+@nTZntt zh4r#N|E)MPucuws2E5EP7Y&fV)FIpW_-{{?5A7_hHtsF84yn51v2bF( zHTWY6WVAuCgXuu$2EIhXmPF920&QTBYqwqcL_SCNNF>lWzZPJ?u z;wjnMBqj4M#j4if)E(8-N|rmToT%KjvhYjKYuY;@V{(oKeP$?ivLyzPj6Eb0UFfhd z*x((ANSJ1+1}9FVk(Im*y$pAp8zOy>En>Kv3XPD zBPdRQ80SJBS`*+!!?U2%I$yCoal|?ClOz&+wVg3UqY|G@YG6qPW55jw3b@@BQaCF4(oH+=(3cbWa*Pvd$F}ZB5MdUo6<^I%y zR8yMEDUDEI5{*u4!g+o6*SY>2^4F}Vv-#x$IpPl*DC!@z$5Ei_faM_R>uphvm>MAd#rPE^ckSK0ZvdK8fL=K{ zN#M}YPgf`e(R}&ZvJ`rE55yb-k6>!tTM~fcOn@lw1CRESwo>b=)@1V3 zpy7+CyH@^YaxmrTdYdA+P7M($kV4A z76=7-9?cd!Vp^*&l!!y`PQI>3v3Kx6&nE%2i_3)8VjZ3=(0< zY7JyIg|Iby@v-q_ohQ7MzCsb}Q$r@530%?1?Rt<_RMl%* z3K4_bHDy3RDZTzu2UCkzGxJpscuQLl9Fd3*D*$DHTH#}9QZVr;XVGFw!|I%0qP>^K z5n&-BLzEJfj}oE9WeCG?Axp>=PN=Ldp@EMyhe7dp{@?cFV1gk=^peyX9~R9sBM778 zW|#1yfO&+lnrrA4oi*904*Ll%tR?Vq5}_G_6ShY}h3&Mp7`D$Oo;Dsg<|7VU|3!G%eOis2g~^xuj~&t{`&dQ$OfBEnvDRCbLAZ*Izsos<2dtDkuIpI_=1Kdvq?)y)9h@OCw|InB2@$*Icps7AR!-`Rx{Ut%v#6}Jq;8_(yZV)3xc|cr#f)RseaHZH{Jnau1zJ82QnA7aP$Z2LPEz;+bB*yi-MJ0xqxG7GpNDC~ z1$+#U*ul9swDAjS_pn~egt_5wCkiD(B@hvP39N-vV55!B%xQ+NwXO{1ijo9FxochEhsYBN>M9aS2!ca)40vlqbs@8u zQK}Fa~i^UPsVS$-{n-1WGlRT9EKd6RlRv(rek&50>oZA0(DRX=MS&}kMmGzj!TdT{}IC4-tx7Xk|<7s3UP)`azN^08fIvl ziKoWJm!PZTSo~!f-3x!4Bj809+1}LMvo#rFjrj7&s&10xJBp*)AUDQDix zL5DhXtnHDBBos2xnOjTlAGV-pb?R8BqXI61YVN;H?@Rvt4#jzc@3kw(< z!C+z+G?}v3%@7rR)7(k{_N&Z?`3fPWuhAMikHR}igNxcELFoO+Ch61XhMZcgnan1A zDmo2wm@rcpdMx|h)rEY$+6U7grt0HpIRZP+y;0BFTD3A!yY-GW>A^xDS4OQ;FuWq2 z{NbK1c}k=#L-N%uN4zJTz}0%uwM4<8Y24vm}~Zesv>6HBYLa2^jNH|65^+`bc`6&RgW5K{!)h+a&aVl z*A=~;f9h4=pYEZpwmqPUx-9J1xIuws=xt;<)0tfEW);nv*t3- zN5cSUK-ZHKqFW*06s6|A_!P4}zVf9`k7iufAo*buWVHV9b2qz^>zOH7!!g!@F&`BCu!8#X-6`sNe*)bqtYaK5glPI_gVV4--I4u%pn zsVN&yKwWCy`@2r#<-<9T{o%LVmw19%QtD}<8oxo<*V|4TYp0R!V82Plwx?p#_rYaO zw8RY6zj7XK8XM%&^h}MD+B7N?QyeFks$jRlk+o+D`%mNdTj5>PVl4W0fCa$$Mubg& zjFS9^6U9pZ#y?XqN?4OZGau6fec@|5G+D?{EJDDA=b+C9t|Qhc$|0L#O1W9r|Dh5dzhqPlx}T4=8%`{pCClSDCF)c$Vf(^8v8ci$0!-Kh+I z;aZlRCd>2jW*MC@cua06#iMkWo@=g$i~3ANNYkC0%0FrOxa$~i_3nH1_d*3Pl7_OR zQYKaMj+C2UHcC?TNm@va9<)eWVEPt*3Jg6Go0x+JyDCwBTV#_4cN}{%r%zbHA10aD zW8*r{lJ2KinqtxdaDcdVM)b|W~K6lP@1$y zSqkDwOxM-V;#Y6OX_L(+wQ}l2)IEfb=U87E1QH%{$IT6N&G?^PLvdJX-}oyyz=t0> zZ9MTE9R47w#6(>ctftHR(vhv4JkRj7{%z8T@D&eB==CEAPn~mzpL_oD**-X(uF|lY zcUU`pU&rlkj3d!0zqjpDPWCZWw#+|!$ERS=gMbUZGgDg6)cU#SNIGDvkw(C0yi-UX zxd|TWqBHqhL1{vjspo@N9+sM{hA+~r$9;BvF48Ez`mXNua=52@Y+*u$CtTILSHZ^l zO2De_;r}6lCGhj71ABg^0t-Lw6g)S#8p|-No%-Ey9v9UQiPaE3G$q`6n`BL@gX-ch zAFdtS4}V0m*^rIuk-Ti-`7C^s)(B-x-h-{bV(=$j9dmn}|<%S%p600ZVf`ll%@8JO7@sbXj z;=hRsPJs+{rp-kadT1NV6Wg48dYxEfRK{-D>twK^KG+fh__If-?zg2gG$k;W4Nd{x z_jmpg^8SJ&j%9n7a$h6Sk(h}nbEM5P8qz=ztF{bK!9br_em-L&P9GfWU8~@oj7X~R zS68paH#&=SU9+|@iJ)q!DUcC7Hda)G~PuCpGdiCSJBWbApbFM?m;b7hT zq)nYS$j5iJ=|6}L9}NA+7+g9G-?x|Q^*nfHK6ioX{67>+6{;*_%fx(}e-4w6Nb>_XEXda$S%wU4SW#Sj{W6ul^B|i`5cO5SF*Qz;;~I0MZXmk{%)pT^QGiZ|&U%zfXGyCI{iSur9$y-+$LS^*0^Vjk_#ExO*E_3MRMlKui6>cAZ(DTj!O@1vsKM$5cGRb z)244*c``)9T%L;l_F;P(*D#JYj%QMhh}~@Bg>+nGJr+~r6U`qzBNPn9CF|%Sc^(%S za>2q#Ve3Uqk{zQ`L!(lYk_Ok1ZP>kVC!I={m==jW#r6wX3+UErqMO|!sm@A4> z)aN!X+}B|431z<_Mk;OB+x$mx)}*ex!GZGzE%;dj?%<(Z%s2k7)xuk3?xStS*>~iGfuS)Z-vEb6$hrf+F)pKI%!01uH?FuXjnxHz1WEu4DY-)c?Xg_eYds1fE-fwrV{%|g{!YOyr8GM zU2|V@IHcLIE^?=`;ME8sfoznX+sCW^V$R^%YZ9Iqpx*PWN$i4#9S_Il)Hb0b4U(ym z{r3{$hH=PwPPu5Xt8Y&_bg){4SR3Mj`CsZ&Sm;xDHXk%EoTi66)4lA6=%_ioAR=6w zfKV1zE}zL|&DA_5;bYiL@0|u?c;@gP<}0KywTi}k!yM`wV;Uh^3zAQAnq6y!$>DL% z6bt`|(zxWC$*GDnx0jsh>%))(hT+di*RXKfKDC@G^pmns*SY9b4Xo(yVEfDhGP%)U zxz8pigaMLXVvR^tyn!VdQ8^)E?y)MvU?S&`^!5YNaW02cayo)i5&B#WiwRduf#;+g zf{aL((%Tm2{`%K&WdtMgc>lY;<=P42zK(Z4V?@i+So)q4)_DAG8&XT}z!w{=f~qoy zZ$*t%zrk#NV)~JD)By1l-WcUeA5<=Qi3DSZ)kF0{xd( zxIgld-t>=Mrva({`s3Jl`#-^3KF@7{*y2Z%+Y@+5|BLl~?0>ziAl-k%`_UOTT3*^w zHF$6V4t<&%hZn!;VQr)jUXs!J@ss`Z6a2X|*t6CXZIV|{uUiFvk)nb@ZdS}6N%>su z)-3M(L-D~scOPeo6|7JsPj;1lHF-u8>{D7aGh$+Vp|(%&U?WE6^8Zw~2xDVY|8bw< z|72k8>$s$@(x~}0r0B3U?gwjt(sCi7o_=3y`RG0+GaTo#sO|T8@WZ8j;9luIP+k*Y zd86yk7>lfb-eR`o7L&15z%^dDuq5Wsiv#9kTNdf#J zsmva4AS|DEo1*a*%v@yZ^ zm&~Bz5OJS!XlG*l9c|p%Du^{%AP0Hf@qVJTJWZCPpGU^;j-#A0FRPwC;M}veEiBhMGVM-<>rHVGL9aS>2S`Lb0>vqx27_ZP08T2zQUWubvZY}CfZm$&+*@7<{;6^c9`_tL8zkevN? z0c2uSx71^dhyBbO4;PMgTqR1SAUJTaP=~MZJJlBMHYIQflNI&9=Qi$6N7UYG(}iDV z#Eiy_IC5#K@ru!YVov{2h0B zP{J!_gB3ONJ$vO;^GuVXo*SMRU^M5qHZ)M>w7fl)Di4$VQ%ctI&X?OIXqt{aJ)nno znV5-c)7+Y3l+-uIinMTte3VDYs*xnwSijA!eqTEuXXj&I8RnAcg)CPm2lKg_Y4B`J z^LQTBM7BSDaL_$Sbc4)T-3SpruTqK^8Ggf|dWNz=cqAf8@#4OzSw1 zt-o2GP;q4MC~%MRJmE7D!{MQNcZ0NBb$b(o5(}+Ef=iMtJ0}``?7pXfyyeP>3x8ntyUD4)j*SXB0gxz( zCieMvGqZ$+7RzHd7MSNg?Ft525~=*onh;TwiiOt#KkB*XRbt&tl`GFNpA`aP9OjOo z&`TiEP)<%)4w<+cv&f3E$e>mt@qXPfb)I55$+%aJ9daa00l9#5oayj;LQUYR5m$mTdq2}Xs&B+^#Zl5T=`l(# z+G!uWPz7lasX?>{QPSnKW{Tl=A0Do7=JZP;xWG}1dS`!Ep@J_e4s`-kblS6&<)~EU zeso{#*_qjuR zzD+`OX;k(WhSVWmt$r5eAgAdKM~;Mjg)&X*)bLI^+tGIq5AitQGHs7km)#eOA9K)T zbpfV9kHarlf?fhgY&{m7V*z-vSbqXMKfQ>y9x8B0W~Az?3rkDN-Fp>EpguZb{Yl!u zvz4dm#P+RT^Jv&&62iLf;^{)GlrwKFCI?YGwkDL)yd2Y!WhHksJdKB}zvp?Qr7#$8 z<3vYRv3nQZILV3F88sBzpG%pt*Y2p}+n0xMuA7Gh#{6poZmB@t!6>9?S5XsDM=BgV z5|ObqhYbG#6S4RLB0aG^g}Vn5kTtc2dP+XnZak)KBh|Mt$nnH znJS>@9C{Cgx;*W0P$jnASy2tMAkV%9*5p+1h?6%7gO8M5&>@ zY^?!YV5^I%abijaqFw*8Hm*v+BYxI@(RQ4*^jSgIieC$=8yz?9O3Cu+9_zZ5?L=$w0RsPx>%drf*Ds3`j57#|M_98y z++%ReN4Tc6Ncj+QUPs*oInzt#LplrPGgugZcbI!3EoI+Kgb1HZOE^pH5^7(s1=Ak< zY1)&`CDXoSP0%d|RX`xDM)mHJi&J-_j1wEOwS${}m=0@+j}DKqtfqE$ML&hU>Fv}{ zvslRFUJar*$WTp^_o@24>ML8ShRXSu{Whxg85SvLelzdvdGrH4szQo~;$CxOL%4^_ zQO#C=?)5Hc`PL1VaFa2BtdhWRt1 z}}>pJCU<#nJ{vo7b_bG5(gj& zVV%6t{`hnaBxU3WHDGTGhniju8ezx}7F0L9f4fZZ7nh5_S_&3OK1&Rl(#JH`?|6y7 zzE6u2oUZ#$`}W^S5G?JGiUulkCMt$Wq*;Cpw?&mL6P5`RR-&jf%ZDiTAJ?)bNjUUD zgu6d}cn#aizWOxHOmtRb^Y+`HW8bg?+=!XieTTL7c0>r9?!UeXQXsMu(bz}r&u9lZA)pp75i}CUtL={9as+9Q2?UJ zJ3T6H=`ZV<_R5ji8yA`WrJGL5Q#Rg-{mg5K$Ec}wxW!jGm~cyuh-N%}xk05h!!^Un zuyf8=qZwO~&JYUjAG{CJE!NNpyPLR%|Y zS~F5ox3j* zn$+~%RVW$U6&bZma&SiFj{iS28qecb|R_{Pp^bk;}AMul>K&EGq+fXSo;1J1eiPKMX7|GmVt8fCJKLFV`z88J&(e z{Yb0*^!rykqEcjct#B^i{baRYK`$_@4)m-Ie|Wt=9ymQx<~*%V^6n$6(>F_}{Il|| zmyJC3b*WbTf?km0S6+ZR-XSu3ZpP&qdw`2a&H|Sk%6hL&7B79Vm@oFq#?_@~&N>$U z1r=+(DY5Zpdf90!C#K$*vnC=p>|Xyw%e0iE-hfc9I%vAj)>otQoNuCv9uDH*!FPE=Xsl*vhIIR4F46oog#O=!6~X0l%k4P z#{UKeQpc;~H-G~q28=r`r(0Tr{MmU41b+hxF<$>8bg=d#Wzp$P!i&o-w3 literal 0 HcmV?d00001 diff --git a/lab/docs/Lab-physical b/lab/docs/Lab-physical new file mode 100755 index 0000000..6bf85dd --- /dev/null +++ b/lab/docs/Lab-physical @@ -0,0 +1,126 @@ +rackdiag { + +//r1 + rack { + 42U; + description = "R1 - Fully enclosed cabinet, holds all cisco routers/switches.)"; + 42: + 41: + 40: + 39: + 38: + 37: + 36: + 35: + 34: + 33: + 32: + 31: + 30: + 29: + 28: + 27: + 26: + 25: + 24: + 23: + 22: + 21: + 20: + 19: + 18: + 17: + 16: + 15: + 14: + 13: + 12: + 11: + 10: + 09: + 08: + 07: + 06: + 05: + 04: + 03: + 02: + 01: + } + +//r2 + rack { + 42U; + description = "R2 - Fully enclosed cabinet, holds all the prod gear.)"; + 42: N/A + 41: unmanaged pdu + 40: pdu01 + 39: pdu02 + 38: devrtr02 mikrotik + 37: devrtr01 ubiquiti edge router + 36: devsw04 Cisco 3500 poe + 35: devsw01 Cisco 2950 + 34: devsw02 Cisco 2950 + 33: devsw03 Cisco 3500 + 32: labsw01 Dell PowerConnect + 31: switch patch panel + 30: devrtr03 Cisco ISR 1841 + 29: devrtr04 Cisco ISR 1841 + 28: labcon01 ACS48 + 27: console server patch panel + 26: devrtr06 Cisco 26xx + 25: devsw05 Cisco 2948G + 24: devsw05 Cisco 2948G + 23: devrtr07 Cisco 3640 + 22: devrtr07 Cisco 3640 + 21: available slot + 20: available slot + 19: devrtr08 (firebox) devrtr05 (pix 501) + 18: available slot + 17: available slot + 16: ups fsrtr01 + 15: devrtr09 (6500) + 14: devrtr09 + 13: devrtr09 + 12: devrtr09 + 11: devrtr09 + 10: devrtr09 + 09: devrtr09 + 08: devrtr09 + 07: devrtr09 + 06: devrtr09 + 05: devrtr09 + 04: devrtr09 + 03: devrtr09 + } + + +//r3 + rack { + 24U; + description = "R3 - Skeltek 2 post, holds client end points"; + 24: + 23: + 22: + 21: + 20: + 19: + 18: + 17: + 16: + 15: + 14: + 13: + 12: + 11: + 10: + 09: + 08: + 07: + 06: + 05: + 04: + 03: + 02: + 01: + } diff --git a/lab/docs/LabLogical-Backbone b/lab/docs/LabLogical-Backbone new file mode 100755 index 0000000..2c0227c --- /dev/null +++ b/lab/docs/LabLogical-Backbone @@ -0,0 +1,59 @@ +nwdiag { + network OVH_TRANSIT_WAN { + address = "192.168.204.0/30" + ovh-wanrtr [ address = ".1"]; + ausprod-coreap01-vpnwan [ address = ".2"]; + } + + group ovhtransitwan { + ovh-wanrtr + ausprod-coreap01-vpnwan + } + + + network ATT_UVERSE_LAN { + address = "192.168.1.0/24"; + + group attuverselan { + ausprod-coreap01-wan [address = ".253"]; + } + } + + network TURNSYS_TRANSIT_LAN { + address = "192.168.2.0/24"; + ausprod-coreap01-lan [address = ".1"]; + ausprod-coresw01 [address = ".22"]; + auslab-labrtr-wan [address = ".21"]; + + group turnsystransitlan { + ausprod-coreap01-lan; + ausprod-coresw01; + auslab-labrtr-wan; + } + } + + network TURNSYS_MGMT_LAN { + address = "10.251.2.0/24"; + auslab-labrtr-mgmtgw [ address = ".254"]; + auslab-ips [ address = ".97"]; + auslab-labsw01 [ address = ".2"]; + auslab-labsw02 [ address = ".4"]; + auslab-labsw03 [ address = ".5"]; + auslab-labcon01 [ address = ".3"]; + auslab-linsrv [ address = ".99"]; + auslab-winsrv [ address = ".98"]; + + group turnsysmgmtlan-vlan2 { + auslab-labrtr-mgmtgw; + auslab-ips + auslab-labsw01; + auslab-labsw02; + auslab-labsw03; + auslab-labcon01; + auslab-linsrv + auslab-winsrv + } + } + +} + diff --git a/lab/docs/LabLogical-Backbone.png b/lab/docs/LabLogical-Backbone.png new file mode 100755 index 0000000000000000000000000000000000000000..a92ca9429d2da88028de3ceee3e92b920f805218 GIT binary patch literal 36514 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 SCo8zWe>Oa4Q1s((SN|7pnSurY literal 0 HcmV?d00001 diff --git a/lab/vagrant/Vagrantfile b/lab/vagrant/Vagrantfile new file mode 100755 index 0000000..d427347 --- /dev/null +++ b/lab/vagrant/Vagrantfile @@ -0,0 +1,88 @@ +# -*- mode: ruby -*- +# vi: set ft=ruby : + +# Vagrantfile API/syntax version. Don't touch unless you know what you're doing! +VAGRANTFILE_API_VERSION = "2" + +# Convenience function for running Postgres commands. Accesses via temporarily-linked container. +def postgres(cmd) + "docker run --rm --link postgres:postgres -u postgres postgres:9.3 #{cmd}" +end + +Vagrant.configure(VAGRANTFILE_API_VERSION) do |config| + + # All Vagrant configuration is done here. The most common configuration + # options are documented and commented below. For a complete reference, + # please see the online documentation at vagrantup.com. + + # Create a private network, which allows host-only access to the machine + # using a specific IP. + # config.vm.network "private_network", ip: "192.168.33.10" + + # Create a public network, which generally matched to bridged network. + # Bridged networks make the machine appear as another physical device on + # your network. + # config.vm.network "public_network" + + # If true, then any SSH connections made will enable agent forwarding. + # Default value: false + # config.ssh.forward_agent = true + + # Share an additional folder to the guest VM. The first argument is + # the path on the host to the actual folder. The second argument is + # the path on the guest to mount the folder. And the optional third + # argument is a set of non-required options. + # config.vm.synced_folder "../data", "/vagrant_data" + + # Provider-specific configuration so you can fine-tune various + # backing providers for Vagrant. These expose provider-specific options. + # Example for VirtualBox: + # + config.vm.provider "virtualbox" do |vb| + # # Don't boot with headless mode + # vb.gui = true + # + # # Use VBoxManage to customize the VM. For example to change memory: + # vb.customize ["modifyvm", :id, "--memory", "1024"] + vb.memory = 1024 + end + # + # View the documentation for the provider you're using for more + # information on available options. # Enable provisioning with CFEngine. CFEngine Community packages are + + config.vm.define :hearth do |hearth| + + hearth.vm.box = "ubuntu/trusty64" + + hearth.vm.hostname = "hearth" + + hearth.vm.network :forwarded_port, guest: 80, host: 8080 + + hearth.vm.provision :docker do |d| + d.pull_images "postgres:9.3" + d.build_image "/vagrant/docker/thefnf/freeradius", args: "-t thefnf/freeradius" + d.build_image "/vagrant/docker/thefnf/odoo", args: "-t thefnf/odoo" + d.run "thefnf/freeradius", args: "--name radius -p :1813:1813 -p :1863:1863" + d.run "postgres:9.3", args: "--name postgres" + end + + hearth.vm.provision :shell, inline: """ + sleep 5 # Give Postgres a chance to start + #{postgres("psql -h postgres -c \"CREATE USER odoo WITH UNENCRYPTED PASSWORD 'password' CREATEDB;\"")} + """ + + hearth.vm.provision :docker do |d| + d.run "thefnf/odoo", args: "--name odoo --link postgres:postgres -p :80:8069" + end + + end + + config.vm.define :freedomlink do |fl| + + fl.vm.box = "box-cutter/debian76" + + fl.vm.hostname = "freedomlink" + + end + +end \ No newline at end of file diff --git a/lab/vagrant/docker/thefnf/freeradius/Dockerfile b/lab/vagrant/docker/thefnf/freeradius/Dockerfile new file mode 100755 index 0000000..f3a1430 --- /dev/null +++ b/lab/vagrant/docker/thefnf/freeradius/Dockerfile @@ -0,0 +1,6 @@ +FROM ubuntu:14.04 +EXPOSE 1813 1863 +RUN apt-get update && \ + apt-get upgrade -y && \ + apt-get install -y freeradius +CMD freeradius -f \ No newline at end of file diff --git a/lab/vagrant/docker/thefnf/freeside/Dockerfile b/lab/vagrant/docker/thefnf/freeside/Dockerfile new file mode 100755 index 0000000..7828ad9 --- /dev/null +++ b/lab/vagrant/docker/thefnf/freeside/Dockerfile @@ -0,0 +1,55 @@ +FROM debian:7 +ENV VERSION 3.3 +RUN echo deb http://freeside.biz/~ivan/freeside-wheezy/ ./ >/etc/apt/sources.list.d/freeside.list && \ + apt-get update && \ + apt-get upgrade -y && \ + apt-get install -y --force-yes --no-install-recommends adduser apache2 apache2-mpm-prefork apache2-utils curl gcc gnupg ghostscript gsfonts gzip latex-xcolor \ + less libapache-dbi-perl libapache2-mod-perl2 libapache2-request-perl libapache-session-perl \ + libbusiness-creditcard-perl libcache-cache-perl libcache-simple-timedexpiry-perl libchart-perl \ + libclass-container-perl libclass-data-inheritable-perl libclass-returnvalue-perl libcolor-scheme-perl \ + libio-compress-perl libconvert-binhex-perl libcrypt-passwdmd5-perl libcrypt-ssleay-perl libcss-squish-perl \ + libdate-manip-perl libdbd-mysql-perl libdbd-pg-perl libdbi-perl libdbix-dbschema-perl libdbix-searchbuilder-perl \ + libdevel-stacktrace-perl libdevel-symdump-perl liberror-perl libexception-class-perl \ + libfile-counterfile-perl libfile-rsync-perl libfont-afm-perl libfreezethaw-perl libfrontier-rpc-perl \ + libgd-gd2-perl libgd-graph-perl libgd2-xpm libhtml-format-perl libhtml-mason-perl libhtml-parser-perl \ + libhtml-scrubber-perl libhtml-tagset-perl libhtml-tree-perl libhtml-widgets-selectlayers-perl libio-stringy-perl \ + libipc-run-perl libipc-run3-perl libipc-sharelite-perl libjavascript-rpc-perl libjson-perl \ + liblingua-en-inflect-perl liblingua-en-nameparse-perl liblocale-gettext-perl liblocale-maketext-fuzzy-perl \ + liblocale-maketext-lexicon-perl liblocale-subcountry-perl liblog-dispatch-perl libmailtools-perl libmime-tools-perl \ + libmodule-versions-report-perl libnet-daemon-perl libnet-ping-external-perl libnet-scp-perl libnet-ssh-perl \ + libnet-whois-raw-perl libnetaddr-ip-perl libnumber-format-perl libpam-modules libpam-runtime libpaper-utils \ + libparams-validate-perl libparse-recdescent-perl libpcre3 libpg-perl libregexp-common-perl \ + libspreadsheet-writeexcel-perl libstring-approx-perl libstring-shellquote-perl libterm-readkey-perl \ + libtest-inline-perl libtext-autoformat-perl libtext-charwidth-perl libtext-csv-perl libtext-csv-xs-perl libtext-iconv-perl \ + libtext-quoted-perl libtext-reform-perl libtext-template-perl libtext-wrapi18n-perl libtext-wrapper-perl \ + libtie-ixhash-perl libtime-duration-perl libtime-modules-perl libtimedate-perl libtree-simple-perl \ + libuniversal-require-perl liburi-perl libwant-perl libwww-perl libxml-parser-perl libyaml-perl lmodern make \ + perl perl-base perl-modules texlive \ + texlive-latex-extra texinfo traceroute ttf-bitstream-vera ttf-dustin ucf zlib1g \ + libdatetime-perl libdatetime-format-strptime-perl libfile-slurp-perl libspreadsheet-parseexcel-perl \ + libauthen-passphrase-perl libnet-domain-tld-perl libbusiness-us-usps-webtools-perl libxml-simple-perl \ + libemail-sender-perl libemail-sender-transport-smtp-tls-perl libemail-sender-perl \ + libemail-sender-transport-smtp-tls-perl libhtml-defang-perl libdatetime-format-natural-perl libcgi-pm-perl \ + libfile-sharedir-perl libmodule-versions-report-perl libtext-wikiformat-perl libnet-server-perl \ + libhttp-server-simple-perl libhtml-rewriteattributes-perl libmime-types-perl libperlio-eol-perl \ + libgnupg-interface-perl libdata-ical-perl libcalendar-simple-perl libdatetime-set-perl \ + libhook-lexwrap-perl libhttp-server-simple-mason-perl libxml-rss-perl libipc-run-safehandles-perl libpoe-perl \ + libsoap-lite-perl libhtml-tableextract-perl libhtml-element-extended-perl libcam-pdf-perl libgd-barcode-perl \ + libnet-openssh-perl libgeo-coder-googlev3-perl libgeo-googleearth-pluggable-perl libnet-snmp-perl \ + libcrypt-openssl-rsa-perl libpdf-webkit-perl wkhtmltopdf xvfb \ + sam2p psmisc libsys-sigaction-perl liblog-dispatch-perl libconvert-color-perl libdate-simple-perl libemail-valid-perl \ + libencode-perl libexcel-writer-xlsx-perl libhtml-mason-psgihandler-perl libhtml-quoted-perl libio-string-perl \ + libregexp-common-net-cidr-perl libregexp-ipv6-perl libsnmp-perl libtext-password-pronounceable-perl \ + libparse-fixedlength-perl && \ + cd /usr/src && \ + curl http://www.freeside.biz/freeside/freeside-$VERSION.tar.gz |tar xz && \ + adduser freeside --system --group --shell /bin/bash && \ + rm -rf /var/www/* +ADD Makefile /usr/src/freeside-$VERSION/Makefile +RUN cd /usr/src/freeside-$VERSION && \ + make perl-modules && \ + make install-perl-modules && \ + make create-config && \ + make install-docs && \ + make install-apache +USER freeside \ No newline at end of file diff --git a/lab/vagrant/docker/thefnf/freeside/Makefile b/lab/vagrant/docker/thefnf/freeside/Makefile new file mode 100755 index 0000000..5d7dec7 --- /dev/null +++ b/lab/vagrant/docker/thefnf/freeside/Makefile @@ -0,0 +1,468 @@ +#!/usr/bin/make + +#solaris and perhaps other very weirdass /bin/sh +#SHELL="/bin/ksh" + +DB_TYPE = Pg +#DB_TYPE = mysql + +DB_USER = freeside +DB_PASSWORD=password + +DATASOURCE = DBI:${DB_TYPE}:dbname=freeside;host=postgres + +#changable now (some things which should go to the others still go to CONF) +FREESIDE_CONF = /usr/local/etc/freeside +FREESIDE_LOG = /usr/local/etc/freeside +FREESIDE_LOCK = /usr/local/etc/freeside +FREESIDE_CACHE = /usr/local/etc/freeside +FREESIDE_EXPORT = /usr/local/etc/freeside + +MASON_HANDLER = ${FREESIDE_CONF}/handler.pl +MASONDATA = ${FREESIDE_CACHE}/masondata + +#where to put the default configuraiton used by freeside-setup to initialize +#a new database (not used after that). primarily of interest to distro +#package maintainers +DIST_CONF = ${FREESIDE_CONF}/default_conf + +#deb +FREESIDE_DOCUMENT_ROOT = /var/www +#redhat, fedora, mandrake +#FREESIDE_DOCUMENT_ROOT = /var/www/html/freeside +#freebsd +#FREESIDE_DOCUMENT_ROOT = /usr/local/www/data/freeside +#openbsd +#FREESIDE_DOCUMENT_ROOT = /var/www/htdocs/freeside +#suse +#FREESIDE_DOCUMENT_ROOT = /srv/www/htdocs/freeside +#apache +#FREESIDE_DOCUMENT_ROOT = /usr/local/apache/htdocs/freeside + +#deb, redhat, fedora, mandrake, suse, others? +INIT_FILE = /etc/init.d/freeside +#freebsd +#INIT_FILE = /usr/local/etc/rc.d/011.freeside.sh + +#deb +INIT_INSTALL = PATH=$PATH:/sbin /usr/sbin/update-rc.d freeside defaults 23 01 +#redhat, fedora +#INIT_INSTALL = /sbin/chkconfig freeside on +#not necessary (freebsd) +#INIT_INSTALL = /usr/bin/true + +#deb, suse +#HTTPD_RESTART = /etc/init.d/apache restart +#deb w/apache2 +HTTPD_RESTART = /etc/init.d/apache2 restart +#redhat, fedora, mandrake +#HTTPD_RESTART = /etc/init.d/httpd restart +#freebsd +#HTTPD_RESTART = /usr/local/etc/rc.d/apache.sh stop || true; sleep 10; /usr/local/etc/rc.d/apache.sh start +#openbsd +#HTTPD_RESTART = kill -TERM `cat /var/www/logs/httpd.pid`; sleep 10; /usr/sbin/httpd -u -DSSL +#apache +#HTTPD_RESTART = /usr/local/apache/bin/apachectl stop; sleep 10; /usr/local/apache/bin/apachectl startssl + +#(an include directory, not a file, "Include /etc/apache/conf.d" in httpd.conf) +#deb (3.1+), apache2 +APACHE_CONF = /etc/apache2/conf.d +INSSERV_OVERRIDE = /etc/insserv/overrides + +FREESIDE_RESTART = ${INIT_FILE} restart + +#deb, redhat, fedora, mandrake, suse, others? +INSTALLGROUP = root +#freebsd, openbsd +#INSTALLGROUP = wheel + +#edit the stuff below to have the daemons start + +QUEUED_USER=fs_queue +API_USER = fs_api + +SELFSERVICE_USER = fs_selfservice +#never run on the same machine in production!!! +SELFSERVICE_MACHINES = +# SELFSERVICE_MACHINES = www.example.com +# SELFSERVICE_MACHINES = web1.example.com web2.example.com + +#user with sudo access on SELFSERVICE_MACHINES for automated self-service +#installation. +SELFSERVICE_INSTALL_USER = ivan +SELFSERVICE_INSTALL_USERADD = /usr/sbin/useradd +#SELFSERVICE_INSTALL_USERADD = "/usr/sbin/pw useradd" + +#RT_ENABLED = 0 +RT_ENABLED = 1 +RT_DOMAIN = example.com +RT_TIMEZONE = US/Pacific +#RT_TIMEZONE = US/Eastern +FREESIDE_URL = "http://localhost/freeside/" + +#for now, same db as specified in DATASOURCE... eventually, otherwise? +RT_DB_DATABASE = freeside + +TORRUS_ENABLED = 0 + +# for auto-version updates, so we can "make release" more things automatically +RPM_SPECFILE = rpm/freeside.spec + +#--- + +#rt/config.layout.in +RT_PATH = /opt/rt3 + +#only used for dev kludge now, not a big deal +FREESIDE_PATH = `pwd` +PERL_INC_DEV_KLUDGE = /usr/local/share/perl/5.14.2/ + +VERSION := `grep '^$$VERSION' FS/FS.pm | cut -d\' -f2` +TAG := freeside_`grep '^$$VERSION' FS/FS.pm | cut -d\' -f2 | perl -pe 's/\./_/g'` + +#DEBVERSION = `echo ${VERSION} | perl -pe 's/(\d)([a-z])/\1~\2/'`-1 + +TEXMFHOME := "\$$TEXMFHOME" + +ver: + @echo "${VERSION}" + +tag: + @echo "${TAG}" + +help: + @echo "supported targets:" + @echo " create-database create-config" + @echo " install deploy" + @echo " configure-rt create-rt" + @echo " clean help" + @echo + @echo " install-docs install-perl-modules" + @echo " install-init install-apache" + @echo " install-rt install-texmf" + @echo " install-selfservice update-selfservice" + @echo + @echo " dev dev-docs dev-perl-modules" + @echo + @echo " masondocs alldocs docs" + @echo " wikiman" + @echo " perl-modules" + #@echo + #@echo " upload-docs release" + + +masondocs: httemplate/* httemplate/*/* httemplate/*/*/* httemplate/*/*/*/* + rm -rf masondocs + cp -pr httemplate masondocs + touch masondocs + +alldocs: masondocs + +docs: + make masondocs + +wikiman: + chmod a+rx ./bin/pod2x + ./bin/pod2x + +install-docs: docs + #ancient attempt to avoid overwriting customer modifications directly to production web files that's overlived its usefulness + #[ -e ${FREESIDE_DOCUMENT_ROOT} ] && mv ${FREESIDE_DOCUMENT_ROOT} ${FREESIDE_DOCUMENT_ROOT}.`date +%Y%m%d%H%M%S` || true + #cp -r masondocs ${FREESIDE_DOCUMENT_ROOT} + [ -h ${FREESIDE_DOCUMENT_ROOT} ] && rm ${FREESIDE_DOCUMENT_ROOT} || true + mkdir -p ${FREESIDE_DOCUMENT_ROOT} + cp -r masondocs/* masondocs/.htaccess ${FREESIDE_DOCUMENT_ROOT} + chown -R freeside:freeside ${FREESIDE_DOCUMENT_ROOT} + install -D htetc/handler.pl ${MASON_HANDLER} + perl -p -i -e "\ + s|%%%FREESIDE_EXPORT%%%|${FREESIDE_EXPORT}|g;\ + s'%%%RT_ENABLED%%%'${RT_ENABLED}'g; \ + " ${MASON_HANDLER} || true + mkdir -p ${FREESIDE_EXPORT}/profile + chown freeside ${FREESIDE_EXPORT}/profile + cp htetc/htpasswd.logout ${FREESIDE_CONF} + [ ! -e ${MASONDATA} ] && mkdir ${MASONDATA} || true + chown -R freeside ${MASONDATA} + +dev-docs: + [ -e ${FREESIDE_DOCUMENT_ROOT} ] && mv ${FREESIDE_DOCUMENT_ROOT} ${FREESIDE_DOCUMENT_ROOT}.`date +%Y%m%d%H%M%S` || true + ln -s ${FREESIDE_PATH}/httemplate ${FREESIDE_DOCUMENT_ROOT} + cp htetc/handler.pl ${MASON_HANDLER} + perl -p -i -e "\ + s'###use Module::Refresh;###'use Module::Refresh;'; \ + s'###Module::Refresh->refresh;###'Module::Refresh->refresh;'; \ + s|%%%FREESIDE_EXPORT%%%|${FREESIDE_EXPORT}|g;\ + s'%%%RT_ENABLED%%%'${RT_ENABLED}'g; \ + " ${MASON_HANDLER} || true + +perl-modules: + cd FS; \ + [ -e Makefile ] || perl Makefile.PL; \ + make; \ + perl -p -i -e "\ + s|%%%FREESIDE_CONF%%%|${FREESIDE_CONF}|g;\ + s|%%%FREESIDE_CACHE%%%|${FREESIDE_CACHE}|g;\ + s'%%%FREESIDE_DOCUMENT_ROOT%%%'${FREESIDE_DOCUMENT_ROOT}'g; \ + s'%%%RT_ENABLED%%%'${RT_ENABLED}'g; \ + s'%%%RT_PATH%%%'${RT_PATH}'g; \ + s'%%%MASONDATA%%%'${MASONDATA}'g;\ + s/%%%SELFSERVICE_USER%%%/${SELFSERVICE_USER}/g;\ + " blib/lib/FS/*.pm;\ + perl -p -i -e "\ + s/%%%SELFSERVICE_USER%%%/${SELFSERVICE_USER}/g;\ + s/%%%SELFSERVICE_MACHINES%%%/${SELFSERVICE_MACHINES}/g;\ + s|%%%FREESIDE_EXPORT%%%|${FREESIDE_EXPORT}|g;\ + " blib/lib/FS/Cron/*.pm;\ + perl -p -i -e "\ + s|%%%FREESIDE_CONF%%%|${FREESIDE_CONF}|g;\ + s|%%%FREESIDE_EXPORT%%%|${FREESIDE_EXPORT}|g;\ + s|%%%FREESIDE_LOG%%%|${FREESIDE_LOG}|g;\ + " blib/lib/FS/part_export/*.pm;\ + perl -p -i -e "\ + s|%%%FREESIDE_CACHE%%%|${FREESIDE_CACHE}|g;\ + " blib/lib/FS/cust_main/*.pm blib/lib/FS/cust_pkg/*.pm;\ + perl -p -i -e "\ + s|%%%FREESIDE_LOG%%%|${FREESIDE_LOG}|g;\ + " blib/lib/FS/Daemon/*.pm;\ + perl -p -i -e "\ + s|%%%FREESIDE_CONF%%%|${FREESIDE_CONF}|g;\ + s|%%%FREESIDE_LOG%%%|${FREESIDE_LOG}|g;\ + s|%%%FREESIDE_LOCK%%%|${FREESIDE_LOCK}|g;\ + s|%%%FREESIDE_CACHE%%%|${FREESIDE_CACHE}|g;\ + s|%%%FREESIDE_EXPORT%%%|${FREESIDE_EXPORT}|g;\ + s|%%%DIST_CONF%%%|${DIST_CONF}|g;\ + " blib/script/* + +install-perl-modules: perl-modules install-rt-initialdata + [ -L ${PERL_INC_DEV_KLUDGE}/FS ] \ + && rm ${PERL_INC_DEV_KLUDGE}/FS \ + && mv ${PERL_INC_DEV_KLUDGE}/FS.old ${PERL_INC_DEV_KLUDGE}/FS \ + || true + cd FS; \ + make install UNINST=1 + #install this for freeside-setup + install -d $(DIST_CONF) + #install conf/[a-z]* $(DEFAULT_CONF) + #CVS is not [a-z] + install `ls -d conf/[a-z]* | grep -v CVS | grep -v '^conf/registries'` $(DIST_CONF) + +dev-perl-modules: perl-modules + [ -d ${PERL_INC_DEV_KLUDGE}/FS -a ! -L ${PERL_INC_DEV_KLUDGE}/FS ] \ + && mv ${PERL_INC_DEV_KLUDGE}/FS ${PERL_INC_DEV_KLUDGE}/FS.old \ + || true + + rm -rf ${PERL_INC_DEV_KLUDGE}/FS + ln -sf ${FREESIDE_PATH}/FS/blib/lib/FS ${PERL_INC_DEV_KLUDGE}/FS + +install-texmf: + install -D -o freeside -m 444 etc/longtable.sty \ + /usr/local/share/texmf/tex/latex/longtable.sty + texhash /usr/local/share/texmf + +install-init: + #[ -e ${INIT_FILE} ] || install -o root -g ${INSTALLGROUP} -m 711 init.d/freeside-init ${INIT_FILE} + install -o root -g ${INSTALLGROUP} -m 711 init.d/freeside-init ${INIT_FILE} + perl -p -i -e "\ + s/%%%QUEUED_USER%%%/${QUEUED_USER}/g;\ + s/%%%API_USER%%%/${API_USER}/g;\ + s/%%%SELFSERVICE_USER%%%/${SELFSERVICE_USER}/g;\ + s/%%%SELFSERVICE_MACHINES%%%/${SELFSERVICE_MACHINES}/g;\ + " ${INIT_FILE} + ${INIT_INSTALL} + +install-apache: + [ -e ${APACHE_CONF}/freeside-base.conf ] && rm ${APACHE_CONF}/freeside-base.conf || true + [ -d ${APACHE_CONF} ] && \ + ( install -o root -m 755 htetc/freeside-base2.conf ${APACHE_CONF} && \ + ( [ ${RT_ENABLED} -eq 1 ] && install -o root -m 755 htetc/freeside-rt.conf ${APACHE_CONF} || true ) && \ + ( [ ${TORRUS_ENABLED} -eq 1 ] && install -o root -m 755 htetc/freeside-torrus.conf ${APACHE_CONF} || true ) && \ + perl -p -i -e "\ + s'%%%FREESIDE_DOCUMENT_ROOT%%%'${FREESIDE_DOCUMENT_ROOT}'g; \ + s'%%%FREESIDE_CONF%%%'${FREESIDE_CONF}'g; \ + s'%%%MASON_HANDLER%%%'${MASON_HANDLER}'g; \ + " ${APACHE_CONF}/freeside-*.conf \ + ) || true + [ -d ${INSSERV_OVERRIDE} ] && [ -x /sbin/insserv ] && ( install -o root -m 755 init.d/insserv-override-apache2 ${INSSERV_OVERRIDE}/apache2 && insserv -d ) || true + +install-selfservice: + [ -e ~freeside ] || cp -pr /etc/skel ~freeside && chown -R freeside ~freeside + [ -e ~freeside/.ssh/id_dsa.pub ] || [ -e ~freeside/.ssh/id_rsa.pub ] || su - freeside -c 'ssh-keygen -t dsa' + for MACHINE in ${SELFSERVICE_MACHINES}; do \ + scp -r fs_selfservice/FS-SelfService ${SELFSERVICE_INSTALL_USER}@$$MACHINE:. ;\ + ssh ${SELFSERVICE_INSTALL_USER}@$$MACHINE "cd FS-SelfService; perl Makefile.PL && make" ;\ + ssh ${SELFSERVICE_INSTALL_USER}@$$MACHINE "cd FS-SelfService; sudo make install" ;\ + scp ~freeside/.ssh/id_dsa.pub ${SELFSERVICE_INSTALL_USER}@$$MACHINE:. ;\ + ssh ${SELFSERVICE_INSTALL_USER}@$$MACHINE "sudo ${SELFSERVICE_INSTALL_USERADD} freeside; sudo install -d -o freeside -m 755 ~freeside/.ssh/; sudo install -o freeside -m 600 ./id_dsa.pub ~freeside/.ssh/authorized_keys" ;\ + ssh ${SELFSERVICE_INSTALL_USER}@$$MACHINE "sudo install -o freeside -d /usr/local/freeside" ;\ + done + +update-selfservice: + for MACHINE in ${SELFSERVICE_MACHINES}; do \ + RSYNC_RSH=ssh rsync -rlptz fs_selfservice/FS-SelfService/ ${SELFSERVICE_INSTALL_USER}@$$MACHINE:FS-SelfService ;\ + ssh ${SELFSERVICE_INSTALL_USER}@$$MACHINE "cd FS-SelfService; make clean; perl Makefile.PL && make" ;\ + ssh ${SELFSERVICE_INSTALL_USER}@$$MACHINE "cd FS-SelfService; sudo make install" ;\ + done + +install-chown: + chown freeside "${FREESIDE_CACHE}/counters.${DATASOURCE}" + chown freeside "${FREESIDE_CACHE}/cache.${DATASOURCE}" + chown freeside "${FREESIDE_EXPORT}/export.${DATASOURCE}" + +install: install-perl-modules install-docs install-init install-apache install-rt install-torrus install-texmf install-chown + +deploy: install + ${HTTPD_RESTART} + ${FREESIDE_RESTART} + +dev: dev-perl-modules dev-docs + +create-database: + perl -e 'use DBIx::DataSource qw( create_database ); create_database( "${DATASOURCE}", "${DB_USER}", "${DB_PASSWORD}" ) or die $$DBIx::DataSource::errstr;' + +create-config: install-perl-modules + [ -e ${FREESIDE_CONF} ] && mv ${FREESIDE_CONF} ${FREESIDE_CONF}.`date +%Y%m%d%H%M%S` || true + install -d -o freeside ${FREESIDE_CONF} + + touch ${FREESIDE_CONF}/secrets + chown freeside ${FREESIDE_CONF}/secrets + chmod 600 ${FREESIDE_CONF}/secrets + + /bin/echo -e "${DATASOURCE}\n${DB_USER}\n${DB_PASSWORD}" >${FREESIDE_CONF}/secrets + chmod 600 ${FREESIDE_CONF}/secrets + chown freeside ${FREESIDE_CONF}/secrets + + mkdir "${FREESIDE_CACHE}/counters.${DATASOURCE}" + chown freeside "${FREESIDE_CACHE}/counters.${DATASOURCE}" + + mkdir "${FREESIDE_CACHE}/cache.${DATASOURCE}" + chown freeside "${FREESIDE_CACHE}/cache.${DATASOURCE}" + + mkdir "${FREESIDE_EXPORT}/export.${DATASOURCE}" + chown freeside "${FREESIDE_EXPORT}/export.${DATASOURCE}" + + #install this for freeside-setup + install -d $(DIST_CONF) + #install conf/[a-z]* $(DEFAULT_CONF) + #CVS is not [a-z] + install `ls -d conf/[a-z]* | grep -v CVS | grep -v '^conf/registries'` $(DIST_CONF) + + +configure-rt: + cd rt; \ + cp config.layout.in config.layout; \ + perl -p -i -e "\ + s'%%%FREESIDE_DOCUMENT_ROOT%%%'${FREESIDE_DOCUMENT_ROOT}'g;\ + s'%%%MASONDATA%%%'${MASONDATA}'g;\ + " config.layout; \ + ./configure --enable-layout=Freeside\ + --with-db-type=${DB_TYPE} \ + --with-db-dba=${DB_USER} \ + --with-db-database=${RT_DB_DATABASE} \ + --with-db-rt-user=${DB_USER} \ + --with-db-rt-pass="${DB_PASSWORD}" \ + --with-web-user=freeside \ + --with-web-group=freeside \ + --with-rt-group=freeside \ + --with-web-handler=modperl2 + +create-rt: configure-rt + [ -d /opt ] || mkdir /opt #doh + [ -d /opt/rt3 ] || mkdir /opt/rt3 # + [ -d /opt/rt3/share ] || mkdir /opt/rt3/share # + cd rt; make install + rt/sbin/rt-setup-database --dba '${DB_USER}' \ + --dba-password '${DB_PASSWORD}' \ + --action schema \ + || true + rt/sbin/rt-setup-database --dba-password '${DB_PASSWORD}' \ + --action coredata \ + && rt/sbin/rt-setup-database --dba-password '${DB_PASSWORD}' \ + --action insert \ + --datafile ${RT_PATH}/etc/initialdata \ + || true + +install-rt: + if [ ${RT_ENABLED} -eq 1 ]; then ( cd rt; make install ); fi + if [ ${RT_ENABLED} -eq 1 ]; then perl -p -i -e "\ + s'%%%RT_DOMAIN%%%'${RT_DOMAIN}'g;\ + s'%%%RT_TIMEZONE%%%'${RT_TIMEZONE}'g;\ + s'%%%FREESIDE_URL%%%'${FREESIDE_URL}'g;\ + " ${RT_PATH}/etc/RT_SiteConfig.pm; fi + if [ ${RT_ENABLED} -eq 1 ]; then \ + chown -R freeside:freeside ${RT_PATH}/etc; fi + +install-rt-initialdata: + if [ ${RT_ENABLED} -eq 1 ] && [ -d ${RT_PATH} ]; then \ + chown -R freeside:freeside ${RT_PATH}/etc; \ + install -D -o freeside -g freeside -m 0440 rt/etc/initialdata \ + ${RT_PATH}/etc/initialdata; fi + +configure-torrus: + cd torrus; \ + torrus_user=freeside var_user=freeside var_group=freeside ./configure + +install-torrus: + if [ ${TORRUS_ENABLED} -eq 1 ]; then ( cd torrus; \ + make; \ + make install; \ + perl -p -i -e "\ + s'%%%FREESIDE_URL%%%'${FREESIDE_URL}'g;\ + " /usr/local/etc/torrus/conf/torrus-siteconfig.pl; \ + torrus clearcache \ + );fi + +clean: + rm -rf masondocs + rm -rf httemplate/docs/man + rm -rf pod2htmi.tmp + rm -rf pod2htmd.tmp + -cd FS; \ + make clean + -cd fs_selfservice/FS-SelfService; \ + make clean + +#these are probably only useful if you're me... + +#release: upload-docs +.PHONY: release +release: + # Update the changelog + #./bin/cvs2cl + #cvs commit -m "Updated for ${VERSION}" ChangeLog + + # Update the RPM specfile + #cvs edit ${RPM_SPECFILE} + #perl -p -i -e "s/\d+[^\}]+/${VERSION}/ if /%define\s+version\s+(\d+[^\}]+)\}/;" ${RPM_SPECFILE} + #perl -p -i -e "s/\d+[^\}]+/1/ if /%define\s+release\s+(\d+[^\}]+)\}/;" ${RPM_SPECFILE} + #cvs commit -m "Updated for ${VERSION}" ${RPM_SPECFILE} + + # Update the Debian changelog + #cvs edit debian/changelog + #dch -v ${DEBVERSION} -p "New upstream release" + #cvs commit -m "Updated for ${VERSION}" debian/changelog + + # Make sure other people's changes are pulled in! + git pull + + # Tag the release + git tag -f ${TAG} + + #cd /home/ivan + git archive --prefix=freeside-${VERSION}/ ${TAG} | gzip -9 >freeside-${VERSION}.tar.gz + + scp freeside-${VERSION}.tar.gz ivan@420.am:/var/www/www.sisd.com/freeside/ + mv freeside-${VERSION}.tar.gz .. + + #these things failing should not make release target fail, so: "|| true" + + #kick off vmware update + #./BUILD_VMWARE_APPLIANCE ${$TAG} || true + + #kick off deb package update + + #kick off rpm package update too? + + #update web demo? + + #update web demo self-service? + diff --git a/lab/vagrant/docker/thefnf/odoo/Dockerfile b/lab/vagrant/docker/thefnf/odoo/Dockerfile new file mode 100755 index 0000000..c8c4d31 --- /dev/null +++ b/lab/vagrant/docker/thefnf/odoo/Dockerfile @@ -0,0 +1,13 @@ +FROM python:2.7 +RUN apt-get install -y libldap2-dev libsasl2-dev && \ + adduser odoo --system --group --shell /bin/bash +USER odoo +ENV HOME /home/odoo +ENV PATH $HOME/.local/bin:$PATH +WORKDIR /home/odoo +RUN curl http://nightly.odoo.com/8.0/nightly/src/odoo_8.0-latest.tar.gz |tar xz --strip-components 1 && \ + python setup.py install --user && \ + python setup.py install --user --single-version-externally-managed --root / # Strips version hash from module directories +ADD openerp_serverrc /home/odoo/.openerp_serverrc +EXPOSE 8069 8072 +CMD openerp-server \ No newline at end of file diff --git a/lab/vagrant/docker/thefnf/odoo/openerp_serverrc b/lab/vagrant/docker/thefnf/odoo/openerp_serverrc new file mode 100755 index 0000000..7a17b45 --- /dev/null +++ b/lab/vagrant/docker/thefnf/odoo/openerp_serverrc @@ -0,0 +1,62 @@ +[options] +addons_path = /home/odoo/.local/lib/python2.7/site-packages/openerp/addons +admin_passwd = admin +auto_reload = False +csv_internal_sep = , +data_dir = /home/odoo/.local/share/Odoo +db_host = postgres +db_maxconn = 64 +db_name = False +db_password = odoo +db_port = 5432 +db_template = template1 +db_user = odoo +dbfilter = .* +debug_mode = False +demo = {} +email_from = False +import_partial = +limit_memory_hard = 2684354560 +limit_memory_soft = 2147483648 +limit_request = 8192 +limit_time_cpu = 60 +limit_time_real = 120 +list_db = True +log_db = False +log_handler = [':INFO'] +log_level = info +logfile = None +logrotate = False +longpolling_port = 8072 +max_cron_threads = 2 +osv_memory_age_limit = 1.0 +osv_memory_count_limit = False +pg_path = None +pidfile = None +proxy_mode = False +reportgz = False +secure_cert_file = server.cert +secure_pkey_file = server.pkey +server_wide_modules = None +smtp_password = False +smtp_port = 25 +smtp_server = localhost +smtp_ssl = False +smtp_user = False +syslog = False +test_commit = False +test_enable = False +test_file = False +test_report_directory = False +timezone = False +translate_modules = ['all'] +unaccent = False +without_demo = False +workers = 0 +xmlrpc = True +xmlrpc_interface = +xmlrpc_port = 8069 +xmlrpcs = True +xmlrpcs_interface = +xmlrpcs_port = 8071 + diff --git a/mtpconfigs/ovh/shared-router/shorewall/conntrack b/mtpconfigs/ovh/shared-router/shorewall/conntrack new file mode 100755 index 0000000..963696e --- /dev/null +++ b/mtpconfigs/ovh/shared-router/shorewall/conntrack @@ -0,0 +1,53 @@ +# +# Shorewall version 4 - conntrack File +# +# For information about entries in this file, type "man shorewall-conntrack" +# +############################################################################################################## +?FORMAT 3 +#ACTION SOURCE DESTINATION PROTO DEST SOURCE USER/ SWITCH +# PORT(S) PORT(S) GROUP +?if $AUTOHELPERS && __CT_TARGET + +?if __AMANDA_HELPER +CT:helper:amanda:PO - - udp 10080 +?endif + +?if __FTP_HELPER +CT:helper:ftp:PO - - tcp 21 +?endif + +?if __H323_HELPER +CT:helper:RAS:PO - - udp 1719 +CT:helper:Q.931:PO - - tcp 1720 +?endif + +?if __IRC_HELPER +CT:helper:irc:PO - - tcp 6667 +?endif + +?if __NETBIOS_NS_HELPER +CT:helper:netbios-ns:PO - - udp 137 +?endif + +?if __PPTP_HELPER +CT:helper:pptp:PO - - tcp 1723 +?endif + +?if __SANE_HELPER +CT:helper:sane:PO - - tcp 6566 +?endif + +?if __SIP_HELPER +CT:helper:sip:PO - - udp 5060 +?endif + +?if __SNMP_HELPER +CT:helper:snmp:PO - - udp 161 +?endif + +?if __TFTP_HELPER +CT:helper:tftp:PO - - udp 69 +?endif + +?endif diff --git a/mtpconfigs/ovh/shared-router/shorewall/interfaces b/mtpconfigs/ovh/shared-router/shorewall/interfaces new file mode 100755 index 0000000..6ae8037 --- /dev/null +++ b/mtpconfigs/ovh/shared-router/shorewall/interfaces @@ -0,0 +1,13 @@ +#ZONE INTERFACE OPTIONS +rr eth0 detect tcpflags,nosmurfs,routefilter,logmartians +wan eth1 detect tcpflags,nosmurfs,routefilter,logmartians,sourceroute=0 +barm eth2 detect tcpflags,nosmurfs,routefilter,logmartians +mgmt eth3 detect tcpflags,nosmurfs,routefilter,logmartians +asn eth4 detect tcpflags,nosmurfs,routefilter,logmartians +s2l eth5 detect tcpflags,nosmurfs,routefilter,logmartians +fnf eth6 detect tcpflags,nosmurfs,routefilter,logmartians +knel eth7 detect tcpflags,nosmurfs,routefilter,logmartians +tsys eth8 detect tcpflags,nosmurfs,routefilter,logmartians +vpnrwr tun0 detect dhcp +vpnauslab tun1 detect dhcp +vpnasn2net tun2 detect dhcp diff --git a/mtpconfigs/ovh/shared-router/shorewall/masq b/mtpconfigs/ovh/shared-router/shorewall/masq new file mode 100755 index 0000000..6f7067f --- /dev/null +++ b/mtpconfigs/ovh/shared-router/shorewall/masq @@ -0,0 +1,19 @@ +# +# Shorewall version 4.0 - Sample Masq file for two-interface configuration. +# Copyright (C) 2006 by the Shorewall Team +# +# This library is free software; you can redistribute it and/or +# modify it under the terms of the GNU Lesser General Public +# License as published by the Free Software Foundation; either +# version 2.1 of the License, or (at your option) any later version. +# +# See the file README.txt for further details. +#------------------------------------------------------------------------------ +# For information about entries in this file, type "man shorewall-masq" +################################################################################################################ +#INTERFACE:DEST SOURCE ADDRESS PROTO PORT(S) IPSEC MARK USER/ SWITCH ORIGINAL +# GROUP DEST +eth1 10.0.0.0/8,\ + 169.254.0.0/16,\ + 172.16.0.0/12,\ + 192.168.0.0/16 diff --git a/mtpconfigs/ovh/shared-router/shorewall/params b/mtpconfigs/ovh/shared-router/shorewall/params new file mode 100755 index 0000000..a60512b --- /dev/null +++ b/mtpconfigs/ovh/shared-router/shorewall/params @@ -0,0 +1,28 @@ +# +# Shorewall version 4 - Params File +# +# /etc/shorewall/params +# +# Assign any variables that you need here. +# +# It is suggested that variable names begin with an upper case letter +# to distinguish them from variables used internally within the +# Shorewall programs +# +# Example: +# +# NET_IF=eth0 +# NET_BCAST=130.252.100.255 +# NET_OPTIONS=routefilter,norfc1918 +# +# Example (/etc/shorewall/interfaces record): +# +# net $NET_IF $NET_BCAST $NET_OPTIONS +# +# The result will be the same as if the record had been written +# +# net eth0 130.252.100.255 routefilter,norfc1918 +# +############################################################################### + +#LAST LINE -- DO NOT REMOVE diff --git a/mtpconfigs/ovh/shared-router/shorewall/policy b/mtpconfigs/ovh/shared-router/shorewall/policy new file mode 100755 index 0000000..285d387 --- /dev/null +++ b/mtpconfigs/ovh/shared-router/shorewall/policy @@ -0,0 +1,20 @@ +#SOURCE ZONE DESTINATION ZONE POLICY LOG LIMIT:BURST +# LEVEL +#Allow the firewall to get out to the net. Updates/e-mail alerts etc. I could pinhole this, but meh COME AT ME NSA +$FW wan ACCEPT + +#Road warrior is trusted. It serves as an extension of the mgmt net. +vpnrwr all ACCEPT + +#Anything transisting the vpn link between ausprod-core-rtr01 and tsys-rtr has already been passed firewall rules and IPS inspection. +#Otherwise I wouldn't allow this +vpnauslab all ACCEPT + +#Drop everything inbound from the big bad world that isn't explicitly allowed. +#Cause the net is where the NSA lives +wan all DROP + +#Drop everything that isn't explicitly allowed. +#Make explicit rules for everything yo. The NSA says you should. Duh. +# #state-sponsored-malware #stuxnet-was-an-inside-job +all all REJECT info diff --git a/mtpconfigs/ovh/shared-router/shorewall/rules b/mtpconfigs/ovh/shared-router/shorewall/rules new file mode 100755 index 0000000..574c436 --- /dev/null +++ b/mtpconfigs/ovh/shared-router/shorewall/rules @@ -0,0 +1,113 @@ +#ACTION SOURCE DEST PROTO DEST PORT(S) SOURCE ORIGINAL +########################################################################################################################################################################################################### +#Inbound DNAT forwarding from WAN to various zone/ip pinholes +########################################################################################################################################################################################################### +######################################################### +#KNEL rules +#158.69.183.165/29 eth1:2 +######################################################### +DNAT wan knel:10.253.8.72 tcp 443 - 158.69.183.165 +DNAT wan knel:10.253.8.72 tcp 80 - 158.69.183.165 +DNAT wan knel:10.253.8.72 tcp 993 - 158.69.183.165 +DNAT wan knel:10.253.8.72 tcp 25 - 158.69.183.165 +DNAT wan knel:10.253.8.72 tcp 465 - 158.69.183.165 +DNAT wan knel:10.253.8.72 tcp 5222 - 158.69.183.165 + +######################################################### +#TSYS rules +#158.69.183.161/29 eth1 +######################################################### +DNAT wan tsys:10.253.9.78 tcp 443 - 158.69.183.161 +DNAT wan tsys:10.253.9.78 tcp 80 - 158.69.183.161 +DNAT wan tsys:10.253.9.78 tcp 25 - 158.69.183.161 +DNAT wan tsys:10.253.9.78 tcp 465 - 158.69.183.161 +DNAT wan tsys:10.253.9.78 tcp 5222 - 158.69.183.161 + +######################################################### +#RackRental WAN rules +#158.69.183.164/29 eth1:1 +######################################################### +#158.69.183.164/29 +DNAT wan rr:10.253.6.81 tcp 443 - 158.69.183.164 +DNAT wan rr:10.253.6.81 tcp 80 - 158.69.183.164 + +############################################################ +#S2l/asn WAN rules handled by their upstream routers/admins +############################################################ + +########################################################################################################################################################################################################### +#site to site and road warrior VPN rules +########################################################################################################################################################################################################### + +#Allow road warrior connectivity from anywhere +ACCEPT wan fw udp 443 + +#Allow auslab site to site vpn +ACCEPT wan fw tcp 1195 +ACCEPT wan fw udp 1195 + + +############################################################ +#FW rules for RoadWarrior VPN +############################################################ +ACCEPT all vpnrwr all + +############################################################ +#FW rules for STS VPN - AUSLAB +#ACCEPT loc vpnauslab all +############################################################ +ACCEPT vpnauslab all all +ACCEPT $FW vpnauslab all + +############################################################ +#FW rules for STS VPN - client - asn2net +#Lock this down soon +############################################################ +ACCEPT $FW vpnasn2net all +ACCEPT vpnasn2net $FW all + + +########################################################################################################################################################################################################### +#outbound from various local nets and the firewall to WAN +########################################################################################################################################################################################################### +ACCEPT rr wan all #Lock this down soon +ACCEPT rr tsys all #Lock this down soon +ACCEPT knel,tsys,mgmt wan all + + +#Temp rules to get stuff working.. +ACCEPT $FW all all #Fw can access everything for now, Lock this down later +ACCEPT mgmt $FW + +ACCEPT vpnauslab mgmt all +ACCEPT vpnauslab all all + +########################################################################################################################################################################################################### +#intra zone pinhole rules +########################################################################################################################################################################################################### +ACCEPT vpnrwr,rr,barm,tsys,knel,fnf mgmt:10.253.3.86 udp 53 +ACCEPT vpnrwr,rr,barm,tsys,knel,fnf mgmt:10.253.3.86 tcp 53 + +########################################################################################################################################################################################################### +#intra zone wide rules +########################################################################################################################################################################################################### +#Mgmt can hit everything yo, cause it's fucking management with a capital M +ACCEPT mgmt barm,tsys,knel,fnf,vpnrwr,asn,s2l,vpnauslab all + +#Ad replication rule +ACCEPT mgmt:10.253.3.86 vpnauslab:10.251.2.98 all +ACCEPT vpnauslab:10.251.2.98 mgmt:10.253.3.86 all + +#Zenoss rule +ACCEPT mgmt:10.253.3.77 all all + + + + +#Brendan mgmt access +ACCEPT vpnasn2net:10.30.1.2 mgmt:10.253.3.86 udp 53 +ACCEPT vpnasn2net:10.30.1.2 mgmt:10.253.3.86 tcp 53 +ACCEPT vpnasn2net:10.30.3.0/24 $FW +ACCEPT vpnasn2net:10.30.2.0/24 $FW +ACCEPT vpnasn2net:10.30.2.0/24 mgmt +ACCEPT vpnasn2net:10.30.3.0/24 mgmt diff --git a/mtpconfigs/ovh/shared-router/shorewall/shorewall.conf b/mtpconfigs/ovh/shared-router/shorewall/shorewall.conf new file mode 100755 index 0000000..886f4f4 --- /dev/null +++ b/mtpconfigs/ovh/shared-router/shorewall/shorewall.conf @@ -0,0 +1,274 @@ +############################################################################### +# +# Shorewall Version 4 -- /etc/shorewall/shorewall.conf +# +# For information about the settings in this file, type "man shorewall.conf" +# +# Manpage also online at http://www.shorewall.net/manpages/shorewall.conf.html +############################################################################### +# S T A R T U P E N A B L E D +############################################################################### + +STARTUP_ENABLED=Yes + +############################################################################### +# V E R B O S I T Y +############################################################################### + +VERBOSITY=1 + +############################################################################### +# L O G G I N G +############################################################################### + +BLACKLIST_LOG_LEVEL= + +INVALID_LOG_LEVEL= + +LOG_MARTIANS=Yes + +LOG_VERBOSITY=2 + +LOGALLNEW= + +LOGFILE="/var/log/firewall.log" + +LOGFORMAT="%s:%s:" + +LOGTAGONLY=No + +LOGLIMIT= + +MACLIST_LOG_LEVEL=info + +RELATED_LOG_LEVEL= + +RPFILTER_LOG_LEVEL=info + +SFILTER_LOG_LEVEL=info + +SMURF_LOG_LEVEL=info + +STARTUP_LOG=/var/log/shorewall-init.log + +TCP_FLAGS_LOG_LEVEL=info + +UNTRACKED_LOG_LEVEL= + +############################################################################### +# L O C A T I O N O F F I L E S A N D D I R E C T O R I E S +############################################################################### + +ARPTABLES= + +CONFIG_PATH="${CONFDIR}/shorewall:${SHAREDIR}/shorewall" + +GEOIPDIR=/usr/share/xt_geoip/LE + +IPTABLES= + +IP= + +IPSET= + +LOCKFILE= + +MODULESDIR= + +NFACCT= + +PATH="/sbin:/bin:/usr/sbin:/usr/bin:/usr/local/bin:/usr/local/sbin" + +PERL=/usr/bin/perl + +RESTOREFILE=restore + +SHOREWALL_SHELL=/bin/sh + +SUBSYSLOCK="" + +TC= + +############################################################################### +# D E F A U L T A C T I O N S / M A C R O S +############################################################################### + +ACCEPT_DEFAULT=none +DROP_DEFAULT=Drop +NFQUEUE_DEFAULT=none +QUEUE_DEFAULT=none +REJECT_DEFAULT=Reject + +############################################################################### +# R S H / R C P C O M M A N D S +############################################################################### + +RCP_COMMAND='scp ${files} ${root}@${system}:${destination}' +RSH_COMMAND='ssh ${root}@${system} ${command}' + +############################################################################### +# F I R E W A L L O P T I O N S +############################################################################### + +ACCOUNTING=Yes + +ACCOUNTING_TABLE=filter + +ADD_IP_ALIASES=No + +ADD_SNAT_ALIASES=No + +ADMINISABSENTMINDED=Yes + +IGNOREUNKNOWNVARIABLES=No + +AUTOCOMMENT=Yes + +AUTOHELPERS=Yes + +AUTOMAKE=No + +BLACKLIST="NEW,INVALID,UNTRACKED" + +CHAIN_SCRIPTS=Yes + +CLAMPMSS=No + +CLEAR_TC=Yes + +COMPLETE=No + +DEFER_DNS_RESOLUTION=Yes + +DELETE_THEN_ADD=Yes + +DETECT_DNAT_IPADDRS=No + +DISABLE_IPV6=No + +DONT_LOAD= + +DYNAMIC_BLACKLIST=Yes + +EXPAND_POLICIES=Yes + +EXPORTMODULES=Yes + +FASTACCEPT=No + +FORWARD_CLEAR_MARK= + +HELPERS= + +IMPLICIT_CONTINUE=No + +IPSET_WARNINGS=Yes + +IP_FORWARDING=On + +KEEP_RT_TABLES=No + +LEGACY_FASTSTART=Yes + +LOAD_HELPERS_ONLY=No + +MACLIST_TABLE=filter + +MACLIST_TTL= + +MANGLE_ENABLED=Yes + +MAPOLDACTIONS=No + +MARK_IN_FORWARD_CHAIN=No + +MODULE_SUFFIX=ko + +MULTICAST=Yes + +MUTEX_TIMEOUT=60 + +NULL_ROUTE_RFC1918=No + +OPTIMIZE=0 + +OPTIMIZE_ACCOUNTING=No + +REJECT_ACTION= + +REQUIRE_INTERFACE=No + +RESTORE_DEFAULT_ROUTE=Yes + +RESTORE_ROUTEMARKS=Yes + +RETAIN_ALIASES=No + +ROUTE_FILTER=Yes + +SAVE_ARPTABLES=No + +SAVE_IPSETS=No + +TC_ENABLED=Internal + +TC_EXPERT=No + +TC_PRIOMAP="2 3 3 3 2 3 1 1 2 2 2 2 2 2 2 2" + +TRACK_PROVIDERS=No + +TRACK_RULES=No + +USE_DEFAULT_RT=No + +USE_PHYSICAL_NAMES=No + +USE_RT_NAMES=No + +WARNOLDCAPVERSION=Yes + +ZONE2ZONE=2 + +############################################################################### +# P A C K E T D I S P O S I T I O N +############################################################################### + +BLACKLIST_DISPOSITION=DROP + +INVALID_DISPOSITION=CONTINUE + +MACLIST_DISPOSITION=REJECT + +RELATED_DISPOSITION=ACCEPT + +RPFILTER_DISPOSITION=DROP + +SMURF_DISPOSITION=DROP + +SFILTER_DISPOSITION=DROP + +TCP_FLAGS_DISPOSITION=DROP + +UNTRACKED_DISPOSITION=CONTINUE + +################################################################################ +# P A C K E T M A R K L A Y O U T +################################################################################ + +TC_BITS= + +PROVIDER_BITS= + +PROVIDER_OFFSET= + +MASK_BITS= + +ZONE_BITS=0 + +################################################################################ +# L E G A C Y O P T I O N +# D O N O T D E L E T E O R A L T E R +################################################################################ + +IPSECFILE=zones diff --git a/mtpconfigs/ovh/shared-router/shorewall/zones b/mtpconfigs/ovh/shared-router/shorewall/zones new file mode 100755 index 0000000..e585906 --- /dev/null +++ b/mtpconfigs/ovh/shared-router/shorewall/zones @@ -0,0 +1,14 @@ +#ZONE TYPE OPTIONS +fw firewall +rr ipv4 +wan ipv4 +barm ipv4 +mgmt ipv4 +asn ipv4 +s2l ipv4 +fnf ipv4 +knel ipv4 +tsys ipv4 +vpnrwr ipv4 +vpnauslab ipv4 +vpnasn2net ipv4 diff --git a/rubix/Monitoring/mibs/LM-SENSORS-MIB b/rubix/Monitoring/mibs/LM-SENSORS-MIB new file mode 100755 index 0000000..d0734b3 --- /dev/null +++ b/rubix/Monitoring/mibs/LM-SENSORS-MIB @@ -0,0 +1,230 @@ +LM-SENSORS-MIB DEFINITIONS ::= BEGIN + +-- +-- Derived from the original VEST-INTERNETT-MIB. Open issues: +-- +-- (a) where to register this MIB? +-- (b) use not-accessible for diskIOIndex? +-- + + +IMPORTS + MODULE-IDENTITY, OBJECT-TYPE, Integer32, Gauge32 + FROM SNMPv2-SMI + DisplayString + FROM SNMPv2-TC + ucdExperimental + FROM UCD-SNMP-MIB; + +lmSensorsMIB MODULE-IDENTITY + LAST-UPDATED "200011050000Z" + ORGANIZATION "AdamsNames Ltd" + CONTACT-INFO + "Primary Contact: M J Oldfield + email: m@mail.tc" + DESCRIPTION + "This MIB module defines objects for lm_sensor derived data." + REVISION "200011050000Z" + DESCRIPTION + "Derived from DISKIO-MIB ex UCD." + ::= { lmSensors 1 } + +lmSensors OBJECT IDENTIFIER ::= { ucdExperimental 16 } + +-- + +lmTempSensorsTable OBJECT-TYPE + SYNTAX SEQUENCE OF LMTempSensorsEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "Table of temperature sensors and their values." + ::= { lmSensors 2 } + +lmTempSensorsEntry OBJECT-TYPE + SYNTAX LMTempSensorsEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "An entry containing a device and its statistics." + INDEX { lmTempSensorsIndex } + ::= { lmTempSensorsTable 1 } + +LMTempSensorsEntry ::= SEQUENCE { + lmTempSensorsIndex Integer32, + lmTempSensorsDevice DisplayString, + lmTempSensorsValue Gauge32 +} + +lmTempSensorsIndex OBJECT-TYPE + SYNTAX Integer32 (0..65535) + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Reference index for each observed device." + ::= { lmTempSensorsEntry 1 } + +lmTempSensorsDevice OBJECT-TYPE + SYNTAX DisplayString + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The name of the temperature sensor we are reading." + ::= { lmTempSensorsEntry 2 } + +lmTempSensorsValue OBJECT-TYPE + SYNTAX Gauge32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The temperature of this sensor in mC." + ::= { lmTempSensorsEntry 3 } +-- + +lmFanSensorsTable OBJECT-TYPE + SYNTAX SEQUENCE OF LMFanSensorsEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "Table of fan sensors and their values." + ::= { lmSensors 3 } + +lmFanSensorsEntry OBJECT-TYPE + SYNTAX LMFanSensorsEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "An entry containing a device and its statistics." + INDEX { lmFanSensorsIndex } + ::= { lmFanSensorsTable 1 } + +LMFanSensorsEntry ::= SEQUENCE { + lmFanSensorsIndex Integer32, + lmFanSensorsDevice DisplayString, + lmFanSensorsValue Gauge32 +} + +lmFanSensorsIndex OBJECT-TYPE + SYNTAX Integer32 (0..65535) + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Reference index for each observed device." + ::= { lmFanSensorsEntry 1 } + +lmFanSensorsDevice OBJECT-TYPE + SYNTAX DisplayString + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The name of the fan sensor we are reading." + ::= { lmFanSensorsEntry 2 } + +lmFanSensorsValue OBJECT-TYPE + SYNTAX Gauge32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The rotation speed of the fan in RPM." + ::= { lmFanSensorsEntry 3 } + +-- + +lmVoltSensorsTable OBJECT-TYPE + SYNTAX SEQUENCE OF LMVoltSensorsEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "Table of voltage sensors and their values." + ::= { lmSensors 4 } + +lmVoltSensorsEntry OBJECT-TYPE + SYNTAX LMVoltSensorsEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "An entry containing a device and its statistics." + INDEX { lmVoltSensorsIndex } + ::= { lmVoltSensorsTable 1 } + +LMVoltSensorsEntry ::= SEQUENCE { + lmVoltSensorsIndex Integer32, + lmVoltSensorsDevice DisplayString, + lmVoltSensorsValue Gauge32 +} + +lmVoltSensorsIndex OBJECT-TYPE + SYNTAX Integer32 (0..65535) + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Reference index for each observed device." + ::= { lmVoltSensorsEntry 1 } + +lmVoltSensorsDevice OBJECT-TYPE + SYNTAX DisplayString + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The name of the device we are reading." + ::= { lmVoltSensorsEntry 2 } + +lmVoltSensorsValue OBJECT-TYPE + SYNTAX Gauge32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The voltage in mV." + ::= { lmVoltSensorsEntry 3 } + +-- + +lmMiscSensorsTable OBJECT-TYPE + SYNTAX SEQUENCE OF LMMiscSensorsEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "Table of miscellaneous sensor devices and their values." + ::= { lmSensors 5 } + +lmMiscSensorsEntry OBJECT-TYPE + SYNTAX LMMiscSensorsEntry + MAX-ACCESS not-accessible + STATUS current + DESCRIPTION + "An entry containing a device and its statistics." + INDEX { lmMiscSensorsIndex } + ::= { lmMiscSensorsTable 1 } + +LMMiscSensorsEntry ::= SEQUENCE { + lmMiscSensorsIndex Integer32, + lmMiscSensorsDevice DisplayString, + lmMiscSensorsValue Gauge32 +} + +lmMiscSensorsIndex OBJECT-TYPE + SYNTAX Integer32 (0..65535) + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "Reference index for each observed device." + ::= { lmMiscSensorsEntry 1 } + +lmMiscSensorsDevice OBJECT-TYPE + SYNTAX DisplayString + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The name of the device we are reading." + ::= { lmMiscSensorsEntry 2 } + +lmMiscSensorsValue OBJECT-TYPE + SYNTAX Gauge32 + MAX-ACCESS read-only + STATUS current + DESCRIPTION + "The value of this sensor." + ::= { lmMiscSensorsEntry 3 } + + +END diff --git a/rundeck/auslab b/rundeck/auslab new file mode 100644 index 0000000..547c7cd --- /dev/null +++ b/rundeck/auslab @@ -0,0 +1,30 @@ +ausprod-core-rtr01-vlmgmt.turnsys.net: + hostname: ausprod-core-rtr01-vlmgmt.turnsys.net + username: root + ssh-keypath: /var/lib/rundeck/ssh-keys/tsys_root.key + tags: 'prod,auslab,physical,infra' +ausprod-labsvr.turnsys.net: + hostname: ausprod-labsvr.turnsys.net + username: root + ssh-keypath: /var/lib/rundeck/ssh-keys/tsys_root.key + tags: 'prod,auslab,physical,subo' +fsky2-rpi3.turnsys.net: + hostname: fsky2-rpi3.turnsys.net + username: root + ssh-keypath: /var/lib/rundeck/ssh-keys/tsys_root.key + tags: 'prod,auslab,physical,subo' +subo-logtest.turnsys.net: + hostname: subo-logtest.turnsys.net + username: root + ssh-keypath: /var/lib/rundeck/ssh-keys/tsys_root.key + tags: 'prod,auslab,physical,subo' +fground01.turnsys.net: + hostname: fground01.turnsys.net + username: root + ssh-keypath: /var/lib/rundeck/ssh-keys/tsys_root.key + tags: 'prod,auslab,physical,subo' +fground-flink.turnsys.net: + hostname: fground-flink.turnsys.net + username: root + ssh-keypath: /var/lib/rundeck/ssh-keys/tsys_root.key + tags: 'prod,auslab,physical,subo' diff --git a/rundeck/ovh b/rundeck/ovh new file mode 100644 index 0000000..b9ed7c1 --- /dev/null +++ b/rundeck/ovh @@ -0,0 +1,35 @@ +shared-router.turnsys.net: + hostname: shared-router.turnsys.net + username: root + ssh-keypath: /var/lib/rundeck/ssh-keys/tsys_root.key + tags: 'prod,ovh,virtual,infra' +tsys-cloud.turnsys.net: + hostname: tsys-cloud.turnsys.net + username: root + ssh-keypath: /var/lib/rundeck/ssh-keys/tsys_root.key + tags: 'prod,ovh,virtual,tsys' +tsys-rr-shell.turnsys.net: + hostname: tsys-rr-shell.turnsys.net + username: root + ssh-keypath: /var/lib/rundeck/ssh-keys/tsys_root.key + tags: 'prod,ovh,virtual,rr' +tsys-rr-app.turnsys.net: + hostname: tsys-rr-app.turnsys.net + username: root + ssh-keypath: /var/lib/rundeck/ssh-keys/tsys_root.key + tags: 'prod,ovh,virtual,rr' +toolbox.turnsys.net: + hostname: toolbox.turnsys.net + username: root + ssh-keypath: /var/lib/rundeck/ssh-keys/tsys_root.key + tags: 'prod,ovh,virtual,infra' +shared-build.turnsys.net: + hostname: shared-build.turnsys.net + username: root + ssh-keypath: /var/lib/rundeck/ssh-keys/tsys_root.key + tags: 'prod,ovh,virtual,infra' +shared-zenoss.turnsys.net: + hostname: shared-zenoss.turnsys.net + username: root + ssh-keypath: /var/lib/rundeck/ssh-keys/tsys_root.key + tags: 'prod,ovh,virtual,infra' diff --git a/rundeck/satx b/rundeck/satx new file mode 100644 index 0000000..29680ff --- /dev/null +++ b/rundeck/satx @@ -0,0 +1,20 @@ +ausprod-linsrv.turnsys.net: + hostname: ausprod-linsrv.turnsys.net + username: root + ssh-keypath: /var/lib/rundeck/ssh-keys/tsys_root.key + tags: 'prod,satx,physical,infra' +tsyscn4.turnsys.net: + hostname: tsyscn4.turnsys.net + username: root + ssh-keypath: /var/lib/rundeck/ssh-keys/tsys_root.key + tags: 'satx,physical,infra,tsys' +satxtimeserver.turnsys.net: + hostname: satxtimeserver.turnsys.net + username: root + ssh-keypath: /var/lib/rundeck/ssh-keys/tsys_root.key + tags: 'prod,satx,physical,infra' +octoprint.turnsys.net: + hostname: octoprint.turnsys.net + username: root + ssh-keypath: /var/lib/rundeck/ssh-keys/tsys_root.key + tags: 'prod,satx,physical,infra' diff --git a/rundeck/sshConfig b/rundeck/sshConfig new file mode 100755 index 0000000..3603328 --- /dev/null +++ b/rundeck/sshConfig @@ -0,0 +1,99 @@ +StrictHostKeyChecking no + + +#IdentityFile /home/cwyble/.ssh/id_rsa + +#Production systems + +Host asn2net-linsrv + User asn2net + Hostname asn2net-linsrv.turnsys.net +Host asn2net-router + User admin + Hostname asn2net-router.turnsys.net +Host ausprod-core-ap01 + Hostname ausprod-core-ap01.turnsys.net + User cisco +Host ausprod-core-rtr01 + User localuser + Hostname ausprod-core-rtr01-vlmgmt.turnsys.net +Host ausprod-lab-sw01 + Hostname ausprod-labsw01.turnsys.net +Host ausprod-lab-sw02 + Hostname ausprod-labsw02.turnsys.net +Host ausprod-consrv + User root + ForwardX11 no + Hostname ausprod-consrv.turnsys.net +Host auslab-power + User root:7048 + Hostname ausprod-consrv.turnsys.net + ForwardX11 no +Host ausprod-labsvr + User root + Hostname ausprod-labsvr.turnsys.net +Host ausprod-linsrv + User localuser + Hostname ausprod-linsrv.turnsys.net +Host dedi + User root + Hostname dedi.turnsys.com + ForwardX11 yes +Host shared-boss + User localuser + Hostname shared-boss.turnsys.net +Host shared-build + User localuser + Hostname shared-build.turnsys.net +Host shared-router + User root + Hostname shared-router.turnsys.net +Host toolbox + User localuser + Hostname toolbox.turnsys.net +Host shared-voip + User localuser + Hostname shared-voip.turnsys.net +Host shared-zenoss + User root + Hostname shared-zenoss.turnsys.net +Host tsys-rr-app + User root + Hostname tsys-rr-app.turnsys.net +Host tsys-rr-shell + User localuser + Hostname tsys-rr-shell.turnsys.net +Host tsys-cloud + User root + Hostname tsys-cloud.turnsys.net +Host tsyscn4 + User localuser + Hostname tsyscn4.turnsys.net +Host shallowblue + User localuser + Hostname shallowblue.turnsys.net +Host tsys-taiga + User localuser + Hostname tsys-taiga.turnsys.net +Host subo-fground + User fground + Hostname fground01.turnsys.net +Host subo-fground-flink + User pi + Hostname fground-flink.turnsys.net +Host subo-fsky + User pi + Hostname fsky2-rpi3.turnsys.net +Host subo-logtest + User fground + Hostname subo-logtest.turnsys.net +Host satxtimeserver + User pi + Hostname satxtimeserver.turnsys.net + +#Host ausprod-oob-sw01 +#Host ausprod-oob-sw02 + + +Host * + ForwardAgent yes diff --git a/slack/bin/distro b/slack/bin/distro new file mode 100755 index 0000000..a1eae12 --- /dev/null +++ b/slack/bin/distro @@ -0,0 +1,257 @@ +#!/bin/sh +# Observium License Version 1.0 +# +# Copyright (c) 2013 Joe Holden +# +# The intent of this license is to establish the freedom to use, share and contribute to +# the software regulated by this license. +# +# This license applies to any software containing a notice placed by the copyright holder +# saying that it may be distributed under the terms of this license. Such software is herein +# referred to as the Software. This license covers modification and distribution of the +# Software. +# +# Granted Rights +# +# 1. You are granted the non-exclusive rights set forth in this license provided you agree to +# and comply with any and all conditions in this license. Whole or partial distribution of the +# Software, or software items that link with the Software, in any form signifies acceptance of +# this license. +# +# 2. You may copy and distribute the Software in unmodified form provided that the entire package, +# including - but not restricted to - copyright, trademark notices and disclaimers, as released +# by the initial developer of the Software, is distributed. +# +# 3. You may make modifications to the Software and distribute your modifications, in a form that +# is separate from the Software, such as patches. The following restrictions apply to modifications: +# +# a. Modifications must not alter or remove any copyright notices in the Software. +# b. When modifications to the Software are released under this license, a non-exclusive royalty-free +# right is granted to the initial developer of the Software to distribute your modification in +# future versions of the Software provided such versions remain available under these terms in +# addition to any other license(s) of the initial developer. +# +# Limitations of Liability +# +# In no event shall the initial developers or copyright holders be liable for any damages whatsoever, +# including - but not restricted to - lost revenue or profits or other direct, indirect, special, +# incidental or consequential damages, even if they have been advised of the possibility of such damages, +# except to the extent invariable law, if any, provides otherwise. +# +# No Warranty +# +# The Software and this license document are provided AS IS with NO WARRANTY OF ANY KIND, INCLUDING THE +# WARRANTY OF DESIGN, MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. +# +# URL: https://github.com/joeholden/distroscript/ +# README: https://raw.github.com/joeholden/distroscript/master/README.md + +# Shells are made of dicks. +DISTROSCRIPT="1.0.15" + +if [ -z ${DISTROFORMAT} ]; then + DISTROFORMAT="pipe" +fi + +if [ -n "${AGENT_LIBDIR}" -o -n "${MK_LIBDIR}" ]; then + # Set output for check_mk/observium agent + DISTROFORMAT="export" +fi + +getos() { + OS=`uname -s` + if [ "${OS}" = "SunOS" ]; then + OS="Solaris" + elif [ "${OS}" = "DragonFly" ]; then + OS="DragonFlyBSD" + fi + export OS + return 0 +} + +getkernel() { + KERNEL=`uname -r` + export KERNEL + return 0 +} + +getdistro() { + if [ "${OS}" = "Linux" ]; then + if [ -f /etc/os-release ]; then + . /etc/os-release + DISTRO=`echo ${NAME} | awk '{print $1}'` + elif [ -x /usr/bin/lsb_release ]; then + DISTRO=`/usr/bin/lsb_release -si 2>/dev/null` + elif [ -f /etc/redhat-release ]; then + DISTRO=`cat /etc/redhat-release | awk '{print $1}'` + elif [ -f /etc/fedora-release ]; then + DISTRO="Fedora" + elif [ -f /etc/mandriva-release ]; then + DISTRO="Mandriva" + elif [ -f /etc/arch-release ]; then + DISTRO="ArchLinux" + elif [ -f /etc/gentoo-release ]; then + DISTRO="Gentoo" + elif [ -f /etc/SuSE-release ]; then + DISTRO="SuSE" + elif [ -f /etc/mandrake-release ]; then + DISTRO="Mandrake" + elif [ -f /etc/debian_version ]; then + # shit based on debian + if [ -f /etc/mailcleaner/etc/mailcleaner/version.def ]; then + DISTRO="MailCleaner" + else + DISTRO="Debian" + fi + elif [ -f /etc/UnitedLinux-release ]; then + DISTRO="UnitedLinux" + elif [ -f /etc/openwrt_version ]; then + DISTRO="OpenWRT" + elif [ -f /etc/slackware-version ]; then + DISTRO="Slackware" + else + DISTRO="Unknown" + fi + + # Fixing some Distro names + if [ "${DISTRO}" = "Debian GNU/Linux" ]; then + DISTRO="Debian" + elif [ "${DISTRO}" = "Red" -o "${DISTRO}" = "RedHatEnterpriseServer" ]; then + DISTRO="RedHat" + elif [ "${DISTRO}" = "Arch" ]; then + DISTRO="ArchLinux" + fi + + elif [ "${OS}" = "FreeBSD" ]; then + if [ -f /etc/platform -a -f /etc/version ]; then + DISTRO="pfSense" + elif [ -f /etc/platform -a -f /etc/prd.name ]; then + DISTRO=`cat /etc/prd.name` + elif [ -f /usr/local/bin/pbreg ]; then + DISTRO="PC-BSD" + elif [ -f /tmp/freenas_config.md5 ]; then + DISTRO="FreeNAS" + else + DISTRO= + fi + elif [ "${OS}" = "Solaris" ]; then + DISTRO=`head -n 1 /etc/release | awk '{print $1}'` + if [ "${DISTRO}" = "Solaris" -o "${DISTRO}" = "Oracle" ]; then + DISTRO= + fi + elif [ "${OS}" = "Darwin" ]; then + case `uname -m` in + AppleTV2*) + DISTRO="AppleTV2" + ;; + AppleTV3*) + DISTRO="AppleTV3" + ;; + iPhone*) + DISTRO="iPhone" + ;; + iPod*) + DISTRO="iPOD" + ;; + *) + DISTRO="OSX" + ;; + esac + else + DISTRO= + fi + export DISTRO + return 0 +} + +getarch() { + if [ "${OS}" = "Solaris" ]; then + ARCH=`isainfo -k` + elif [ "${OS}" = "Darwin" ]; then + ARCH=`uname -p` + else + ARCH=`uname -m` + fi + if [ "${OS}" = "Linux" ]; then + if [ "${ARCH}" = "x86_64" ]; then + ARCH="amd64" + elif [ "${ARCH}" = "i486" -o "${ARCH}" = "i586" -o "${ARCH}" = "i686" ]; then + ARCH="i386" + fi + fi + export ARCH + return 0 +} + +getversion() { + if [ "${OS}" = "FreeBSD" -o "${OS}" = "DragonFlyBSD" ]; then + if [ "${DISTRO}" = "pfSense" ]; then + VERSION=`cat /etc/version` + elif [ "${DISTRO}" = "PC-BSD" ]; then + VERSION=`pbreg get /PC-BSD/Version` + elif [ -f /etc/prd.version ]; then + VERSION=`cat /etc/prd.version` + else + VERSION=`uname -i` + fi + elif [ "${OS}" = "OpenBSD" -o "${OS}" = "NetBSD" ]; then + VERSION=`uname -v` + elif [ "${OS}" = "Linux" ]; then + if [ "${DISTRO}" = "OpenWRT" ]; then + VERSION=`cat /etc/openwrt_version` + elif [ "${DISTRO}" = "Slackware" ]; then + VERSION=`cat /etc/slackware-version | cut -d" " -f2` + elif [ -f /etc/redhat-release ]; then + VERSION=`cat /etc/redhat-release | sed 's/.*release\ //' | sed 's/\ .*//'` + elif [ -x /usr/bin/lsb_release ]; then + VERSION=`lsb_release -sr 2>/dev/null` + elif [ -f /etc/os-release ]; then + . /etc/os-release + VERSION=${VERSION_ID} + else + VERSION= + fi + elif [ "${OS}" = "Darwin" ]; then + VERSION=`sw_vers -productVersion` + elif [ "${OS}" = "Solaris" ]; then + VERSION=`uname -v` + fi + export VERSION + return 0 +} + + +if [ -z ${DISTROEXEC} ]; then + getos + getkernel + getarch + getdistro + getversion + if [ "${AGENT_LIBDIR}" -o "${MK_LIBDIR}" ]; then + echo "<<>>" + fi + if [ "${DISTROFORMAT}" = "pipe" ]; then + echo "${OS}|${KERNEL}|${ARCH}|${DISTRO}|${VERSION}" + elif [ "${DISTROFORMAT}" = "twopipe" ]; then + echo "${OS}||${KERNEL}||${ARCH}||${DISTRO}||${VERSION}" + elif [ "${DISTROFORMAT}" = "ini" ]; then + echo "[distroscript]" + echo " OS = ${OS}" + echo " KERNEL = ${KERNEL}" + echo " ARCH = ${ARCH}" + echo " DISTRO = ${DISTRO}" + echo " DISTROVER = ${VERSION}" + echo " SCRIPTVER = ${DISTROSCRIPT}" + elif [ "${DISTROFORMAT}" = "export" ]; then + echo "OS=${OS}" + echo "KERNEL=${KERNEL}" + echo "ARCH=${ARCH}" + echo "DISTRO=${DISTRO}" + echo "DISTROVER=${VERSION}" + echo "SCRIPTVER=${DISTROSCRIPT}" + else + echo "Unsupported output format." + exit 1 + fi + exit 0 +fi diff --git a/slack/bin/slackInstall.sh b/slack/bin/slackInstall.sh new file mode 100755 index 0000000..9cd6e81 --- /dev/null +++ b/slack/bin/slackInstall.sh @@ -0,0 +1,60 @@ +#!/bin/bash +#A script to bootstrap slack onto any TURNSYS managed system in any environment. +#Use this as a template for writing TURNSYS shell scripts + +slack-install() +{ + +wget http://toolbox.turnsys.net/sysinfra/slack/bin/distro -O /usr/bin/distro +chmod +x /usr/bin/distro + +apt-get -y install make perl rsync + +mkdir /tmp/slackDist +wget http://toolbox.turnsys.net/sysinfra/slack/slackDist.tar.gz -O /tmp/slackDist/slackDist.tar.gz +cd /tmp/slackDist +tar xvfz slackDist.tar.gz +make install +cd /tmp +rm -rf slackDist + +mkdir /root/.ssh +chmod 700 /root/.ssh +chown -R root:root /root/.ssh + +wget http://toolbox.turnsys.net/sysinfra/slack/env/SlackConfig-$SERVER_TYPE.config -O /etc/slack.conf + +wget http://toolbox.turnsys.net/sysinfra/slack/env/SlackSSH-$SERVER_TYPE.config -O /root/.ssh/config +chmod 400 /root/.ssh/config + +wget http://toolbox.turnsys.net/sysinfra/slack/env/SlackSSH-$SERVER_TYPE.key -O /root/.ssh/SlackSSH-$SERVER_TYPE.key +chmod 400 /root/.ssh/SlackSSH-$SERVER_TYPE.key +} + + +####################################################################################################################################################### +#main() #For ease of searching +# Script starts here +# This code serves as a generic template for entrypoint code which is able to handle multi distro, multi environment execution. +# !!!!! DO NOT WRAP IN A FUNCTION. THESE ARE GLOBAL VARIABLES !!!!! +####################################################################################################################################################### + +#If we have a fleet later, we can use this code to do fleet stuff +#if [ $(hostname -s|egrep -i -c -E 'ts|ts[0-9]|ts[0-9][0-9]|ts[0-9][0-9][0-9]|linux') -eq 1 ]; then +#export server_type=ts +#fi + + +case $server_type in + ts) + export SERVER_TYPE="ts" + ;; + *) + export SERVER_TYPE="prod" + ;; +esac + +####################################################################################################################################################### +#Kick everything off +# +slack-install diff --git a/slack/dist/Makefile b/slack/dist/Makefile new file mode 100755 index 0000000..0f62449 --- /dev/null +++ b/slack/dist/Makefile @@ -0,0 +1,39 @@ +# Makefile for slack/src +# $Id: Makefile 187 2008-03-03 02:00:18Z alan $ +include Makefile.common + +BACKENDS = slack-getroles slack-installfiles slack-runscript slack-sync slack-stage slack-rolediff + +all: + +install: install-bin install-conf install-lib install-man + +install-bin: all + $(MKDIR) $(DESTDIR)$(sbindir) + $(INSTALL) slack $(DESTDIR)$(sbindir) + $(MKDIR) $(DESTDIR)$(bindir) + $(INSTALL) slack-diff $(DESTDIR)$(bindir) + $(MKDIR) $(DESTDIR)$(slack_libexecdir) + @set -ex;\ + for i in $(BACKENDS); do \ + $(INSTALL) $$i $(DESTDIR)$(slack_libexecdir); done + $(INSTALL) -d -m $(PRIVDIRMODE) $(DESTDIR)$(slack_localstatedir) + $(INSTALL) -d -m $(PRIVDIRMODE) $(DESTDIR)$(slack_localcachedir) + +install-conf: all + $(MKDIR) $(DESTDIR)$(sysconfdir) + $(INSTALL) -m 0644 slack.conf $(DESTDIR)$(sysconfdir) + +install-lib: all + $(MKDIR) $(DESTDIR)$(slack_libdir) + $(INSTALL) -m 0644 Slack.pm $(DESTDIR)$(slack_libdir) + +install-man: all + +clean: + +realclean: clean + +distclean: clean + +test: diff --git a/slack/dist/Makefile.common b/slack/dist/Makefile.common new file mode 100755 index 0000000..198f557 --- /dev/null +++ b/slack/dist/Makefile.common @@ -0,0 +1,27 @@ +# Common code included in every Makefile +# $Id: Makefile.common 189 2008-04-21 00:52:56Z sundell $ + +PACKAGE=slack +VERSION=0.15.2 + +DESTDIR = + +prefix = / +exec_prefix = /usr +sysconfdir = ${prefix}/etc +mandir = ${exec_prefix}/share/man +bindir = ${exec_prefix}/bin +sbindir = ${exec_prefix}/sbin +libdir = ${exec_prefix}/lib +libexecdir = ${exec_prefix}/lib +localstatedir = ${prefix}/var + +slack_libdir = ${libdir}/slack +slack_libexecdir = ${libexecdir}/slack +slack_localstatedir = ${localstatedir}/lib/slack +slack_localcachedir = ${localstatedir}/cache/slack + +INSTALL = install +MKDIR = mkdir -p + +PRIVDIRMODE = 0700 diff --git a/slack/dist/Slack.pm b/slack/dist/Slack.pm new file mode 100755 index 0000000..9f0a57d --- /dev/null +++ b/slack/dist/Slack.pm @@ -0,0 +1,371 @@ +# $Id: Slack.pm 189 2008-04-21 00:52:56Z sundell $ +# vim:sw=2 +# vim600:fdm=marker +# Copyright (C) 2004-2008 Alan Sundell +# All Rights Reserved. This program comes with ABSOLUTELY NO WARRANTY. +# See the file COPYING for details. + +package Slack; + +require 5.006; +use strict; +use Carp qw(cluck confess croak); +use File::Find; +use POSIX qw(WIFEXITED WEXITSTATUS WIFSIGNALED WTERMSIG); + +use base qw(Exporter); +use vars qw($VERSION @EXPORT @EXPORT_OK $DEFAULT_CONFIG_FILE); +$VERSION = '0.15.2'; +@EXPORT = qw(); +@EXPORT_OK = qw(); + +$DEFAULT_CONFIG_FILE = '/etc/slack.conf'; + +my $term; + +my @default_options = ( + 'help|h|?', + 'version', + 'verbose|v+', + 'quiet', + 'config|C=s', + 'source|s=s', + 'rsh|e=s', + 'cache|c=s', + 'stage|t=s', + 'root|r=s', + 'dry-run|n', + 'backup|b', + 'backup-dir=s', + 'hostname|H=s', +); + +sub default_usage ($) { + my ($synopsis) = @_; + return < config file to read +# opthash => hashref in which to store the options +# verbose => whether to be verbose +sub read_config (%) { + my %arg = @_; + my ($config_fh); + local $_; + + confess "Slack::read_config: no config file given" + if not defined $arg{file}; + $arg{opthash} = {} + if not defined $arg{opthash}; + + open($config_fh, '<', $arg{file}) + or confess "Could not open config file '$arg{file}': $!"; + + # Make this into a hash so we can quickly see if we're looking + # for a particular option + my %looking_for; + if (ref $arg{options} eq 'ARRAY') { + %looking_for = map { $_ => 1 } @{$arg{options}}; + } + + while(<$config_fh>) { + chomp; + s/#.*//; # delete comments + s/\s+$//; # delete trailing spaces + next if m/^$/; # skip empty lines + + if (m/^[A-Z_]+=\S+/) { + my ($key, $value) = split(/=/, $_, 2); + $key =~ tr/A-Z_/a-z-/; + # Only set options we're looking for + next if (%looking_for and not $looking_for{$key}); + # Don't set options that are already set + next if defined $arg{opthash}->{$key}; + + $arg{verbose} and print STDERR "Slack::read_config: Setting '$key' to '$value'\n"; + $arg{opthash}->{$key} = $value; + } else { + cluck "Slack::read_config: Garbage line '$_' in '$arg{file}' line $. ignored"; + } + } + + close($config_fh) + or confess "Slack::read_config: Could not close config file: $!"; + + # The verbose option is treated specially in so many places that + # we need to make sure it's defined. + $arg{opthash}->{verbose} ||= 0; + + return $arg{opthash}; +} + +# Just get the exit code from a command that failed. +# croaks if anything weird happened. +sub get_system_exit (@) { + my @command = @_; + + if (WIFEXITED($?)) { + my $exit = WEXITSTATUS($?); + return $exit if $exit; + } + if (WIFSIGNALED($?)) { + my $sig = WTERMSIG($?); + croak "'@command' caught sig $sig"; + } + if ($!) { + croak "Syserr on system '@command': $!"; + } + croak "Unknown error on '@command'"; +} + +sub check_system_exit (@) { + my @command = @_; + my $exit = get_system_exit(@command); + # Exit is non-zero if get_system_exit() didn't croak. + croak "'@command' exited $exit"; +} + +# get options from the command line and the config file +# Arguments +# opthash => hashref in which to store options +# usage => usage statement +# required_options => arrayref of options to require -- an exception +# will be thrown if these options are not defined +# command_line_hash => store options specified on the command line here +sub get_options { + my %arg = @_; + use Getopt::Long; + Getopt::Long::Configure('bundling'); + + if (not defined $arg{opthash}) { + $arg{opthash} = {}; + } + + if (not defined $arg{usage}) { + $arg{usage} = default_usage($0); + } + + my @extra_options = (); # extra arguments to getoptions + if (defined $arg{command_line_options}) { + @extra_options = @{$arg{command_line_options}}; + } + + # Make a --quiet function that turns off verbosity + $arg{opthash}->{quiet} = sub { $arg{opthash}->{verbose} = 0; }; + + unless (GetOptions($arg{opthash}, + @default_options, + @extra_options, + )) { + print STDERR $arg{usage}; + exit 1; + } + if ($arg{opthash}->{help}) { + print $arg{usage}; + exit 0; + } + + if ($arg{opthash}->{version}) { + print "slack version $VERSION\n"; + exit 0; + } + + # Get rid of the quiet handler + delete $arg{opthash}->{quiet}; + + # If we've been given a hashref, save our options there at this + # stage, so the caller can see what was passed on the command line. + # Unfortunately, perl has no .replace function, so we iterate. + if (ref $arg{command_line_hash} eq 'HASH') { + while (my ($k, $v) = each %{$arg{opthash}}) { + $arg{command_line_hash}->{$k} = $v; + } + } + + # Use the default config file + if (not defined $arg{opthash}->{config}) { + $arg{opthash}->{config} = $DEFAULT_CONFIG_FILE; + } + + # We need to decide whether to be verbose about reading the config file + # Currently we just do it if global verbosity > 2 + my $verbose_config = 0; + if (defined $arg{opthash}->{verbose} + and $arg{opthash}->{verbose} > 2) { + $verbose_config = 1; + } + + # Read options from the config file, passing along the options we've + # gotten so far + read_config( + file => $arg{opthash}->{config}, + opthash => $arg{opthash}, + verbose => $verbose_config, + ); + + # The "verbose" option gets compared a lot and needs to be defined + $arg{opthash}->{verbose} ||= 0; + + # The "hostname" option is set specially if it's not defined + if (not defined $arg{opthash}->{hostname}) { + use Sys::Hostname; + $arg{opthash}->{hostname} = hostname; + } + + # We can require some options to be set + if (ref $arg{required_options} eq 'ARRAY') { + for my $option (@{$arg{required_options}}) { + if (not defined $arg{opthash}->{$option}) { + croak "Required option '$option' not given on command line or specified in config file!\n"; + } + } + } + + return $arg{opthash}; +} + +sub prompt ($) { + my ($prompt) = @_; + if (not defined $term) { + require Term::ReadLine; + $term = new Term::ReadLine 'slack' + } + + $term->readline($prompt); +} + + +# Calls the callback on absolute pathnames of files in the source directory, +# and also on names of directories that don't exist in the destination +# directory (i.e. where $source/foo exists but $destination/foo does not). +sub find_files_to_install ($$$) { + my ($source, $destination, $callback) = @_; + return find ({ + wanted => sub { + if (-l or not -d _) { + # Copy all files, links, etc + my $file = $File::Find::name; + &$callback($file); + } elsif (-d _) { + # For directories, we only want to copy it if it doesn't + # exist in the destination yet. + my $dir = $File::Find::name; + # We know the root directory will exist (we make it above), + # so skip the base of the source + (my $short_source = $source) =~ s#/$##; + return if $dir eq $short_source; + + # Strip the $source from the path, + # so we can build the destination dir from it. + my $subdir = $dir; + ($subdir =~ s#^$source##) + or croak "sub failed: $source|$subdir"; + + if (not -d "$destination/$subdir") { + &$callback($dir); + } + } + } + }, + $source, + ); +} + +# Runs rsync with the necessary redirection to its filehandles +sub wrap_rsync (@) { + my @command = @_; + my ($pid); + + if ($pid = fork) { + # Parent + } elsif (defined $pid) { + # Child + open(STDIN, "<", "/dev/null") + or die "Could not redirect STDIN from /dev/null\n"; + # This redirection is necessary because rsync sends + # verbose output to STDOUT + open(STDOUT, ">&STDERR") + or die "Could not redirect STDOUT to STDERR\n"; + exec(@command); + die "Could not exec '@command': $!\n"; + } else { + die "Could not fork: $!\n"; + } + + my $kid = waitpid($pid, 0); + if ($kid != $pid) { + die "waitpid returned $kid\n"; + } elsif ($?) { + Slack::check_system_exit(@command); + } +} + +# Runs rsync with the necessary redirection to its filehandles, but also +# returns an FH to stdin and a PID. +sub wrap_rsync_fh (@) { + my @command = @_; + my ($fh, $pid); + + if ($pid = open($fh, "|-")) { + # Parent + } elsif (defined $pid) { + # Child + # This redirection is necessary because rsync sends + # verbose output to STDOUT + open(STDOUT, ">&STDERR") + or die "Could not redirect STDOUT to STDERR\n"; + exec(@command); + die "Could not exec '@command': $!\n"; + } else { + die "Could not fork: $!\n"; + } + return($fh, $pid); +} + +1; diff --git a/slack/dist/slack b/slack/dist/slack new file mode 100755 index 0000000..d8e9fbb --- /dev/null +++ b/slack/dist/slack @@ -0,0 +1,329 @@ +#!/usr/bin/perl -w +# $Id: slack 180 2008-01-19 08:26:19Z alan $ +# vim:sw=2 +# vim600:fdm=marker +# Copyright (C) 2004-2008 Alan Sundell +# All Rights Reserved. This program comes with ABSOLUTELY NO WARRANTY. +# See the file COPYING for details. + +# This script is in charge of copying files from the (possibly remote) +# master directory to a local cache, using rsync + +require 5.006; +use warnings FATAL => qw(all); +use strict; +use sigtrap qw(die untrapped normal-signals + stack-trace any error-signals); + +use File::Path; +use File::Find; +use POSIX; # for strftime + +use constant LIBEXEC_DIR => '/usr/lib/slack'; +use constant LIB_DIR => '/usr/lib/slack'; +use lib LIB_DIR; +use Slack; + +sub run_backend(@); +sub run_conditional_backend($@); + +(my $PROG = $0) =~ s#.*/##; + +# Arguments to pass to each backends (initialized to a hash of empty arrays) +my %backend_flags = ( map { $_ => [] } + qw(getroles sync stage preview preinstall fixfiles installfiles postinstall) +); + +my @roles; + +######################################## +# Environment +# Helpful prefix to die messages +$SIG{__DIE__} = sub { die "FATAL[$PROG]: @_"; }; +# Set a reasonable umask +umask 077; +# Get out of wherever (possibly NFS-mounted) we were +chdir("/") + or die "Could not chdir /: $!"; +# Autoflush on STDERR +select((select(STDERR), $|=1)[0]); + +######################################## +# Config and option parsing {{{ +my $usage = Slack::default_usage("$PROG [options] [...]"); +$usage .= < \%opt, + command_line_options => [ + 'preview=s', + 'role-list=s', + 'no-scripts|noscripts', + 'no-files|nofiles', + 'no-sync|nosync', + 'libexec-dir=s', + 'diff=s', + 'sleep=i', + ], + required_options => [ qw(source cache stage root) ], + command_line_hash => \%command_line_opt, + usage => $usage, +); + +# Special options +if ($opt{'dry-run'}) { + $opt{'no-scripts'} = 1; + $opt{'no-files'} = 1; +} +if ($opt{'no-scripts'}) { + for my $action (qw(fixfiles preinstall postinstall)) { + push @{$backend_flags{$action}}, + '--dry-run'; + } +} +if ($opt{'no-files'}) { + push @{$backend_flags{installfiles}}, + '--dry-run'; +} +# propagate verbosity - 1 to all backends +if (defined $command_line_opt{'verbose'} and + $command_line_opt{'verbose'} > 1) { + for my $action (keys %backend_flags) { + push @{$backend_flags{$action}}, + ('--verbose') x ($command_line_opt{'verbose'} - 1); + } +} +# propagate these flags to all the backends +for my $option (qw(config root cache stage source hostname rsh)) { + if ($command_line_opt{$option}) { + for my $action (keys %backend_flags) { + push @{$backend_flags{$action}}, + "--$option=$command_line_opt{$option}"; + } + } +} +# getroles also can take 'role-list' +if ($command_line_opt{'role-list'}) { + push @{$backend_flags{'getroles'}}, + "--role-list=$command_line_opt{'role-list'}"; +} + +# The libexec dir defaults to this if it wasn't specified +# on the command line or in a config file. +if (not defined $opt{'libexec-dir'}) { + $opt{'libexec-dir'} = LIBEXEC_DIR; +} + +# Pass diff option along to slack-rolediff +if ($opt{'diff'}) { + push @{$backend_flags{preview}}, + "--diff=$opt{'diff'}"; +} + +# Preview takes an optional argument. If no argument is given, +# it gets "" from getopt. +if (defined $opt{'preview'}) { + if (not grep /^$opt{'preview'}$/, qw(simple prompt)) { + die "Unknown preview mode '$opt{'preview'}'!"; + } +} + +# The backup option defaults to on if it wasn't specified +# on the command line or in a config file +if (not defined $opt{backup}) { + $opt{backup} = 1; +} +# Figure out a place to put backups +if ($opt{backup} and $opt{'backup-dir'}) { + push @{$backend_flags{installfiles}}, + '--backup', + '--backup-dir='. + $opt{'backup-dir'}. + "/". + strftime('%F-%T', localtime(time)) + ; +} +# }}} + +# Random sleep, helpful when called from cron. +if ($opt{sleep}) { + my $secs = int(rand($opt{sleep})) + 1; + $opt{verbose} and print STDERR "$PROG: sleep $secs\n"; + sleep($secs); +} + +# Get a list of roles to install from slack-getroles {{{ +if (not @ARGV) { + my @command = ($opt{'libexec-dir'}.'/slack-getroles', + @{$backend_flags{'getroles'}}); + $opt{verbose} and print STDERR "$PROG: getroles\n"; + ($opt{verbose} > 2) and print STDERR "$PROG: Calling '@command' to get a list of roles for this host.\n"; + my ($roles_pid, $roles_fh); + if ($roles_pid = open($roles_fh, "-|")) { + # Parent + } elsif (defined $roles_pid) { + # Child + exec(@command); + die "Could not exec '@command': $!\n"; + } else { + die "Could not fork to run '@command': $!\n"; + } + @roles = split(/\s+/, join(" ", <$roles_fh>)); + unless (close($roles_fh)) { + Slack::check_system_exit(@command); + } +} else { + @roles = @ARGV; +} +# }}} + +# Check role name syntax {{{ +for my $role (@roles) { + # Roles MUST begin with a letter. All else is reserved. + if ($role !~ m/^[a-zA-Z]/) { + die "Role '$role' does not begin with a letter!"; + } +} +# }}} + +$opt{verbose} and print STDERR "$PROG: installing roles: @roles\n"; + +unless ($opt{'no-sync'}) { + # sync all the roles down at once + $opt{verbose} and print STDERR "$PROG: sync @roles\n"; + run_backend('slack-sync', + @{$backend_flags{sync}}, @roles); +} + +ROLE: for my $role (@roles) { + # stage + $opt{verbose} and print STDERR "$PROG: stage files $role\n"; + run_backend('slack-stage', + @{$backend_flags{stage}}, '--subdir=files', $role); + + if ($opt{preview}) { + if ($opt{preview} eq 'simple') { + $opt{verbose} and print STDERR "$PROG: preview $role\n"; + # Here, we run the backend in no-prompt mode. + run_conditional_backend(0, 'slack-rolediff', + @{$backend_flags{preview}}, $role); + # ...and we skip further action in the ROLE after showing the diff. + next ROLE; + } elsif ($opt{preview} eq 'prompt') { + $opt{verbose} and print STDERR "$PROG: preview scripts $role\n"; + # Here, we want to prompt and just do the scripts, since + # we need to run preinstall and fixfiles before doing the files. + run_conditional_backend(1, 'slack-rolediff', + @{$backend_flags{preview}}, '--subdir=scripts', $role); + } else { + # Should get caught in option processing, above + die "Unknown preview mode!\n"; + } + } + + $opt{verbose} and print STDERR "$PROG: stage scripts $role\n"; + run_backend('slack-stage', + @{$backend_flags{stage}}, '--subdir=scripts', $role); + + # preinstall + $opt{verbose} and print STDERR "$PROG: preinstall $role\n"; + run_backend('slack-runscript', + @{$backend_flags{preinstall}}, 'preinstall', $role); + + # fixfiles + $opt{verbose} and print STDERR "$PROG: fixfiles $role\n"; + run_backend('slack-runscript', + @{$backend_flags{fixfiles}}, 'fixfiles', $role); + + # preview files + if ($opt{preview} and $opt{preview} eq 'prompt') { + $opt{verbose} and print STDERR "$PROG: preview files $role\n"; + run_conditional_backend(1, 'slack-rolediff', + @{$backend_flags{preview}}, '--subdir=files', $role); + } + + # installfiles + $opt{verbose} and print STDERR "$PROG: install $role\n"; + run_backend('slack-installfiles', + @{$backend_flags{installfiles}}, $role); + + # postinstall + $opt{verbose} and print STDERR "$PROG: postinstall $role\n"; + run_backend('slack-runscript', + @{$backend_flags{postinstall}}, 'postinstall', $role); +} +exit 0; + +sub run_backend (@) { + my ($backend, @args) = @_; + # If we weren't given an explicit path, prepend the libexec dir + unless ($backend =~ m#^/#) { + $backend = $opt{'libexec-dir'} . '/' . $backend; + } + + # Assemble our command line + my (@command) = ($backend, @args); + ($opt{verbose} > 2) and print STDERR "$PROG: Calling '@command'\n"; + unless (system(@command) == 0) { + Slack::check_system_exit(@command); + } +} + +sub run_conditional_backend ($@) { + my ($prompt, $backend, @args) = @_; + # If we weren't given an explicit path, prepend the libexec dir + unless ($backend =~ m#^/#) { + $backend = $opt{'libexec-dir'} . '/' . $backend; + } + + # Assemble our command line + my (@command) = ($backend, @args); + ($opt{verbose} > 2) and print STDERR "$PROG: Calling '@command'\n"; + unless (system(@command) == 0) { + my $exit = Slack::get_system_exit(@command); + + if ($exit == 1) { + # exit 1 means a difference found or something normal that requires + # a prompt before continuing. + if ($prompt) { + exit 1 unless Slack::prompt("Continue? [yN] ") eq 'y'; + } + } else { + # any other non-successful exit is a serious error. + die "'@command' exited $exit"; + } + } +} diff --git a/slack/dist/slack-diff b/slack/dist/slack-diff new file mode 100755 index 0000000..dde4f16 --- /dev/null +++ b/slack/dist/slack-diff @@ -0,0 +1,514 @@ +#!/usr/bin/perl -w +# $Id: slack-diff 122 2006-09-27 07:34:32Z alan $ +# vim:sw=2 +# vim600:fdm=marker +# Copyright (C) 2004-2006 Alan Sundell +# All Rights Reserved. This program comes with ABSOLUTELY NO WARRANTY. +# See the file COPYING for details. +# +# This script is a wrapper for diff that gives output about special files +# and file modes. (diff can only compare regular files) + +require 5.006; +use warnings FATAL => qw(all); +use strict; +use sigtrap qw(die untrapped normal-signals + stack-trace any error-signals); + +use Errno; +use File::stat; +use File::Basename; +use File::Find; +use Getopt::Long; +use POSIX qw(SIGPIPE strftime); +use Fcntl qw(:mode); # provides things like S_IFMT that POSIX does not + + +my $VERSION = '0.1'; +(my $PROG = $0) =~ s#.*/##; +my @diff; # diff program to use +my $exit = 0; # our exit code + +sub compare ($$); +sub recursive_compare ($$); +sub filetype_to_string ($;$); +sub compare_files ($$); +sub diff ($$); + +######################################## +# Environment +# Helpful prefix to die messages +$SIG{__DIE__} = sub { die "FATAL[$PROG]: @_"; }; +# Set a reasonable umask +umask 077; +# Autoflush on STDOUT +$|=1; +# Autoflush on STDERR +select((select(STDERR), $|=1)[0]); + +# Default options +my %opt = ( + fakediff => 1, + perms => 1, + 'new-file' => 1, + diff => 'diff', +); + +# Config and option parsing +my $usage = < + $PROG -r + +Options: + -u, -U NUM, --unified=NUM + Tell diff to use unified output format. + --diff PROG + Use this program for diffing, instead of "$opt{diff}" + --fakediff + Make a fake diff for file modes and other things that are not file + contents. Default is on, can be disabled with --nofakediff. + --perms + Care about owner, group, and permissions when doing fakediff. + Default is on, can be disabled with --noperms. + -r, --recursive + Recursively compare directories. + -N, --new-file + Treat missing files as empty. Default is on, can be disabled with + --nonew-file. + --unidirectional-new-file + Treat only missing files in the first directory as empty. + --from-file + Treat arguments as a list of files from which to read filenames to + compare, two lines at a time. + -0, --null + Use NULLs instead of newlines as the separator in --from-file mode + --devnullhack + You have a version of diff that can't deal with -N when not in + recursive mode, so we need to feed it /dev/null instead of the + missing file. Default is on, can be disabled with --nodevnullhack. + --version + Output version info + --help + Output this help text + +Exit codes: + 0 Found no differences + 1 Found a difference + 2 Had a serious error + 3 Found a difference and had a serious error +EOF + +{ + Getopt::Long::Configure ("bundling"); + GetOptions(\%opt, + 'help|h|?', + 'version', + 'null|0', + 'devnullhack', + 'new-file|N', + 'u', + 'unified|U=i', + 'recursive|r', + 'from-file', + 'unidirectional-new-file', + 'fakediff!', + 'perms!', + 'diff=s', + ) or die $usage; + if ($opt{help}) { + print $usage; + exit 0; + } + if ($opt{version}) { + print "$PROG version $VERSION\n"; + exit 0; + } +} + +if ($opt{diff}) { + # We split on spaces here to be useful -- so that people can give + # their diff options. + @diff = split(/\s+/, $opt{diff}); +} else { + die "$PROG: No diff program!\n"; +} + +if ($opt{'u'}) { + push @diff, '-u'; +} elsif ($opt{'unified'}) { + $opt{'u'} = 1; # We use this value later + push @diff, "--unified=$opt{'unified'}"; +} + +if (not $opt{'devnullhack'}) { + push @diff, '-N'; +} + +# usually, sigpipe would be someone quitting their pager, so don't sweat it +$SIG{PIPE} = sub { exit $exit }; + +if ($opt{'from-file'}) { + local $/ = "\0" if $opt{'null'}; + while (my $old = <>) { + my $new = <>; + die "Uneven number of lines in --from-file mode!\n" + if not defined $new; + chomp($old); + chomp($new); + $exit |= compare($old, $new); + } +} else { + die $usage unless $#ARGV == 1; + $exit |= compare($ARGV[0], $ARGV[1]); +} +exit $exit; + +## +# Subroutines + +sub compare ($$) { + my ($old, $new) = @_; + + if ($opt{recursive}) { + return recursive_compare($old, $new); + } else { + return compare_files($old, $new); + } +} + +# compare two directories. We do this by walking down the *new* +# directory, and comparing everything that's there to the stuff in +# the old directory +sub recursive_compare ($$) { + my ($olddir, $newdir) = @_; + my ($retval, $basere, $wanted); + my (%seen); + + $retval = 0; + + if (-d $newdir) { + $basere = qr(^$newdir); + $wanted = sub { + my ($newfile) = $_; + my $oldfile = $newfile; + + $oldfile =~ s#$basere#$olddir#; + $seen{$oldfile} = 1; + $retval |= compare_files($oldfile, $newfile); + }; + + eval { find({ wanted => $wanted , no_chdir => 1}, $newdir) }; + if ($@) { + warn "$PROG: error during find: $@\n"; + $retval |= 2; + } + } + return $retval + if $opt{'unidirectional-new-file'}; + + # If we're not unidirectional, we want to go through the old directory + # and diff any files we didn't see in the newdir. + if (-d $olddir) { + $basere = qr(^$olddir); + $wanted = sub { + my ($oldfile) = $_; + my $newfile; + + return if $seen{$oldfile}; + $newfile = $oldfile; + + $newfile =~ s#$basere#$newdir#; + $retval |= compare_files($oldfile, $newfile); + }; + + eval { find({ wanted => $wanted , no_chdir => 1}, $olddir) }; + if ($@) { + warn "$PROG: error during find: $@\n"; + $retval |= 2; + } + } + return $retval; +} + +# filetype_to_string(mode) +# filetype_to_string(mode, plural) +# +# Takes a mode returned from stat(), returns a noune describing the filetype, +# e.g. "directory", "symlink". +# If the "plural" argument is provided and true, returns the plural form of +# the noun, e.g. "directories", "symlinks". +sub filetype_to_string ($;$) { + my ($mode, $plural) = @_; + + if (S_ISREG($mode)) { + return "regular file".($plural ? "s" : ""); + } elsif (S_ISDIR($mode)) { + return "director".($plural ? "ies" : "y"); + } elsif (S_ISLNK($mode)) { + return "symlink".($plural ? "s" : ""); + } elsif (S_ISBLK($mode)) { + return "block device".($plural ? "s" : ""); + } elsif (S_ISCHR($mode)) { + return "character device".($plural ? "s" : ""); + } elsif (S_ISFIFO($mode)) { + return "fifo".($plural ? "s" : ""); + } elsif (S_ISSOCK($mode)) { + return "socket".($plural ? "s" : ""); + } else { + return "unknown filetype".($plural ? "s" : ""); + } +} + +# compare_files(oldfile, newfile) +# This is the actual diffing routine. It's quite long because we need to +# deal with all sorts of special cases. It will print to STDOUT a +# description of the differences between the two files. For regular files, +# diff(1) will be run to show the differences. +# +# return codes: +# 1 found a difference +# 2 had an error +# 3 found a difference and had an error +sub compare_files ($$) { + my ($oldname, $newname) = @_; + my ($old, $new); # stat buffers + my $return = 0; + + # Get rid of unsightly double slashes + $oldname =~ s#//#/#g; + $newname =~ s#//#/#g; + + eval { $old = lstat($oldname); }; + if (not defined $old and not $!{ENOENT}) { + warn "$PROG: Could not stat $oldname: $!\n"; + return 2; + } + eval { $new = lstat($newname); }; + if (not defined $new and not $!{ENOENT}) { + warn "$PROG: Could not stat $newname: $!\n"; + return 2; + } + # At this point, $old or $new should only be undefined if the + # file does not exist. + + if (defined $old and defined $new) { + if (S_IFMT($old->mode) != S_IFMT($new->mode)) { + if ($opt{fakediff}) { + fakediff('filetype', + $oldname => filetype_to_string($old->mode), + $newname => filetype_to_string($new->mode), + ); + } else { + print "File types differ between ". + filetype_to_string($old->mode)." $oldname and ". + filetype_to_string($new->mode)." $newname\n"; + } + return 1; + } + if ($old->nlink != $new->nlink) { + # In recursive mode, we don't care about link counts in directories, + # as we'll pick that up with what files do and don't exist. + unless ($opt{recursive} and S_ISDIR($old->mode)) { + if ($opt{fakediff}) { + fakediff('nlink', + $oldname => $old->nlink, + $newname => $new->nlink, + ); + } else { + print "Link counts differ between ". + filetype_to_string($old->mode, 1). + " $oldname and $newname\n"; + } + $return = 1; + } + } + if ($old->uid != $new->uid and $opt{perms}) { + if ($opt{fakediff}) { + fakediff('uid', + $oldname => $old->uid, + $newname => $new->uid, + ); + } else { + print "Owner differs between ". + filetype_to_string($old->mode, 1). + " $oldname and $newname\n"; + } + $return = 1; + } + if ($old->gid != $new->gid and $opt{perms}) { + if ($opt{fakediff}) { + fakediff('gid', + $oldname => $old->gid, + $newname => $new->gid, + ); + } else { + print "Group differs between ". + filetype_to_string($old->mode, 1). + " $oldname and $newname\n"; + } + $return = 1; + } + if (S_IMODE($old->mode) != S_IMODE($new->mode) and $opt{perms}) { + if ($opt{fakediff}) { + fakediff('mode', + $oldname => sprintf('%04o', S_IMODE($old->mode)), + $newname => sprintf('%04o', S_IMODE($new->mode)), + ); + } else { + print "Modes differ between ". + filetype_to_string($old->mode, 1). + " $oldname and $newname\n"; + } + $return = 1; + } + + # We don't want to compare anything more about sockets, fifos, or + # directories, once we've checked the permissions and link counts + if (S_ISSOCK($old->mode) or + S_ISFIFO($old->mode) or + S_ISDIR($old->mode)) { + return $return; + } + + # Check device file devs, and that's it for them + if (S_ISCHR($old->mode) or + S_ISBLK($old->mode)) { + if ($old->rdev != $new->rdev) { + if ($opt{fakediff}) { + fakediff('rdev', + $oldname => $old->rdev, + $newname => $new->rdev, + ); + } else { + print "Device numbers differ between ". + filetype_to_string($old->mode, 1). + " $oldname and $newname\n"; + } + $return = 1; + } + return $return; + } + + # Compare the targets of symlinks + if (S_ISLNK($old->mode)) { + my $oldtarget = readlink $oldname + or (warn("$PROG: Could not readlink($oldname): $!\n"), + return $return | 2); + my $newtarget = readlink $newname + or (warn("$PROG: Could not readlink($newname): $!\n"), + return $return | 2); + if ($oldtarget ne $newtarget) { + if ($opt{fakediff}) { + fakediff('target', + $oldname => $oldtarget, + $newname => $newtarget, + ); + } else { + print "Symlink targets differ between $oldname and $newname\n"; + } + $return = 1; + } + return $return; + } + + if (not S_ISREG($old->mode)) { + warn "$PROG: Don't know what to do with file mode $old->mode!\n"; + return 2; + } + } elsif (not defined $old and not defined $new) { + print "Neither $oldname nor $newname exists\n"; + return $return; + } elsif (not defined $old) { + if (not S_ISREG($new->mode) or not $opt{'new-file'}) { + print "Only in ".dirname($newname).": ". + filetype_to_string($new->mode)." ".basename($newname)."\n"; + return 1; + } elsif ($opt{'devnullhack'}) { + $oldname = '/dev/null'; + } + } elsif (not defined $new) { + if (not S_ISREG($old->mode) or not $opt{'new-file'}) { + print "Only in ".dirname($oldname).": ". + filetype_to_string($old->mode)." ".basename($oldname)."\n"; + return 1; + } elsif ($opt{'devnullhack'}) { + $newname = '/dev/null'; + } + } + # They are regular files! We can actually run diff! + return diff($oldname, $newname) | $return; +} + +sub diff ($$) { + my ($oldname, $newname) = @_; + my @command = (@diff, $oldname, $newname); + my $status; + + # If we're not specifying unified diff, we need to print a header + # to indicate what's being diffed. (I'm not sure if this actually would + # work for patch, but it does tell our user what's going on). + # FIXME: We only need to specify this if the files are different + print "@command\n" + if not $opt{u}; + + { + # There is a bug in perl with use warnings FATAL => qw(all) + # that will cause the child process from system() to stick + # around if there is a warning generated. + # Shut off warnings -- we'll catch the error below. + no warnings; + $status = system(@command); + } + return 0 if ($status == 0); + if ($? == -1) { + die "$PROG: failed to execute '@command': $!\n"; + } + if ($? & 128) { + die "$PROG: '@command' dumped core\n"; + } + if (my $sig = $? & 127) { + die "$PROG: '@command' caught sig $sig\n" + unless ($sig == SIGPIPE); + } + if (my $exit = $? >> 8) { + if ($exit == 1) { + return 1; + } else { + die "$PROG: '@command' returned $exit\n"; + } + } + return 0; +} + + +sub fakediff ($$) { + my ($type, $oldname, $oldvalue, $newname, $newvalue) = @_; + + return unless $opt{fakediff}; + my $time = strftime('%F %T.000000000 %z', localtime(0)); + + # We add a suffix onto the filenames to show we're not actually looking + # at file contents. There's no good way to indicate this that's compatible + # with patch, and this is simple enough. + $oldname .= '#~~' . $type; + $newname .= '#~~' . $type; + + if ($opt{u}) { + # fake up a unified diff + print < $newvalue +EOF + } +} diff --git a/slack/dist/slack-getroles b/slack/dist/slack-getroles new file mode 100755 index 0000000..77eba20 --- /dev/null +++ b/slack/dist/slack-getroles @@ -0,0 +1,161 @@ +#!/usr/bin/perl -w +# $Id: slack-getroles 180 2008-01-19 08:26:19Z alan $ +# vim:sw=2 +# vim600:fdm=marker +# Copyright (C) 2004-2008 Alan Sundell +# All Rights Reserved. This program comes with ABSOLUTELY NO WARRANTY. +# See the file COPYING for details. + +# This script is in charge of copying files from the (possibly remote) +# master directory to a local cache, using rsync + +require 5.006; +use warnings FATAL => qw(all); +use strict; +use sigtrap qw(die untrapped normal-signals + stack-trace any error-signals); + +use File::Path; + +use constant LIB_DIR => '/usr/lib/slack'; +use lib LIB_DIR; +use Slack; + +my @rsync = ('rsync', + '--links', + '--times', + ); + +(my $PROG = $0) =~ s#.*/##; + +sub sync_list (); + +######################################## +# Environment +# Helpful prefix to die messages +$SIG{__DIE__} = sub { die "FATAL[$PROG]: @_"; }; +# Set a reasonable umask +umask 077; +# Get out of wherever (possibly NFS-mounted) we were +chdir("/") + or die "Could not chdir /: $!"; +# Autoflush on STDERR +select((select(STDERR), $|=1)[0]); + +######################################## +# Config and option parsing {{{ +my $usage = Slack::default_usage("$PROG [options]"); +$usage .= < \%opt, + command_line_options => [ + 'role-list=s', + 'remote-role-list', + ], + required_options => [ qw(role-list hostname) ], + usage => $usage, +); + +# Prepare for backups +if ($opt{backup} and $opt{'backup-dir'}) { + # Make sure backup directory exists + unless (-d $opt{'backup-dir'}) { + ($opt{verbose} > 0) and print STDERR "Creating backup directory '$opt{'backup-dir'}'\n"; + if (not $opt{'dry-run'}) { + eval { mkpath($opt{'backup-dir'}); }; + die "Could not mkpath backup dir '$opt{'backup-dir'}': $@\n" if $@; + } + } + push(@rsync, "--backup", "--backup-dir=$opt{'backup-dir'}"); +} +# Pass options along to rsync +if ($opt{'dry-run'}) { + push @rsync, '--dry-run'; +} +# Pass options along to rsync +if ($opt{'verbose'} > 1) { + push @rsync, '--verbose'; +} +# }}} + +# See if role-list is actually relative to source, and pre-pend source +# if need be. +unless ($opt{'role-list'} =~ m#^/# or + $opt{'role-list'} =~ m#^\./# or + $opt{'role-list'} =~ m#^[\w@\.-]+:#) { + if (not defined $opt{source}) { + die "Relative path to role-list given, but source not defined!\n\n$usage\n"; + } + $opt{'role-list'} = $opt{source} . '/' . $opt{'role-list'}; +} + +# auto-detect remote role list +if ($opt{'role-list'} =~ m#^[\w@\.-]+:#) { + $opt{'remote-role-list'} = 1; +} + +# Copy a remote list locally +if ($opt{'remote-role-list'}) { + # We need a cache directory if the role list is not local + if (not defined $opt{cache}) { + die "Remote path to role-list given, but cache not defined!\n\n$usage\n"; + } + # Look at source type, and add options if necessary + if ($opt{'rsh'} or $opt{'role-list'} =~ m/^[\w@\.-]+::/) { + # This is tunnelled rsync, and so needs an extra option + if ($opt{'rsh'}) { + push @rsync, '-e', $opt{'rsh'}; + } else { + push @rsync, '-e', 'ssh'; + } + } + sync_list(); +} + +# Read in the roles list +my @roles = (); +my $host_found = 0; +($opt{verbose} > 0) and print STDERR "$PROG: Reading '$opt{'role-list'}'\n"; +open(ROLES, "<", $opt{'role-list'}) + or die "Could not open '$opt{'role-list'}' for reading: $!\n"; +while() { + s/#.*//; # Strip comments + chomp; + if (s/^$opt{hostname}:\s*//) { + $host_found++; + push @roles, split(); + } +} +close(ROLES) + or die "Could not close '$opt{'role-list'}': $!\n"; +if (not $host_found) { + die "Host '$opt{hostname}' not found in '$opt{'role-list'}'!\n"; +} +print join("\n", @roles), "\n"; +exit 0; + +sub sync_list () { + my $source = $opt{'role-list'}; + my $destination = $opt{cache} . "/_role_list"; + unless (-d $opt{cache}) { + eval { mkpath($opt{cache}); }; + die "Could not mkpath '$opt{cache}': $@\n" if $@; + } + # All this to run an rsync command + my @command = (@rsync, $source, $destination); + ($opt{verbose} > 0) and print STDERR "$PROG: Calling '@command'\n"; + Slack::wrap_rsync(@command); + $opt{'role-list'} = $destination; +} + diff --git a/slack/dist/slack-installfiles b/slack/dist/slack-installfiles new file mode 100755 index 0000000..65d1e22 --- /dev/null +++ b/slack/dist/slack-installfiles @@ -0,0 +1,149 @@ +#!/usr/bin/perl -w +# $Id: slack-installfiles 180 2008-01-19 08:26:19Z alan $ +# vim:sw=2 +# vim600:fdm=marker +# Copyright (C) 2004-2008 Alan Sundell +# All Rights Reserved. This program comes with ABSOLUTELY NO WARRANTY. +# See the file COPYING for details. +# +# This script is in charge of copying files from the local stage to the root +# of the local filesystem + +require 5.006; +use warnings FATAL => qw(all); +use strict; +use sigtrap qw(die untrapped normal-signals + stack-trace any error-signals); + +use File::Path; + +use constant LIB_DIR => '/usr/lib/slack'; +use lib LIB_DIR; +use Slack; + +my @rsync = ('rsync', + '--relative', + '--times', + '--perms', + '--group', + '--owner', + '--links', + '--devices', + '--sparse', + '--no-implied-dirs', # SO GOOD! + '--files-from=-', + '--from0', + ); + +(my $PROG = $0) =~ s#.*/##; + +sub install_files ($); + +######################################## +# Environment +# Helpful prefix to die messages +$SIG{__DIE__} = sub { die "FATAL[$PROG]: @_"; }; +# Set a reasonable umask +umask 077; +# Get out of wherever (possibly NFS-mounted) we were +chdir("/") + or die "Could not chdir /: $!"; +# Autoflush on STDERR +select((select(STDERR), $|=1)[0]); + +######################################## +# Config and option parsing {{{ +my $usage = Slack::default_usage("$PROG [options] [...]"); +# Option defaults +my %opt = (); +Slack::get_options( + opthash => \%opt, + usage => $usage, + required_options => [ qw(root stage) ], +); +# }}} + +# Arguments are required +die "No roles given!\n\n$usage" unless @ARGV; + +unless (-d $opt{root}) { + if (not $opt{'dry-run'}) { + eval { + mkpath($opt{root}); + # We have a tight umask, and a root of mode 0700 would be undesirable + # in most cases. + chmod(0755, $opt{root}); + }; + die "Could not mkpath destination directory '$opt{root}': $@\n" if $@; + } + warn "WARNING[$PROG]: Created destination directory '".$opt{root}."'\n"; +} + +# Prepare for backups +if ($opt{backup} and $opt{'backup-dir'}) { + # Make sure backup directory exists + unless (-d $opt{'backup-dir'}) { + ($opt{verbose} > 0) and print STDERR "$PROG: Creating backup directory '$opt{'backup-dir'}'\n"; + if (not $opt{'dry-run'}) { + eval { mkpath($opt{'backup-dir'}); }; + die "Could not mkpath backup dir '$opt{'backup-dir'}': $@\n" if $@; + } + } + push(@rsync, "--backup", "--backup-dir=$opt{'backup-dir'}"); +} +# Pass options along to rsync +if ($opt{'dry-run'}) { + push @rsync, '--dry-run'; +} +if ($opt{'verbose'} > 1) { + push @rsync, '--verbose'; +} + +# copy over the new files +for my $role (@ARGV) { + install_files($role); +} +exit 0; + +# This subroutine takes care of actually installing the files for a role +sub install_files ($) { + my ($role) = @_; + # final / is important for rsync + my $source = $opt{stage} . "/roles/" . $role . "/files/"; + my $destination = $opt{root} . "/"; + my @command = (@rsync, $source, $destination); + + if (not -d $source) { + ($opt{verbose} > 0) and + print STDERR "$PROG: No files to install -- '$source' does not exist\n"; + return; + } + + # Try to give some sensible message here + if ($opt{verbose} > 0) { + if ($opt{'dry-run'}) { + print STDERR "$PROG: Dry-run syncing '$source' to '$destination'\n"; + } else { + print STDERR "$PROG: Syncing '$source' to '$destination'\n"; + } + } + + my ($fh) = Slack::wrap_rsync_fh(@command); + + select((select($fh), $|=1)[0]); # Turn on autoflush + + my $callback = sub { + my ($file) = @_; + ($file =~ s#^$source##) + or die "sub failed: $source|$file"; + print $fh "$file\0"; + }; + + # This will print files to be synced to the $fh + Slack::find_files_to_install($source, $destination, $callback); + + # Close fh, waitpid, and check return value + unless (close($fh)) { + Slack::check_system_exit(@command); + } +} diff --git a/slack/dist/slack-rolediff b/slack/dist/slack-rolediff new file mode 100755 index 0000000..92def93 --- /dev/null +++ b/slack/dist/slack-rolediff @@ -0,0 +1,146 @@ +#!/usr/bin/perl -w +# $Id: slack-rolediff 125 2006-09-27 07:50:07Z alan $ +# vim:sw=2 +# vim600:fdm=marker +# Copyright (C) 2004-2006 Alan Sundell +# All Rights Reserved. This program comes with ABSOLUTELY NO WARRANTY. +# See the file COPYING for details. +# +# This script provides a preview of scripts or files about to be installed. +# Basically, it calls diff -- its smarts are in knowing where things are. + +require 5.006; +use warnings FATAL => qw(all); +use strict; +use sigtrap qw(die untrapped normal-signals + stack-trace any error-signals); + +use File::Path; +use File::Find; + +use constant LIB_DIR => '/usr/lib/slack'; +use lib LIB_DIR; +use Slack; + +my @diff = ('slack-diff', + '-uN', + ); + +# directories to compare +my %subdir = ( + files => 1, + scripts => 1, +); + +(my $PROG = $0) =~ s#.*/##; + +sub diff ($$;@); + +######################################## +# Environment +# Helpful prefix to die messages +$SIG{__DIE__} = sub { die "FATAL[$PROG]: @_"; }; +# Set a reasonable umask +umask 077; +# Get out of wherever (possibly NFS-mounted) we were +chdir("/") + or die "Could not chdir /: $!"; +# Autoflush on STDERR +select((select(STDERR), $|=1)[0]); + +######################################## +# Config and option parsing {{{ +my $usage = Slack::default_usage("$PROG [options] [...]"); +$usage .= < \%opt, + command_line_options => [ + 'subdir=s', + 'diff=s', + ], + usage => $usage, + required_options => [ qw(cache stage root) ], +); + +# Arguments are required +die "No roles given!\n\n$usage" unless @ARGV; + +# We only allow certain values for this option +if ($opt{subdir}) { + unless ($opt{subdir} eq 'files' or $opt{subdir} eq 'scripts') { + die "--subdir option must be 'files' or 'scripts'\n\n$usage"; + } + # Only do this subdir + %subdir = ( $opt{subdir} => 1 ); +} + +# Let people override our diff. Split on spaces so they can pass args. +if ($opt{diff}) { + @diff = split(/\s+/, $opt{diff}); +} + +# }}} + +my $exit = 0; +# Do the diffs +for my $full_role (@ARGV) { + # Split the full role (e.g. google.foogle.woogle) into components + my @role = split(/\./, $full_role); + + if ($subdir{scripts}) { + # Then we compare the cache vs the stage + my $old = $opt{stage} . "/roles/" . $full_role . "/scripts"; + my $new = $opt{cache} . "/roles/" . $role[0] . "/scripts"; + # For scripts, we don't care so much about mode and owner (since those are + # inherited in the CACHE from the SOURCE), so --noperms. + $exit |= diff($old, $new, '--noperms'); + } + + if ($subdir{files}) { + # Then we compare the stage vs the root + my $old = $opt{root}; + my $new = $opt{stage} . "/roles/" . $full_role . "/files"; + # For files, we don't care about files that exist in $old but not $new + $exit |= diff($old, $new, '--unidirectional-new-file'); + } +} +exit $exit; + +sub diff ($$;@) { + my ($old, $new, @options) = @_; + + my @command = (@diff, @options); + + # return if there's nothing to do + return 0 if (not -d $old and not -d $new); + + ($opt{verbose} > 0) and print STDERR "$PROG: Previewing with '@command'\n"; + + my $return = 0; + my $callback = sub { + my ($new_file) = @_; + my $old_file = $new_file; + ($old_file =~ s#^$new#$old#) + or die "sub failed: $new|$new_file"; + if (system(@command, $old_file, $new_file) != 0) { + $return |= Slack::get_system_exit(@command); + } + }; + + # We have to use this function, rather than recursive mode for slack-diff, + # because otherwise we'll print a bunch of bogus stuff about directories + # that exist in $ROOT and therefore aren't being synced. + Slack::find_files_to_install($new, $old, $callback); + + return $return; +} diff --git a/slack/dist/slack-runscript b/slack/dist/slack-runscript new file mode 100755 index 0000000..05790c4 --- /dev/null +++ b/slack/dist/slack-runscript @@ -0,0 +1,111 @@ +#!/usr/bin/perl -w +# $Id: slack-runscript 118 2006-09-25 18:35:17Z alan $ +# vim:sw=2 +# vim600:fdm=marker +# Copyright (C) 2004-2006 Alan Sundell +# All Rights Reserved. This program comes with ABSOLUTELY NO WARRANTY. +# See the file COPYING for details. +# +# This script is in charge of running scripts out of the local stage + +require 5.006; +use warnings FATAL => qw(all); +use strict; +use sigtrap qw(die untrapped normal-signals + stack-trace any error-signals); + +use File::Path; +use File::Find; + +use constant LIB_DIR => '/usr/lib/slack'; +use lib LIB_DIR; +use Slack; + +# Export these options to the environment of the script +my @export_options = qw(root stage hostname verbose); + +(my $PROG = $0) =~ s#.*/##; + +######################################## +# Environment +# Helpful prefix to die messages +$SIG{__DIE__} = sub { die "FATAL[$PROG]: @_"; }; +# Set a reasonable umask +umask 077; +# Autoflush on STDERR +select((select(STDERR), $|=1)[0]); +# Get out of wherever (possibly NFS-mounted) we were +chdir('/') + or die "Could not chdir '/': $!"; + +######################################## +# Config and option parsing {{{ +my $usage = Slack::default_usage("$PROG [options] [...]"); +# Option defaults +my %opt = (); +Slack::get_options( + opthash => \%opt, + usage => $usage, + required_options => \@export_options, +); + +my $action = shift || die "No script to run!\n\n$usage"; +# Arguments are required +die "No roles given!\n\n$usage" unless @ARGV; + +# }}} + +# Start with a clean environment +%ENV = ( + PATH => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', +); +# Export certain variables to the environment. These are guaranteed to +# be set because we require them in get_options above. +for my $option (@export_options) { + my $env_var = $option; + $env_var =~ tr/a-z-/A-Z_/; + $ENV{$env_var} = $opt{$option}; +} +# We want to decrement the verbose value for the child if it's set. +$ENV{VERBOSE}-- if $ENV{VERBOSE}; + +# Run the script for each role given, if it exists and is executable +for my $role (@ARGV) { + my $script_to_run = "$opt{stage}/roles/$role/scripts/$action"; + unless (-x $script_to_run) { + if (-e _) { + # A helpful warning + warn "WARNING[$PROG]: Skipping '$script_to_run' because it's not executable\n"; + } elsif ($opt{verbose} > 0) { + print STDERR "$PROG: Skipping '$script_to_run' because it doesn't exist\n"; + } + next; + } + my $dir; + if ($action eq 'fixfiles') { + $dir = "$opt{stage}/roles/$role/files"; + } else { + $dir = "$opt{stage}/roles/$role/scripts"; + } + my @command = ($script_to_run , $role); + + # It's OK to chdir even if we're not going to run the script. + # Might as well see if it works. + chdir($dir) + or die "Could not chdir '$dir': $!\n"; + if ($opt{'dry-run'}) { + ($opt{verbose} > 0) + and print STDERR "$PROG: Not calling '@command' in '$dir' ". + "because --dry-run specified.\n"; + } else { + ($opt{verbose} > 0) + and print STDERR "$PROG: Calling '@command' in '$dir'.\n"; + unless (system("script /root/slackLog -a -f -c @command") == 0) { + Slack::check_system_exit(@command); + } + } + chdir('/') + or die "Could not chdir '/': $!\n" +} +exit 0; + diff --git a/slack/dist/slack-runscript.orig b/slack/dist/slack-runscript.orig new file mode 100755 index 0000000..5125a83 --- /dev/null +++ b/slack/dist/slack-runscript.orig @@ -0,0 +1,111 @@ +#!/usr/bin/perl -w +# $Id: slack-runscript 118 2006-09-25 18:35:17Z alan $ +# vim:sw=2 +# vim600:fdm=marker +# Copyright (C) 2004-2006 Alan Sundell +# All Rights Reserved. This program comes with ABSOLUTELY NO WARRANTY. +# See the file COPYING for details. +# +# This script is in charge of running scripts out of the local stage + +require 5.006; +use warnings FATAL => qw(all); +use strict; +use sigtrap qw(die untrapped normal-signals + stack-trace any error-signals); + +use File::Path; +use File::Find; + +use constant LIB_DIR => '/usr/lib/slack'; +use lib LIB_DIR; +use Slack; + +# Export these options to the environment of the script +my @export_options = qw(root stage hostname verbose); + +(my $PROG = $0) =~ s#.*/##; + +######################################## +# Environment +# Helpful prefix to die messages +$SIG{__DIE__} = sub { die "FATAL[$PROG]: @_"; }; +# Set a reasonable umask +umask 077; +# Autoflush on STDERR +select((select(STDERR), $|=1)[0]); +# Get out of wherever (possibly NFS-mounted) we were +chdir('/') + or die "Could not chdir '/': $!"; + +######################################## +# Config and option parsing {{{ +my $usage = Slack::default_usage("$PROG [options] [...]"); +# Option defaults +my %opt = (); +Slack::get_options( + opthash => \%opt, + usage => $usage, + required_options => \@export_options, +); + +my $action = shift || die "No script to run!\n\n$usage"; +# Arguments are required +die "No roles given!\n\n$usage" unless @ARGV; + +# }}} + +# Start with a clean environment +%ENV = ( + PATH => '/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin', +); +# Export certain variables to the environment. These are guaranteed to +# be set because we require them in get_options above. +for my $option (@export_options) { + my $env_var = $option; + $env_var =~ tr/a-z-/A-Z_/; + $ENV{$env_var} = $opt{$option}; +} +# We want to decrement the verbose value for the child if it's set. +$ENV{VERBOSE}-- if $ENV{VERBOSE}; + +# Run the script for each role given, if it exists and is executable +for my $role (@ARGV) { + my $script_to_run = "$opt{stage}/roles/$role/scripts/$action"; + unless (-x $script_to_run) { + if (-e _) { + # A helpful warning + warn "WARNING[$PROG]: Skipping '$script_to_run' because it's not executable\n"; + } elsif ($opt{verbose} > 0) { + print STDERR "$PROG: Skipping '$script_to_run' because it doesn't exist\n"; + } + next; + } + my $dir; + if ($action eq 'fixfiles') { + $dir = "$opt{stage}/roles/$role/files"; + } else { + $dir = "$opt{stage}/roles/$role/scripts"; + } + my @command = ($script_to_run, $role); + + # It's OK to chdir even if we're not going to run the script. + # Might as well see if it works. + chdir($dir) + or die "Could not chdir '$dir': $!\n"; + if ($opt{'dry-run'}) { + ($opt{verbose} > 0) + and print STDERR "$PROG: Not calling '@command' in '$dir' ". + "because --dry-run specified.\n"; + } else { + ($opt{verbose} > 0) + and print STDERR "$PROG: Calling '@command' in '$dir'.\n"; + unless (system(@command) == 0) { + Slack::check_system_exit(@command); + } + } + chdir('/') + or die "Could not chdir '/': $!\n" +} +exit 0; + diff --git a/slack/dist/slack-stage b/slack/dist/slack-stage new file mode 100755 index 0000000..3833736 --- /dev/null +++ b/slack/dist/slack-stage @@ -0,0 +1,278 @@ +#!/usr/bin/perl -w +# $Id: slack-stage 180 2008-01-19 08:26:19Z alan $ +# vim:sw=2 +# vim600:fdm=marker +# Copyright (C) 2004-2008 Alan Sundell +# All Rights Reserved. This program comes with ABSOLUTELY NO WARRANTY. +# See the file COPYING for details. +# +# This script is in charge of copying files from the local cache +# directory to the local stage, building a unified single tree onstage +# from the multiple trees that are the role + subroles in the cache + +require 5.006; +use warnings FATAL => qw(all); +use strict; +use sigtrap qw(die untrapped normal-signals + stack-trace any error-signals); + +use File::Path; +use File::Find; + +use constant LIB_DIR => '/usr/lib/slack'; +use lib LIB_DIR; +use Slack; + +my @rsync = ('rsync', + '--recursive', + '--times', + '--ignore-times', + '--perms', + '--sparse', + ); + +(my $PROG = $0) =~ s#.*/##; + +sub check_stage (); +sub sync_role ($$@); +sub apply_default_perms_to_role ($$); + +######################################## +# Environment +# Helpful prefix to die messages +$SIG{__DIE__} = sub { die "FATAL[$PROG]: @_"; }; +# Set a reasonable umask +umask 077; +# Get out of wherever (possibly NFS-mounted) we were +chdir("/") + or die "Could not chdir /: $!"; +# Autoflush on STDERR +select((select(STDERR), $|=1)[0]); + +######################################## +# Config and option parsing {{{ +my $usage = Slack::default_usage("$PROG [options] [...]"); +$usage .= < \%opt, + command_line_options => [ + 'subdir=s', + ], + usage => $usage, + required_options => [ qw(cache stage) ], +); + +# Arguments are required +die "No roles given!\n\n$usage" unless @ARGV; + +# We only allow certain values for this option +if ($opt{subdir}) { + unless ($opt{subdir} eq 'files' or $opt{subdir} eq 'scripts') { + die "--subdir option must be 'files' or 'scripts'\n\n$usage"; + } +} else { + $opt{subdir} = ''; +} + +# Prepare for backups +if ($opt{backup} and $opt{'backup-dir'}) { + # Make sure backup directory exists + unless (-d $opt{'backup-dir'}) { + ($opt{verbose} > 0) and print STDERR "Creating backup directory '$opt{'backup-dir'}'\n"; + if (not $opt{'dry-run'}) { + eval { mkpath($opt{'backup-dir'}); }; + die "Could not mkpath backup dir '$opt{'backup-dir'}': $@\n" if $@; + } + } + push(@rsync, "--backup", "--backup-dir=$opt{'backup-dir'}"); +} + +# Pass options along to rsync +if ($opt{'dry-run'}) { + push @rsync, '--dry-run'; +} +# Pass options along to rsync +if ($opt{'verbose'} > 1) { + push @rsync, '--verbose'; +} +# }}} + +# copy over the new files +for my $full_role (@ARGV) { + # Split the full role (e.g. google.foogle.woogle) into components + my @role_parts = split(/\./, $full_role); + die "Internal error: Expect at least one role part" if not @role_parts; + # Reassemble parts one at a time onto @role and sync as we go, + # so we do "google", then "google.foogle", then "google.foogle.woogle" + my @role = (); + # Make sure we've got the right perms before we copy stuff down + check_stage(); + + # For the base role, do both files and scripts. + push @role, shift @role_parts; + for my $subdir(qw(files scripts)) { + if (not $opt{subdir} or $opt{subdir} eq $subdir) { + ($opt{verbose} > 1) + and print STDERR "$PROG: Calling sync_role for $full_role, @role\n"; + # @role here will have one element, so sync_role will use --delete + sync_role($full_role, $subdir, @role) + } + } + + # For all subroles, just do the files. + # (If we wanted script subroles to work like files, we'd get rid of this + # distinction and simplify the code.) + if (not $opt{subdir} or $opt{subdir} eq 'files') { + while (@role_parts) { + push @role, shift @role_parts; + ($opt{verbose} > 1) + and print STDERR "$PROG: Calling sync_role for $full_role, @role\n"; + sync_role($full_role, 'files', @role); + } + } + + for my $subdir (qw(files scripts)) { + apply_default_perms_to_role($full_role, $subdir) + if (not $opt{subdir} or $opt{subdir} eq $subdir); + } +} +exit 0; + +# Make sure the stage directory exists and is mode 0700, to protect files +# underneath in transit +sub check_stage () { + my $stage = $opt{stage} . "/roles"; + if (not $opt{'dry-run'}) { + if (not -d $stage) { + ($opt{verbose} > 0) and print STDERR "$PROG: Creating '$stage'\n"; + eval { mkpath($stage); }; + die "Could not mkpath cache dir '$stage': $@\n" if $@; + } + ($opt{verbose} > 0) and print STDERR "$PROG: Checking perms on '$stage'\n"; + if ($> != 0) { + warn "WARNING[$PROG]: Not superuser; unable to chown files\n"; + } else { + chown(0, 0, $stage) + or die "Could not chown 0:0 '$stage': $!\n"; + } + chmod(0700, $stage) + or die "Could not chmod 0700 '$stage': $!\n"; + } +} + +# Copy the files for a role from CACHE to STAGE +sub sync_role ($$@) { + my ($full_role, $subdir, @role) = @_; + my @this_rsync = @rsync; + + # If we were only given one role part, we're in the base role + my $in_base_role = (scalar @role == 1); + + # For the base role, delete any files that don't exist in the cache. + # Not for the subrole (otherwise we'll delete all files not in + # the subrole, which may be most of them!) + if ($in_base_role) { + push @this_rsync, "--delete"; + } + + # (a) => a/files + # (a,b,c) => a/files.b.c + my $src_path = $role[0].'/'.join(".", $subdir, @role[1 .. $#role]); + # This one's a little simpler: + my $dst_path = $full_role.'/'.$subdir; + + # final / is important for rsync + my $source = $opt{cache} . "/roles/" . $src_path . "/"; + my $destination = $opt{stage} . "/roles/" . $dst_path . "/"; + if (not -d $destination and -d $source) { + ($opt{verbose} > 0) and print STDERR "$PROG: Creating '$destination'\n"; + if (not $opt{'dry-run'}) { + eval { mkpath($destination); }; + die "Could not mkpath stage dir '$destination': $@\n" if $@; + } + } + + # We no longer require the source to exist + if (not -d $source) { + # but we need to remove the destination if the source + # doesn't exist and we're in the base role + if ($in_base_role) { + rmtree($destination); + # rmtree() doesn't throw exceptions or give a return value useful + # for detecting failure, so we just check after the fact. + die "Could not rmtree '$destination' when '$source' missing\n" + if -e $destination; + } + # if we continue, rsync will fail because source is missing, + # so we don't. + return; + } + + # All this to run an rsync command + my @command = (@this_rsync, $source, $destination); + ($opt{verbose} > 0) and print STDERR "$PROG: Syncing $src_path with '@command'\n"; + Slack::wrap_rsync(@command); +} + +# This just takes the base role, and chowns/chmods everything under it to +# give it some sensible permissions. Basically, the only thing we preserve +# about the original permissions is the executable bit, since that's the +# only thing source code controls systems like CVS, RCS, Perforce seem to +# preserve. +sub apply_default_perms_to_role ($$) { + my ($role, $subdir) = @_; + my $destination = $opt{stage} . "/roles/" . $role; + + if ($subdir) { + $destination .= '/' . $subdir; + } + + # If the destination doesn't exist, it's probably because the source didn't + return if not -d $destination; + + ($opt{verbose} > 0) and print STDERR "$PROG: Setting default perms on $destination\n"; + if ($> != 0) { + warn "WARNING[$PROG]: Not superuser; won't be able to chown files\n"; + } + # Use File::Find to recurse the directory + find({ + # The "wanted" subroutine is called for every directory entry + wanted => sub { + return if $opt{'dry-run'}; + ($opt{verbose} > 2) and print STDERR "$File::Find::name\n"; + if (-l) { + # symlinks shouldn't be in here, + # since we dereference when copying + warn "WARNING[$PROG]: Skipping symlink at $File::Find::name: $!\n"; + return; + } elsif (-f _) { # results of last stat saved in the "_" + if (-x _) { + chmod 0555, $_ + or die "Could not chmod 0555 $File::Find::name: $!"; + } else { + chmod 0444, $_ + or die "Could not chmod 0444 $File::Find::name: $!"; + } + } elsif (-d _) { + chmod 0755, $_ + or die "Could not chmod 0755 $File::Find::name: $!"; + } else { + warn "WARNING[$PROG]: Unknown file type at $File::Find::name: $!\n"; + } + return if $> != 0; # skip chowning if not superuser + chown 0, 0, $_ + or die "Could not chown 0:0 $File::Find::name: $!"; + }, + # end of wanted function + }, + # way down here, we have the directory to traverse with File::Find + $destination, + ); +} diff --git a/slack/dist/slack-sync b/slack/dist/slack-sync new file mode 100755 index 0000000..e334ef4 --- /dev/null +++ b/slack/dist/slack-sync @@ -0,0 +1,169 @@ +#!/usr/bin/perl -w +# $Id: slack-sync 180 2008-01-19 08:26:19Z alan $ +# vim:sw=2 +# vim600:fdm=marker +# Copyright (C) 2004-2008 Alan Sundell +# All Rights Reserved. This program comes with ABSOLUTELY NO WARRANTY. +# See the file COPYING for details. +# +# This script is in charge of copying files from the (possibly remote) +# master directory to a local cache, using rsync + +require 5.006; +use warnings FATAL => qw(all); +use strict; +use sigtrap qw(die untrapped normal-signals + stack-trace any error-signals); + +use File::Path; + +use constant LIB_DIR => '/usr/lib/slack'; +use lib LIB_DIR; +use Slack; + +my @rsync = ('rsync', + '--cvs-exclude', + '--recursive', + '--links', + '--copy-links', + '--times', + '--perms', + '--sparse', + '--delete', + '--files-from=-', + '--from0', + ); + +(my $PROG = $0) =~ s#.*/##; + +sub check_cache ($); +sub rsync_source ($$@); + +######################################## +# Environment +# Helpful prefix to die messages +$SIG{__DIE__} = sub { die "FATAL[$PROG]: @_"; }; +# Set a reasonable umask +umask 077; +# Get out of wherever (possibly NFS-mounted) we were +chdir("/") + or die "Could not chdir /: $!"; +# Autoflush on STDERR +select((select(STDERR), $|=1)[0]); + +######################################## +# Config and option parsing {{{ +my $usage = Slack::default_usage("$PROG [options] [...]"); +# Option defaults +my %opt = (); +Slack::get_options( + opthash => \%opt, + usage => $usage, + required_options => [ qw(source cache) ], +); + +# Arguments are required +die "No roles given!\n\n$usage" unless @ARGV; + +# Prepare for backups +if ($opt{backup} and $opt{'backup-dir'}) { + # Make sure backup directory exists + unless (-d $opt{'backup-dir'}) { + ($opt{verbose} > 0) and print STDERR "Creating backup directory '$opt{'backup-dir'}'\n"; + if (not $opt{'dry-run'}) { + eval { mkpath($opt{'backup-dir'}); }; + die "Could not mkpath backup dir '$opt{'backup-dir'}': $@\n" if $@; + } + } + push(@rsync, "--backup", "--backup-dir=$opt{'backup-dir'}"); +} +# Look at source type, and add options if necessary +if ($opt{'rsh'} or $opt{source} =~ m/^[\w@\.-]+::/) { + # This is tunnelled rsync, and so needs an extra option + if ($opt{'rsh'}) { + push @rsync, '-e', $opt{'rsh'}; + } else { + push @rsync, '-e', 'ssh'; + } +} + +# Pass options along to rsync +if ($opt{'dry-run'}) { + push @rsync, '--dry-run'; +} +# Pass options along to rsync +if ($opt{'verbose'} > 1) { + push @rsync, '--verbose'; +} +# }}} + +my @roles = (); + +{ + # This hash is just to avoid calling rsync twice if two subroles are + # installed. We only care since it's remote, and therefore slow. + my %roles_to_sync = (); + + # copy over the new files + for my $full_role (@ARGV) { + # Get the first element of the role name (the base role) + # e.g., from "google.foogle.woogle", get "google" + my $base_role = (split /\./, $full_role, 2)[0]; + + $roles_to_sync{$base_role} = 1; + } + @roles = keys %roles_to_sync; +} + +my $cache = $opt{cache} . "/roles/"; +# Make sure we've got the right perms before we copy stuff down +check_cache($cache); + +rsync_source( + $opt{source} . '/roles/', + $cache, + @roles, +); + +exit 0; + +# Make sure the cache directory exists and is mode 0700, to protect files +# underneath in transit +sub check_cache ($) { + my ($cache) = @_; + if (not $opt{'dry-run'}) { + if (not -d $cache) { + ($opt{verbose} > 0) and print STDERR "$PROG: Creating '$cache'\n"; + eval { mkpath($cache); }; + die "Could not mkpath cache dir '$cache': $@\n" if $@; + } + ($opt{verbose} > 0) and print STDERR "$PROG: Checking perms on '$cache'\n"; + if ($> != 0) { + warn "WARNING[$PROG]: Not superuser; unable to chown files\n"; + } else { + chown(0, 0, $cache) + or die "Could not chown 0:0 '$cache': $!\n"; + } + chmod(0700, $cache) + or die "Could not chmod 0700 '$cache': $!\n"; + } +} + +# Pull down roles from an rsync source +sub rsync_source($$@) { + my ($source, $destination, @roles) = @_; + my @command = (@rsync, $source, $destination); + + ($opt{verbose} > 0) + and print STDERR "$PROG: Syncing cache with '@command'\n"; + + my ($fh) = Slack::wrap_rsync_fh(@command); + + # Shove the roles down its throat + print $fh join("\0", @roles), "\0"; + + # Close fh, waitpid, and check return value + unless (close($fh)) { + Slack::check_system_exit(@command); + } +} diff --git a/slack/dist/slack.conf b/slack/dist/slack.conf new file mode 100755 index 0000000..e69de29 diff --git a/slack/env/SlackConfig-prod.config b/slack/env/SlackConfig-prod.config new file mode 100644 index 0000000..5ebdd6d --- /dev/null +++ b/slack/env/SlackConfig-prod.config @@ -0,0 +1,6 @@ +ROLE_LIST=toolbox.turnsys.net:/local/slack-prod/etc/roles.conf +SOURCE=toolbox.turnsys.net:/local/slack-prod/ +CACHE=/var/cache/slack +STAGE=/var/lib/slack/stage +ROOT=/ +BACKUP_DIR=/var/lib/slack/backups diff --git a/slack/env/SlackSSH-prod.config b/slack/env/SlackSSH-prod.config new file mode 100644 index 0000000..af12fda --- /dev/null +++ b/slack/env/SlackSSH-prod.config @@ -0,0 +1,4 @@ +Host toolbox.turnsys.net + User slack-prod + IdentityFile /root/.ssh/SlackSSH-prod.key + StrictHostKeyChecking no diff --git a/slack/env/SlackSSH-prod.key b/slack/env/SlackSSH-prod.key new file mode 100644 index 0000000..447e4bd --- /dev/null +++ b/slack/env/SlackSSH-prod.key @@ -0,0 +1,27 @@ +-----BEGIN RSA PRIVATE KEY----- +MIIEowIBAAKCAQEAycZwe0FuYISsFaHvaplNhb9uplG8YeMkffIKXp633MwihACm +oNoKEQHlqSKD1urZfLYjwf1YBKAPt9QRdIguwsQ3hl3xKpsO+gsmaOpF3eJMVWHZ +dS/T7lplIOcXr0tbUeibQ9p+c+MgICfpdAJvUnuD8grDmaTuvasBat4Ow6rXIzsQ +WKzSrP3iQJ0xeq+mqRIlPP5dwl66RF+dlaloVxlvG95i3u512EkNg+sMt1X5KbhH +ecQSicpA8K2qK4G71CqRIm7DmXCheSlDzqLACwJAFOU4xN3eqTO3B4Bm5Wri9Oip +hkwzMgWrDNFx/69ZnGF69g0VP8Qyl4R7d3FZDQIDAQABAoIBAQCzCDYpxybO0Sl3 +kFXEuf3FHNRrEr8aA9cPQUHeLuppKV++zG0M8CpaaNqENjHQ8lTDiUE1ETuV7wfD +TpGmWmdTPZMe0B/6c9bYGiickrInbHHamJXAmw1qwh5VEXc8fJqslL2feTEWVoLc +xU0pODfacenjS5W+sE99T0xUrG9hQJMRtNOorMQiUraLl670yIZnzMszDIdd1xdv +4XCuQ5Phnup22/kvByIdiNXPaSY/gOooBTZDUzka+FV3Nn9XXhZoNBnNfk6XgHZw +x9vQvnN+tuDr6RX4g1RPq/u6IhsQO2/OT9wwu74KLdkLFTssGold73uys2WvC0NW +zNFVBuBBAoGBAO6lhTWE2hvt5h7btEY36XgoJbu0k/E7fVgEud2yCdRdQ5ApAHVs +xvol1D3waVKUrRePKq2BhaylwtYACYAow3geMsGrlf4ndlLOQ1z6ByNncJPF3Tr1 +lFp025QLijoKmnCq3CdIVPrdhTm44go2usXytobpxS2nB5hZwZfyDju5AoGBANhy +i9vOlRXcLiHpmzAKwFs/jR9D09DUZ6ALm22HvDOsISJS+nR2neun+7HXXHm1Kqyu +w1GA8xaqBnuFfuHP09ZYTNammEROS8dL/5muGCwrfwIrd/H4ELsE0spWOrTlfgY/ +GN5WeoXZGAwjiu67AoRkpKIQxnsjEKSNKZQntjn1AoGAOyAdIcZZd2P4iJqsTl1Z +5aAkwR2bLcAsbNs25XtPviKhM51E9NLPdXhb3kCrB3+4ZsbcrwIRCVZEMFrv/6WZ +0C/DKYKGdeJ3CUr7G5UCob3mAWabShk/+S1MnaBCTeEEpHdgdgcQrtqlQEjTD+7B +VXutxz0x0f64/gD22ttotVkCgYAma4a52JyMCc5ChMXgLDhiuhAhuZdynRFbzlOj +iJF2lpo3DoWYgKmdd+7sbW7jx62wg0D2Sa5cmoeWC2cvTAWtKXVSMLYcgc1frfTL +4aQ2yu27g93BnKfTmpKUCeRX0dih4TdX1//dnGBxXym9IILc30R94/5nQx0kKE52 +Fup4tQKBgHrDPBIJG3MkA5UIkBPnxE9Ei8V4g/TpYjmC+6JiWkBTQCNZ4A2KKl7S +pwGQwdcqA5OsPbw0T54HwMtDm0ao0b3krb70vBw/xdIAHNe3DCmeOuKelvjDyzr1 +ZL6gF557VfKFjz23Hp2PbOYo88BAdX1H1zy0FUZJ7Zh4GbOjgVFQ +-----END RSA PRIVATE KEY----- diff --git a/slack/env/SlackSSH-prod.key.pub b/slack/env/SlackSSH-prod.key.pub new file mode 100644 index 0000000..6ae1fb0 --- /dev/null +++ b/slack/env/SlackSSH-prod.key.pub @@ -0,0 +1 @@ +ssh-rsa AAAAB3NzaC1yc2EAAAADAQABAAABAQDJxnB7QW5ghKwVoe9qmU2Fv26mUbxh4yR98gpenrfczCKEAKag2goRAeWpIoPW6tl8tiPB/VgEoA+31BF0iC7CxDeGXfEqmw76CyZo6kXd4kxVYdl1L9PuWmUg5xevS1tR6JtD2n5z4yAgJ+l0Am9Se4PyCsOZpO69qwFq3g7DqtcjOxBYrNKs/eJAnTF6r6apEiU8/l3CXrpEX52VqWhXGW8b3mLe7nXYSQ2D6wy3VfkpuEd5xBKJykDwraorgbvUKpEibsOZcKF5KUPOosALAkAU5TjE3d6pM7cHgGblauL06KmGTDMyBasM0XH/r1mcYXr2DRU/xDKXhHt3cVkN charles@ultix-mini diff --git a/slack/slackDist.tar.gz b/slack/slackDist.tar.gz new file mode 100755 index 0000000000000000000000000000000000000000..2b7969a9116934debffff82389e4dc6b17ba9806 GIT binary patch literal 16474 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 literal 0 HcmV?d00001