From 633b26f380b048f46c87702f6e14a7503573a30a Mon Sep 17 00:00:00 2001 From: mrjk Date: Sat, 26 Apr 2025 01:30:44 -0400 Subject: [PATCH] add: Base code --- galaxy.yml | 62 +++ roles/nfs_client/tasks/main.yml | 31 ++ roles/nfs_server/handlers/main.yml | 9 + roles/nfs_server/tasks/main.yml | 22 + roles/nfs_server/templates/exports.j2 | 18 + roles/os_base/defaults/main.yml | 6 + roles/os_base/tasks/main.yml | 96 ++++ roles/os_disks/defaults/main.yml | 4 + roles/os_disks/files/setup_lvm_devices.sh | 38 ++ roles/os_disks/tasks/main.yml | 76 +++ roles/os_tweaks/files/bash_profile | 575 ++++++++++++++++++++++ roles/os_tweaks/files/gitconfig | 103 ++++ roles/os_tweaks/files/skel_bashrc | 27 + roles/os_tweaks/files/vimrc | 24 + roles/os_tweaks/tasks/main.yml | 27 + roles/os_update/defaults/main.yml | 7 + roles/os_update/tasks/main.yml | 19 + 17 files changed, 1144 insertions(+) create mode 100644 galaxy.yml create mode 100644 roles/nfs_client/tasks/main.yml create mode 100644 roles/nfs_server/handlers/main.yml create mode 100644 roles/nfs_server/tasks/main.yml create mode 100644 roles/nfs_server/templates/exports.j2 create mode 100644 roles/os_base/defaults/main.yml create mode 100644 roles/os_base/tasks/main.yml create mode 100644 roles/os_disks/defaults/main.yml create mode 100755 roles/os_disks/files/setup_lvm_devices.sh create mode 100644 roles/os_disks/tasks/main.yml create mode 100644 roles/os_tweaks/files/bash_profile create mode 100644 roles/os_tweaks/files/gitconfig create mode 100644 roles/os_tweaks/files/skel_bashrc create mode 100644 roles/os_tweaks/files/vimrc create mode 100644 roles/os_tweaks/tasks/main.yml create mode 100644 roles/os_update/defaults/main.yml create mode 100644 roles/os_update/tasks/main.yml diff --git a/galaxy.yml b/galaxy.yml new file mode 100644 index 0000000..7a9d583 --- /dev/null +++ b/galaxy.yml @@ -0,0 +1,62 @@ +### REQUIRED +# The namespace of the collection. This can be a company/brand/organization or product namespace under which all +# content lives. May only contain alphanumeric lowercase characters and underscores. Namespaces cannot start with +# underscores or numbers and cannot contain consecutive underscores +namespace: mrjk + +# The name of the collection. Has the same character restrictions as 'namespace' +name: debian + +# The version of the collection. Must be compatible with semantic versioning +version: 1.0.0 + +# The path to the Markdown (.md) readme file. This path is relative to the root of the collection +readme: README.md + +# A list of the collection's content authors. Can be just the name or in the format 'Full Name (url) +# @nicks:irc/im.site#channel' +authors: +- your name + + +### OPTIONAL but strongly recommended +# A short summary description of the collection +description: your collection description + +# Either a single license or a list of licenses for content inside of a collection. Ansible Galaxy currently only +# accepts L(SPDX,https://spdx.org/licenses/) licenses. This key is mutually exclusive with 'license_file' +license: +- GPL-2.0-or-later + +# The path to the license file for the collection. This path is relative to the root of the collection. This key is +# mutually exclusive with 'license' +license_file: '' + +# A list of tags you want to associate with the collection for indexing/searching. A tag name has the same character +# requirements as 'namespace' and 'name' +tags: [] + +# Collections that this collection requires to be installed for it to be usable. The key of the dict is the +# collection label 'namespace.name'. The value is a version range +# L(specifiers,https://python-semanticversion.readthedocs.io/en/latest/#requirement-specification). Multiple version +# range specifiers can be set and are separated by ',' +dependencies: {} + +# The URL of the originating SCM repository +repository: http://example.com/repository + +# The URL to any online docs +documentation: http://docs.example.com + +# The URL to the homepage of the collection/project +homepage: http://example.com + +# The URL to the collection issue tracker +issues: http://example.com/issue/tracker + +# A list of file glob-like patterns used to filter any files or directories that should not be included in the build +# artifact. A pattern is matched from the relative path of the file or directory of the collection directory. This +# uses 'fnmatch' to match the files or directories. Some directories and files like 'galaxy.yml', '*.pyc', '*.retry', +# and '.git' are always filtered +build_ignore: [] + diff --git a/roles/nfs_client/tasks/main.yml b/roles/nfs_client/tasks/main.yml new file mode 100644 index 0000000..535f85c --- /dev/null +++ b/roles/nfs_client/tasks/main.yml @@ -0,0 +1,31 @@ +--- + +- name: Ensure NFS utilities are installed. + package: + name: "{{ item }}" + state: present + with_items: + - nfs-common + +- name: Create mount directories + ansible.builtin.file: + path: "{{ item.path }}" + state: directory + loop: "{{ nfs_mounts }}" + vars: + path: "{{ item.path }}" + +- name: Mount NFS volumes + ansible.posix.mount: + path: "{{ path }}" + src: "{{ src }}" + fstype: "{{ fstype }}" + state: "{{ state }}" + loop: "{{ nfs_mounts }}" + vars: + state: "{{ item.state | default('mounted') }}" + fstype: nfs + src: "{{ nfs_server }}:{{ item.src }}" + path: "{{ item.path }}" + + diff --git a/roles/nfs_server/handlers/main.yml b/roles/nfs_server/handlers/main.yml new file mode 100644 index 0000000..b7e67ce --- /dev/null +++ b/roles/nfs_server/handlers/main.yml @@ -0,0 +1,9 @@ +--- + +- name: Restart NFS server + service: + name: nfs-kernel-server + state: restarted + ignore_errors: "{{ ansible_check_mode }}" + + diff --git a/roles/nfs_server/tasks/main.yml b/roles/nfs_server/tasks/main.yml new file mode 100644 index 0000000..2e84f50 --- /dev/null +++ b/roles/nfs_server/tasks/main.yml @@ -0,0 +1,22 @@ +--- + +# yamllint disable-line rule:line-length +# See: https://advishnuprasad.com/blog/2016/03/29/setup-nfs-server-and-client-using-ansible/ + +- name: Ensure NFS utilities are installed. + package: + name: "{{ item }}" + state: present + with_items: + - nfs-common + - nfs-kernel-server + +- name: copy /etc/exports + template: + src: exports.j2 + dest: /etc/exports + owner: root + group: root + notify: + - Restart NFS server + diff --git a/roles/nfs_server/templates/exports.j2 b/roles/nfs_server/templates/exports.j2 new file mode 100644 index 0000000..6da3ad4 --- /dev/null +++ b/roles/nfs_server/templates/exports.j2 @@ -0,0 +1,18 @@ +# Managed by Ansible +# /etc/exports: the access control list for filesystems which may be exported +# to NFS clients. See exports(5). +# +# Example for NFSv2 and NFSv3: +# /srv/homes hostname1(rw,sync,no_subtree_check) hostname2(ro,sync,no_subtree_check) +# +# Example for NFSv4: +# /srv/nfs4 gss/krb5i(rw,sync,fsid=0,crossmnt,no_subtree_check) +# /srv/nfs4/homes gss/krb5i(rw,sync,no_subtree_check) +# + +{% for share in nfs_shares %} +# {{ share.desc | default(share.path) }} +{{ share.path }} {{ share.allow }}({{ share.options }}) + +{% endfor %} + diff --git a/roles/os_base/defaults/main.yml b/roles/os_base/defaults/main.yml new file mode 100644 index 0000000..a9ae966 --- /dev/null +++ b/roles/os_base/defaults/main.yml @@ -0,0 +1,6 @@ +--- + +system_accounts: [] +system_packages: [] +system_packages_norecommend: false +system_packages_nosuggest: false diff --git a/roles/os_base/tasks/main.yml b/roles/os_base/tasks/main.yml new file mode 100644 index 0000000..453eb4c --- /dev/null +++ b/roles/os_base/tasks/main.yml @@ -0,0 +1,96 @@ +--- + +# Configure groups and users +# ========================== + +- name: Ensure system security groups exists + ansible.builtin.group: + name: "{{ item }}" + state: present + system: true + loop: + - wheel + - sudo + +- name: Create users + user: + name: "{{ item.name }}" + append: true + groups: "{{ item.groups | default([]) }}" + state: "{{ item.state | default('present') }}" + shell: "{{ item.shell | default('/bin/bash') }}" + system: "{{ item.system | default(False) }}" + comment: "{{ item.comment | default(omit) }}" + createhome: true + home: "{{ item.home | default('/home/' + item.name ) }}" + uid: "{{ item.uid | default(omit) }}" + loop: "{{ system_accounts }}" + +- name: Deploy all ssh keys + ansible.posix.authorized_key: + user: "{{ user_name }}" + state: "{{ sshkey_state }}" + key: "{{ sshkey }}" + follow: true + path: "{{ home_dir }}/.ssh/authorized_keys" + loop: "{{ system_accounts|selectattr('sshkeys', 'defined') | subelements('sshkeys') }}" + vars: + user_name: "{{ item.0.name }}" + home_dir: "{{ item.0.home | default('/home/' + item.0.name ) }}" + sshkey_state: "{{ item.0.sshkey_state | default('present') }}" + sshkey: "{{ item.1 }}" + + +# Configure package manager +# ========================== + +- name: Configure APT preferences + copy: + dest: "/etc/apt/apt.conf.d/{{ item.name }}" + content: "{{ item.content }}" + loop: + - name: 01-norecommend + content: | + APT::Install-Recommends "{{ system_packages_norecommend | bool | ternary(0, 1) }}"; + - name: 02-suggest + content: | + APT::Install-Suggests "{{ system_packages_nosuggest | bool | ternary(0, 1) }}"; + +- name: Install base tools + package: + name: "{{ system_packages }}" + ignore_errors: "{{ ansible_check_mode }}" + + +# Configure sudo +# ============== + +- name: Prepare sudo config for wheel group + copy: + dest: "/etc/sudoers.d/wheel" + mode: "0440" + content: | + Defaults:%wheel !requiretty + %wheel ALL=(ALL) NOPASSWD: ALL + +- name: Add managed users to sudo with password + user: + name: "{{ item.name }}" + append: true + groups: + - sudo + with_items: "{{ system_accounts }}" + when: "'sudo' in perm" + vars: + perm: "{{ item.permissions | default([]) }}" + +- name: Add managed users to sudo without password + user: + name: "{{ system_accounts[0].name }}" + append: true + groups: + - wheel + when: "'sudo_nopass' in perm" + vars: + perm: "{{ item.permissions | default([]) }}" + diff --git a/roles/os_disks/defaults/main.yml b/roles/os_disks/defaults/main.yml new file mode 100644 index 0000000..4fe4dbf --- /dev/null +++ b/roles/os_disks/defaults/main.yml @@ -0,0 +1,4 @@ +--- + +disks_vg: [] +disks_lv: [] diff --git a/roles/os_disks/files/setup_lvm_devices.sh b/roles/os_disks/files/setup_lvm_devices.sh new file mode 100755 index 0000000..12552fe --- /dev/null +++ b/roles/os_disks/files/setup_lvm_devices.sh @@ -0,0 +1,38 @@ +#!/bin/bash +# Requires: lvm2 parted + +set -eu + +get_uuid () +{ + blkid -s UUID -o value $1 +} + +disk_init () +{ + local dev=$1 + + echo "INFO: Init devide $dev ..." + pvcreate "$dev" + + local uuid=$(get_uuid "$dev") + echo "INFO: Device id of $dev is $uuid" + echo "INFO: Device path id is /dev/disk/by-id/lvm-pv-uuid-$uuid" + +} + +main () +{ + local devices=$(ls -1 /dev/vd[a-z] | sort) + + for dev in $devices; do + if ! blkid "$dev" &>/dev/null; then + disk_init $dev + else + echo "INFO: Device path id for $dev: $(get_uuid $dev)" + fi + done + partprobe +} + +main $@ diff --git a/roles/os_disks/tasks/main.yml b/roles/os_disks/tasks/main.yml new file mode 100644 index 0000000..f5192cf --- /dev/null +++ b/roles/os_disks/tasks/main.yml @@ -0,0 +1,76 @@ +--- + +- name: Ensure LVM is installed. + package: + name: + - lvm2 + - parted + state: present + +# This should be the way, as it is not possible with cloudinit ... +- name: Copy lvm volume detector script + copy: + src: setup_lvm_devices.sh + dest: /usr/local/sbin/setup_lvm_devices.sh + mode: "755" + +- name: Ensure presence of all VG + community.general.lvg: + vg: "{{ vg }}" + pvs: "{{ pvs }}" + pvresize: true + state: "{{ state }}" + loop: "{{ disks_vg }}" + vars: + state: "{{ item.state | default('present') }}" + vg: "{{ item.vg }}" + # pvs: "{{ ['/dev/disk/by-id/lvm-pv-uuid-']|product(item.devices_id) | map('join') | join(',') }}" + pvs: "{{ item.devices_dev | join(',') }}" + ignore_errors: "{{ ansible_check_mode }}" + +- name: Create logical volumes + community.general.lvol: + vg: "{{ vg }}" + lv: "{{ lv }}" + size: "{{ size }}" + shrink: false + state: "{{ state }}" + loop: "{{ disks_lv }}" + vars: + state: "{{ item.state | default('present') }}" + lv: "{{ item.lv }}" + vg: "{{ item.vg }}" + size: "{{ item.size }}" + ignore_errors: "{{ ansible_check_mode }}" + +- name: Create file systems + community.general.filesystem: + fstype: "{{ fstype }}" + dev: "{{ dev }}" + resizefs: false + force: false + state: "{{ state }}" + loop: "{{ disks_lv }}" + vars: + state: "{{ item.state | default('present') }}" + fstype: "{{ item.fstype | default('ext4') }}" + dev: "/dev/{{ item.vg }}/{{ item.lv }}" + size: "{{ item.size | default ('1G') }}" + ignore_errors: "{{ ansible_check_mode }}" + +- name: Mount file systems + ansible.posix.mount: + path: "{{ path }}" + src: "{{ src }}" + fstype: "{{ fstype }}" + # opts: ro,noauto + state: "{{ state }}" + loop: "{{ disks_lv }}" + vars: + state: "{{ item.state | default('mounted') }}" + fstype: "{{ item.fstype | default('ext4') }}" + src: "/dev/{{ item.vg }}/{{ item.lv }}" + path: "/{{ item.lv | replace('_', '/') }}" + ignore_errors: "{{ ansible_check_mode }}" + + diff --git a/roles/os_tweaks/files/bash_profile b/roles/os_tweaks/files/bash_profile new file mode 100644 index 0000000..019c755 --- /dev/null +++ b/roles/os_tweaks/files/bash_profile @@ -0,0 +1,575 @@ +########################## +# Initialisation +########################## + +# To live try: +# source <( curl https://raw.githubusercontent.com/mrjk/linux-personal-env/master/bash/bash.bashrc) +# To install locally +# curl https://raw.githubusercontent.com/mrjk/linux-personal-env/master/bash/bash.bashrc > ~/.bashrc + +# If not running interactively, don't do anything +case $- in + *i*) + ;; + *) + return + ;; +esac + + +########################## +# Func: Global variables +########################## + +shell_global_variable () { + HOSTNAME=$(head -n 1 /etc/hostname) + + # Custom variables + ########################## + + # Regex to match IP + RGX_IP='(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)' + RGX_IP='([0-2][0-9]{2}\.){3}' + + # Regex to match emplty lines and comments ... use with grep -E -v + RGX_EL='^[[:blank:]]*#|^$' + + # Match a username + RGX_USER='[a-z0-9-]' + + # Match a domain ANSI + RGX_DOM='([a-z][a-z0-9\-]+(\.|\-*\.))+[a-z]{2,6}' + RGX_DOM='[a-z0-9-]+(\.[a-z0-9-]+)?\.[a-z0-9-]{2,6}' + + # Match Hexadecimal, + RGX_HEX='#?([a-f0-9]{6}|[a-f0-9]{3})' + + # Match email + RGX_EMAIL='([a-z0-9_\.-]+)@([\da-z\.-]+)\.([a-z\.]{2,6})' + + # Match URL + RGX_URL='(https?:\/\/)?([\da-z\.-]+)\.([a-z\.]{2,6})([\/\w \.-]*)*\/?' +} + + +########################## +# Func: Global color +########################## + +shell_global_color () { + # Easy + RED='\[\033[31m\]' + GREEN='\[\033[32m\]' + YELLOW='\[\033[33m\]' + BLUE='\[\033[34m\]' + PURPLE='\[\033[35m\]' + CYAN='\[\033[36m\]' + WHITE='\[\033[37m\]' + NIL='\[\033[00m\]' + + # Reset + Color_Off='\e[0m' # Text Reset + + # Regular Colors + Black='\e[0;30m' # Black + Red='\e[0;31m' # Red + Green='\e[0;32m' # Green + Yellow='\e[0;33m' # Yellow + Blue='\e[0;34m' # Blue + Purple='\e[0;35m' # Purple + Cyan='\e[0;36m' # Cyan + White='\e[0;37m' # White + + # Bold + BBlack='\e[1;30m' # Black + BRed='\e[1;31m' # Red + BGreen='\e[1;32m' # Green + BYellow='\e[1;33m' # Yellow + BBlue='\e[1;34m' # Blue + BPurple='\e[1;35m' # Purple + BCyan='\e[1;36m' # Cyan + BWhite='\e[1;37m' # White + + # Underline + UBlack='\e[4;30m' # Black + URed='\e[4;31m' # Red + UGreen='\e[4;32m' # Green + UYellow='\e[4;33m' # Yellow + UBlue='\e[4;34m' # Blue + UPurple='\e[4;35m' # Purple + UCyan='\e[4;36m' # Cyan + UWhite='\e[4;37m' # White + + # Background + On_Black='\e[40m' # Black + On_Red='\e[41m' # Red + On_Green='\e[42m' # Green + On_Yellow='\e[43m' # Yellow + On_Blue='\e[44m' # Blue + On_Purple='\e[45m' # Purple + On_Cyan='\e[46m' # Cyan + On_White='\e[47m' # White + + # High Intensity + IBlack='\e[0;90m' # Black + IRed='\e[0;91m' # Red + IGreen='\e[0;92m' # Green + IYellow='\e[0;93m' # Yellow + IBlue='\e[0;94m' # Blue + IPurple='\e[0;95m' # Purple + ICyan='\e[0;96m' # Cyan + IWhite='\e[0;97m' # White + + # Bold High Intensity + BIBlack='\e[1;90m' # Black + BIRed='\e[1;91m' # Red + BIGreen='\e[1;92m' # Green + BIYellow='\e[1;93m' # Yellow + BIBlue='\e[1;94m' # Blue + BIPurple='\e[1;95m' # Purple + BICyan='\e[1;96m' # Cyan + BIWhite='\e[1;97m' # White + + # High Intensity backgrounds + On_IBlack='\e[0;100m' # Black + On_IRed='\e[0;101m' # Red + On_IGreen='\e[0;102m' # Green + On_IYellow='\e[0;103m' # Yellow + On_IBlue='\e[0;104m' # Blue + On_IPurple='\e[0;105m' # Purple + On_ICyan='\e[0;106m' # Cyan + On_IWhite='\e[0;107m' # White +} + + +########################## +# Func: shell PS1 +########################## + +# Full function wrapper +shell_ps1 () { + shell_ps1_advanced + #shell_ps1_simple +} + +# PS1 shell reset (in case of emergency) +shell_ps1_simple () { + PS1='\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$ ' + #PS1='$USER@$(hostname):$PWD\$ ' +} + +# Full function +shell_ps1_advanced () { + PS1_HOST_COLOR=${PS1_HOST_COLOR:-Green} + + # Define dynamic prompt variables (Fucking bashisms :-() + local PS1_RETURN="\$( + PS1_EXIT=\$?; + [[ \$PS1_EXIT == 0 ]] || echo -n \"\[$Red\]\${PS1_EXIT}\[${Color_Off}\] \" + )" + + local PS1_PATH="\$( + if [ -s \"\${PWD}\" ] ; then + # PS1_DF=\$(command df -P \"\${PWD}\" | grep -E -o '[0-9]{1,3}%' | grep -E -o '[0-9]{1,3}'); + PS1_DF=\$(command timeout 1s df -P \"\${PWD}\" | awk 'END {print \$5} {sub(/%/,\"\")}'); + + if [ \"\${PS1_DF:-0}\" -gt 95 ]; then + PS1_PATH=\"\[$Red\]:\" + elif [ \"\${PS1_DF:-0}\" -gt 90 ]; then + PS1_PATH=\"\[$Yellow\]:\" + else + PS1_PATH=\"\[$White\]:\" + fi + else + # Current directory is size '0' (like /proc, /sys etc). + PS1_PATH=\"\[$Yellow\]:\"; + fi + if [ -w \"\${PWD}\" ] ; then + PS1_PATH=\"\${PS1_PATH}\[$Blue\]\w\" + else + # No 'write' privilege in the current directory. + PS1_PATH=\"\${PS1_PATH}\[$Yellow\]\w\" + fi + + echo -e \"\${PS1_PATH}\" + )" + + # Get jobs + local PS1_JOBS="\$( + PS1_JOBS=''; + PS1_JOBS_RUNNING=\$(jobs -r | wc -l); + PS1_JOBS_STOPPED=\$(jobs -s | wc -l); + if [ \${PS1_JOBS_RUNNING} -gt 0 ] || [ \${PS1_JOBS_STOPPED} -gt 0 ] + then + if [ \${PS1_JOBS_RUNNING:-0} -gt 0 ]; then + PS1_JOBS_RUNNING=\"\[$Green\]\${PS1_JOBS_RUNNING}\[$Color_Off\]\" + else + PS1_JOBS_RUNNING='' + fi + + if [ \${PS1_JOBS_STOPPED:-0} -gt 0 ]; then + PS1_JOBS_STOPPED=\"\[$Yellow\]\${PS1_JOBS_STOPPED}\[$Color_Off\]\" + else + PS1_JOBS_STOPPED='' + fi + PS1_JOBS=\"\${PS1_JOBS_RUNNING}:\${PS1_JOBS_STOPPED} \"; + else + PS1_JOBS='' + fi + echo -e \"\${PS1_JOBS}\"; + )" + + # Time execution checker + + # Maximal time to consider prompt as slow in ms + local PS1_MAX_EXEC_TIME=500 + # Number of time needed before swithing to basic prompt + local PS1_MAX_TIME=3 + # Time windows to check + local PS1_MAX_EXEC_DELAY=60 + # Time before reloading full PS1 after showing simple prompt + local PS1_DELAY_RELOAD=300 + + # Debug +# local PS1_MAX_EXEC_TIME=5 +# local PS1_MAX_TIME=3 +# local PS1_MAX_EXEC_DELAY=60 +# local PS1_DELAY_RELOAD=30 + + local PS1_TMP_FILE=/tmp/.load-$(whoami) + chown $(whoami):$(whoami) ${PS1_TMP_FILE} 2>/dev/null + local PS1_START="\$( + if [ -f ${PS1_TMP_FILE} ] && [ \"\$(cat ${PS1_TMP_FILE} | grep -E -o '^reset')\" = \"reset\" ] + then + echo '\u@\h:\[\033[01;34m\]\w\[\033[00m\]\\$ ' + if [ \$((\$(date +%s) - \$(stat -c %Y ${PS1_TMP_FILE}) )) -gt ${PS1_DELAY_RELOAD} ] + then + echo -n \"Shell: full prompt reactivated.\n\" + > ${PS1_TMP_FILE}; + fi + else + ts=\$(date +%s%N); + echo -e \"" + local PS1_STOP="\"; + tt=\$(((\$(date +%s%N) - \${ts})/1000000)); + if [ \${tt} -gt ${PS1_MAX_EXEC_TIME} ] + then + echo 1 >> ${PS1_TMP_FILE}; + if [ \$((\$(date +%s) - \$(stat -c %Y ${PS1_TMP_FILE}) )) -gt ${PS1_MAX_EXEC_DELAY} ] || [ \$(wc -l ${PS1_TMP_FILE} | grep -E -o '^[0-9]{1,3}') -gt ${PS1_MAX_TIME} ] + then + echo "reset" > ${PS1_TMP_FILE}; + echo -n \"Shell: prompt is taking more than ${PS1_MAX_EXEC_TIME}ms to anwser. Normal prompt will be reactivated in ${PS1_DELAY_RELOAD}s. Execute 'rm ${PS1_TMP_FILE}' to force.\n\" ; + fi + fi + fi + )" + + # Define static prompt variables + local PS1_ACOUNT="\[$White\]\\$ " + local PS1_CHROOT_DEB="${debian_chroot:+($debian_chroot)}" + + # Set variable identifying the chroot you work in (used in the prompt below) + local debian_chroot= + if [ -z "${debian_chroot:-}" ] && [ -r /etc/debian_chroot ]; then + debian_chroot=$(cat /etc/debian_chroot) + fi + + # Define sudo detection + local PS1_SUDO="\[$Color_Off\]@" + if [ ! -z "${SUDO_USER-}" ]; then + PS1_SUDO="\[$Cyan\]@\[$Color_Off\]" + fi + + # Define prompt depending user + local PS1_USER="\u" + if [ $(id -u) -eq 0 ]; + then # you are root, make the prompt red + # Are you root ? + PS1_USER="\[$Yellow\]\u" + # In green + if [ -z "${SUDO_USER-}" ]; then + PS1_SUDO="\[$Red\]@\[$Color_Off\]" + fi + elif [ -n "$(cat /etc/passwd | grep $(whoami) | grep -E -v ':/bin/(ba|z|t)?sh')" ]; then + # The you are a no login user ... + PS1_USER="\[$Red\]\u" + # In red + elif [ $(id -u) -lt 1000 ]; then + # Are you a system user ? + PS1_USER="\[$White\]\u" + # In orange + elif [ $(id -u) -ge 1000 ]; then + # Are you a regular user ? + PS1_USER="\[$Cyan\]\u" + # In white + fi + + # Detect serial connection (virtualisation, ttySx) + local PS1_HOST="$PS1_SUDO\[${!PS1_HOST_COLOR}\]\h" + if [ $(ps ax | grep $$ | awk '{ print $2 }' | grep 'ttyS.' | wc -l ) -gt 0 ]; then + PS1_HOST="$PS1_SUDO\[$Red\]\h" + fi + + # Set the prompt depending the shell + if [ "${CURRENT_SHELL}" = "bash" ]; then + PS1="\[$Color_Off\]${PS1_RETURN}${PS1_START}${PS1_JOBS}${PS1_USER}${PS1_HOST}${PS1_PATH}${PS1_ACOUNT}\[$Color_Off\]${PS1_STOP}" + elif [ "${CURRENT_SHELL}" = "dash" ] ; then + PS1='$USER@$HOSTNAME:$PWD\$ ' + else + PS1='${debian_chroot:+($debian_chroot)}\[\033[01;32m\]\u@\h\[\033[00m\]:\[\033[01;34m\]\w\[\033[00m\]\$ ' + fi +} + + +########################## +# Func: Bash alias +########################## + +bash_alias () { + alias ll='ls -lh' + alias la='ls -lAh' + alias l='ls -ClFh' + alias ltr='ls -ahltr' + alias lsd="ls -l | grep ^d" + + alias mkdir='mkdir -p' + + alias ..='cd ..' + alias ...='cd ../..' + alias ....='cd ../..' + + alias h='history' + alias j='jobs -l' + + alias vih='vim /etc/hosts ' + alias vit='vim /etc/fstab ' + alias vif='vim /etc/network/interfaces ' + ! command -v colordiff >&/dev/null || alias diff='colordiff ' + alias tmount='mount |column -t ' + + alias wgets='wget --no-check-certificate ' + alias wgeth='wget --no-check-certificate -S -O /dev/null ' + alias uncmt="grep '^[^#|^$|^ *$]' " + alias monip='wget -q -O - "$@" monip.org | grep -o "[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}"' + alias monhost='echo "My host is ..."; host $(wget -q -O - "$@" monip.org | grep -o "[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}\.[0-9]\{1,3\}")' + alias text2ascii='tail --bytes=+4' + + alias iptlist='sudo /sbin/iptables -L -n -v --line-numbers' + alias iptlistin='sudo /sbin/iptables -L INPUT -n -v --line-numbers' + alias iptlistout='sudo /sbin/iptables -L OUTPUT -n -v --line-numbers' + alias iptlistfw='sudo /sbin/iptables -L FORWARD -n -v --line-numbers' + + # Typo correction + alias cd..='cd ..' + + # List directory when moving + #cd() { builtin cd "$@"; ll; } + + # Chroot helper + chroot_mount_system () { + if [ -d $1 ]; then + mount -t proc none $1/proc + mount -obind /dev $1/dev + mount -obind /sys $1/sys + echo "Then: chroot $1 /bin/bash " + else + echo "Usage: chroot_mount_system " + fi + } + + # SSH Helper + alias ssh_unsecure='ssh -o UserKnownHostsFile=/dev/null -o StrictHostKeyChecking=no CheckHostIP=no' + alias ssh_local='ssh -o CheckHostIP=no ' +} + + +########################## +# Func: Command not found +########################## + +bash_completion () { + + # SSH Host completion + if [ -e ~/.ssh/known_hosts ] ; then + complete -W "$(echo `cat ~/.ssh/known_hosts | cut -f 1 -d ' ' | sed -e s/,.*//g | uniq | grep -v "\["`;)" ssh + # Note: HashKnownHosts need to be set 'no' in /etc/ssh/ssh_config + fi + +} + + +########################## +# Func: Command not found +########################## + +shell_command_not_found () { + # if the command-not-found package is installed, use it + if [ -x /usr/lib/command-not-found -o -x /usr/share/command-not-found/command-not-found ]; then + command_not_found_handle () { + # check because c-n-f could've been removed in the meantime + if [ -x /usr/lib/command-not-found ]; then + /usr/bin/python /usr/lib/command-not-found -- "$1" + return $? + elif [ -x /usr/share/command-not-found/command-not-found ]; then + /usr/bin/python /usr/share/command-not-found/command-not-found -- "$1" + return $? + else + printf "%s: command not found\n" "$1" >&2 + return 127 + fi + } + fi +} + +########################## +# Func: Bash command color +########################## + +bash_command_color () { + + if [ -x /usr/bin/dircolors ]; then + test -r ~/.dircolors && eval "$(dircolors -b ~/.dircolors)" || eval "$(dircolors -b)" + alias ls='ls --color=auto' + alias dir='dir --color=auto' + alias vdir='vdir --color=auto' + + alias grep='grep --color=auto' + alias fgrep='fgrep --color=auto' + alias egrep='egrep --color=auto' + fi + + + if [ -x /usr/bin/colordiff ]; then + alias diff='colordiff' + fi + + + LESS_TERMCAP_mb=$'\E[01;31m' + LESS_TERMCAP_us=$'\E[01;32m' + LESS_TERMCAP_md=$'\E[01;31m' + LESS_TERMCAP_se=$'\E[0m' + LESS_TERMCAP_so=$'\E[01;44;33m' + LESS_TERMCAP_ue=$'\E[0m' + LESS_TERMCAP_me=$'\E[0m' + + # Colored GCC warnings and errors + export GCC_COLORS='error=01;31:warning=01;35:note=01;36:caret=01;32:locus=01:quote=01' + + # Ajout log en couleurs + ctail() { tail -f $1 | ccze -A; } + cless() { ccze -A < "$1" | less -R; } +} + + + +########################## +# Func: Bash config +########################## + + +bash_config () { + ########################## + # History management + ########################## + + # Force timestamp in history + export HISTTIMEFORMAT='%F %T ' + + # Ignore duplicates and lines starting by a space + export HISTCONTROL="" + + # Setting history to infinite see HISTSIZE and HISTFILESIZE in bash(1) + export HISTSIZE= + export HISTFILESIZE=10000 + + # Enable bash history if possible + if touch ~/.bash_history > /dev/null 2>&1 ; then + export HISTFILE=~/.bash_history + else + unset HISTFILE + fi + + + ########################## + # Misc + ########################## + + # Disable mail check + unset MAILCHECK + + # Update shell output according to the terminal size + shopt -s checkwinsize + + # Load other aliases + if [ -f ~/.bash_aliases ]; then + . ~/.bash_aliases + fi + + # Synchronise history + shopt -s histappend + export PROMPT_COMMAND="history -a" + + # Enable completion + if ! shopt -oq posix; then + if [ -f /usr/share/bash-completion/bash_completion ]; then + . /usr/share/bash-completion/bash_completion + elif [ -f /etc/bash_completion ]; then + . /etc/bash_completion + fi + fi + + # Bash correction + shopt -s autocd + shopt -s cdspell + shopt -s checkjobs + shopt -s hostcomplete + shopt -s nocaseglob + + # Environment vars + export EDITOR=vim + + # Pager config + if command -v most >&/dev/null; then + export MANPAGER='/usr/bin/most -S' + else + export MANPAGER='/usr/bin/less' + fi + +} + + + +########################## +# Function calls +########################## + +# Checking the shell +case $(readlink -f $SHELL) in + */zsh) + CURRENT_SHELL="zsh" + ;; + */bash) + CURRENT_SHELL="bash"; + ;; + */dash) + CURRENT_SHELL="dash"; + ;; + *) + # assume something else + CURRENT_SHELL="none" +esac + +# Preset +shell_global_variable +shell_global_color +shell_ps1 +shell_command_not_found + +bash_alias +bash_command_color + +if [ "${CURRENT_SHELL}" = "bash" ]; then + bash_config + bash_completion +fi + diff --git a/roles/os_tweaks/files/gitconfig b/roles/os_tweaks/files/gitconfig new file mode 100644 index 0000000..1a7197b --- /dev/null +++ b/roles/os_tweaks/files/gitconfig @@ -0,0 +1,103 @@ +#[user] +# email = myuser@domain.net +# name = My User + +[core] + pager = less -x2 + #hooksPath = ~/.config/git/hooks/ + +[credential] + # Keep in cache credentials 24h + helper = cache --timeout=86400 + +[push] + default = simple + +[color] + ui = auto + diff = auto + status = auto + branch = auto + all = auto + +[color "diff"] + whitespace = "red reverse" + +[color "branch"] + remote = yellow + +[alias] + + # Simple Aliases + st = status -sb + br = branch + bra = branch -av + brdr = push --delete + co = checkout + cob = checkout -b + c = commit --verbose + cm = commit -m + a = add + ap = add -p + wdiff = diff --color-words + + # Personal aliases + subup = submodule update --init + unstage = reset HEAD + rms = rm --cached + alias = "!git config -l | grep alias | cut -c 7-" + + # Log commands + l = log --pretty=oneline --abbrev-commit --graph --decorate --all --date-order --pretty=format:'%C(yellow)%h%Creset%C(auto)%d %Creset%s %C(dim)(%an, %cr)' + ll = log --graph --date=short --all --date-order + + # Show all references, even the lost ones + lll = log --pretty=oneline --abbrev-commit --graph --all --date-order --branches --reflog + + # Unecessary useless + rao = remote add origin + rs = remote show + rso = remote show origin + + # Workflow commands + sync = push -u origin --all + syncall = "!git fetch --all; git push -u origin --all" + wip = commit -am "WIP" + save = !git add -A && git commit -m 'SAVEPOINT' + wipe = !git add -A && git commit -qm 'WIPE SAVEPOINT' && git reset HEAD~1 --hard + + undo-commit = reset --soft HEAD~1 + undo = reset HEAD~1 --mixed + + # Advanced aliases + # quick-amend = !VISUAL=/bin/true git commit --amend + # sync = !git pull --rebase && git push + # merge-to = "!f() { local DEST=$1 ; shift ; local CURRENT=`git rev-parse --abbrev-ref HEAD` && git checkout "$DEST" && git merge "$CURRENT" $@ && git checkout "$CURRENT"; unset CURRENT; }; f" + + # ca = commit -a --verbose + # cam = commit -a -m + # m = commit --amend --verbose + # + # d = diff + # ds = diff --stat + # dc = diff --cached + # + # # list branches sorted by last modified + # b = "!git for-each-ref --sort='-authordate' --format='%(authordate)%09%(objectname:short)%09%(refname)' refs/heads | sed -e 's-refs/heads/--'" + # + +[url "https://github.com/"] + insteadOf = gh: + +[url "https://gist.github.com/"] + insteadOf = gist: + +[url "https://bitbucket.org/"] + insteadOf = bb: + +[status] + submoduleSummary = true + +[diff] + submodule = log + diff --git a/roles/os_tweaks/files/skel_bashrc b/roles/os_tweaks/files/skel_bashrc new file mode 100644 index 0000000..ebee754 --- /dev/null +++ b/roles/os_tweaks/files/skel_bashrc @@ -0,0 +1,27 @@ +# ~/.bashrc: executed by bash(1) for non-login shells. +# see /usr/share/doc/bash/examples/startup-files (in the package bash-doc) +# for examples + +# If not running interactively, don't do anything +case $- in + *i*) ;; + *) return;; +esac + +# Note: PS1 and umask are already set in /etc/profile. You should not +# need this unless you want different defaults for root. +# PS1='${debian_chroot:+($debian_chroot)}\h:\w\$ ' +# umask 022 + +# You may uncomment the following lines if you want `ls' to be colorized: +# export LS_OPTIONS='--color=auto' +# eval "`dircolors`" +# alias ls='ls $LS_OPTIONS' +# alias ll='ls $LS_OPTIONS -l' +# alias l='ls $LS_OPTIONS -lA' +# +# Some more alias to avoid making mistakes: +# alias rm='rm -i' +# alias cp='cp -i' +# alias mv='mv -i' + diff --git a/roles/os_tweaks/files/vimrc b/roles/os_tweaks/files/vimrc new file mode 100644 index 0000000..ecae374 --- /dev/null +++ b/roles/os_tweaks/files/vimrc @@ -0,0 +1,24 @@ + +" Base options +set showcmd " Show (partial) command in status line. +set showmatch " Show matching brackets. +set incsearch " Incremental search +set autowrite " Automatically save before commands like :next and :make +set ttymouse= " Disable mouse tty +set mouse= " Disable mouse for good + +" Color support +syntax on +set background=dark +set nu + +" Enable indentation rules per files +filetype plugin indent on + +" Vim sane tabs +set tabstop=2 +set shiftwidth=2 +set softtabstop=2 +set expandtab +set backspace=indent,eol,start " Proper backspace behavior. + diff --git a/roles/os_tweaks/tasks/main.yml b/roles/os_tweaks/tasks/main.yml new file mode 100644 index 0000000..f4bddb8 --- /dev/null +++ b/roles/os_tweaks/tasks/main.yml @@ -0,0 +1,27 @@ +--- + +- name: Ensure base packages are installed + package: + name: + - vim + - htop + - jq + - bash-completion + state: present + + +- name: Configure bash + copy: + src: bash_profile + dest: /etc/profile.d/bash_tweaks.sh + +- name: Configure git + copy: + src: gitconfig + dest: /etc/gitconfig + +- name: Configure vim + copy: + src: vimrc + dest: /etc/vim/vimrc.local + diff --git a/roles/os_update/defaults/main.yml b/roles/os_update/defaults/main.yml new file mode 100644 index 0000000..0ef72af --- /dev/null +++ b/roles/os_update/defaults/main.yml @@ -0,0 +1,7 @@ +--- + +os_apt_autoremove: false +os_apt_update: true +os_apt_upgrade: false + + diff --git a/roles/os_update/tasks/main.yml b/roles/os_update/tasks/main.yml new file mode 100644 index 0000000..e8cfc37 --- /dev/null +++ b/roles/os_update/tasks/main.yml @@ -0,0 +1,19 @@ +--- + +- name: Autoremove dependencies + apt: + autoremove: yes + when: os_apt_autoremove | bool + +- name: Update systeme + apt: + name: "*" + state: latest + when: os_apt_update | bool + +- name: Updgrade systeme + apt: + upgrade: dist + when: os_apt_upgrade | bool + +