Compare commits

...

31 Commits

Author SHA256 Message Date
heath 8d40ddc636 create local.yml and configure chrony with it 2026-08-30 15:50:18 -05:00
heath 5706fc9854 x 2026-08-22 10:59:19 -05:00
heath 5e0d333c7b aargh... 2026-08-21 18:56:36 -05:00
heath 76d0fe843a allow output to STDOUT via cmdline 2026-08-21 18:32:18 -05:00
heath 8c9a79c07a clean up 2026-08-21 17:23:09 -05:00
heath f0dbaef0e4 correct copying directories 2026-08-21 17:03:41 -05:00
heath 01e471ec0f change to copy sudoers.d at the directory instead of file level 2026-08-21 16:45:22 -05:00
heath 6cdfecfd8d change to copy whole directories instead of individual files 2026-08-21 16:40:28 -05:00
heath 4665903b01 default ansible-pull to one level of verbose mode 2026-08-21 15:42:52 -05:00
heath a935e484d9 create jsonvar.bash 2026-08-07 16:59:32 -05:00
heath 2fa109335f x 2026-08-02 10:24:31 -05:00
heath f9ee2fcc05 x 2026-08-02 09:54:44 -05:00
heath 316e6018fc x 2026-08-02 09:48:36 -05:00
heath ed627fbd19 x 2026-08-01 13:49:29 -05:00
heath 7859a609eb x 2026-08-01 10:58:43 -05:00
heath fad2891925 x 2026-07-31 19:07:46 -05:00
heath 1e8f162672 x 2026-07-31 18:35:11 -05:00
heath 90de36e0b2 x 2026-07-31 18:25:22 -05:00
heath bfe44f6b17 x 2026-07-31 14:43:17 -05:00
heath 331b2ba504 x 2026-07-26 19:49:05 -05:00
heath 26142f24b0 x 2026-07-26 14:36:27 -05:00
heath 97b4169bdc x 2026-07-26 14:32:20 -05:00
heath b8792fc523 add --force flag 2026-07-26 14:24:07 -05:00
heath 1a0d1e5d0b clean up locking 2026-07-26 14:04:53 -05:00
heath 8b50cacb1b preparing to schedule ansible-pull.sh 2026-07-26 12:03:03 -05:00
heath e1592fca85 x 2026-07-26 11:11:49 -05:00
heath 456ee502ee x 2026-07-25 19:41:02 -05:00
heath 4fe4ca317a x 2026-07-25 17:14:41 -05:00
heath 4f86f4c114 x 2026-07-25 16:58:57 -05:00
heath bcd45cff9e x 2026-07-25 14:40:04 -05:00
heath 0e820b49f9 x 2026-07-25 14:04:38 -05:00
18 changed files with 789 additions and 346 deletions
+1 -1
View File
@@ -1,4 +1,4 @@
# ---> Ansible
*.retry
EXAMPLES
roles
View File
+1
View File
@@ -1,6 +1,7 @@
[defaults]
inventory = ./inventory
roles_path = ./roles
remote_user = hpf-ans
host_key_checking = False
+113 -116
View File
@@ -1,23 +1,5 @@
---
####
#### WARNING:
####
#### bootstrap.sh and bootstrap.yml should be updated together. They should do the
#### exact same things with the following exceptions:
####
#### * bootstrap.sh
#### - at the end it should run ansible-pull.sh against bootstrap.yml
####
#### * bootstrap.yml
#### - at the end it should configure cron to schedule ansible-pull.sh
####
#### !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
#### ! Make sure to keep them in sync !
#### !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
####
- name: bootstrap.yml
- name: Bootstrap playbook
hosts: all
tasks:
@@ -28,19 +10,19 @@
- name: Update repositories
become: true
ansible.builtin.apt:
update_cache: yes
update_cache: true
- name: Install bootstrap packages
become: true
ansible.builtin.apt:
state: latest
state: present
pkg:
- bash
- curl
- python3
- python3-pip
- python3-venv
- python3-virtualenv
- logrotate
#### Configure sudo
@@ -61,81 +43,45 @@
system: true
gid: 701
- name: Make sure /etc/sudoers.d exists
become: true
ansible.builtin.file:
path: /etc/sudoers.d
state: directory
owner: root
group: root
mode: u=rwx,go=
- name: Get /etc/sudoers.d/hpf
- name: Get /etc/sudoers.d
become: true
ansible.builtin.copy:
src: etc/sudoers.d/hpf
dest: /etc/sudoers.d/hpf
src: etc/sudoers.d
dest: /etc/
owner: root
group: root
mode: u=rw,go=
directory_mode: u=rwx,go=
mode: u=rw,g=r,o=
backup: true
validate: /usr/sbin/visudo -csf %s
#### Configure sshd
## New
- name: Make sure /etc/ssh/sshd_config.d exists
become: true
ansible.builtin.file:
path: /etc/ssh/sshd_config.d
state: directory
owner: root
group: root
mode: u=rwx,go=rx
## New
- name: Get /etc/ssh/sshd_config.d/hpf.conf
- name: Get /etc/ssh/sshd_config.d
become: true
ansible.builtin.copy:
src: etc/ssh/sshd_config.d/hpf.conf
dest: /etc/ssh/sshd_config.d/hpf.conf
src: etc/ssh/sshd_config.d
dest: /etc/ssh/
owner: root
group: root
mode: u=rwx,go=rx
backup: yes
directory_mode: u=rwx,go=rx
mode: u=rw,go=r
backup: true
validate: /usr/sbin/sshd -t -f %s
notify: Restart sshd
#### Configure /etc/skel
- name: Make sure /etc/skel/.profile.d exists
become: true
ansible.builtin.file:
path: /etc/skel/.profile.d
state: directory
owner: root
group: root
mode: u=rwx,go=
- name: Get /etc/skel/.profile.d/ansible-venv.sh
- name: Get /etc/skel
become: true
ansible.builtin.copy:
src: etc/skel/.profile.d/ansible-venv.sh
dest: /etc/skel/.profile.d/ansible-venv.sh
owner: root
group: root
mode: u=rw,go=
backup: true
- name: Get /etc/skel/.profile
become: true
ansible.builtin.copy:
src: etc/skel/.profile
dest: /etc/skel/.profile
src: etc/skel
dest: /etc/
owner: root
group: root
directory_mode: u=rwx,go=rx
mode: u=rw,go=
backup: true
@@ -147,7 +93,40 @@
ansible.posix.authorized_key:
user: root
state: present
key: "{{ lookup('file', 'files/ssh-keys/heath.pub') }}"
key: "{{ lookup('file', item) }}"
loop:
- files/ssh-keys/heath.pub
- name: Lock the root user's password
become: true
ansible.builtin.user:
name: root
password_lock: true
#### User: first
- name: Create the first user
become: true
ansible.builtin.user:
name: first
comment: First User
state: present
system: false
groups: hpf-sudo-np
append: true
create_home: true
shell: /usr/bin/bash
- name: Set first's authorized_keys
become: true
ansible.posix.authorized_key:
user: first
state: present
key: "{{ lookup('file', item) }}"
loop:
- files/ssh-keys/first.pub
- files/ssh-keys/heath.pub
#### User: hpf-ans
@@ -169,9 +148,22 @@
uid: 800
group: hpf-ans
groups: hpf-sudo-np
append: yes
append: true
create_home: true
shell: /usr/bin/bash
password_lock: true
- name: Get /home/hpf-ans/bin
become: true
become_user: hpf-ans
ansible.builtin.copy:
src: home/hpf-ans/bin
dest: $HOME/
owner: hpf-ans
group: hpf-ans
directory_mode: u=rwx,go=
mode: u=rwx,go=
backup: true
- name: Set hpf-ans's authorized_keys
become: true
@@ -180,7 +172,6 @@
state: present
key: "{{ lookup('file', item) }}"
loop:
- files/ssh-keys/hpf-ans.pub
- files/ssh-keys/heath.pub
- name: Make sure pip is up to date
@@ -199,52 +190,43 @@
virtualenv: $HOME/.ansible-venv
extra_args: --upgrade
- name: Make sure /home/hpf-ans/bin exists
become: true
become_user: hpf-ans
ansible.builtin.file:
path: $HOME/bin
state: directory
owner: hpf-ans
group: hpf-ans
mode: u=rwx,go=
- name: Get /home/hpf-ans/bin/ansible-pull.sh
become: true
become_user: hpf-ans
ansible.builtin.copy:
src: home/hpf-ans/bin/ansible-pull.sh
dest: $HOME/bin/ansible-pull.sh
owner: hpf-ans
group: hpf-ans
mode: u=rwx,go=
backup: true
#### User: first
- name: Set first's authorized_keys
become: true
ansible.posix.authorized_key:
user: first
state: present
key: "{{ lookup('file', item) }}"
loop:
- files/ssh-keys/first.pub
- files/ssh-keys/heath.pub
#### User: heath
- name: Create the heath group
become: true
ansible.builtin.group:
name: heath
state: present
system: false
gid: 60001
- name: Create the heath user
become: true
ansible.builtin.user:
name: heath
comment: Heath Petersen
state: present
system: false
uid: 60001
group: heath
groups: hpf-sudo
append: true
create_home: true
shell: /usr/bin/bash
password: '$y$j9T$.NJVASBkVLnvqgznpcpdx1$7poH23pou7VHti3IfvDzwECdLtTcMercYNCeevgV.xC'
- name: Set heath's authorized_keys
become: true
ansible.posix.authorized_key:
user: heath
state: present
key: "{{ lookup('file', 'files/ssh-keys/heath.pub') }}"
key: "{{ lookup('file', item) }}"
loop:
- files/ssh-keys/heath.pub
#### Schedule ansible-pull.sh
#### ansible-pull.sh
- name: Make sure log directory exists
become: true
@@ -253,30 +235,45 @@
state: directory
owner: hpf-ans
group: root
mode: u=rwx,go=
mode: u=rwx,g=r,o=
# - name: Create ansible-pull.sh crontab entry
# become: true
# become_user: hpf-ans
# ansible.builtin.cron:
# name: "ansible-pull"
# minute: "*/27"
# job: $HOME/bin/ansible-pull.sh
# backup: true
- name: Rotate ansible-pull.sh.log
become: true
community.general.logrotate:
name: ansible-pull.sh
paths:
- /var/log/ansible-pull.sh/*.log
rotation_period: daily
rotate_count: 32
compress: true
compress_options: "-9"
delay_compress: true
missing_ok: true
not_if_empty: true
backup: true
#### Clean System Software
- name: Remove packages installed as dependencies that are no longer required and purge their configuration files
become: true
ansible.builtin.apt:
autoremove: yes
autoremove: true
purge: true
- name: Remove old downloaded packages
become: true
ansible.builtin.apt:
autoclean: yes
# changed_when: false
autoclean: true
#### Handlers
+119
View File
@@ -0,0 +1,119 @@
# ~/.bashrc: executed by bash(1) for non-login shells.
# see /usr/share/doc/bash/examples/startup-files (in the package bash-doc)
# for examples
# If not running interactively, don't do anything
case $- in
*i*) ;;
*) return;;
esac
# don't put duplicate lines or lines starting with space in the history.
# See bash(1) for more options
HISTCONTROL=ignoreboth
# append to the history file, don't overwrite it
shopt -s histappend
# for setting history length see HISTSIZE and HISTFILESIZE in bash(1)
HISTSIZE=1000
HISTFILESIZE=2000
# check the window size after each command and, if necessary,
# update the values of LINES and COLUMNS.
shopt -s checkwinsize
# If set, the pattern "**" used in a pathname expansion context will
# match all files and zero or more directories and subdirectories.
#shopt -s globstar
# make less more friendly for non-text input files, see lesspipe(1)
#[ -x /usr/bin/lesspipe ] && eval "$(SHELL=/bin/sh lesspipe)"
# set variable identifying the chroot you work in (used in the prompt below)
if [ -z "${debian_chroot:-}" ] && [ -r /etc/debian_chroot ]; then
debian_chroot=$(cat /etc/debian_chroot)
fi
# set a fancy prompt (non-color, unless we know we "want" color)
case "$TERM" in
xterm-color|*-256color) color_prompt=yes;;
esac
# uncomment for a colored prompt, if the terminal has the capability; turned
# off by default to not distract the user: the focus in a terminal window
# should be on the output of commands, not on the prompt
#force_color_prompt=yes
if [ -n "$force_color_prompt" ]; then
if [ -x /usr/bin/tput ] && tput setaf 1 >&/dev/null; then
# We have color support; assume it's compliant with Ecma-48
# (ISO/IEC-6429). (Lack of such support is extremely rare, and such
# a case would tend to support setf rather than setaf.)
color_prompt=yes
else
color_prompt=
fi
fi
if [ "$color_prompt" = yes ]; then
PS1='${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$ '
else
PS1='${debian_chroot:+($debian_chroot)}\u@\h:\w\$ '
fi
unset color_prompt force_color_prompt
# If this is an xterm set the title to user@host:dir
case "$TERM" in
xterm*|rxvt*)
PS1="\[\e]0;${debian_chroot:+($debian_chroot)}\u@\h: \w\a\]$PS1"
;;
*)
;;
esac
# enable color support of ls and also add handy aliases
if [ -x /usr/bin/dircolors ]; then
test -r ~/.dircolors && eval "$(dircolors -b ~/.dircolors)" || eval "$(dircolors -b)"
alias ls='ls --color=auto'
#alias dir='dir --color=auto'
#alias vdir='vdir --color=auto'
#alias grep='grep --color=auto'
#alias fgrep='fgrep --color=auto'
#alias egrep='egrep --color=auto'
fi
# colored GCC warnings and errors
#export GCC_COLORS='error=01;31:warning=01;35:note=01;36:caret=01;32:locus=01:quote=01'
# some more ls aliases
#alias ll='ls -l'
#alias la='ls -A'
#alias l='ls -CF'
# Alias definitions.
# You may want to put all your additions into a separate file like
# ~/.bash_aliases, instead of adding them here directly.
# See /usr/share/doc/bash-doc/examples in the bash-doc package.
if [ -f ~/.bash_aliases ]; then
. ~/.bash_aliases
fi
# enable programmable completion features (you don't need to enable
# this, if it's already enabled in /etc/bash.bashrc and /etc/profile
# sources /etc/bash.bashrc).
if ! shopt -oq posix; then
if [ -f /usr/share/bash-completion/bash_completion ]; then
. /usr/share/bash-completion/bash_completion
elif [ -f /etc/bash_completion ]; then
. /etc/bash_completion
fi
fi
if [ -d "$HOME/.bashrc.d" ] ; then
for bashrc_script in $HOME/.bashrc.d/*.sh ; do
. "${bashrc_script}"
done
fi
-1
View File
@@ -31,4 +31,3 @@ if [ -d "$HOME/.profile.d" ] ; then
. "${profile_script}"
done
fi
+60 -22
View File
@@ -1,43 +1,81 @@
#!/bin/bash
#!/usr/bin/env bash
if [ -r /etc/ansible-pull.sh.conf ] ; then
. /etc/ansible-pull.sh.conf
fi
SCRIPT_NAME="$(basename "${0}")"
GIT_REPO_BRANCH="${GIT_REPO_BRANCH:-production}"
OIC_FLAG="--only-if-changed"
VERBOSE_FLAG="--verbose"
DEBUG_FLAG="false"
# - Process command line
GIT_REPO_BRANCH="production"
while [ $# -gt 0 ]; do
case "$1" in
-h|--help)
echo "Usage: $0 [--branch <branch name>]"
echo "Usage: $0 [--branch <branch name>] [--force] [--quiet] [-- <ansible-pull args>]"
exit 0
;;
--branch)
-d|--debug)
VERBOSE_FLAG="-vvv"
DEBUG_FLAG="true"
shift 1
if [ $# -eq 0 ] ; then echo "$0: ERROR - Branch not specified." ; exit 1 ; fi
;;
-b|--branch)
shift 1
if [ $# -eq 0 ] ; then echo "${SCRIPT_NAME}: ERROR - Branch not specified." ; exit 1 ; fi
GIT_REPO_BRANCH="$1"
shift 1
;;
-f|--force)
OIC_FLAG=""
shift 1
;;
-q|--quiet)
VERBOSE_FLAG=""
shift 1
;;
--)
shift 1
break
;;
*)
echo "${SCRIPT_NAME}: ERROR - Invalid argument '${1}'." ; exit 2
;;
esac
done
# - Include ansible virtual environment
. "${HOME}/.ansible-venv/bin/activate"
SCRIPT_NAME="$(basename "${0}")"
GIT_REPO_BASE="https://gitea.admin-a.hpetersenfamily.com/heath/ansible"
GIT_REPO="${GIT_REPO_BASE}.git"
VENV_ACTIVATE_SCRIPT="${HOME}/.ansible-venv/bin/activate"
LOCK_FILE="/var/run/lock/ansible-pull.sh.lock"
LOG_DIR="/var/log/ansible-pull.sh"
LOG_FILE="${LOG_DIR}/ansible-pull.sh.log"
LOCK_FILE="/tmp/ansible-pull.sh.lock"
GIT_REPO_BASE="https://gitea.admin-a.hpetersenfamily.com/heath/ansible"
GIT_REPO="${GIT_REPO_BASE}.git"
# - Redirect all further output to the log file
exec >>"${LOG_FILE}" 2>&1
# - Include ansible virtual environment (in case not already done - we don't know how we're being run)
. "${VENV_ACTIVATE_SCRIPT}"
# - If we can't get a lock, don't proceed
if ! exec 9>"${LOCK_FILE}" ; then
echo "${SCRIPT_NAME}: ERROR - Unable to open the lock file (${LOCK_FILE})! Exiting..." >&2
exit 10
fi
if ! flock -n 9 ; then
echo "${SCRIPT_NAME}: ERROR - Another copy is already running! Exiting..." >&2
exit 11
fi
# - If debugging requested or running from a terminal . . .
if [ "${DEBUG_FLAG}" = "true" ] || test -t 0 ; then
exec > >(tee -a "${LOG_FILE}") 2>&1 # - send STDOUT and STDERR to both STDOUT and the log file
else
exec >>"${LOG_FILE}" 2>&1 # - send STDOUT and STDERR to the log file only
fi
# - Log that we've gotten this far
echo -n "$(basename "${0}"): $(date "+%Y-%m-%d %H:%M:%S")"
# - If we can't lock the lock file, don't proceed
exec 9>"${LOCK_FILE}"
if ! flock -n 9 ; then echo " - ERROR - Another copy of ${SCRIPT_NAME} is already running! Exiting..." ; exit 1 ; fi
echo
echo "${SCRIPT_NAME}: ------------------------------- $(date "+%Y-%m-%d %H:%M:%S") -------------------------------"
# - Do our work
echo
ansible-pull --only-if-changed --url "${GIT_REPO}" --checkout "${GIT_REPO_BRANCH}" "${@}"
ansible-pull ${OIC_FLAG} ${VERBOSE_FLAG} --url "${GIT_REPO}" --checkout "${GIT_REPO_BRANCH}" "${@}"
+9 -5
View File
@@ -8,6 +8,11 @@ fi
ANSIBLE_OS_FAMILY="${1}"
shift
if [ "${#}" -ne 0 ] ; then
echo "ERROR - unknown command line parameter specified." >&2
exit 2
fi
useradd_D() {
case "${ANSIBLE_OS_FAMILY}" in
@@ -25,11 +30,10 @@ useradd_D() {
}
user_vars() {
useradd_D | sed 's/.*=/hpf_fact_\L&/'
useradd_D | sed 's/.*=/\L&/'
}
#echo '{"hpf":'
#(user_vars; ) | jo
#echo '}'
(
user_vars
) | jo
+1 -1
View File
@@ -1 +1 @@
ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBM5BBUOxkuSK7WlpaDvp6lrM9ajLSyh4PWD7VFzYOFN5/zfafy6Vf/oxtLE4UACw5ZGvBMQNH40bW+T9aO0lQ9g= first Heath@HPetersenFamily.com
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIJOr+lI3L/cXv31JrdPEMjrCQziBacNnLWsToetpFUCk first@hpetersenfamily.com
+1 -1
View File
@@ -1 +1 @@
ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBBFiio/AimTUloJdfk4TXyWO7A0Fd9SoUcqheBjEvj4TnrxpSL/EhwF2CU9jZTasm6NBo2eKcH4aMt1l2ejOtIM= Heath@HPetersenFamily.com
ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIPNOrXhub0nCmr0s8u8BK6jyJJt07rBB25PlEtzflj+y heath@hpetersenfamily.com
-1
View File
@@ -1 +0,0 @@
ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBGKMs/y5N2ROuPabOAFUGDYb50ER/vssX9Zcsm/yPEn81EWl7NezZ1ULCchiXfEsC1qB4jm9NxocpwXmo0A5YbY= hpf-ans Heath@HPetersenFamily.com
+18
View File
@@ -0,0 +1,18 @@
---
- name: Configure time synchronization
hosts: all
become: true
vars:
timesync_ntp_provider: chrony
timesync_ntp_servers:
- hostname: 0.north-america.pool.ntp.org
iburst: true
- hostname: 1.north-america.pool.ntp.org
iburst: true
- hostname: 2.north-america.pool.ntp.org
iburst: true
timesync_chrony_custom_settings:
- "logdir /var/log/chrony"
- "log measurements statistics tracking"
roles:
- linux-system-roles.timesync
+4
View File
@@ -0,0 +1,4 @@
---
roles:
- name: linux-system-roles.timesync
version: 1.14.1
+38 -65
View File
@@ -1,55 +1,48 @@
x root
x authorized_keys = heath
x hpf-ans
x system user
x /usr/bin/bash
x member of hpf-sudo-np
x authorized_keys = hpf-ans, heath
* first
* normal user
* /usr/bin/bash
* member of hpf-sudo
x authorized_keys = first, heath
* heath
* normal user w/ special number
* /usr/bin/bash
* member of hpf-sudo
x authorized_keys = heath
Manually on each system:
* set hostname to fqdn
* set ansible branch if not production
* run bootstrap.yml
* update first password
iris.heath.hpetersenfamily.com admin-a.hpetersenfamily.com core.mary.hpetersenfamily.com
heath
authorized_keys:
- heath@hpetersenfamily.com
password:
status: VALID
value: COMMON STRONG FOR ALL HOSTS
first
authorized_keys:
- first@hpetersenfamily.com
- heath@hpetersenfamily.com
password:
status: VALID
value: UNIQUE LONG FOR EACH HOST
root
authorized_keys:
- heath@hpetersenfamily.com
password:
status: LOCKED
hpf-ans:
authorized_keys:
- heath@hpetersenfamily.com
password:
status: LOCKED
# Change the following to work with multiple distros (nothing hardcoded)
# Change to work with multiple distros (nothing hardcoded)
* create production, development branches
* have bootstrap.sh get ansible_pull_branch variable value
# add /home/hpf-ans/bin/ansible-pull.sh crontab
* cron job for ansible-pull
* Configure hosts
# cat >>/etc/hosts <<!!TheEnd!!
127.0.0.1 name.f.q.d.n name-ipv4.f.q.d.n name name-ipv4
# cat >>/etc/hosts <<-!!TheEnd!!
::1 name.f.q.d.n name-ipv6.f.q.d.n name name-ipv6
!!TheEnd!!
* Configure chrony
# cat >/etc/chrony/sources.d/hpetersenfamily-north-america.sources <<!!TheEnd!!
pool 0.north-america.pool.ntp.org iburst
!!TheEnd!!
* Configure SSH
# cat >/etc/ssh/sshd_config.d/hpetersenfamily.conf <<!!TheEnd!!
PasswordAuthentication no
PermitEmptyPasswords no
PermitRootLogin no
!!TheEnd!!
# cat >>/home/first/.ssh/authorized_keys <<!!TheEnd!!
ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBM5BBUOxkuSK7WlpaDvp6lrM9ajLSyh4PWD7VFzYOFN5/zfafy6Vf/oxtLE4UACw5ZGvBMQNH40bW+T9aO0lQ9g= first Heath@HPetersenFamily.com
ecdsa-sha2-nistp256 AAAAE2VjZHNhLXNoYTItbmlzdHAyNTYAAAAIbmlzdHAyNTYAAABBBBFiio/AimTUloJdfk4TXyWO7A0Fd9SoUcqheBjEvj4TnrxpSL/EhwF2CU9jZTasm6NBo2eKcH4aMt1l2ejOtIM= heath Heath@HPetersenFamily.com
127.0.0.1 name.f.q.d.n name-ipv4.f.q.d.n name name-ipv4
!!TheEnd!!
@@ -75,30 +68,14 @@ x hpf-ans
pkg:
- chrony
#- name: Set host name
# ansible.builtin.hostname:
# name: ## Fully qualified domain name ##
# use: systemd
* Configure chrony
# cat >/etc/chrony/sources.d/hpetersenfamily-north-america.sources <<!!TheEnd!!
pool 0.north-america.pool.ntp.org iburst
!!TheEnd!!
proxmox-clients
hw:
pve-lxc:
pve-oci:
pve-kvm:
~heath/.ssh/heath ## WARNING - SeCrEt! - Make sure this is not in the repo! - Does this need to be on every machine?
~heath/.ssh/authorized_keys
~first/.ssh/authorized_keys
~heath/.gitconfig
fail2ban
uptime kuma
@@ -106,9 +83,5 @@ uptime kuma
==============================================================
==============================================================
logrotate /var/log/ansible-pull.log
cron job for ansible-pull
use tags to do things like allow selecting software updates, software cleanup, etc.
+28
View File
@@ -0,0 +1,28 @@
---
- name: Create user
hosts: all
tasks:
- name: Create the second user
become: true
ansible.builtin.user:
name: second
comment: second User
state: present
system: false
groups: hpf-sudo-np
append: true
create_home: true
shell: /usr/bin/bash
uid: 60002
- name: Set second's authorized_keys
become: true
ansible.posix.authorized_key:
user: second
state: present
key: "{{ lookup('file', item) }}"
loop:
- files/ssh-keys/second.pub
- files/ssh-keys/heath.pub
+257
View File
@@ -0,0 +1,257 @@
#!/usr/bin/env bash
#
# Serialize bash variables to JSON output
#
# # Created
# Author: Dave Eddy <ysap@daveeddy.com>
# Date: July 09, 2026
# License: MIT
#
# # Contributors
# - Dave Eddy <ysap@daveeddy.com>
_jv-usage() {
local usage
read -r -d '' usage <<-EOF
Usage: jsonvar [-aev] [[name], ...]
Serialize bash variables to JSON output
Options
-a show all variables
-e show only exported variables
-v show only the values of the variables
-h show this message and exit
EOF
echo "$usage"
}
_jv-json-encode-string() {
local s=$1
local LC_ALL=C
local -A table=()
# we can start at 1 because bash variables can't have nul bytes in them
local hex byte esc i
for ((i = 1; i < 0x20; i++)); do
printf -v hex '%02x' "$i"
printf -v byte '%b' "\\x$hex"
printf -v esc '\\u%04x' "$i"
table[$byte]=$esc
done
table[$'\b']='\b'
table[$'\t']='\t'
table[$'\n']='\n'
table[$'\f']='\f'
table[$'\r']='\r'
table['\']='\\'
table['"']='\"'
# serialize the string
local out=''
local len=${#s}
local c
for ((i = 0; i < len; i++)); do
c=${s:i:1}
esc=${table[$c]}
if [[ -n $esc ]]; then
# lookup table matched for this byte
out+=$esc
else
# no lookup table match, byte falls through
out+=$c
fi
done
printf '"%s"' "$out"
}
_jv-encode-variable() {
local _jv_name=$1
local -n _jv_ref=$_jv_name
local _jv_attrs=${_jv_ref@a}
case "$_jv_attrs" in
*a*) # process indexed array
echo -n '['
local _jv_value _jv_i=0
for _jv_value in "${_jv_ref[@]}"; do
((_jv_i++))
# check member type
if [[ $_jv_attrs == *i* ]]; then
printf '%d' "$_jv_value"
else
_jv-json-encode-string "$_jv_value"
fi
if ((_jv_i < ${#_jv_ref[@]})); then
echo -n ', '
fi
done
echo -n ']'
;;
*A*) # process associative array
echo -n '{'
local _jv_key _jv_value _jv_i=0
for _jv_key in "${!_jv_ref[@]}"; do
((_jv_i++))
_jv_value=${_jv_ref[$_jv_key]}
_jv-json-encode-string "$_jv_key"
echo -n ': '
if [[ $_jv_attrs == *i* ]]; then
printf '%d' "$_jv_value"
else
_jv-json-encode-string "$_jv_value"
fi
if ((_jv_i < ${#_jv_ref[@]})); then
echo -n ', '
fi
done
echo -n '}'
;;
*i*) # process integer
echo -n "$_jv_ref"
;;
*) # anything else, it's probably a string lol
_jv-json-encode-string "$_jv_ref"
;;
esac
}
jsonvar() {
local _jv_all='false'
local _jv_exported='false'
local _jv_value='false'
# get arguments from user
local OPTIND OPTARG _jv_opt
while getopts 'aevh' _jv_opt; do
case "$_jv_opt" in
a) _jv_all='true';;
e) _jv_exported='true';;
v) _jv_value='true';;
h) _jv-usage; return 0;;
*) _jv-usage >&2; return 2;;
esac
done
shift "$((OPTIND - 1))"
local _jv_key
# figure out what variables to look at
local -a _jv_variables
if $_jv_all; then
readarray -t _jv_variables < <(compgen -v)
elif $_jv_exported; then
readarray -t _jv_variables < <(compgen -e)
else
_jv_variables=("$@")
# ensure the user gave us *something*
if (( ${#_jv_variables[@]} == 0 )); then
echo 'variable name or flag required' >&2
_jv-usage >&2
return 2
fi
# check variables given
local _jv_error='false'
for _jv_key in "${_jv_variables[@]}"; do
# warn the user if they gave us an internal name
if [[ $_jv_key == _jv_* ]]; then
echo "[error] invalid internal variable '$_jv_key'" >&2
_jv_error='true'
fi
# check to make sure the variable is defined
if ! declare -p "$_jv_key" &>/dev/null; then
echo "[error] variable '$_jv_key' not defined" >&2
_jv_error='true'
fi
done
if $_jv_error; then
return 1
fi
fi
# loop the variables first to filter out hidden / internal var names
local _jv_i
local _jv_len=${#_jv_variables[@]}
for ((_jv_i = 0; _jv_i < _jv_len; _jv_i++)); do
_jv_key=${_jv_variables[_jv_i]}
# filter out internal variables by name
if [[ $_jv_key == _jv_* ]]; then
unset '_jv_variables[_jv_i]'
continue
fi
# variable name was good, do nothing
done
# loop the remaining variables and format them
$_jv_value || echo '{'
_jv_i=0
for _jv_key in "${_jv_variables[@]}"; do
((_jv_i++))
if ! $_jv_value; then
# indent
echo -n ' '
# print the key
_jv-json-encode-string "$_jv_key"
echo -n ': '
fi
# print the value
_jv-encode-variable "$_jv_key"
# optionally print the comma
if ! $_jv_value && ((_jv_i < ${#_jv_variables[@]})); then
echo -n ','
fi
echo
done
$_jv_value || echo '}'
}
_jv-complete() {
COMPREPLY=(
# add all variables
$(compgen -v -- "${COMP_WORDS[COMP_CWORD]}")
# add the individual flags
$(compgen -W '-a -e -v -h' -- "${COMP_WORDS[COMP_CWORD]}")
)
}
if ( return 0 &>/dev/null ); then
# we are being sourced
complete -F _jv-complete jsonvar
else
# we are being executed directly
declare -a test_indexed=(a b c)
declare -a test_sparse=(a b c [67]=d)
declare -A test_assoc=([a]=1 [b]=2 [c]=3)
declare -i test_int=67
declare -- test_string='hello world'
declare -ai test_indexed_ints=(0 1 2 0xff foo bar baz)
declare -Ai test_assoc_ints=([foo]=0 [bar]=1 [baz]=0xff [bat]=foo)
jsonvar "$@"
fi
+11
View File
@@ -0,0 +1,11 @@
#!/usr/bin/env bash
send_some_output() {
echo "hello"
echo "here"
echo "goodbye"
}
exec > >(tee -a ./x.out) 2>&1
send_some_output >&2
+9 -14
View File
@@ -1,34 +1,29 @@
---
- name: test-get_hpf_facts.yml
- name: test-get-hpf-facts.yml
hosts: all
tasks:
- name: Copy over get_hpf_facts.sh
- name: Copy over get-hpf-facts.sh
ansible.builtin.copy:
src: hpf-ans/bin/get_hpf_facts.sh
dest: bin/get_hpf_facts.sh
src: home/hpf-ans/bin/get-hpf-facts.sh
dest: bin/get-hpf-facts.sh
owner: hpf-ans
group: hpf-ans
mode: u=rwx,go=gx
backup: true
- name: Run get_hpf_facts.sh
- name: Run get-hpf-facts.sh
ansible.builtin.command:
cmd: bin/get_hpf_facts.sh {{ ansible_facts["os_family"] }}
register: hpf_facts
cmd: bin/get-hpf-facts.sh {{ ansible_facts["os_family"] }}
register: registered_hpf_facts
changed_when: false
- name: Convert k=v stdout into facts
ansible.builtin.set_fact:
"{{ item.split('=', 1)[0] }}": "{{ item.split('=', 1)[1] }}"
loop: "{{ hpf_facts.stdout.splitlines() }}"
- name: Print all variables
ansible.builtin.debug:
var: hostvars[inventory_hostname]
hpf_facts: "{{ registered_hpf_facts.stdout | from_json }}"
- name: Print skel
ansible.builtin.debug:
var: hpf_fact_skel
var: hpf_facts.skel