Wednesday 7 August 2019

Grafana / Infludb K8s deployment via piepline

Grafana


1. Dockerfile


FROM grafana/grafana:latest
LABEL description="Grafana docker image with custom setup"
ENV GF_SMTP_ENABLED true
ENV GF_SMTP_HOST mxrelay.ara.ac.nz:25
ENV GF_SMTP_FROM_ADDRESS admin@grafana.ara.ac.nz

USER root

RUN apt-get -q update &&\
    DEBIAN_FRONTEND="noninteractive" apt-get -q upgrade -y -o Dpkg::Options::="--force-confnew" --no-install-recommends &&\
    DEBIAN_FRONTEND="noninteractive" apt-get -q install -y -o Dpkg::Options::="--force-confnew" --no-install-recommends curl gosu &&\
    apt-get -q autoremove &&\
    apt-get -q clean -y && rm -rf /var/lib/apt/lists/* && rm -f /var/cache/apt/*.bin

ADD run.sh /run.sh
RUN chmod +x /run.sh
RUN mkdir -p /opt/grafana/dashboards
ADD ["*.json", "/opt/grafana/dashboards/"]
ADD ["default-dashboard.yaml", "/etc/grafana/provisioning/dashboards/"]
ADD ["notification.yaml", "/etc/grafana/provisioning/notifiers/"]
ENTRYPOINT ["/run.sh", "GF_SMTP_ENABLED", "GF_SMTP_HOST", "GF_SMTP_FROM_ADDRESS"]

2. run.sh


#!/bin/bash -e

: "${GF_PATHS_DATA:=/var/lib/grafana}"
: "${GF_PATHS_LOGS:=/var/log/grafana}"
: "${GF_PATHS_PLUGINS:=/var/lib/grafana/plugins}"
: "${GF_PATHS_PROVISIONING:=/etc/grafana/provisioning}"
: "${GF_SMTP_FROM_ADDRESS:=admin@grafana.ara.ac.nz}"
: "${GF_SMTP_ENABLED:=true}"
: "${GF_SMTP_HOST:=mxrelay.ara.ac.nz:25}"

chown -R grafana:grafana "$GF_PATHS_DATA" "$GF_PATHS_LOGS"
chown -R grafana:grafana /etc/grafana

# Start grafana with gosu
exec gosu grafana /usr/share/grafana/bin/grafana-server  \
  --homepath=/usr/share/grafana             \
  --config=/etc/grafana/grafana.ini         \
  cfg:default.paths.data="$GF_PATHS_DATA"   \
  cfg:default.paths.logs="$GF_PATHS_LOGS"   \
  cfg:default.paths.plugins="$GF_PATHS_PLUGINS" \
  cfg:default.smtp.enabled="$GF_SMTP_ENABLED" \
  cfg:default.smtp.host="$GF_SMTP_HOST" \
  cfg:default.smtp.from_address="$GF_SMTP_FROM_ADDRESS" &

sleep 5

###############################################################
# Creating Default Data Source

# Set new Data Source name
INFLUXDB_DATA_SOURCE="InfluxDB"
INFLUXDB_DATA_SOURCE_WEB=`echo ${INFLUXDB_DATA_SOURCE} | sed 's/ /%20/g'`

# Set information about grafana host
GRAFANA_URL=`hostname -i`
GRAFANA_PORT="3000"
GRAFANA_USER="admin"
GRAFANA_PASSWORD="admin"

# Check $INFLUXDB_DATA_SOURCE status
INFLUXDB_DATA_SOURCE_STATUS=`curl -s -L -i \
 -H "Accept: application/json" \
 -H "Content-Type: application/json" \
 -X GET http://${GRAFANA_USER}:${GRAFANA_PASSWORD}@${GRAFANA_URL}:${GRAFANA_PORT}/api/datasources/name/${INFLUXDB_DATA_SOURCE_WEB} | head -1 | awk '{print $2}'`

#Debug Time!
curl -s -L -i \
 -H "Accept: application/json" \
 -H "Content-Type: application/json" \
 -X GET http://${GRAFANA_USER}:${GRAFANA_PASSWORD}@${GRAFANA_URL}:${GRAFANA_PORT}/api/datasources/name/${INFLUXDB_DATA_SOURCE_WEB} >>$GF_PATHS_LOGS/grafana.log 2>>$GF_PATHS_LOGS/grafana.log 
echo "http://${GRAFANA_USER}:${GRAFANA_PASSWORD}@${GRAFANA_URL}:${GRAFANA_PORT}/api/datasources/name/${INFLUXDB_DATA_SOURCE_WEB}" >> $GF_PATHS_LOGS/grafana.log
echo "INFLUXDB_DATA_SOURCE_STATUS: "$INFLUXDB_DATA_SOURCE_STATUS >> $GF_PATHS_LOGS/grafana.log
echo "GRAFANA_URL: "$GRAFANA_URL >> $GF_PATHS_LOGS/grafana.log
echo "GRAFANA_PORT: "$GRAFANA_PORT >> $GF_PATHS_LOGS/grafana.log
echo "GRAFANA_USER: "$GRAFANA_USER >> $GF_PATHS_LOGS/grafana.log
echo "GRAFANA_PASSWORD: "$GRAFANA_PASSWORD >> $GF_PATHS_LOGS/grafana.log

# Check if $INFLUXDB_DATA_SOURCE exists
if [ ${INFLUXDB_DATA_SOURCE_STATUS} != 200 ]
then
  # If not exists, create one 
  echo "Data Source: '"${INFLUXDB_DATA_SOURCE}"' not found in Grafana configuration"
  echo "Creating Data Source: '"$INFLUXDB_DATA_SOURCE"'"
  curl -L -i \
   -H "Accept: application/json" \
   -H "Content-Type: application/json" \
   -X POST -d '{
    "name":"'"${INFLUXDB_DATA_SOURCE}"'",
    "type":"influxdb",
    "url":"http://influxdb:8086",
    "access":"proxy",
    "basicAuth":false,
    "database":"telegraf",
    "user":"grafana",
    "password":"grafana"}
  ' \
  http://${GRAFANA_USER}:${GRAFANA_PASSWORD}@${GRAFANA_URL}:${GRAFANA_PORT}/api/datasources
else
  #Continue if it doesn't exists
  echo "Data Source '"${INFLUXDB_DATA_SOURCE}"' already exists."
fi

tail -f $GF_PATHS_LOGS/grafana.log

3. graf-serv-deploy.yml


---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: grafana
  namespace: default
  labels:
    app: grafana
spec:
  replicas: 1
  selector:
    matchLabels:
      app: grafana
  strategy:
    rollingUpdate:
      maxSurge: 25%
      maxUnavailable: 25%
    type: RollingUpdate
  template:
    metadata:
      labels:
        app: grafana
    spec:
      containers:
      - image: araregistry.azurecr.io/ara/nashgrafana:latest
        imagePullPolicy: Always
        name: nashgrafana
        terminationMessagePath: /dev/termination-log
        terminationMessagePolicy: File
      dnsPolicy: ClusterFirst
      imagePullSecrets:
      - name: azurecr
      restartPolicy: Always
---
apiVersion: v1
kind: Service
metadata:
  labels:
    app: grafana
  name: grafana
  namespace: default
spec:
  type: NodePort
  ports:
  - nodePort: 30030
    port: 3000
    protocol: TCP
    targetPort: 3000
  selector:
    app: grafana

4. notification.yml


notifiers:
  - name: notification-channel
    type: email
    uid: notifier1
    org_name: Main Org.
    is_default: true
    disable_resolve_message: false
    settings:
      addresses: naveed.sheikh@ara.ac.nz

5. default-dashboard.yml


# # config file version
apiVersion: 1

providers:
 - name: 'default'
   orgId: 1
   folder: ''
   type: file
   options:
     path: /opt/grafana/dashboards

6. Jenkinsfile


pipeline {
  agent any
  stages {
    stage('Build') {
      environment {
        KUBECONFIG = '/home/isadmin/.kube/config-mon1'
      }
      steps {
        sh '''sudo docker build -t araregistry.azurecr.io/ara/nashgrafana:latest -f Dockerfile .

sudo docker push araregistry.azurecr.io/ara/nashgrafana:latest'''
      }
    }
    stage('Pull Changes') {
      steps {
        sh '''sudo ssh -T root@logmon1.ara.ac.nz docker login araregistry.azurecr.io -u AraRegistry -p xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx

sudo ssh -T root@logmon1.ara.ac.nz docker pull araregistry.azurecr.io/ara/nashgrafana:latest'''
      }
    }
    stage('Deploy') {
      steps {
        sh '''# Deploy service
kubectl apply -f ${WORKSPACE}/fullgrafana.yml'''
      }
    }
  }
  environment {
    KUBECONFIG = '/home/isadmin/.kube/config-mon1'
  }
}

--------------------------------------------------------------------------------------------------------------------------

InfluxdB



1. Dockerfile


FROM influxdb:latest
LABEL description="InfluxDB docker image with custom setup"

USER root

ADD influxdb.template.conf /influxdb.template.conf

ADD run.sh /run.sh
RUN chmod +x /run.sh

CMD ["/run.sh"]


2. Jenkinsfile


pipeline {
  agent any
  stages {
    stage('Build') {
      environment {
        KUBECONFIG = '/home/isadmin/.kube/config-mon1'
      }
      steps {
        sh '''sudo docker build -t araregistry.azurecr.io/ara/nashflux:latest -f Dockerfile .

sudo docker push araregistry.azurecr.io/ara/nashflux:latest'''
      }
    }
    stage('Pull Changes') {
      steps {
        sh '''sudo ssh -T root@logmon1.ara.ac.nz docker login araregistry.azurecr.io -u AraRegistry -p xxxxxxxxxxxxxxxxxxx

sudo ssh -T root@logmon1.ara.ac.nz docker pull araregistry.azurecr.io/ara/nashflux:latest'''
      }
    }
    stage('Deploy') {
      steps {
        sh '''# Deploy service
kubectl apply -f ${WORKSPACE}/fulldeploymentinflux.yml'''
      }
    }
  }
  environment {
    KUBECONFIG = '/home/isadmin/.kube/config-mon1'
  }
}

3. run.sh


#!/bin/bash

set -m
CONFIG_TEMPLATE="/influxdb.template.conf"
CONFIG_FILE="/etc/influxdb/influxdb.conf"
CURR_TIMESTAMP=`date +%s`

INFLUX_HOST="localhost"
INFLUX_API_PORT="8086"
[ "${INFLUX_ADMIN_USER}" = "" ] &&
        INFLUX_ADMIN_USER="grafana"
[ "${INFLUX_ADMIN_PASS}" = "" ] &&
        INFLUX_ADMIN_PASS="grafana"
[ "${INFLUX_DATABASE}" = "" ] &&
        INFLUX_DATABASE="telegraf"

mv -v $CONFIG_FILE $CONFIG_FILE.$CURR_TIMESTAMP
cp -v $CONFIG_TEMPLATE $CONFIG_FILE

exec influxd -config=$CONFIG_FILE 1>>/var/log/influxdb/influxdb.log 2>&1 &
sleep 5

USER_EXISTS=`influx -host=${INFLUX_HOST} -port=${INFLUX_API_PORT} -execute="SHOW USERS" | awk '{print $1}' | grep "${INFLUX_ADMIN_USER}" | wc -l`

if [ -n ${USER_EXISTS} ]
then
  influx -host=${INFLUX_HOST} -port=${INFLUX_API_PORT} -execute="CREATE USER ${INFLUX_ADMIN_USER} WITH PASSWORD '${INFLUX_ADMIN_PASS}' WITH ALL PRIVILEGES"
  influx -host=${INFLUX_HOST} -port=${INFLUX_API_PORT} -username=${INFLUX_ADMIN_USER} -password="${INFLUX_ADMIN_PASS}" -execute="create database ${INFLUX_DATABASE} WITH DURATION 180d NAME biannual"
fi

tail -f /var/log/influxdb/influxdb.log

4. influx-serv-full.yml


---
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
  namespace: default
  name: standard
provisioner: kubernetes.io/host-path
volumeBindingMode: WaitForFirstConsumer
---
apiVersion: v1
kind: PersistentVolume
metadata:
  name: influxvol
  namespace: default
spec:
  storageClassName: 'standard'
  capacity:
    storage: 100Gi
  accessModes:
    - ReadWriteOnce
  hostPath:
    path: "/var/k8sdata"
---
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
  name: influxvol
  namespace: default
spec:
  storageClassName: 'standard'
  accessModes:
    - ReadWriteOnce
  resources:
    requests:
      storage: 100Gi
---
apiVersion: extensions/v1beta1
kind: Deployment
metadata:
  name: influxdb
  namespace: default
  labels:
    app: influxdb
spec:
  replicas: 1
  selector:
    matchLabels:
      app: influxdb
  strategy:
    rollingUpdate:
      maxSurge: 25%
      maxUnavailable: 25%
    type: RollingUpdate
  template:
    metadata:
      labels:
        app: influxdb
    spec:
      containers:
      - image: araregistry.azurecr.io/ara/nashflux:latest
        imagePullPolicy: Always
        name: nashflux
        terminationMessagePath: /dev/termination-log
        terminationMessagePolicy: File
        ports:
        - containerPort: 8086
        volumeMounts:
        - name: influxstorage
          mountPath: /var/lib/influxdb
      volumes:
      - name: influxstorage
        persistentVolumeClaim:
          claimName: influxvol
      dnsPolicy: ClusterFirst
      imagePullSecrets:
      - name: azurecr
      restartPolicy: Always
---
apiVersion: v1
kind: Service
metadata:
  labels:
    app: influxdb
  name: influxdb
  namespace: default
spec:
  type: NodePort
  ports:
  - nodePort: 31050
    port: 8086
    protocol: TCP
    targetPort: 8086
  selector:
    app: influxdb

--------------------------------------------------------------------------------------------------------------------------

Dont forget to add secret and if 1 node master then untaint the master node for this to work.

Thanks

Tuesday 6 August 2019

Telegraf for K8s Cluster monitering

RBAC

kubectl create clusterrolebinding default-admin --clusterrole cluster-admin --serviceaccount=default:default

Secret

kubectl create secret -n monitoring generic telegraf --from-literal=env=prod --from-literal=monitor_username=youruser --from-literal=monitor_password=yourpassword --from-literal=monitor_host=https://your.influxdb.local --from-literal=monitor_database=yourdb

Daemon apply

apiVersion: v1
kind: ConfigMap
metadata:
  name: telegraf
  namespace: monitoring
  labels:
    k8s-app: telegraf
data:
  telegraf.conf: |+
    [global_tags]
      env = "$ENV"
    [agent]
      hostname = "$HOSTNAME"
    [[outputs.influxdb]]
      urls = ["$MONITOR_HOST"] # required
      database = "$MONITOR_DATABASE" # required
      timeout = "5s"
      username = "$MONITOR_USERNAME"
      password = "$MONITOR_PASSWORD"
   
    [[inputs.cpu]]
      percpu = true
      totalcpu = true
      collect_cpu_time = false
      report_active = false
    [[inputs.disk]]
      ignore_fs = ["tmpfs", "devtmpfs", "devfs"]
    [[inputs.diskio]]
    [[inputs.kernel]]
    [[inputs.mem]]
    [[inputs.processes]]
    [[inputs.swap]]
    [[inputs.system]]
    [[inputs.net]]
    [[inputs.docker]]
      endpoint = "unix:///var/run/docker/libcontainerd/docker-containerd.sock"
    [[inputs.kubernetes]]
      url = "https://$HOSTNAME:10250"
      #bearer_token = "/var/run/secrets/kubernetes.io/serviceaccount/token"
      bearer_token_string = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
      insecure_skip_verify = true

---
# Section: Daemonset
apiVersion: apps/v1
kind: DaemonSet
metadata:
  name: telegraf
  namespace: monitoring
  labels:
    k8s-app: telegraf
spec:
  selector:
    matchLabels:
      name: telegraf
  template:
    metadata:
      labels:
        name: telegraf
    spec:
      containers:
      - name: telegraf
        image: docker.io/telegraf:latest
        resources:
          limits:
            memory: 500Mi
          requests:
            cpu: 500m
            memory: 500Mi
        env:
        - name: HOSTNAME
          valueFrom:
            fieldRef:
              fieldPath: spec.nodeName
        - name: "HOST_PROC"
          value: "/rootfs/proc"
        - name: "HOST_SYS"
          value: "/rootfs/sys"
        - name: ENV
          valueFrom:
            secretKeyRef:
              name: telegraf
              key: env
        - name: MONITOR_USERNAME
          valueFrom:
            secretKeyRef:
              name: telegraf
              key: monitor_username
        - name: MONITOR_PASSWORD
          valueFrom:
            secretKeyRef:
              name: telegraf
              key: monitor_password
        - name: MONITOR_HOST
          valueFrom:
            secretKeyRef:
              name: telegraf
              key: monitor_host
        - name: MONITOR_DATABASE
          valueFrom:
            secretKeyRef:
              name: telegraf
              key: monitor_database
        volumeMounts:
        - name: sys
          mountPath: /rootfs/sys
          readOnly: true
        - name: proc
          mountPath: /rootfs/proc
          readOnly: true
        - name: docker-socket
          mountPath: /var/run/docker/libcontainerd/docker-containerd.sock
          readOnly: true
        - name: utmp
          mountPath: /var/run/utmp
          readOnly: true
        - name: config
          mountPath: /etc/telegraf
      terminationGracePeriodSeconds: 30
      volumes:
      - name: sys
        hostPath:
          path: /sys
      - name: docker-socket
        hostPath:
          path: /var/run/docker/libcontainerd/docker-containerd.sock
      - name: proc
        hostPath:
          path: /proc
      - name: utmp
        hostPath:
          path: /var/run/utmp
      - name: config
        configMap:
          name: telegraf

Wednesday 31 July 2019

Kubernetes Deployment Via Ansible

/etc/ansible/playbook/kube-dependencies.yaml

- hosts: all
  become: yes
  tasks:
   - name: install gpg
     apt:
       name: gpg
       state: present
       update_cache: true

   - name: install Docker
     apt:
       name: docker.io
       state: present
       update_cache: true

   - name: Enable service
     service:
       name: docker
       enabled: yes

   - name: start service
     service:
       name: docker
       state: started

   - name: install APT Transport HTTPS
     apt:
       name: apt-transport-https
       state: present

   - name: add Kubernetes apt-key
     apt_key:
       url: https://packages.cloud.google.com/apt/doc/apt-key.gpg
       state: present

   - name: add Kubernetes' APT repository
     apt_repository:
      repo: deb http://apt.kubernetes.io/ kubernetes-xenial main
      state: present
      filename: 'kubernetes'

   - name: install kubelet
     apt:
       name: kubelet
       state: present
       update_cache: true

   - name: install kubeadm
     apt:
       name: kubeadm
       state: present

- hosts: master
  become: yes
  tasks:
   - name: install kubectl
     apt:
       name: kubectl
       state: present
       force: yes

/etc/ansible/playbook/master.yaml

- hosts: master
  become: yes
  tasks:
    - name: Disable SWAP since kubernetes can't work with swap enabled (1/2)
      shell: |
        swapoff -a
      when: ansible_swaptotal_mb > 0

    - name: Disable SWAP in fstab since kubernetes can't work with swap enabled (2/2)
      replace:
        path: /etc/fstab
        regexp: '^(.+?\sswap\s+sw\s+.*)$'
        replace: '# \1'

    - name: initialize the cluster
      shell: kubeadm init --pod-network-cidr=10.244.0.0/16 >> cluster_initialized.txt
      args:
        chdir: $HOME
        creates: cluster_initialized.txt

    - name: create .kube directory
      become: yes
      file:
        path: $HOME/.kube
        state: directory
        mode: 0755

    - name: copy admin.conf to user's kube config
      copy:
        src: /etc/kubernetes/admin.conf
        dest: $HOME/.kube/config
        remote_src: yes

    - name: install Pod network
      become: yes
      shell: kubectl apply -f "https://cloud.weave.works/k8s/net?k8s-version=$(kubectl version | base64 | tr -d '\n')"
      args:
        chdir: $HOME
        creates: pod_network_setup.txt

/etc/ansible/playbook/workers.yaml

- hosts: master
  become: yes
  gather_facts: false
  tasks:
    - name: get join command
      shell: kubeadm token create --print-join-command
      register: join_command_raw

    - name: set join command
      set_fact:
        join_command: "{{ join_command_raw.stdout_lines[0] }}"

- hosts: workers
  become: yes
  tasks:
    - name: Remove swapfile from /etc/fstab
      mount:
        name: swap
        fstype: swap
        state: absent

    - name: Disable swap
      command: swapoff -a
      when: ansible_swaptotal_mb > 0
    
    - name: join cluster
      shell: "{{ hostvars[groups['master'][0]].join_command }} >> node_joined.txt"
      args:
        chdir: $HOME
        creates: node_joined.txt

/etc/ansible/hosts

[master]
192.168.109.150

[workers]
192.168.109.151

[all:vars]
ansible_python_interpreter=/usr/bin/python3


Wednesday 29 May 2019

Reverse Engineer a docker image for Dockerfile

#!/bin/bash

if [[ "$(docker images -q chenzj/dfimage:latest 2> /dev/null)" == "" ]]; then
  docker pull chenzj/dfimage
fi

read -e -p "Enter Image ID: " IMAGE_ID

if grep -q dfimage /etc/profile;
 then
 :
 else
  echo "" >> /etc/profile
  echo alias dfimage="'docker run -v /var/run/docker.sock:/var/run/docker.sock --rm chenzj/dfimage'" >> /etc/profile
  source /etc/profile
fi

docker run -v /var/run/docker.sock:/var/run/docker.sock --rm chenzj/dfimage $IMAGE_ID > Dockerfile1

docker history --no-trunc $IMAGE_ID  | tac | tr -s ' ' | cut -d " " -f 5- | sed 's,^/bin/sh -c #(nop) ,,g' | sed 's,^/bin/sh -c,RUN,g' | sed 's, && ,\n  & ,g' | sed 's,\s*[0-9]*[\.]*[0-9]*[kMG]*B\s*$,,g' | head -n -1 > Dockerfile2


Wednesday 22 May 2019

Systemd Service only initiates at shutdown ( no reboot ) and keeps network intact

# the %H is the env var for systemd file which is $(hostname) for bash

[Unit]
Description=Run a Bash script at shutdown
DefaultDependencies=no
Wants=network-online.target
After=network-online.target
Before=poweroff.target halt.target

[Service]
ExecStart=/usr/bin/curl -X POST 'http://box21.ara.ac.nz:32446/query?db=telegraf' --data-urlencode "q=DROP SERIES WHERE host = '%H'"
Type=oneshot
RemainAfterExit=yes

[Install]
WantedBy=poweroff.target halt.target 

Monday 29 April 2019

Reboot and Volume detach/attach

#!/usr/bin/env bash

if [ ! -f /home/resume-after-reboot ]; then

function sqlkiller {
while :
do
  sqlstatus=$(systemctl status mysql | awk 'FNR == 3 {print $2}')
  if [[ "${sqlstatus}" == "active" ]]; then
  break
  else
  /etc/init.d/mysql start
  sleep 5s
  continue
  fi
done
}

function createnewvol {
while :
do
 progress=$(aws ec2 describe-snapshots --snapshot-id $snapid --query "Snapshots[*].{Cond:State}" --output text --region us-east-1)
 if [[ "${progress}" == "completed" ]]; then
 freshvol=$(aws ec2 create-volume --region us-east-1 --availability-zone us-east-1d --snapshot-id $snapid --volume-type gp2 --output text | awk '{print $8}')
 touch /home/freshvol.txt
 echo $freshvol > /home/freshvol.txt
 sleep 2m
 break
 else
 continue
 fi
done
}

function searchsnap {
for ((i=0;i<5;i++))
 do
  current=$(date +%Y%m%d -d "-$i days")
  snapid=$(aws ec2 describe-snapshots --filters Name=description,Values=""$value"_$current" --query "Snapshots[*].{SD:SnapshotId}" --region us-east-1 --output text)
  if [[ $snapid == *"snap-"* ]]; then
  echo "Snapshot found - continuing with ID: "$snapid" " >> /var/log/ebs-update.log
  createnewvol
  break
  elif [[ $i -ne 4 ]]; then
  continue
  else
  echo "Snapshot not found - exiting" >> /var/log/ebs-update.log
  echo "--" >> /var/log/ebs-update.log
  exit 1
  fi
exit 1
done
}

while :
do
 status=$(pidof mysqld)
 if [[ $status -eq 0 ]]; then
 echo "Mysql is off - $(date) - Proceeding with updating Database" >> /var/log/ebs-update.log
 break
 else
 sqlkiller
 /etc/init.d/mysql stop
 pkill -9 mysql
 pkill -9 mysqld
 pkill -9 mysqld_safe
 continue
 fi
done

prefix=$(hostname)
value=${prefix#*-}
value="$value-snapshot"
value=$(echo "$value" | sed -r 's/master/slave/g')

instanceid=$(ec2metadata --instance-id)
for letter in /dev/xvdj xvdj /dev/sdj sdj; do
  volumeid=$(aws ec2 describe-volumes --filters Name=attachment.instance-id,Values=$instanceid Name=attachment.device,Values=$letter --query "Volumes[*].{ID:VolumeId}" --output text --region us-east-1)
  if [ -z "$volumeid" ]; then
  continue
  else
  break
  fi
done

fuser -km /dev/xvdj
umount -d /dev/xvdj
fuser -km /dev/sdj
umount -d /dev/sdj
fuser -km /dev/mapper/mysql--product--master-mysql
umount -d /dev/mapper/mysql--product--master-mysql

aws ec2 detach-volume --volume-id $volumeid --region us-east-1 --force

while :
do
 status=$(aws ec2 describe-volumes --volume-ids $volumeid --query "Volumes[*].{OP:State}" --output text --region us-east-1)
 if [[ "${status}" == "available" ]]; then
 searchsnap
 break
 else
 sleep 2m
 continue
 fi
done

sed -i 's/server.*/server = puppet-master.srv.fish.1/' /etc/puppetlabs/puppet/puppet.conf
script="@reboot root /opt/fishpond/bin/ebs-update"
echo "$script" >> /etc/crontab
touch /home/resume-after-reboot
/sbin/reboot

