Vagrant replacements for local development?

Here’s a really good exercise, and classic example for somebody that wants to learn automation.

Nextcloud Full Setup Implementation - From Jay

  • Spin up a VM / BM server
  • Get the base OS updated, etc
  • Automate this deployment (Shell Scripts, Ansible, whatever)

You’ll learn “a lot” from going through this process no matter what framework you choose.

4 Likes

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.

Reference Documentation: Python3 Fabric

"""
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')
2 Likes

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? :slight_smile:

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 

1 Like