I just saw this posted, I have been meaning to setup something similar for along time… I think I just need to get some small scale practice with this type of projects first, see what works and what goes wrong, fix issues, etc.
I was digging through my old script archive, and ran across a bunch of Python Fabric modules I used some time ago. I’ve got a bunch more for deploying Nginx, and other tests I was playing with (if I can find them)
You can edit the ENV list and run the commands on multiple servers. It’s not Ansible, it’s Fabic, running commands remotely. You could easily create Bash function to call these methods directly.
This particular set of functions is rather simple, and used on/for Ubuntu based servers.
Save file as: fab.py
You could get fancy and create a connection module, list a bunch of IP’s, and do it all that way. This is just a simple example.
This could be handy for creating the functions to deploy the exercise above without going full Ansible or learning other intricate automation frameworks.
After you write up each individual function, you could write a simple main function that runs them all to deploys the service in its entirety.
"""
Date.........: 2/19/2017
Author.......: KI7MT
Description..: Remote server commands using Fabric3
Updating package list
fab -u username -p password --sudo-password=password setup update
Check for updates
fab -u username -p password --sudo-password=password setup check
Update and Upgrade (reboot if necessary)
fab -u username -p pasword --sudo-password=password setup upgrade
"""
from fabric.api import sudo, run, env
from fabric.colors import red
from fabric.contrib.files import exists
from fabric.contrib.console import confirm
def setup():
"""
Sets up the environment using the given user and host addresses
"""
global env
env.hosts = ["192.168.1.1"] # Change this to your remote server IP address
def update():
"""
Updates the package list
"""
sudo('apt-get -qq update')
def check():
"""
Displays package updates needed
"""
run("""apt-get dist-upgrade -s | python3 -c "import sys; [sys.stderr.write(l) for l in sys.stdin.readlines()[7:] if not (l.startswith('Inst') or l.startswith('Conf'))]" """)
def upgrade():
"""
Upgrades the system, updating packages and reboots if needed
"""
sudo('apt-get -y -qq upgrade')
if exists('/var/run/reboot-required') and confirm('Needs reboot, do it now?'):
print(red('Rebooting now', True))
sudo('reboot')
def clean():
"""
Cleans the packages and install script in /var/cache/apt/archives
"""
sudo('apt-get -y -q clean')
def autoclean():
"""
Removes obsolete unbuntu-packages
"""
sudo('apt-get -y -q autoclean')
def autoremove():
"""
Removes packages that are no longer needed
"""
sudo('apt-get -y -q autoremove')
def autoremove_purge():
"""
Removes packages that are no longer needed plus residual files
"""
sudo('apt-get -y -q autoremove --purge')
After a couple of days I’m now realizing is probably going to be easier to simply switch from Virtualbox to libvirt as the default provider in Vagrant. This way I can maintain all the configuration as code and everything will continue to work fairly easily, including private networks, ssh, etc. As you can also specify the provisioner in form of ansible or shell scripts, I think it’s going to be more flexible.
I still haven’t test this but from the look of it, the fact that it returns Python object I think makes it really useful for more complex cases where you can easily account for errors, specific versions, etc. I will try this out for sure, thanks! Do you have any more scripts like this?
I found one project I was messing with on Digital Ocean. It simply deployed a .NetCore Web app along with Nginx.If I have some time this weekend, I’ll clean it up and push the example to my Gihub repo.
This won’t work at present, as it needs the dependent files (systemd, service file, project HelloMvc, etc)
"""
Date.........: 3/3/2017
Author.......: KI7MT
Description..: Hellomvc Web Server Functions using Fabric3
SYNOPSIS
Example .Net Core MVC project that runs on Ubuntu 16.04 with Nginx Proxy
server. For simplicity, and to prevent inadvertent installation of
cross-projects, each project should have it's own *.py file.
Publishing with Python Fabric3 is functional, but may not be the best
solution for this activity. Each project requires a SystemD *.service file
in order to maintain the service. This script will provide for such measure,
but, subsequent updates (Agile Style of Continuous Integration) to the
application could be provided by repository tools.
USAGE
Initial Deployment: fab -f hellomvc_example.py -u USER -p PASSWORD --sudo-password="PASSWORD" connect initial_webapp_deployment
Republish: fab -f hellomvc_example.py -u USER -p PASSWORD --sudo-password="PASSWORD" connect republish_webapp
"""
import os
import sys
from fabric.api import *
from fabric.colors import *
from server_connect import connect as connect
# Project Data
PROJECT_NAME='NginxTesting'
PACKAGE_NAME='Hellomvc'
GIT_URL='<UPDATE_THIS-REPO>'
SOURCE_DIR='~/src/'
DESTINATION_DIR='/var/webapps/hellomvc'
SERVICE_FILE='hellomvc.service'
INSTALL_LOCATION='/etc/systemd/system'
#------------------------------------------------------------------------------
# GENERAL PURPOSE FUNCTIONS
#------------------------------------------------------------------------------
def checkout_project():
"""
As a normal user, clone the sample project
Usage: fab -f hellomvc_example.py -u USER -p PASSWORD connect checkout_project
@param GIT_URL: is the url of the git repository
"""
print(yellow("\nChecking Out Project: %s " % PROJECT_NAME))
run('mkdir -p ~/src && cd ~/src && git clone %s' % GIT_URL)
def fetch_updates():
"""
Fetch updated from the remote repository
Usage: fab -f hellomvc_example.py -u USER -p PASSWORD connect fetch_updates
"""
print(yellow("\nFetching Updates for: %s " % PROJECT_NAME))
run('cd ~/src/%s && git fetch' % PROJECT_NAME)
def service_generate():
"""
Generate systemd service file for the project
NOTE: Normal Ubuntu systemd.service files go into /lib/systemd/system, then
a syslink (ln -s) in /etc/systemd/system. However, the Microsoft instructions
claim it should be installed in /etc/systemd/system directory.
To maintain the continuity with the Microsoft How-Too, /etc/systemd/system
is used for this example.
Usage: fab -f hellomvc_example.py -u USER -p PASSWORD --sudo-password="PASSWORD" connect service_generate
"""
# function variables
f = SERVICE_FILE
sf = SOURCE_DIR + f
dest = DESTINATION_DIR
# start the generation process
print(yellow("\nGenerating [ %s ] File" % f))
run('cd ~')
run('rm -f %s' % sf)
run('touch %s' % sf)
run('echo [Unit] >> %s' % sf)
run('echo Description="Dot Net Core Hello MVC Example" >> %s' % sf)
run('echo "" >> %s' % sf)
run('echo [Service] >> %s' % sf)
run('echo WorkingDirectory=%s >> %s' %(dest,sf))
run('echo ExecStart=/usr/bin/dotnet %s/Hellomvc.dll >> %s' % (dest,sf))
run('echo Restart=always >> %s' % sf)
run('echo RestartSec=10 >> %s' % sf)
run('echo SyslogIdentifier=dotnet-example >> %s' % sf)
run('echo User=www-data >> %s' % sf)
run('echo Environment=ASPNETCORE_ENVIRONMENT=Production >> %s' % sf)
run('echo Environment=DOTNET_PRINT_TELEMETRY_MESSAGE=false >> %s' % sf)
run('echo "" >> %s' % sf)
run('echo [Install] >> %s' % sf)
run('echo WantedBy=multi-user.target >> %s' % sf)
print(green("Finished!"))
# Now install the service file to the final location
print(yellow("\nInstalling [ %s ] File" % f))
sudo('cp -u %s /etc/systemd/system/%s' % (sf,f))
# change the permissions.
sudo('chown root:root /etc/systemd/system/%s' % f)
print(green("Finished!"))
def service_enable():
"""
Enable a unit to be started on bootup: helloomvc service
Usage: fab -f hellomvc_example.py -u USER -p PASSWORD --sudo-password="PASSWORD" connect enable_service
"""
print(yellow("\nEmable Service [ %s ] " % SERVICE_FILE))
sudo('systemctl enable %s' % SERVICE_FILE)
def service_start():
"""
Start a unit immediately: hellomvc.service
Usage: fab -f hellomvc_example.py -u USER -p PASSWORD --sudo-password="PASSWORD" connect start_service
"""
print(yellow("\nStarting Service [ %s ] " % SERVICE_FILE))
sudo('systemctl start %s' % SERVICE_FILE)
def service_stop():
"""
Stop a unit immediately: hellomvc.service
Usage: fab -f hellomvc_example.py -u USER -p PASSWORD --sudo-password="PASSWORD" connect stop_service
"""
print(yellow("\nStopping Service [ %s ] " % SERVICE_FILE))
sudo('systemctl stop %s' % SERVICE_FILE)
def service_restart():
"""
Restart a unit: hellomvc.service
Usage: fab -f hellomvc_example.py -u USER -p PASSWORD --sudo-password="PASSWORD" connect restart_service
"""
print(yellow("\nRestarting Service [ %s ] " % SERVICE_FILE))
sudo('systemctl restart %s' % SERVICE_FILE)
def service_disable():
"""
Disable a unit to not start during bootup: hellomvc.service
Usage: fab -f hellomvc_example.py -u USER -p PASSWORD --sudo-password="PASSWORD" connect disable_service
"""
print(yellow("\nDisabling Service [ %s ] " % SERVICE_FILE))
sudo('systemctl disable %s' % SERVICE_FILE)
def service_check():
"""
Check whether a unit is already enabled or not: hellomvc.service
Usage: fab -f hellomvc_example.py -u USER -p PASSWORD --sudo-password="PASSWORD" connect check_enabled
"""
print(yellow("\nChecking Service Enabled [ %s ] " % SERVICE_FILE))
sudo('systemctl is-enabled %s' % SERVICE_FILE)
def service_status():
"""
Display status of hellomvc.service
Usage: fab -f hellomvc_example.py -u USER -p PASSWORD --sudo-password="PASSWORD" connect status_service
"""
print(yellow("\nChecking Service Status [ %s ] " % SERVICE_FILE))
sudo('systemctl status %s' % SERVICE_FILE)
def reload_systemd():
"""
Reload Systemd Discovery Deamon
Usage: fab -f hellomvc_example.py -u USER -p PASSWORD --sudo-password="PASSWORD" connect reload_systemd
"""
print(yellow("\nReloading Systemd Daemon"))
sudo('systemctl daemon-reload')
#------------------------------------------------------------------------------
# PUBLISH and UPDATE FUNCTIONS
#------------------------------------------------------------------------------
def update_webapp():
"""
Republish the project to a specified location
Note: By design, this function requires the user to enter the sudo password
Usage: fab -f hellomvc_example.py -u USER -p PASSWORD connect update_webapp
"""
# fetch new updates
fetch_updates()
# Stop the Web Service
service_stop()
# disable the service
service_disable()
# Rebuild the project
print(yellow("\nPublishing Project : %s/%s (Requires SUDO Password)" % (PROJECT_NAME,PACKAGE_NAME)))
run('cd ~/src/%s/%s && sudo dotnet publish -c Release -o %s' % (PROJECT_NAME,PACKAGE_NAME,DESTINATION_DIR))
# Update Permissions on Destination directory
print(yellow("\nUpdateing Permissions on [%s]" % DESTINATION_DIR))
sudo('chown -R www-data:www-data %s' % DESTINATION_DIR)
# Re-Enable the Service
service_enable()
# Re-Start the system service
service_start()
# Reload Systemd
reload_systemd()
print(green("\nFinished Publishing [%s]" % PACKAGE_NAME))
def publish_webapp():
"""
Initial project deployment
Note: By design, this function requires the user to enter the sudo password
Usage: fab -f hellomvc_example.py -u USER -p PASSWORD connect publish_webapp
"""
print(yellow("\nInitial Project Deployment : %s/%s (Requires SUDO Password)" % (PROJECT_NAME,PACKAGE_NAME)))
run('cd ~/src/%s/%s && sudo dotnet publish -c Release -o %s' % (PROJECT_NAME,PACKAGE_NAME,DESTINATION_DIR))
print(green("\nFinished Publishing [%s]" % PACKAGE_NAME))
#------------------------------------------------------------------------------
# PUBLISH NEW PROJECT
#------------------------------------------------------------------------------
def initial_webapp_deployment():
"""
Deploy Hellomvc on a new webserver after update, upgrades, Nginx and .Net SKD installation
Usage: fab -f hellomvc_example.py -u USER -p PASSWORD --sudo-password="PASSWORD" connect initial_webapp_deployment
"""
checkout_project()
publish_webapp()
service_generate()
service_enable()
service_start()
reload_systemd()
service_status()
# END hellomvc_example.py