else
sed -i '/@reboot/d' /etc/crontab
rm -f /home/resume-after-reboot
while :
do
 freshvolafter=$(cat /home/freshvol.txt)
 instanceidafter=$(ec2metadata --instance-id)
 newstatus=$(aws ec2 describe-volumes --volume-ids $freshvolafter --query "Volumes[*].{OP:State}" --output text --region us-east-1)
 if [[ "${newstatus}" == "available" ]]; then
 aws ec2 attach-volume --volume-id $freshvolafter --instance-id $instanceidafter --device /dev/sdj --region us-east-1
 sleep 5m
 break
 else
 continue
 fi
done

while :
do
 freshvolafterattach=$(cat /home/freshvol.txt)
 instanceidafterattach=$(ec2metadata --instance-id)
 newstatusattach=$(aws ec2 describe-volumes --volume-ids $freshvolafterattach --query "Volumes[*].{OP:State}" --output text --region us-east-1)
 if [[ "${newstatusattach}" == "in-use" ]]; then
 break
 else
 continue
 fi
done

mount /dev/mapper/mysql--product--master-mysql /mnt/mysql
mount /dev/xvdj /mnt/mysql
mount /dev/sdj /mnt/mysql

 if grep -qs '/mnt/mysql' /proc/mounts; then
   logline=$(tail -n2 /var/log/mysql/mysql-error.log | head -1)
    if [[ "${logline}" == *"Shutdown complete"* ]]; then
    /etc/init.d/mysql start
    else
    /etc/init.d/mysql restart
    fi
  sleep 10s
 else
   mount /dev/mapper/mysql--product--master-mysql /mnt/mysql
   mount /dev/xvdj /mnt/mysql
   mount /dev/sdj /mnt/mysql
 fi

