Skip to content

Commit

Permalink
Make the new cabsagent work on windows
Browse files Browse the repository at this point in the history
  • Loading branch information
jacobobryant committed Nov 29, 2016
1 parent 85865ab commit 96e2b36
Show file tree
Hide file tree
Showing 14 changed files with 166 additions and 484 deletions.
1 change: 1 addition & 0 deletions .gitignore
Expand Up @@ -5,3 +5,4 @@ venv
*.rpm
*.deb
dist
*.exe
23 changes: 23 additions & 0 deletions agent/Makefile
@@ -0,0 +1,23 @@
SHELL=/bin/bash
SHELLFLAGS="-O extglob -c"
VERSION=$(shell cat ../version.txt)
NAME=cabsagent-windows-$(VERSION)
DIR=build/$(NAME)

default: installer archive

archive:
mkdir -p $(DIR)
cd app && cp agent_server.pem \
broker_cert.pem \
cabsagent.conf \
cabsagentsvc.exe \
install.exe \
../$(DIR)
cd build && zip -r $(NAME).zip $(NAME)/

installer:
makensis app/install.nsi

clean:
rm -rf build/*
34 changes: 25 additions & 9 deletions agent/README.md
Expand Up @@ -12,16 +12,32 @@ must be added to the Broker's database manually. See cabs-broker for more
information.

### Linux
Copy the `app/` directory to the machine and run
`app/install.sh`. This will install the agent to `/opt/cabsagent/`. After
installation, edit `/opt/cabsagent/cabsagent.conf` as needed. Start the service with
`systemctl start cabsagent`. Set it to start on boot with `systemctl enable cabsagent`.
Copy the `app/` directory to the machine and run `app/install.sh`. This will install the agent
to `/opt/cabsagent/`. After installation, edit `/opt/cabsagent/cabsagent.conf` as needed. Start
the service with `systemctl start cabsagent`. Set it to start on boot with `systemctl enable
cabsagent`.

### Windows
The most recent version of the Agent is incomplete for Windows.* A previous
version is in the windows folder. Run `windows/Install_CABS_Agent.exe` to
install.
#### Building
First, you have to create cabsagentsvc.exe with pyinstaller. In a Windows environment,
- install ActiveState python. This will ensure the win32 python modules are installed
correctly. If the modules aren't installed correctly, later on the Windows service will give
an error about the service not starting in a timely fashion.
- Install dependency modules: `pip -r app/requirements.txt`.
- Install pyinstaller: `pip install pyinstaller`
- Create the executable: `pyinstaller --onefile app/cabsagentsvc.py`
- Move the executable from `dist/cabsagentsvc.exe` to `app/cabsagentsvc.exe`

*The script itself is working, but it isn't installable as a service yet.
After that, you can run `make` from Linux to create a zipfile with the installation script.
Make will include ssl certificates that are not checked into git, so make sure those are in the
app directory. You may want to edit `app/cabsagent.conf` before running `make` so that the
zipfile will contain the configuration you want.

See the README and wiki in the cabs-broker repo for more information about the CABS system.
#### Installing
Once the zipfile is created (it will be at `build/cabsagent-windows-<version>.zip`), copy it to
the target machine, unzip and run `install.exe`. After installing, this will start the agent
immediately and set it to start on boot.

If something doesn't work, you can test it out by
running `cabsagentsvc.exe debug` from a command prompt in the `C:\Program Files\CABS\Agent`
directory. You may have to run `cabsagentsvc.exe stop` first if the service is already running.
9 changes: 5 additions & 4 deletions agent/app/cabsagent.conf
Expand Up @@ -3,7 +3,7 @@
# commented. Spaces in filenames are ok.

# Address of the broker.
#Host_Addr: broker
Host_Addr: cabs.et.byu.edu

# Port for the agent to report to the broker.
#Agent_Port: 18182
Expand All @@ -16,15 +16,16 @@

# Can be a relative (to Cert_Dir) or absolute path.
# If Agent_Priv_Key is unset, Agent_Cert must contain the private key.
#Broker_Cert: broker_cert.pem
#Agent_Cert: agent_server.pem
Broker_Cert: broker_cert.pem
Agent_Cert: agent_server.pem
#Agent_Priv_Key:

# How often (in seconds) the agent will report to the broker. If this is too
# large, then machines will not free up as soon as they are availible. This MUST
# be shorter than the Broker's Reserve_Time, but should probably be 2 or 3 times
# shorter.
#Interval: 120
Interval: 120

# Which process the agent should monitor.
#Process_Listen: rgsender
Process_Listen: rgsender.exe
62 changes: 26 additions & 36 deletions agent/app/cabsagent.py
Expand Up @@ -3,6 +3,8 @@

# Workaround until a bugfix in pyinstaller gets released on pypi.
# See https://github.com/pyinstaller/pyinstaller/commit/f788dec36b8d55f4518881be9f4188ad865306ec
import ctypes.util

import socket, ssl
import sys
import os
Expand Down Expand Up @@ -37,10 +39,13 @@
#global heartbeat_pid
requestStop = False

application_path = os.path.dirname(os.path.abspath(
sys.executable if getattr(sys, 'frozen', False) else __file__))
default_config = os.path.join(application_path, 'cabsagent.conf')
settings = { "Host_Addr":'broker',
"Agent_Port":18182,
"Command_Port":18185,
"Cert_Dir":"/etc/ssl/certs",
"Cert_Dir":application_path,
"Broker_Cert":None,
"Agent_Cert":None,
"Agent_Priv_Key":None,
Expand All @@ -49,6 +54,8 @@
"Hostname":None }
checks = []

DEBUG = False

def ps_check():
# get the status of a process that matches settings.get("Process_Listen")
# then check to make sure it has at least one listening conection on windows, you can't
Expand Down Expand Up @@ -103,7 +110,7 @@ def restart():


def win_info(user, display):
if argv.debug:
if DEBUG:
template = ('0x01e00003 -1 0 {} 1024 24 rgsl-07 Top Expanded Edge Panel\n'
'0x01e00024 -1 0 1536 1024 24 rgsl-07 Bottom Expanded Edge Panel\n')
return template.format('-48' if isfile('/tmp/no_panel') else '0')
Expand Down Expand Up @@ -134,9 +141,10 @@ def panel_check():

else:
assert os.name == "nt"
#import win32service
#import win32event
#import servicemanager

# Fix for another pyinstaller problem.
import _cffi_backend

import win32api
import win32serviceutil
from getpass import getuser
Expand All @@ -155,14 +163,6 @@ def find_process():
return None
return psutil.Process(int(m.group(0)))

#def heartbeat_loop():
# if len(sys.argv) == 1:
# servicemanager.Initialize()
# servicemanager.PrepareToHostSingle(AgentService)
# servicemanager.StartServiceCtrlDispatcher()
# else:
# win32serviceutil.HandleCommandLine(AgentService)

def restart():
print "restarting"
if settings["Process_Listen"] is None:
Expand All @@ -183,9 +183,7 @@ def heartbeat_loop():
s = scheduler(time, sleep)
#read config for time interval, in seconds
print "Starting. Pulsing every {0} seconds.".format(settings.get("Interval"))
while True:
if requestStop:
break
while not requestStop:
s.enter(int(settings.get("Interval")), 1, heartbeat, ())
s.run()

Expand All @@ -207,7 +205,7 @@ def heartbeat():
traceback.print_exc()

def getStatus():
if argv.debug and isfile('/tmp/oldstatus'):
if DEBUG and isfile('/tmp/oldstatus'):
return "rgsender3"

problems = [result for result in [func() for func in checks]
Expand Down Expand Up @@ -240,9 +238,9 @@ def start_ssl_cmd_server():
factory = Factory.forProtocol(CommandHandler)
reactor.listenSSL(int(settings.get("Command_Port")), factory, certificate.options(authority))

def readConfigFile():
if isfile(argv.config):
with open(argv.config, 'r') as f:
def readConfigFile(config):
if isfile(config):
with open(config, 'r') as f:
for line in f:
line = line.strip()
if line.startswith('#') or not line:
Expand All @@ -268,22 +266,9 @@ def readConfigFile():
#If we want a fqdn we can use socket.gethostbyaddr(socket.gethostname())[0]
settings["Hostname"] = socket.gethostname()

def stop():
requestStop = True
reactor.callFromThread(reactor.stop)

def start():
application_path = os.path.dirname(os.path.abspath(
sys.executable if getattr(sys, 'frozen', False) else __file__))
default_config = os.path.join(application_path, 'cabsagent.conf')
global argv
parser = ArgumentParser()
parser.add_argument('-d', '--debug', action='store_true')
parser.add_argument('-f', '--config', default=default_config)
argv = parser.parse_args()

def start(config=default_config):
print("starting up")
readConfigFile()
readConfigFile(config)
global checks
if settings['Process_Listen'] and psutil:
checks.append(ps_check)
Expand All @@ -300,4 +285,9 @@ def start():
reactor.run()

if __name__ == "__main__":
start()
parser = ArgumentParser()
parser.add_argument('-d', '--debug', action='store_true')
parser.add_argument('-f', '--config', default=default_config)
argv = parser.parse_args()
DEBUG = argv.debug
start(argv.config)
78 changes: 78 additions & 0 deletions agent/app/cabsagentsvc.py
@@ -0,0 +1,78 @@
import win32serviceutil
import win32event
import win32service
import win32api
import servicemanager
import time
import cabsagent
import sys
import os
#from sched import scheduler

class AgentService(win32serviceutil.ServiceFramework):
#_svc_name_ = "aservice"
#_svc_display_name_ = "a service - it does nothing"
#_svc_description_ = "foo bar"
_svc_name_ = "CABS_Agent"
_svc_display_name_ = "CABS Agent"
_svc_description_ = "The Agent reporting to the CABS Broker"

def __init__(self, args):
win32serviceutil.ServiceFramework.__init__(self, args)
self.stop_event = win32event.CreateEvent(None, 0, 0, None)

def SvcStop(self):
self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
win32event.SetEvent(self.stop_event)
cabsagent.stop()

def SvcDoRun(self):
servicemanager.LogMsg(servicemanager.EVENTLOG_INFORMATION_TYPE,
servicemanager.PYS_SERVICE_STARTED,
(self._svc_name_, ''))
cabsagent.start()

# These methods can be used instead for testing.

# def __init__(self, args):
# win32serviceutil.ServiceFramework.__init__(self, args)
# #logfile = os.path.join(os.getenv('APPDATA'), 'cabsagent.log')
# #print("log location:", logfile)
# #logging.basicConfig(filename=logfile, format='%(asctime)s %(message)s',
# # level=logging.DEBUG)
# #logging.info("AgentService.__init__()")
# self.hWaitStop = win32event.CreateEvent(None, 0, 0, None)
# #self.stop_requested = False
#
# def SvcStop(self):
# self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
# win32event.SetEvent(self.hWaitStop)
#
# def SvcDoRun(self):
# self.ReportServiceStatus(win32service.SERVICE_RUNNING)
# import servicemanager
# servicemanager.LogMsg(servicemanager.EVENTLOG_INFORMATION_TYPE,
# servicemanager.PYS_SERVICE_STARTED,
# (self._svc_name_, ''))
# self.timeout = 3000
#
# while 1:
# rc = win32event.WaitForSingleObject(self.hWaitStop, self.timeout)
# if rc == win32event.WAIT_OBJECT_0:
# servicemanager.LogInfoMsg("aservice - STOPPED")
# break
# else:
# servicemanager.LogInfoMsg("aservice - is alive and well")
#
#def ctrlHandler(ctrlType):
# return True

if __name__ == "__main__":
#win32api.SetConsoleCtrlHandler(ctrlHandler, True)
#win32serviceutil.HandleCommandLine(aservice)
if len(sys.argv) == 1:
servicemanager.Initialize()
servicemanager.PrepareToHostSingle(AgentService)
servicemanager.StartServiceCtrlDispatcher()
else:
win32serviceutil.HandleCommandLine(AgentService)
16 changes: 8 additions & 8 deletions agent/windows/install.nsi → agent/app/install.nsi
Expand Up @@ -6,7 +6,7 @@
Name "CABS Windows Agent"

# The file to write
OutFile "Install_CABS_Agent.exe"
OutFile "install.exe"

# The default installation directory
InstallDir "C:\Program Files\CABS\Agent"
Expand Down Expand Up @@ -42,7 +42,7 @@ Section "CABS Agent (required)"
SetOutPath $INSTDIR

# Put file there
File "CABS_agent.exe"
File "cabsagentsvc.exe"

#Copy over the other items
CopyFiles $EXEDIR\cabsagent.conf $INSTDIR
Expand All @@ -52,16 +52,16 @@ Section "CABS Agent (required)"
FindClose $0

#Install the Service
Exec '"$INSTDIR\CABS_agent.exe" --startup=auto install'
Exec '"$INSTDIR\CABS_agent.exe" start'
Exec '"$INSTDIR\cabsagentsvc.exe" --startup=auto install'
Exec '"$INSTDIR\cabsagentsvc.exe" start'


# Write the installation path into the registry
WriteRegStr HKLM SOFTWARE\CABS_agent "Install_Dir" "$INSTDIR"
WriteRegStr HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\CABS_agent" "UninstallString" '"$INSTDIR\uninstall.exe"'
WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\CABS_agent" "NoModify" 1
WriteRegDWORD HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\CABS_agent" "NoRepair" 1
WriteUninstaller $INSTDIR\uninstaller.exe
WriteUninstaller $INSTDIR\uninstall.exe

SectionEnd

Expand All @@ -70,10 +70,10 @@ Section "Uninstall"
DeleteRegKey HKLM "Software\Microsoft\Windows\CurrentVersion\Uninstall\CABS_agent"
DeleteRegKey HKLM SOFTWARE\CABS_agent

Delete $INSTDIR\uninstaller.exe
Delete $INSTDIR\uninstall.exe

Delete $INSTDIR\CABS_agent.exe
Delete $INSTDIR\CABS_agent.conf
Delete $INSTDIR\cabsagentsvc.exe
Delete $INSTDIR\cabsagent.conf
FindFirst $0 $1 $INSTDIR\*.pem
Delete $INSTDIR\$1
FindClose $0
Expand Down

0 comments on commit 96e2b36

Please sign in to comment.