RANCID – Really Awesome New Cisco config Differ monitors a router’s (or more generally a device’s) configuration, including software and hardware (cards, serial numbers, etc) and uses CVS (Concurrent Version System), Subversion or Git to maintain history of changes.

Rancid:

  • login to each device in the router table (router.db)
  • runs various commands to get the information that will be saved,
  • cook the output; re-format, remove oscillating or incrementing data,
  • email any differences (sample) from the previous collection to a mail list
  • commit those changes to the revision control system

Installing required components

dnf update -y
dnf install -y epel-release 
dns install -y python2 vim wget git mlocate 
dnf install dnf-utils http://rpms.remirepo.net/enterprise/remi-release-8.rpm 
dnf module reset php 
dnf module enable php:remi-7.4 
dnf install php php-opcache php-gd php-curl php-mysqlnd 
systemctl enable --now php-fpm 
rpm -ivh https://dev.mysql.com/get/mysql80-community-release-el8-1.noarch.rpm 
yum install -y wget ftp telnet mariadb-server mariadb perl tcl expect gcc cvs httpd autoconf php-common php-gd php-pear php-pecl-memcache php-mysql php-xml mod_ssl tar sendmail postfix  
pip2 install mysql-connector-python MySQL-Python 

If, during installing MySQL-Python you face following error:

Building wheels for collected packages: MySQL-python
Running setup.py bdist_wheel for MySQL-python ... error
Complete output from command /usr/bin/python -u -c "import setuptools, tokenize;file='/tmp/pip-build-3oXEzH/MySQL-python/setup.py';exec(compile(getattr( tokenize, 'open', open)(file).read().replace('\r\n', '\n'), file, 'exec'))" bdist_wheel -d /tmp/tmpXv05tnpip-wheel- --python-tag cp27:
running bdist_wheel
running build
running build_py
creating build
creating build/lib.linux-x86_64-2.7
copying mysql_exceptions.py -> build/lib.linux-x86_64-2.7
creating build/lib.linux-x86_64-2.7/MySQLdb
copying MySQLdb/init.py -> build/lib.linux-x86_64-2.7/MySQLdb
copying MySQLdb/converters.py -> build/lib.linux-x86_64-2.7/MySQLdb
copying MySQLdb/connections.py -> build/lib.linux-x86_64-2.7/MySQLdb
copying MySQLdb/cursors.py -> build/lib.linux-x86_64-2.7/MySQLdb
copying MySQLdb/release.py -> build/lib.linux-x86_64-2.7/MySQLdb
copying MySQLdb/times.py -> build/lib.linux-x86_64-2.7/MySQLdb
creating build/lib.linux-x86_64-2.7/MySQLdb/constants
copying MySQLdb/constants/init.py -> build/lib.linux-x86_64-2.7/MySQLdb/constants
copying MySQLdb/constants/CR.py -> build/lib.linux-x86_64-2.7/MySQLdb/constants
copying MySQLdb/constants/FIELD_TYPE.py -> build/lib.linux-x86_64-2.7/MySQLdb/constants
copying MySQLdb/constants/ER.py -> build/lib.linux-x86_64-2.7/MySQLdb/constants
copying MySQLdb/constants/FLAG.py -> build/lib.linux-x86_64-2.7/MySQLdb/constants
copying MySQLdb/constants/REFRESH.py -> build/lib.linux-x86_64-2.7/MySQLdb/constants
copying MySQLdb/constants/CLIENT.py -> build/lib.linux-x86_64-2.7/MySQLdb/constants
running build_ext
building 'mysql' extension
creating build/temp.linux-x86_64-2.7
x86_64-linux-gnu-gcc -pthread -DNDEBUG -g -fwrapv -O2 -Wall -Wstrict-prototypes -fno-strict-aliasing -Wdate-time -D_FORTIFY_SOURCE=2 -g -fstack-protector-strong -Wformat -Werror=format-security -fPIC -Dversion_info=(1,2,5,'final',1) -D__version=1.2.5 -I/usr/include/mysql -I/usr/include/ python2.7 -c _mysql.c -o build/temp.linux-x86_64-2.7/_mysql.o
In file included from _mysql.c:44:0:
/usr/include/mysql/my_config.h:3:2: warning: #warning This file should not be included by clients, include only <mysql.h> [-Wcpp]
#warning This file should not be included by clients, include only <mysql.h>
^
In file included from _mysql.c:46:0:
/usr/include/mysql/mysql.h:440:3: warning: function declaration isn’t a prototype [-Wstrict-prototypes]
MYSQL_CLIENT_PLUGIN_HEADER
^
/usr/include/mysql/mysql.h:585:1: warning: function declaration isn’t a prototype [-Wstrict-prototypes]
my_bool STDCALL mysql_embedded();
^
_mysql.c: In function ‘_mysql_ConnectionObject_ping’:
_mysql.c:2005:41: error: ‘MYSQL {aka struct st_mysql}’ has no member named ‘reconnect’
if ( reconnect != -1 ) self->connection.reconnect = reconnect;
^
error: command 'x86_64-linux-gnu-gcc' failed with exit status 1