rm -f /home/freshvol.txt
sed -i 's/server.*/server = puppet-master.srv.fish/' /etc/puppetlabs/puppet/puppet.conf
/opt/puppetlabs/bin/puppet agent -t
sleep 5s
echo "Script ran correctly at $(date)" >> /var/log/ebs-update.log
echo "--"  >> /var/log/ebs-update.log
fi

Thursday 18 April 2019

Sync directory - encrypt and move

Backup Script:

#!/usr/bin/env bash

echo "Rstudio backup has been started on $(date)" >> /var/log/rstudiobackup.log

dir1="/media/somedirectory/backup-dir"

now=$(date +"%m_%d_%Y_%H")
if [ -d "dir1" ]; then
 :
else
 mkdir -p /media/somedirectory/backup-dir
fi

rsync -avhz /media/dironserver/dirtobackup/ /media/somedirectory/backup-dir
cd /media/somedirectory
tar -I pigz -cf $now.tar.gz backup-dir
gpg --recipient naveed@nasheikh.com --trust-model always --encrypt --armor $now.tar.gz
mv $now.tar.gz.asc /srv/some-remote-dir

echo "Rstudio backup has been Completed on $(date)" >> /var/log/rstudiobackup.log
echo "--" >> /var/log/rstudiobackup.log

exit 0

Place this in /usr/local/bin ( hence no PATH problems )

Packages to install :

apt install pigz

Install cron job

crontab -e

30 3 * * SUN /usr/local/bin/backupper.sh

30 3 * * 1-6  /usr/bin/rsync -avhz /media/dironserver/dirtobackup/ /media/somedirectory/backup-dir

Job Finish


Mount checker with email capability

This is done in 3 scripts:


1st Script - the init service:

Mount the directory:

mount -t cifs //192.168.02.02/somedirectory /srv/somedirectory -o vers=3.0,credentials=/root/creds

#! /bin/sh

### BEGIN INIT INFO
# Provides:          cifchecker
# Required-Start:    $remote_fs $syslog
# Required-Stop:     $remote_fs $syslog
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: Simple script to start a program at boot
# Description:       A simple script which will start / stop a program a boot / shutdown.
### END INIT INFO

# If you want a command to always run, put it here

# Carry out specific functions when asked to by the system
case "$1" in
  start)
    echo "Starting cifchecker"
    # run application you want to start
    /usr/local/bin/sendemail.sh &
    ;;
  stop)
    echo "Stopping cifchecker"
    # kill application you want to stop
    dead=$(ps -o pgid,cmd -U root | grep -v grep | grep sendemail | awk '{print $1}')
    kill -- -$dead
    ;;
  *)
    echo "Usage: /etc/init.d/cifchecker {start|stop}"
    exit 1
    ;;