Failed building wheel for MySQL-python
Running setup.py clean for MySQL-python
Failed to build MySQL-python

Edit  /usr/include/mysql/mysql.h. Add a line with unsigned int reconnect; after the line unsigned int warning_count;

Installing Rancid

groupadd netadm 
useradd -g netadm -c "Networking Backups" -d /home/rancid rancid 
mkdir /home/rancid/tar 
cd /home/rancid/tar/ 
wget ftp://ftp.shrubbery.net/pub/rancid/rancid-3.9.tar.gz 
tar -xzvf rancid-3.9.tar.gz 
cd rancid-3.9 
./configure --prefix=/usr/local/rancid 
make && make install

Configuring Rancid

Copy over the ‘cloginrc.sample into path /home/rancid/.cloginrc’ file. Then set the ownership and and permissions on the rancid files and directories.

cp cloginrc.sample /home/rancid/.cloginrc 
chmod 0640 /home/rancid/.cloginrc 
chown -R rancid:netadm /home/rancid/.cloginrc 
chown -R rancid:netadm /usr/local/rancid/ 
chmod 775 /usr/local/rancid/ 

Create folders “Routers Switches Firewalls”,you will see when you first log into the ViewVC web front end.

vim /usr/local/rancid/etc/rancid.conf 
Uncomment and add your groups, i.e. 
LIST_OF_GROUPS="Routers Switches Firewalls" 

Apply changes:

su - rancid 
/usr/local/rancid/bin/rancid-cvs
exit

Anytime when /usr/local/rancid/etc/rancid.conf is edited, above command needs to be executed.

Installing ViewVC

ViewVC is a browser interface for CVS and Subversion version control repositories. It generates templatized HTML to present navigable directory, revision, and change log listings. It can display specific versions of files as well as diffs between those versions.

cd /home/rancid/tar/ 
wget http://www.viewvc.org/downloads/viewvc-1.1.27.tar.gz 
tar -xzvf viewvc-1.1.27.tar.gz 
cd viewvc-1.1.27 
./viewvc-install 

Configuring ViewVC

vim /usr/local/viewvc-1.1.27/viewvc.conf 
#Uncomment and change the values, (as shown bellow)# 
root_parents = /usr/local/rancid/var/CVS : cvs 
rcs_dir = /usr/local/bin 
use_rcsparse = 1 

Enable ViewVC to work with Apache httpd, we need to copy over some CGI, and set some permissions.