esac

exit 0

Place this in /etc/init.d/ directory and run:

chmod 755 cifchecker
update-rc.d cifchecker defaults

2nd Script: This keeps an eye on the Partition and calls email script if needed:

#!/usr/bin/env bash

while true;
do
 /bin/findmnt /srv/directoryname
 status=$(echo $?)
 sleep 1m
 if [ $status -ne 0 ]; then
  /usr/local/bin/mailer.py 'Mount partition has been lost'
  while true;
  do
   /bin/findmnt /srv/directoryname
   statusafter=$(echo $?)
   sleep 1m
   if [ $statusafter -ne 0 ]; then
    continue
   else
    /usr/local/bin/mailer.py 'Mount partition restored'
    break
   fi
  done
 else
  continue
 fi
done

3rd Script: This sends the email as per directive:

#!/usr/bin/env python3

import os, fnmatch, subprocess,datetime,time,smtplib,sys
from email.message import EmailMessage

icomm1 = sys.argv[1]
msg = EmailMessage()
msg.set_content(icomm1)
msg['Subject'] = 'cifs mount issue'
msg['From'] = 'naveed@nasheikh.com'
msg['To'] = 'adrian@nasheikh.com','tamy@nasheikh.com'
s = smtplib.SMTP('smtp.stats.govt.nz')
s.send_message(msg)
s.quit()