cp /usr/local/viewvc-1.1.27/bin/cgi/*.cgi /var/www/cgi-bin/ 
chmod +x /var/www/cgi-bin/*.cgi 
chown apache:apache /var/www/cgi-bin/*.cgi 

MariaDB configuration

systemctl enable mariadb 
systemctl start mariadb 
mysql_secure_installation

We need to create a user in MariaDB SQL that ViewVC will use, to do this we need to log into SQL using the root password set up in previous step (mysql_secure_installation)

mysql -u root -p 
Enter your SQL root password 
CREATE USER 'VIEWVC'@'localhost' IDENTIFIED BY 'MyP4ssW0rd'; 
GRANT ALL PRIVILEGES ON *.* TO 'VIEWVC'@'localhost' WITH GRANT OPTION; 
FLUSH PRIVILEGES; 
quit 

Now we can setup database and get ViewVC to create its database.

cd /usr/local/viewvc-1.1.27/bin/ 
./make-database 

Create another user in MariaDB, that will be a ‘read-only’ user.

mysql -u root -p 
CREATE USER 'VIEWVCRO'@'localhost' IDENTIFIED BY 'MyP4ssW0rd'; 
GRANT SELECT ON ViewVC.* TO 'VIEWVCRO'@'localhost' WITH GRANT OPTION; 
FLUSH PRIVILEGES; 
quit 

Edit the ViewVC configuration so that it uses all the parameters you have setup.

vim /usr/local/viewvc-1.1.27/viewvc.conf

enabled = 1 
host = localhost 
port = 3306 
database_name = ViewVC 
user = VIEWVC 
passwd = MyP4ssW0rd 
readonly_user = VIEWVCRO 
readonly_passwd = MyP4ssW0rd

Rebuild the database

/usr/local/viewvc-1.1.27/bin/cvsdbadmin rebuild /usr/local/rancid/var/CVS/CVSROOT/

Apache configuration

Following configuration will:

  • enable SSL/https connection by self-signed certificate
  • will redirect http to https
  • will configure Active directory authentication
dnf install mod_ldap
# create self-signed certificate
cd /etc/ssl/certs
sudo openssl req -x509 -nodes -days 3650 -newkey rsa:2048 -keyout rancid.key -out rancid.crt

Configure SSL Virtual host

vi /etc/httpd/conf.d/ssl.conf

SSLCertificateFile /etc/ssl/certs/rancid.crt 
SSLCertificateKeyFile /etc/ssl/certs/rancid.key 
<VirtualHost _default_:443> 
DocumentRoot "/var/www" 
ScriptAlias /cgi-bin/ "/var/www/cgi-bin" 
ScriptAlias /viewvc /var/www/cgi-bin/viewvc.cgi 
ScriptAlias /query /var/www/cgi-bin/query.cgi 
ServerName rancid.test.com:443 

<Directory "/var/www/cgi-bin"> 
    AllowOverride None 
    Options None 
    Order allow,deny 
    Allow from all 
    AuthType Basic 
    AuthName "login to continue" 
    AuthBasicProvider ldap 
    AuthLDAPBindAuthoritative off 
    AuthLDAPURL "ldap://test.com/dc=test,dc=com?sAMAccountName 
    AuthLDAPBindDN "test@test.com" 
    AuthLDAPBindPassword "somepassword" 
    require valid-user  
</Directory> 

Create virtual host and configure http to https redirection

vi /etc/httpd/conf.d/viewvc.conf

<VirtualHost *:80> 
        ServerAlias * 
        DocumentRoot /var/www 
        ScriptAlias /cgi-bin/ "/var/www/cgi-bin" 
        ScriptAlias /viewvc /var/www/cgi-bin/viewvc.cgi 
        ScriptAlias /query /var/www/cgi-bin/query.cgi 
        RewriteEngine on 
        RewriteRule "^/?(.*)"  "https://%{HTTP_HOST}/$1" [R=301] 
</VirtualHost> 

systemctl enable httpd && systemctl start httpd

Type http://ip/viewvc, you should be automatically forwarded to https/ip/viewvc, credentials pop-up will ask for username/password and following page should be seen

Adding devices to Rancid

Rancid groups are represented by respective folders in /usr/local/rancid/var folder

In this example switch will be added

vi /usr/local/rancid/var/Switches/router.db

Fileformat: ip-or-hostname;vendor;up

In this case content would be

1.1.1.1;cisco,up

Adding credentials

vi /home/rancid/.cloginrc

add user {ip-or-hostname} {username}
add password {ip-or-hostname} {password}
add method {ip-or-hostname} {ssh or telnet}
add autoenable {ip-or-hostname} 1

Applying changes

su rancid
/usr/local/rancid/bin/rancid-run

Above command won’t give any output, in case of errors examine logs

cd /usrcd /usr/local/rancid/var/logs/
ls
cat {log-name}

# or interactively debugging

/usr/local/rancid/bin/clogin -c "sh run" IP/or host name

Configuring notifications

which sendmail
/sbin

Edit /usr/local/rancid/bin/control_rancid

SENDMAIL=${SENDMAIL:=/sbin/sendmail};

Rancid uses groups in following format:

rancid-"group_name" 
rancid-admin-"group_name"

The first group will receive a report after a configuration change, the second one when there is error messages.Vi need to create those aliases so postfix can use it for sending emails.

vi /etc/aliases

rancid-Switches:        email@test.com
rancid-admin-Switches:  email@test.com 

Apply aliases, start sendmail and postfix:

newaliases
systemctl enable postfix && systemctl start postfix
systemctl enable sendmail && systemctl start sendmail

When trying to move files in python, if, for destination, only folder is specified, and if file already exist in destination, python will raise an error that file already exists.

import shutil
import os

source = "C:\Users\user\Downloads\python-2.7.17.msi"
destination = "C:\Users\user\Desktop"
shutil.move(source, destination)

raise Error, "Destination path '%s' already exists" % real_dst
shutil.Error: Destination path 'C:\Users\user\Desktop\python-2.7.17.msi' already exists

In order to overwrite file (if one already exists in destination), we need to specify full path for destination,not only destination folder name, for example C:\Users\user\Downloads\python-2.7.17.msi

import shutil
import os

source = "C:\Users\user\Downloads\python-2.7.17.msi"
destination = "C:\Users\user\Desktop"
filename = os.path.basename(source)
dest = os.path.join(destination,filename)
shutil.move(source, dest)

Usernames and passwords are stored in CSV file:

1.csv:

link,user,password
http://1.1.1.1,user1,password1
http://2.2.2.2,user2,password2

We can extract link,user and password using this Powershell script:

# Constants.
$DELIM = ','
$CSV_F = 'C:\Users\user\Desktop\1.csv' 

# Parse keys
$keys = (gc "${CSV_F}" -TotalCount 1).Split($DELIM)
$csv = Import-CSV "${CSV_F}"
$data = @()

# Iterate through CSV to build array of hashtables.
ForEach ($r in $csv) {
    $tmp_h = @{}

    # Create hash of key-value pairs.
    ForEach($k in $keys) {
        $tmp_h[$k] = $r.($k)
    }

    # Add hash to array of hashes.
    $data += $tmp_h
}
# Display data
foreach($i in $data){
$link = $i.link
$user = $i.user
$password = $i.password
}

Encrypting CSV file

Because this file contains sensitive data, it would be reasonable to encrypt it.We’ll use Protect-CmsMessage cmd-let to achieve that.

Create a certificate for encrypting content

In Powershell console paste certificate request (change subject name and.or inf file name):

# Create .INF file for certreq

{[Version]
Signature = "$Windows NT$"

[Strings]
szOID_ENHANCED_KEY_USAGE = "2.5.29.37"
szOID_DOCUMENT_ENCRYPTION = "1.3.6.1.4.1.311.80.1"

[NewRequest]
Subject = "cn=youralias@emailaddress.com"
MachineKeySet = false
KeyLength = 2048
KeySpec = AT_KEYEXCHANGE
HashAlgorithm = Sha1
Exportable = true
RequestType = Cert
KeyUsage = "CERT_KEY_ENCIPHERMENT_KEY_USAGE | CERT_DATA_ENCIPHERMENT_KEY_USAGE"
ValidityPeriod = "Years"
ValidityPeriodUnits = "1000"

[Extensions]
%szOID_ENHANCED_KEY_USAGE% = "{text}%szOID_DOCUMENT_ENCRYPTION%"
} | Out-File -FilePath DocumentEncryption.inf

After you have created your certificate file, run the following command to add the certificate file to the certificate store.

Only user(s) who have access to this certificate can encrypt/decrypt files.

certreq -new DocumentEncryption.inf DocumentEncryption.cer 

Encrypt CSV file using certificate subject or OID number:

Protect-CmsMessage -To "*youralias@emailaddress.com*" -Path C:\Users\user\Desktop\1.csv -OutFile C:\Users\user\Desktop\1.csv.cms

Following script will decrypt CSV “on the fly”, and store it’s content into $CSV_F variable, avoiding storing un-encrypted CSV file.

$CSV_F = Unprotect-CmsMessage -To "*youralias@emailaddress.com*" -Path .\1.csv.cms 

$Data = $CSV_F | ConvertFrom-Csv
foreach($i in $Data){

$link = $i.link

$user = $i.user

$password = $i.password

}

In this article we’ll be configuring Jenkins server so it can access to minikube cluster.

Jenkins is installed on Windows 10 machine and minikube is running on Virtual Box VM.For details how to run minkube on Windows, see this post.

Preparing a service account for kubernetes-plugin in minikube

account.yaml:

---
apiVersion: v1
kind: ServiceAccount
metadata:
  name: jenkins
  namespace: default
---
kind: Role
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: jenkins
  namespace: default
rules:
- apiGroups: [""]
  resources: ["pods","services"]
  verbs: ["create","delete","get","list","patch","update","watch"]
- apiGroups: ["apps"]
  resources: ["deployments"]
  verbs: ["create","delete","get","list","patch","update","watch"]
- apiGroups: [""]
  resources: ["pods/exec"]
  verbs: ["create","delete","get","list","patch","update","watch"]
- apiGroups: [""]
  resources: ["pods/log"]
  verbs: ["get","list","watch"]
- apiGroups: [""]
  resources: ["secrets"]
  verbs: ["get"]
- apiGroups: [""]
  resources: ["persistentvolumeclaims"]
  verbs: ["create","delete","get","list","patch","update","watch"]

---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
  name: jenkins
  namespace: default
roleRef:
  apiGroup: rbac.authorization.k8s.io
  kind: Role
  name: jenkins
subjects:
- kind: ServiceAccount
  name: jenkins
---
# Allows jenkins to create persistent volumes
# This cluster role binding allows anyone in the "manager" group to read secrets in any namespace.
kind: ClusterRoleBinding
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  name: jenkins-crb
subjects:
- kind: ServiceAccount
  namespace: default
  name: jenkins
roleRef:
  kind: ClusterRole
  name: jenkinsclusterrole
  apiGroup: rbac.authorization.k8s.io
---
kind: ClusterRole
apiVersion: rbac.authorization.k8s.io/v1
metadata:
  # "namespace" omitted since ClusterRoles are not namespaced
  name: jenkinsclusterrole
rules:
- apiGroups: [""]
  resources: ["persistentvolumes"]
  verbs: ["create","delete","get","list","patch","update","watch"]

Apply above file, it will create service account

Get token:

kubectl get secrets
NAME                  TYPE                                  DATA   AGE
default-token-9f5cx   kubernetes.io/service-account-token   3      67m
jenkins-token-rk2mg   kubernetes.io/service-account-token   3      38m

kubectl describe secrets/jenkins-token-rk2mg
Name:         jenkins-token-rk2mg
Namespace:    default
Labels:       <none>
Annotations:  kubernetes.io/service-account.name: jenkins
              kubernetes.io/service-account.uid: 43e75f2b-5dde-4c8c-add7-0613d4a59707

Type:  kubernetes.io/service-account-token

Data
====
ca.crt:     1066 bytes
namespace:  7 bytes
token:      eyJhbGciOiJSUzI1NiIsImtpZCI6InJNMGd2WWwxTENGbWZ5Z1J1ODJJMk84ZXhPRVkxVVhkTENCU0dmWWY4TGsifQ.eyJpc3MiOiJrdWJlcm5ldGVzL3NlcnZpY2VhY2NvdW50Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9uYW1lc3BhY2UiOiJkZWZhdWx0Iiwia3ViZXJuZXRlcy5pby9zZXJ2aWNlYWNjb3VudC9zZWNyZXQubmFtZSI6ImplbmtpbnMtdG9rZW4tcmsybWciLCJrdWJlcm5ldGVzLmlvL3NlcnZpY2VhY2NvdW50L3NlcnZpY2UtYWNjb3VudC5uYW1lIjoiamVua2lucyIsImt1YmVybmV0ZXMuaW8vc2VydmljZWFjY291bnQvc2VydmljZS1hY2NvdW50LnVpZCI6IjQzZTc1ZjJiLTVkZGUtNGM4Yy1hZGQ3LTA2MTNkNGE1OTcwNyIsInN1YiI6InN5c3RlbTpzZXJ2aWNlYWNjb3VudDpkZWZhdWx0OmplbmtpbnMifQ.Gh0xmcYkQUk0hVElueiKmeKS3bzPcEAqeTyHrXV88n9CCucvP84vh4Cq0s1E2sw7UluQInSlHConf4GXB1HcYK5dAv-w7i0cod9u_zBzrlb_Km5BkR3mtjdpoTgGIWR9xEHwfj9_Vh7g89-Y6HO8mB2jGbpovm2EnxyRUMJ7QuV6UNFV-de_xzLLUuwdfhqAxtPnUltz7VzYY0OI_k6tesPva4C4pX0R3b3Fvb8LJjxZDEvrrx5UbGVjFJh9_THYGzMfxpsQwrHqhA1PrjxCJo8I0B19MreghzGllOjZKcIS7EINYfob2KsUBOnXluiglFY3oQ2tyK24JNpzrM5WbA

Copy above token to clipboard, we’ll need it later on.

In C:\users\%USERNAME%\.kube folder there is file named config

apiVersion: v1
clusters:
- cluster:
    certificate-authority: C:\Users\dragan.vucanovic\.minikube\ca.crt
    server: https://172.16.0.104:8443
  name: minikube
contexts:
- context:
    cluster: minikube
    user: minikube
  name: minikube
current-context: minikube
kind: Config
preferences: {}
users:
- name: minikube
  user:
    client-certificate: C:\Users\dragan.vucanovic\.minikube\client.crt
    client-key: C:\Users\dragan.vucanovic\.minikube\client.key

We’ll need server and client-certificate value

In Jenkins click on Manage Jenkins – Configure Credentials – Credentials – Jenkins

In drop-down menu select Add credentials

Kind: secret text

Secret: token string (output of kubectl describe secrets/jenkins-token-rk2mg)

Configuring Kubernetes plugin

Jenkins – manage Jenkins – Configure system scroll to bottom and in Add a new cloud, select Kubernetes

Kubernetes URL: value server from config file

 Kubernetes server certificate key: value certificate-authority from config file

Credentials: credentials created in previous step.

Click on “Test Connection” tab and you should get Connection test successful

We now can reference Jenkins secret into pipeline

stage('Deploy Patient App') {
    steps {
        withCredentials([
            string(credentialsId: 'kubernetes', variable: 'api_token')
            ]) {
             sh 'kubectl --token $api_token --server https://172.17.86.28:8443 --insecure-skip-tls-verify=true apply -f some.yaml '
               }
            }
           }

Install Git for Windows

Install Virtual Box

Install Jenkins

Install Docker toolbox

Enable support for native Linux commands on Windows:

Add C:\Program Files\Git\usr\bin and C:\Program Files\Docker Toolbox to System PATH environment variable

Open CMD and type Docker-machine env default

You’ll get similar output:

SET DOCKER_TLS_VERIFY=1
SET DOCKER_HOST=tcp://172.16.0.102:2376
SET DOCKER_CERT_PATH=C:\Users\dragan.vucanovic.docker\machine\machines\default
SET DOCKER_MACHINE_NAME=default
SET COMPOSE_CONVERT_WINDOWS_PATHS=true
REM Run this command to configure your shell:
REM @FOR /f "tokens=*" %i IN ('Docker-machine env default') DO @%i

Open Jenkins – Manage Jenkins – Configure System – Check Environment variables check box and add following variables:

  • DOCKER_CERT_PATH
  • DOCKER_HOST
  • DOCKER_MACHINE
  • DOCKER_TLS_VERIFY

Define docker command:

Jenkins – Global Tool configuration – Docker – Docker installation

Name: Docker

Installation root: C:\Program Files\Docker Toolbox

Restart Jenkins service

Now you should be able to deploy Docker images same way as in Linux system

stage('Build and Push Image') {
         steps {
           sh 'docker image build -t ${REPOSITORY_TAG} .'
         }
      }

Upgrade awx-cli:

pip install ansible-tower-cli --upgrade

awx-cli config verify_ssl False

Backup AWX

Make sure AWX containers are running and you can login to Web GUI

docker ps

Export Credentials, Inventories, Job templates and Workflows

awx-cli receive -u admin -p 'password' -h http://awx-old --credential all > credential.json
awx-cli receive -u admin -p 'password' -h http://awx-old --project all > project.json
awx-cli receive -u admin -p 'password' -h http://awx-old --inventory all > inventory.json
awx-cli receive -u admin -p 'password' -h http://awx-old --job_template all > job_template.json
awx-cli receive -u admin -p 'password' -h http://awx-old --workflow all > workflow.json

Installing new AWX (on new machine)

Install epel-relase, AWX prerequisites,Docker, docker-compose and Ansible

yum install -y epel-release 
yum -y install git gcc gcc-c++ nodejs gettext device-mapper-persistent-data lvm2 bzip2 python-pip
yum-config-manager --addrepo=https://download.docker.com/linux/centos/docker-ce.repo
yum install -y docker-ce
# Enable and start Docker service
systemctl enable --now docker.service
# install docker-compose
pip install docker-compose
# install Ansible
yum install ansible
# Start and enable Ansible
systemctl enable ansible && systemctl start ansible

Installing Ansible AWX 

git clone --depth 50 https://github.com/ansible/awx.git
#  set a custom admin_password for AWX and PostgreSQL in inventory file.
cd awx/installer
sed -i 's|admin_password=.*|admin_password=pass|g' inventory
# Add secret_key in inventory file.
openssl rand -base64 30
lE7TAtB/EGDfZp2vYJWY1jVwn3nDh3H+a0pqhXHZ
sed -i 's|secret_key=.*|secret_key=lE7TAtB/EGDfZp2vYJWY1jVwn3nDh3H+a0pqhXHZ|g' inventory

Customize other directives if needed in inventory file, for example host_port=9000 and postgres folder – postgres_data_dir = "/data"

Install AWX Ansible

ansible-playbook -i inventory install.yml

# Check if all 5 containers are installed
docker ps

Allow HTTP/HTTPS service in Linux firewall

firewall-cmd --permanent --add-service=http
firewall-cmd --permanent --add-service=https
firewall-cmd --reload

In this example, AWX will be available on port 9000

Try Logging in: http://awx-new:9000

Redirecting HTTP traffic to HTTPS

We’ll use nginx as reverse proxy to redirect HTTP traffic on port 9000 to HTTPS.

yum install nginx
systemctl enable nginx

Create self-signed certificate:

cd /etc/awx
sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 -keyout /etc/awx/awx.key -out /etc/awx/awx.crt

Generating a 2048 bit RSA private key
.....................................+++
.........................................................+++
writing new private key to '/etc/awx/awx.key'
-----
You are about to be asked to enter information that will be incorporated
into your certificate request.
What you are about to enter is what is called a Distinguished Name or a DN.
There are quite a few fields but you can leave some blank
For some fields there will be a default value,
If you enter '.', the field will be left blank.
-----
Country Name (2 letter code) [XX]:SR
State or Province Name (full name) []:
Locality Name (eg, city) [Default City]:Zemoon
Organization Name (eg, company) [Default Company Ltd]:
Organizational Unit Name (eg, section) []:
Common Name (eg, your name or your server's hostname) []:awx-new.test.com
Email Address []:

Edit /etc/nging/nginx.conf

user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /run/nginx.pid;

# Load dynamic modules. See /usr/share/nginx/README.dynamic.
include /usr/share/nginx/modules/*.conf;

events {
    worker_connections 1024;
}

http {
    log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                      '$status $body_bytes_sent "$http_referer" '
                      '"$http_user_agent" "$http_x_forwarded_for"';

    access_log  /var/log/nginx/access.log  main;

    sendfile            on;
    tcp_nopush          on;
    tcp_nodelay         on;
    keepalive_timeout   65;
    types_hash_max_size 2048;

    include             /etc/nginx/mime.types;
    default_type        application/octet-stream;

    # Load modular configuration files from the /etc/nginx/conf.d directory.
    # See http://nginx.org/en/docs/ngx_core_module.html#include
    # for more information.
    include /etc/nginx/conf.d/*.conf;

    server {
        listen       80 default_server;
        listen       [::]:80 default_server;
        server_name  awx-new.test.com;
        add_header Strict-Transport-Security max-age=2592000;
        rewrite ^ https://$server_name$request_uri? permanent;
        root         /example;

        # Load configuration files for the default server block.
        include /etc/nginx/default.d/*.conf;

        location / {
        }

        error_page 404 /404.html;
            location = /40x.html {
        }

        error_page 500 502 503 504 /50x.html;
            location = /50x.html {
        }
    }


server
{
 listen 443 ssl http2;
 server_name awx-new.test.com;

location /
 {
   proxy_http_version 1.1;
   proxy_set_header Host $host;
   proxy_set_header X-Real-IP $remote_addr;
   proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
   proxy_set_header X-Forwarded-Proto $scheme;
   proxy_set_header Upgrade $http_upgrade;
   proxy_set_header Connection "upgrade";
   proxy_pass http://192.168.1.2:9000/;
 }

ssl on;
ssl_certificate /etc/awx/awx.crt;
ssl_certificate_key /etc/awx/awx.key;
ssl_session_timeout 5m;
ssl_ciphers EECDH+CHACHA20:EECDH+AES128:RSA+AES128:EECDH+AES256:RSA+AES256:EECDH+3DES:RSA+3DES:!MD5:HIGH:!aNULL;
ssl_protocols TLSv1 TLSv1.1 TLSv1.2;
ssl_prefer_server_ciphers on;

access_log /var/log/nginx/awx.access.log;
error_log /var/log/nginx/awx.error.log;
}

Start nginx (systemctl start nginx) and try accessing AWX https://awx-new.test.com

Restoring AWX

Install awx-cli

pip install ansible-tower-cli --upgrade

awx-cli config verify_ssl False

Manually create organization: Organizations-“plus” sign

Create Teams (if you had any on old AWX)

# Restore Credentials 

awx-cli send -u admin -p 'pass' -h http://awx-new.test.com:9000 credential.json

#P lease note that passwords won't be exported, you'll need to enter it # manually after usernames are imported (Credentials section in Web GUI)

 # restore project

awx-cli send -u admin -p 'pass' -h http://awx-new.test.com:9000 project.json

# restore inventories

awx-cli send -u admin -p 'pass' -h http://awx-new.test.com:9000 inventory.json

# before restoring job templates, remove line which contains string credential

sed -i '/\bcredential\b/d' job_template.json

# restore job templates

awx-cli send -u admin -p 'pass' -h http://awx-new.test.com:9000 job_template.json

# restore workflows

awx-cli send -u admin -p 'pass' -h http://awx-new.test.com:9000 workflow.json

Active Directory Authentication

LDAP config won’t be exported so we need to set it up manually: In Web portal click Settings-Authentication-LDAP

LDAP SERVER: default

LDAP SERVER URI: ldap://1.2.3.4:389

LDAP BIND DN: CN=Ansible,OU=ServiceUsers,OU=test,DC=com

LDAP BIND PASSWORD: password

LDAP GROUP TYPE: ActiveDirectoryGroupType

LDAP USER SEARCH: [
 "OU=Users,OU=test,DC=com",
 "SCOPE_SUBTREE",
 "(sAMAccountName=%(user)s)"
]
 
LDAP GROUP SEARCH: [
 "CN=Users,DC=test,DC=com",
 "SCOPE_SUBTREE",
 "(objectClass=group)"
]

LDAP ORGANIZATION MAP: {
 "My Organization": {
  "remove_admins": false,
  "admins": "CN=Ansible, OU=Security,OU=Groups,OU=test,DC=com"
 }
}

 

In this example SCCM and SQL services are monitored by NCPA agent.

Open host configuration file /usr/local/nagios/etc/objects/conf.d/hostname.cfg

Add following lines:

define service{
        use                             generic-service
        host_name                       sccm.test.com
        service_description             SMS Agent host
        check_command                   check_ncpa!-t 'API KEY' -P 5693 -M 'services' -q 'service=CcmExec,status=running'
        }


define service{
        use                             generic-service
        host_name                       sccm.test.com
        service_description             SMS EXECUTIVE
        check_command                   check_ncpa!-t 'API KEY' -P 5693 -M 'services' -q 'service=SMS_EXECUTIVE,status=running'
        }

define service{
        use                             generic-service
        host_name                       sccm.test.com
        service_description             SMS NOTIFICATION SERVER
        check_command                   check_ncpa!-t 'API KEY' -P 5693 -M 'services' -q 'service=SMS_NOTIFICATION_SERVER,status=running'
        }


define service{
        use                             generic-service
        host_name                       sccm.test.com
        service_description             SMS SITE COMPONENT MANAGER
        check_command                   check_ncpa!-t 'API KEY' -P 5693 -M 'services' -q 'service=SMS_SITE_COMPONENT_MANAGER,status=running'
        }


define service{
        use                             generic-service
        host_name                       sccm.test.com
        service_description             SMS SITE SQL BACKUP
        check_command                   check_ncpa!-t 'API KEY' -P 5693 -M 'services' -q 'service=SMS_SITE_SQL_BACKUP,status=running'
        }

define service{
        use                             generic-service
        host_name                       sccm.test.com 
        service_description             SMS SITE VSS WRITER
        check_command                   check_ncpa!-t 'API KEY' -P 5693 -M 'services' -q 'service=SMS_SITE_VSS_WRITER,status=running'
        }


define service{
        use                             generic-service
        host_name                       sccm.test.com
        service_description             SQL Server
        check_command                   check_ncpa!-t 'API KEY' -P 5693 -M 'services' -q 'service=MSSQLSERVER,status=running'
        }


define service{
        use                             generic-service
        host_name                       sccm.test.com
        service_description             SQL Server Reporting Services
        check_command                   check_ncpa!-t 'API KEY' -P 5693 -M 'services' -q 'service=SQLServerReportingServices,status=running'
        }

Service name can be found in services.msc snap-in

Restart nagios systemctl restart nagios and new services should appear for host.