Good practice is to place both executable scripts in /usr/local/bin

-------------------------------------------------------------Fi----------------------------------------------------------

Friday 12 April 2019

Nagios Script

#!/bin/bash

response=$(curl -s http://search-orders.srv.fish:8080/binlog-webapp/binlog?type=status)
tstamp=$(curl -s http://search-orders.srv.fish:8080/binlog-webapp/binlog?type=status| jq '.status' |  awk -F'"' '$2=="currentTimestamp"{print $4}')
status=$(curl -s http://search-orders.srv.fish:8080/binlog-webapp/binlog?type=status| jq '.status' |  awk -F'"' '$2=="running"{print $4}')

oldstamp=$(date +%s -d "-24 hours")
respinsec=$(date -d "${tstamp}" +"%s")

if [ -z "$response" ]; then
    echo "CRITICAL status - No API response"
    exit 2

elif [[ "${status}" != "true" ]]; then
    echo "CRITICAL status - Search replication is not running."
    exit 2

elif (( respinsec < oldstamp )); then
    echo "CRITICAL status - Timestamp is over 24 hours."
    exit 2

else
    echo "OK - Search Replication is running correctly"
    exit 0
fi

Wednesday 10 April 2019

DotNet DockerFile

FROM mcr.microsoft.com/dotnet/core/aspnet:2.2

WORKDIR /app

COPY ./src/AspMVC/publish .

ENTRYPOINT ["dotnet", "AspMVC.dll"]

docker run -p 80:80 myimage

Tuesday 9 April 2019

Mysql DB backup with lock table system

#!/usr/bin/env bash

WAITFORLOCK=/root/waitlock

WAITFORSNAPSHOT=/root/waitforsnapshot

LOCKTABLERUN=/root/locktables.pid

function locktable {
(
    echo "FLUSH TABLES WITH READ LOCK;" && \
    sleep 5 && \
    touch ${WAITFORSNAPSHOT} && \
    rm -f ${WAITFORLOCK} && \
    while [ -e ${WAITFORSNAPSHOT} ]; do sleep 1; done && \
    echo "SHOW MASTER STATUS;" && \
    echo "UNLOCK TABLES;" && \
    echo "\quit" \
) | mysql --defaults-file=/root/.my.cnf

rm -f ${LOCKTABLERUN}
}

function prefreeze {

if [ -e ${WAITFORLOCK} ]; then
 echo Previous backup failed, waitforlock file still present && exit 1
fi

if [ -e ${WAITFORSNAPSHOT} ]; then
 echo Previous backup failed, WAITFORSNAPSHOT file still present && exit 1
fi

if [ -e ${LOCKTABLERUN} ]; then
 ps -p `cat ${LOCKTABLERUN}` > /dev/null 2>&1;
 if [ $? -eq 0 ]; then
  echo Panic, locktables script still running && exit 1
 else
  rm -f ${LOCKTABLERUN}
 fi
fi

touch ${WAITFORLOCK}

locktable &

LOCKTABLEPID=$!
echo ${LOCKTABLEPID} > ${LOCKTABLERUN}

while [ -e ${WAITFORLOCK} ]; do
 ps -p ${LOCKTABLEPID} > /dev/null 2>&1;
 if [ $? -eq 1 ]; then
  break
 fi
 sleep 1
done

if [ -e ${WAITFORLOCK} ]; then
 echo Tablelock script exited without removing waitforlock file, something went wrong
else
 echo Tables are locked
fi
}

prefreeze &&

server=$(hostname)
 if [[ "${server}" == *"product"* ]]; then
   server="db-product-slave-snapshot"
 elif [[ "${server}" == *"customer"* ]]; then
   server="db-customer-slave-snapshot"
 elif [[ "${server}" == *"finance"* ]]; then
   server="db-finance-slave-snapshot"
 else
   server=$(hostname)
 fi
instanceid=$(ec2metadata --instance-id)
for letter in /dev/xvdj xvdj /dev/sdj sdj; do
  volumeid=$(aws ec2 describe-volumes --filters Name=attachment.instance-id,Values=$instanceid Name=attachment.device,Values=$letter --query "Volumes[*].{ID:VolumeId}" --output text --region us-east-1)
  if [ -z "$volumeid" ]; then
  continue
  else
  break
  fi
done
snapid=$(aws ec2 create-snapshot --volume-id $volumeid --description ""$server"_$(date +%Y%m%d)" --output text --region us-east-1 | awk '{print $4}')
echo "Backup initiated with SnapshotID: "$snapid"" >> /var/log/ebs-snapshot.log

while :
do
 progress=$(aws ec2 describe-snapshots --snapshot-id $snapid --query "Snapshots[*].{Cond:State}" --output text --region us-east-1)
 if [[ "${progress}" == "pending" ]]; then
 sleep 5m
 continue
 else
 result=$(aws ec2 describe-snapshots --snapshot-id $snapid --query "Snapshots[*].{Cond:State}" --output text --region us-east-1)
 echo "Snap has been "$result" and Mysql has been started on $(date)" >> /var/log/ebs-snapshot.log
 echo "--" >> /var/log/ebs-snapshot.log
 break
 fi
done

rm ${WAITFORSNAPSHOT}

exit 0

Thursday 28 March 2019

MFA CLI AWS Profile based

#!/bin/bash

KEY_PROFILE="main"
EXPIRATION=$(aws configure get expiration --profile $KEY_PROFILE)

RELOAD="true"
if [ -n "$EXPIRATION" ];
then
      # get current time and expiry time in seconds since 1-1-1970
      NOW=$(date -u +"%Y-%m-%dT%H:%M:%SZ")

      # if tokens are set and have not expired yet
      if [[ "$EXPIRATION" > "$NOW" ]];
      then
              echo "Will not fetch new credentials. They expire at (UTC) $EXPIRATION"
              RELOAD="false"
      fi
fi

if [ "$RELOAD" = "true" ];
then
      echo "Need to fetch new STS credentials"
      MFA_SERIAL=$(aws configure get mfa_serial --profile $KEY_PROFILE)
      DURATION=$(aws configure get get_session_token_duration_seconds --profile $KEY_PROFILE)
      read -p "Token for MFA Device ($MFA_SERIAL): " TOKEN_CODE

      read -r AWS_ACCESS_KEY_ID AWS_SECRET_ACCESS_KEY AWS_SESSION_TOKEN EXPIRATION < <(aws sts get-session-token --output text --query 'Credentials.[AccessKeyId,SecretAccessKey,SessionToken,Expiration]' --serial-number $MFA_SERIAL --token-code $TOKEN_CODE --duration-seconds $DURATION --profile $KEY_PROFILE)

      aws configure set aws_secret_access_key "$AWS_SECRET_ACCESS_KEY"
      aws configure set aws_session_token "$AWS_SESSION_TOKEN"
      aws configure set aws_access_key_id "$AWS_ACCESS_KEY_ID"
      aws configure set expiration "$EXPIRATION" --profile $KEY_PROFILE
fi

Thursday 14 March 2019

Auto host file generator

#!/bin/bash
set -xv
> /etc/ansible/file
echo '[server]' >/etc/ansible/file
serverlist=$(aws ec2 describe-instances --query "Reservations[*].Instances[*].Tags[?Key=='Name'].Value[]" --output text)
for server in $serverlist
do
s="${server}.srv.fish"
echo $s >> /etc/ansible/file
done

Tuesday 5 March 2019

AWS MFA Cli enabler

#!/bin/bash

read -e -p "Enter your MFA code...: " mfa

aws sts get-session-token --serial-number arn:aws:iam::018771201686:mfa/naveed --token-code $mfa --output table > todaysession

export AWS_ACCESS_KEY_ID=$(grep "AccessKeyId" todaysession | awk '{print $4}')
export AWS_SECRET_ACCESS_KEY=$(grep "SecretAccessKey" todaysession | awk '{print $3}')
export AWS_SESSION_TOKEN=$(grep "SessionToken" todaysession | awk '{print $4}' | sed 1d)

echo $AWS_ACCESS_KEY_ID
echo $AWS_SECRET_ACCESS_KEY
echo $AWS_SESSION_TOKEN