|
@@ -1,873 +0,0 @@
|
|
|
-#!/usr/bin/env python2
|
|
|
-
|
|
|
-# Copyright (C) 2012-2014, Eduardo Silva <[email protected]>
|
|
|
-#
|
|
|
-# This program is free software; you can redistribute it and/or modify
|
|
|
-# it under the terms of the GNU General Public License as published by
|
|
|
-# the Free Software Foundation; either version 2 of the License, or
|
|
|
-# (at your option) any later version.
|
|
|
-#
|
|
|
-# This program is distributed in the hope that it will be useful,
|
|
|
-# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
-# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
|
-# GNU General Public License for more details.
|
|
|
-#
|
|
|
-# You should have received a copy of the GNU General Public License
|
|
|
-# along with this program; if not, write to the Free Software
|
|
|
-# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
|
|
-
|
|
|
-import os
|
|
|
-import sys
|
|
|
-import shutil
|
|
|
-import getopt
|
|
|
-import datetime
|
|
|
-import ConfigParser
|
|
|
-
|
|
|
-from git import GitProject
|
|
|
-from utils import *
|
|
|
-
|
|
|
-# Version
|
|
|
-DUDAC_VERSION = "0.23"
|
|
|
-
|
|
|
-# Internal / Protocol
|
|
|
-PROTOCOL_HTTPS = 0
|
|
|
-PROTOCOL_GIT = 1
|
|
|
-
|
|
|
-class DudaConfig(ConfigParser.ConfigParser):
|
|
|
- def __init__(self):
|
|
|
- ConfigParser.ConfigParser.__init__(self)
|
|
|
-
|
|
|
- def open(self, path):
|
|
|
- self.read(path)
|
|
|
-
|
|
|
- def get_handlers(self):
|
|
|
- return self.sections()
|
|
|
-
|
|
|
- def get_key(self, handler, key):
|
|
|
- try:
|
|
|
- val = self.get(handler, key)
|
|
|
- return val
|
|
|
- except:
|
|
|
- return None
|
|
|
-
|
|
|
-class Monkey:
|
|
|
- opts = ''
|
|
|
- recent_configure = False
|
|
|
- recent_build = False
|
|
|
- recent_clean = False
|
|
|
-
|
|
|
- def __init__(self, source_path):
|
|
|
- self.mk_path = source_path
|
|
|
- self.SSL = False
|
|
|
-
|
|
|
- def configure(self):
|
|
|
- if self.recent_configure is True:
|
|
|
- return
|
|
|
-
|
|
|
- cpath = os.getcwd()
|
|
|
- os.chdir(self.mk_path)
|
|
|
-
|
|
|
- configure = "./configure --debug --disable-plugins='*' --enable-plugins='liana,duda' " + self.opts
|
|
|
-
|
|
|
- # If we have SSL enable, we have to replace the transport layer, that means
|
|
|
- # disable Liana and enable the new PolarSSL, later we need to generate
|
|
|
- # certificates and configure everything to make it work properly
|
|
|
- if self.SSL is True:
|
|
|
- configure = configure.replace('liana','polarssl')
|
|
|
-
|
|
|
- # Run the configure script
|
|
|
- execute("Monkey : prepare build", configure)
|
|
|
-
|
|
|
- # Revert to original path
|
|
|
- os.chdir(cpath)
|
|
|
- self.recent_configure = True
|
|
|
-
|
|
|
- def make_build(self):
|
|
|
- if self.recent_build is True:
|
|
|
- return
|
|
|
-
|
|
|
- cmd = "make -C %s" % (self.mk_path)
|
|
|
- execute("Monkey : building", cmd)
|
|
|
-
|
|
|
- self.recent_build = True
|
|
|
-
|
|
|
- def make_clean(self):
|
|
|
- if self.recent_clean is True:
|
|
|
- return
|
|
|
-
|
|
|
- if os.path.exists(self.mk_path + '/Makefile') is False:
|
|
|
- return
|
|
|
-
|
|
|
- cmd = "make -C %s clean" % (self.mk_path)
|
|
|
- execute("Monkey : cleaning", cmd)
|
|
|
-
|
|
|
- self.recent_clean = True
|
|
|
-
|
|
|
- def system(self, cmd):
|
|
|
- return commands.getstatusoutput(cmd)
|
|
|
-
|
|
|
- def update_transport_layer(self, t='plain'):
|
|
|
- if t == 'plain':
|
|
|
- pass
|
|
|
- elif t == 'SSL':
|
|
|
- pass
|
|
|
-
|
|
|
-class MonkeyGIT (GitProject):
|
|
|
- def __init__(self):
|
|
|
- https_repo = 'https://github.com/monkey/monkey.git'
|
|
|
- git_repo = '[email protected]:monkey/monkey.git'
|
|
|
- GitProject.__init__(self, 'Monkey', https_repo, git_repo)
|
|
|
-
|
|
|
- def home(self):
|
|
|
- # Check our user temporal directory
|
|
|
- home = os.getenv('USERPROFILE') or os.getenv('HOME')
|
|
|
- dudac_home = "%s/.dudac" % (home)
|
|
|
-
|
|
|
- return "%s/monkey" % (dudac_home)
|
|
|
-
|
|
|
-class DudaGIT(GitProject):
|
|
|
- def __init__(self):
|
|
|
- https_repo = 'https://github.com/monkey/duda.git'
|
|
|
- git_repo = '[email protected]:monkey/duda.git'
|
|
|
- GitProject.__init__(self, 'Duda', https_repo, git_repo)
|
|
|
-
|
|
|
- def home(self):
|
|
|
- # Check our user temporal directory
|
|
|
- home = os.getenv('USERPROFILE') or os.getenv('HOME')
|
|
|
- dudac_home = "%s/.dudac" % (home)
|
|
|
-
|
|
|
- return "%s/duda" % (dudac_home)
|
|
|
-
|
|
|
-class Duda:
|
|
|
- # Default configuration directives for Monkey configuration
|
|
|
- # file located under the [SERVER] section
|
|
|
- MCONF_KNOWN = ['Port',
|
|
|
- 'Listen',
|
|
|
- 'Workers',
|
|
|
- 'Timeout',
|
|
|
- 'PidFile',
|
|
|
- 'UserDir',
|
|
|
- 'Indexfile',
|
|
|
- 'HideVersion',
|
|
|
- 'Resume',
|
|
|
- 'User',
|
|
|
- 'KeepAlive',
|
|
|
- 'KeepAliveTimeout',
|
|
|
- 'MaxKeepAliveRequest',
|
|
|
- 'MaxRequestSize',
|
|
|
- 'SymLink',
|
|
|
- 'TransportLayer',
|
|
|
- 'DefaultMimeType']
|
|
|
-
|
|
|
- def __init__(self):
|
|
|
- self.print_version()
|
|
|
- self.web_service = None
|
|
|
- self.service = None
|
|
|
- self.port = 2001
|
|
|
- self.SSL = False
|
|
|
- self.SSL_default = False
|
|
|
- self.output_stdout = False
|
|
|
- self.api_level = DEFAULT_API_LEVEL
|
|
|
- self.linux_malloc = False
|
|
|
- self.linux_trace = False
|
|
|
- self.jemalloc_stats = False
|
|
|
- self.jemalloc_prof = False
|
|
|
- self.rebuild_monkey = False
|
|
|
- self.mk_git = MonkeyGIT()
|
|
|
- self.duda_git = DudaGIT()
|
|
|
- self.mk_home = self.mk_git.home()
|
|
|
- self.duda_home = self.duda_git.home()
|
|
|
- self.dudac_wd = '%s/.dudac' % (os.getenv('USERPROFILE') or os.getenv('HOME'))
|
|
|
- self.dudac_stage_path = os.getenv('DUDAC_STAGE_PATH')
|
|
|
- self.load_makefile()
|
|
|
-
|
|
|
- # In case the DUDAC_STAGE_PATH environment variable is set, use
|
|
|
- # the alternative stage path. This is useful when using a fixed-path
|
|
|
- # version of Monkey and Duda plugin, mostly for development purposes
|
|
|
- if self.dudac_stage_path is not None:
|
|
|
- self.stage_home = self.dudac_stage_path
|
|
|
- else:
|
|
|
- self.stage_home = self.dudac_wd + '/stage/'
|
|
|
-
|
|
|
- self.monkey = Monkey(self.stage_home + 'monkey/')
|
|
|
- self.get_arguments()
|
|
|
-
|
|
|
- exit(0)
|
|
|
-
|
|
|
- def load_makefile(self):
|
|
|
- dot = os.path.dirname(os.path.abspath(__file__))
|
|
|
- f = open(os.path.join(dot, "dudac.Make"), "r")
|
|
|
- self.dudac_makefile = f.read()
|
|
|
- f.close
|
|
|
-
|
|
|
- # This routine read the config.dudac configuration file which is
|
|
|
- # optional inside every web service source code. It specifies the
|
|
|
- # Monkey sources requirements and perform the right setup
|
|
|
- def config_requirements(self):
|
|
|
- ws = os.path.abspath(self.service)
|
|
|
- if not os.path.isdir(ws):
|
|
|
- print "Error: Invalid web service directory"
|
|
|
- exit(1)
|
|
|
-
|
|
|
- # Check if is an API level
|
|
|
- try:
|
|
|
- api_number = int(self.api_level)
|
|
|
- except:
|
|
|
- api_number = -1
|
|
|
-
|
|
|
- if api_number > 0:
|
|
|
- version = "dst-%i" % (api_number)
|
|
|
- else:
|
|
|
- version = self.api_level
|
|
|
-
|
|
|
- mk_version = version
|
|
|
- mk_https_repo = None
|
|
|
- mk_git_repo = None
|
|
|
- duda_version = version
|
|
|
- duda_https_repo = None
|
|
|
- duda_git_repo = None
|
|
|
-
|
|
|
- # Check if the service have a configuration file
|
|
|
- config_file = os.path.abspath("%s/dudac.conf" % (ws))
|
|
|
- if os.path.isfile(config_file) is True:
|
|
|
- # Read the configuration
|
|
|
- config = DudaConfig()
|
|
|
- config.open(config_file)
|
|
|
-
|
|
|
- for h in config.get_handlers():
|
|
|
- if h == 'MONKEY':
|
|
|
- # Get key/values
|
|
|
- mk_version = config.get_key(h, 'version')
|
|
|
- mk_https_repo = config.get_key(h, 'https_repo')
|
|
|
- mk_git_repo = config.get_key(h, 'git_repo')
|
|
|
- elif h == 'DUDA':
|
|
|
- duda_version = config.get_key(h, 'version')
|
|
|
- duda_https_repo = config.get_key(h, 'https_repo')
|
|
|
- duda_git_repo = config.get_key(h, 'git_repo')
|
|
|
-
|
|
|
- # Configure repos
|
|
|
- self.mk_git.setup(mk_version, mk_https_repo, mk_git_repo)
|
|
|
- self.duda_git.setup(duda_version, duda_https_repo, duda_git_repo)
|
|
|
-
|
|
|
- def update_framework(self, protocol):
|
|
|
- self.mk_git.set_protocol(protocol)
|
|
|
- self.duda_git.set_protocol(protocol)
|
|
|
-
|
|
|
- if os.path.exists(self.mk_home):
|
|
|
- self.mk_git.update(self.mk_home)
|
|
|
- else:
|
|
|
- self.mk_git.clone(self.mk_home)
|
|
|
-
|
|
|
- if os.path.exists(self.duda_home):
|
|
|
- self.duda_git.update(self.duda_home)
|
|
|
- else:
|
|
|
- self.duda_git.clone(self.duda_home)
|
|
|
-
|
|
|
- # Cleanup and rebuild Monkey
|
|
|
- cpath = os.getcwd()
|
|
|
- os.chdir(self.mk_home)
|
|
|
-
|
|
|
- self.mk_git.version = self.api_level
|
|
|
- self.mk_git.snapshot()
|
|
|
-
|
|
|
- self.duda_git.version = self.api_level
|
|
|
- self.duda_git.snapshot()
|
|
|
-
|
|
|
- self.merge_on_stage()
|
|
|
- self.monkey.configure()
|
|
|
-
|
|
|
- if os.path.exists("./Makefile"):
|
|
|
- self.monkey.make_clean()
|
|
|
-
|
|
|
- self.monkey.make_build()
|
|
|
- os.chdir(cpath)
|
|
|
-
|
|
|
- def merge_on_stage(self):
|
|
|
- # Create archives from repos
|
|
|
- self.mk_git.archive_to(self.stage_home + '/monkey')
|
|
|
- self.duda_git.archive_to(self.stage_home + '/monkey/plugins/duda')
|
|
|
-
|
|
|
- # Tag the content with branch used
|
|
|
- f = open(self.stage_home + '/monkey/api_level.dudac', 'w')
|
|
|
- f.write(self.mk_git.version + '\n')
|
|
|
- f.close()
|
|
|
-
|
|
|
-
|
|
|
- def run_webservice(self, schema=None):
|
|
|
- ws = os.path.abspath(self.service)
|
|
|
- monkey_stage = self.monkey.mk_path
|
|
|
-
|
|
|
- # Check if the web service was staged and built previously, we
|
|
|
- # this check to make sure the service is updated as the user needs/want
|
|
|
- stage_level = self.stage_home + '/monkey/api_level.dudac'
|
|
|
- if os.path.isfile(stage_level):
|
|
|
- f = open(stage_level, 'r')
|
|
|
- level = f.read().replace('\n', '')
|
|
|
- f.close()
|
|
|
-
|
|
|
- if level != self.mk_git.version:
|
|
|
- self.rebuild_monkey = True
|
|
|
- else:
|
|
|
- self.rebuild_monkey = True
|
|
|
-
|
|
|
- if self.rebuild_monkey is True:
|
|
|
- # Backup our original path
|
|
|
- cpath = os.getcwd()
|
|
|
-
|
|
|
- # On rebuild, check that stack sources are in place
|
|
|
- if os.path.exists(self.mk_home) is False or \
|
|
|
- os.path.exists(self.duda_home) is False:
|
|
|
- fail_msg("Error: the stack components are missing, try: \n\n" \
|
|
|
- " $ dudac -s\n")
|
|
|
- sys.exit(1)
|
|
|
-
|
|
|
- # Make sure Monkey sources match the snapshot
|
|
|
- if not os.getenv('DUDAC_STAGE_PATH'):
|
|
|
- self.mk_git.snapshot()
|
|
|
- self.duda_git.snapshot()
|
|
|
- self.merge_on_stage()
|
|
|
-
|
|
|
- # Cleanup and rebuild Monkey
|
|
|
- os.chdir(monkey_stage)
|
|
|
-
|
|
|
- if os.path.exists("./Makefile"):
|
|
|
- self.monkey.make_clean()
|
|
|
-
|
|
|
- self.monkey.configure()
|
|
|
- self.monkey.make_build()
|
|
|
-
|
|
|
- # Restore path
|
|
|
- os.chdir(cpath)
|
|
|
-
|
|
|
- makefile = "%s/Makefile" % (ws)
|
|
|
- makefile_in = "%s/Makefile.in" % (ws)
|
|
|
- if os.path.isdir(ws) is False or os.path.exists(makefile_in) is False:
|
|
|
- print "Error: Invalid web service directory " + ws
|
|
|
- exit(1)
|
|
|
-
|
|
|
- # Monkey headers
|
|
|
- mk_inc = monkey_stage + "/src/include"
|
|
|
- mk_duda = monkey_stage + "/plugins/duda/src"
|
|
|
- mk_packages = monkey_stage + "/plugins/duda/"
|
|
|
-
|
|
|
- # Read the Makefile.in file
|
|
|
- mk_ins = []
|
|
|
- for root, dirs, files in os.walk(ws):
|
|
|
- for file in files:
|
|
|
- if file == 'Makefile.in':
|
|
|
- path = "%s/%s" % (root, file)
|
|
|
- mk_ins.append(root)
|
|
|
-
|
|
|
- for mk in mk_ins:
|
|
|
- mk_in = "%s/Makefile.in" % (mk)
|
|
|
-
|
|
|
- CC_SET = None
|
|
|
-
|
|
|
- f = open(mk_in, "r")
|
|
|
- lines = f.readlines()
|
|
|
- f.close()
|
|
|
-
|
|
|
- raw = ""
|
|
|
- for line in lines:
|
|
|
- if line.startswith("INCDIR"):
|
|
|
- prev = line.replace("INCDIR", "")
|
|
|
- prev = prev.replace("=", "").strip()
|
|
|
-
|
|
|
- raw += "INCDIR = " + prev
|
|
|
- raw += " -I" + mk_inc
|
|
|
- raw += " -I" + mk_duda
|
|
|
- raw += " -I" + mk_packages + "\n"
|
|
|
- else:
|
|
|
- raw += line
|
|
|
- raw += "\n"
|
|
|
-
|
|
|
- makefile = "%s/Makefile" % (mk)
|
|
|
- f_mk = open(makefile, "w")
|
|
|
- f_mk.write("# Autogenerated by Duda Client Manager\n")
|
|
|
- f_mk.write("# ====================================\n")
|
|
|
-
|
|
|
- today = datetime.datetime.now()
|
|
|
- f_mk.write("# Date : " + today.strftime('%a %d, %b %Y at %H:%M') + "\n")
|
|
|
- f_mk.write("# Stage Path: " + monkey_stage + "\n\n")
|
|
|
-
|
|
|
- f_mk.write(raw)
|
|
|
- f_mk.write(self.dudac_makefile)
|
|
|
- f_mk.close()
|
|
|
-
|
|
|
- # Cleanup web service and rebuild
|
|
|
- execute("WebService : clean", "make -C " + ws + " clean")
|
|
|
- execute("WebService : build", "make -C " + ws)
|
|
|
-
|
|
|
- # Get services
|
|
|
- services = []
|
|
|
- list = os.listdir(ws)
|
|
|
- for entry in list:
|
|
|
- p = ws + "/" + entry
|
|
|
- if os.path.isfile(p) and entry.endswith(".duda"):
|
|
|
- e = {'name': entry[:-5], 'filename': entry}
|
|
|
- services.append(e)
|
|
|
-
|
|
|
- # check that services exists
|
|
|
- if len(services) == 0:
|
|
|
- print "Error: i could not find Duda services under", ws
|
|
|
- exit(1)
|
|
|
-
|
|
|
- # Setting up virtual host
|
|
|
- vhost = monkey_stage + "/conf/sites/default"
|
|
|
- f = open(vhost, "r")
|
|
|
- lines = f.readlines()
|
|
|
- f.close()
|
|
|
-
|
|
|
- # Setting up web services
|
|
|
- print "%s %-70s" % (MSG_NEW, "Monkey : configure HTTP Server"),
|
|
|
- raw = ""
|
|
|
- for line in lines:
|
|
|
- if line.startswith('[WEB_'):
|
|
|
- break
|
|
|
- else:
|
|
|
- raw += line
|
|
|
-
|
|
|
- for s in services:
|
|
|
- raw += "[WEB_SERVICE]\n"
|
|
|
- raw += " Name " + s['name'] + "\n"
|
|
|
- raw += " Enabled on\n"
|
|
|
-
|
|
|
- html = os.path.abspath(self.service) + '/html/'
|
|
|
- if os.path.exists(html):
|
|
|
- raw += " DocumentRoot %s\n" % (html)
|
|
|
-
|
|
|
- confdir = os.path.abspath(self.service) + '/conf/'
|
|
|
- if os.path.exists(confdir):
|
|
|
- raw += " ConfDir %s\n" % (confdir)
|
|
|
-
|
|
|
- datadir = os.path.abspath(self.service) + '/data/'
|
|
|
- if os.path.exists(datadir):
|
|
|
- raw += " DataDir %s\n" % (datadir)
|
|
|
-
|
|
|
- logdir = os.path.abspath(self.service) + '/logs/'
|
|
|
- if os.path.exists(logdir):
|
|
|
- raw += " LogDir %s\n" % (logdir)
|
|
|
-
|
|
|
- raw += "\n"
|
|
|
-
|
|
|
- f = open(vhost, "w")
|
|
|
- f.write(raw)
|
|
|
- f.close()
|
|
|
-
|
|
|
- # Make sure Duda plugin is enabled on plugins.load
|
|
|
- plugins = monkey_stage + "/conf/plugins.load"
|
|
|
- f = open(plugins, "r")
|
|
|
- lines = f.readlines()
|
|
|
- f.close()
|
|
|
-
|
|
|
- raw = ""
|
|
|
- for line in lines:
|
|
|
- if line.startswith(" # Load") and line.strip().endswith("-duda.so"):
|
|
|
- line = " " + line[6:]
|
|
|
-
|
|
|
- raw += line
|
|
|
-
|
|
|
- f = open(plugins, "w")
|
|
|
- f.write(raw)
|
|
|
- f.close()
|
|
|
-
|
|
|
- # Setting up Duda plugin configuration
|
|
|
- duda = monkey_stage + "/conf/plugins/duda/duda.conf"
|
|
|
- f = open(duda, "r")
|
|
|
- lines = f.readlines()
|
|
|
- f.close()
|
|
|
-
|
|
|
- raw = ""
|
|
|
- for line in lines:
|
|
|
- if line.startswith(" ServicesRoot"):
|
|
|
- raw += " ServicesRoot " + ws + "\n"
|
|
|
- else:
|
|
|
- raw += line
|
|
|
-
|
|
|
- f = open(duda, "w")
|
|
|
- f.write(raw)
|
|
|
- f.close()
|
|
|
-
|
|
|
- # Setting up Monkey
|
|
|
- monkey = monkey_stage + "/conf/monkey.conf"
|
|
|
- f = open(monkey, "r")
|
|
|
- lines = f.readlines()
|
|
|
- f.close()
|
|
|
-
|
|
|
- raw = ""
|
|
|
- for line in lines:
|
|
|
- if line.startswith(" Port"):
|
|
|
- raw += " Port " + str(self.port) + "\n"
|
|
|
- elif line.startswith(" User"):
|
|
|
- raw += " # User Inactivated by DudaC\n"
|
|
|
- elif line.startswith(" TransportLayer") and self.rebuild_monkey is True:
|
|
|
- if self.SSL is True:
|
|
|
- raw += " TransportLayer polarssl\n"
|
|
|
- self.SSL_default = True
|
|
|
- else:
|
|
|
- raw += " TransportLayer liana\n"
|
|
|
- self.SSL_default = False
|
|
|
- elif line.startswith(" TransportLayer") and line.find('polarssl') > 0:
|
|
|
- self.SSL_default = True
|
|
|
- raw += line
|
|
|
- else:
|
|
|
- raw += line
|
|
|
-
|
|
|
- f = open(monkey, "w")
|
|
|
- f.write(raw)
|
|
|
- f.close()
|
|
|
-
|
|
|
- print MSG_OK
|
|
|
-
|
|
|
- # Schema
|
|
|
- # ======
|
|
|
- # Once the new monkey.conf Port and TransportLayer are set, we can start
|
|
|
- # overriding the config if we have a schema. We do this at the end to do not
|
|
|
- # mess with specific settings handled by the previous lines.
|
|
|
- if schema is not None:
|
|
|
- # Change direct Port global
|
|
|
- if 'Port' in schema:
|
|
|
- self.port = schema['Port']
|
|
|
-
|
|
|
- # open the file and read it content
|
|
|
- f = open(monkey, "r")
|
|
|
- lines = f.readlines()
|
|
|
- f.close()
|
|
|
-
|
|
|
- # compose a new buffer
|
|
|
- raw = ""
|
|
|
- for line in lines:
|
|
|
- row = line
|
|
|
- key = None
|
|
|
- val = None
|
|
|
- kv = []
|
|
|
- if line.startswith(" "):
|
|
|
- # strip the indentation
|
|
|
- row = line[4:]
|
|
|
-
|
|
|
- # Lets see if this line can belong to a commented key/value
|
|
|
- if row[:2] == '# ':
|
|
|
- arr = row[2:].split()
|
|
|
- if len(arr) == 2 and arr[0][-1] != ':':
|
|
|
- if arr[0] in self.MCONF_KNOWN:
|
|
|
- # ok, its a known key and is commented, now lets check
|
|
|
- # if this key is bein overriden through the schema
|
|
|
- if not arr[0] in schema:
|
|
|
- raw += line
|
|
|
- else:
|
|
|
- raw += " %s %s\n" % (arr[0], schema[arr[0]])
|
|
|
-
|
|
|
- continue
|
|
|
-
|
|
|
- kv = row.split()
|
|
|
- if len(kv) != 2:
|
|
|
- raw += line
|
|
|
- continue
|
|
|
- else:
|
|
|
- # Start replacing
|
|
|
- key = kv[0]
|
|
|
- val = kv[1]
|
|
|
- if key in schema:
|
|
|
- raw += " %s %s\n" % (key, schema[key])
|
|
|
- continue
|
|
|
-
|
|
|
-
|
|
|
- raw += line
|
|
|
-
|
|
|
- # Flush our new content
|
|
|
- f = open(monkey, "w")
|
|
|
- f.write(raw)
|
|
|
- f.close()
|
|
|
-
|
|
|
- # Configure Transport Layer for SSL
|
|
|
- if self.SSL_default is True:
|
|
|
- self.SSL_configure(monkey_stage)
|
|
|
-
|
|
|
- http = monkey_stage + "bin/monkey"
|
|
|
-
|
|
|
- try:
|
|
|
- if self.SSL_default is True:
|
|
|
- prot = "https"
|
|
|
- else:
|
|
|
- prot = "http"
|
|
|
-
|
|
|
- d = 0
|
|
|
- domain = prot + "://localhost:%s/" % str(self.port)
|
|
|
- schema = ""
|
|
|
- for s in services:
|
|
|
- if d > 0:
|
|
|
- schema += " "
|
|
|
- schema += domain + services[d]['name'] + '/' + "\n"
|
|
|
- d += 1
|
|
|
-
|
|
|
- # Do not trap the output of the server, just print everything
|
|
|
- # to STDOUT
|
|
|
- sc = ANSI_RESET + ANSI_CYAN + schema + ANSI_RESET
|
|
|
- if self.output_stdout is True:
|
|
|
- execute_stdout("%s Service Up : %s" \
|
|
|
- % (MSG_NEW, sc), http, False)
|
|
|
- else:
|
|
|
- execute("%s Service Up : %s" \
|
|
|
- % (MSG_NEW, sc), \
|
|
|
- http, False, True, False)
|
|
|
-
|
|
|
- except (RuntimeError, TypeError, NameError):
|
|
|
- print "\nDone!"
|
|
|
- raise
|
|
|
-
|
|
|
- def SSL_configure(self, monkey_stage):
|
|
|
- plgs = monkey_stage + "/conf/plugins.load"
|
|
|
- f = open(plgs, "r")
|
|
|
- lines = f.readlines()
|
|
|
- f.close()
|
|
|
-
|
|
|
- raw = ""
|
|
|
- for line in lines:
|
|
|
- if line.find('monkey-polarssl') > 0 and self.SSL is True:
|
|
|
- raw += line.replace("# Load", "Load")
|
|
|
- else:
|
|
|
- raw += line
|
|
|
-
|
|
|
- f = open(plgs, "w")
|
|
|
- f.write(raw)
|
|
|
- f.close()
|
|
|
-
|
|
|
- # Check if SSL certificates exists
|
|
|
- sslconf = monkey_stage + "/conf/plugins/polarssl/polarssl.conf"
|
|
|
- f = open(sslconf, "r")
|
|
|
- lines = f.readlines()
|
|
|
- f.close()
|
|
|
-
|
|
|
- certificate_file = None
|
|
|
- rsa_key_file = None
|
|
|
- dh_param_file = None
|
|
|
- for line in lines:
|
|
|
- row = line.strip()
|
|
|
- if row.startswith('CertificateFile'):
|
|
|
- key, val = row.split()
|
|
|
- if os.path.exists(val):
|
|
|
- certificate_file = val
|
|
|
- elif row.startswith('RSAKeyFile'):
|
|
|
- key, val = row.split()
|
|
|
- if os.path.exists(val):
|
|
|
- rsa_key_file = val
|
|
|
- elif row.startswith('DHParameterFile'):
|
|
|
- key, val = row.split()
|
|
|
- if os.path.exists(val):
|
|
|
- dh_param_file = val
|
|
|
-
|
|
|
- # Generate Certificates if they dont exists
|
|
|
- p = monkey_stage + "/conf/plugins/polarssl/"
|
|
|
- if rsa_key_file is None:
|
|
|
- cmd = "openssl genrsa -out " + p + "rsa_key.pem 1024"
|
|
|
- execute("SSL: Generate RSA", cmd)
|
|
|
- rsa_key_file = p + "rsa_key.pem"
|
|
|
- else:
|
|
|
- print_msg("SSL: RSA (cached)", True)
|
|
|
-
|
|
|
- if certificate_file is None:
|
|
|
- cmd = "openssl req -new -x509 -key " + rsa_key_file + \
|
|
|
- " -out " + p + "srv_cert.pem" + " -days 1095 -subj '/C=US'"
|
|
|
- execute("SSL: Generate Certificate", cmd)
|
|
|
- certificate_file = p + "srv_cert.pem"
|
|
|
- else:
|
|
|
- print_msg("SSL: Cert (cached)", True)
|
|
|
-
|
|
|
- if dh_param_file is None:
|
|
|
- cmd = "openssl dhparam -out " + p + "dhparam.pem 1024"
|
|
|
- execute("SSL: Generate DH Params", cmd)
|
|
|
- dh_param_file = p + "dhparam.pem"
|
|
|
- else:
|
|
|
- print_msg("SSL: DH Params (cached)", True)
|
|
|
-
|
|
|
- # Create new config and override polarssl.conf file
|
|
|
- raw = "[SSL]\n"
|
|
|
- raw += " CertificateFile " + certificate_file + "\n"
|
|
|
- raw += " RSAKeyFile " + rsa_key_file + "\n"
|
|
|
- raw += " DHParameterFile " + dh_param_file + "\n\n"
|
|
|
-
|
|
|
- f = open(sslconf, "w")
|
|
|
- f.write(raw)
|
|
|
- f.close()
|
|
|
-
|
|
|
- def reset(self):
|
|
|
- if self.dudac_stage_path is None:
|
|
|
- self.mk_git.remove(self.mk_home)
|
|
|
- self.duda_git.remove(self.duda_home)
|
|
|
-
|
|
|
- def print_version(self):
|
|
|
- print_bold("Duda Client Manager - v%s" % DUDAC_VERSION)
|
|
|
- print_color("http://duda.io", ANSI_YELLOW, True)
|
|
|
- print_color("http://monkey-project.com\n", ANSI_YELLOW, True)
|
|
|
-
|
|
|
- def print_help(self):
|
|
|
- print "Usage: dudac [-g|-s] [-V] [-S] [-h] [-v] [-A] [-J] [-T] -w WEB_SERVICE_PATH\n"
|
|
|
- print ANSI_BOLD + ANSI_WHITE + "Stack Build Options" + ANSI_RESET
|
|
|
- print " -V\t\t\tAPI level (default: %i)" % DEFAULT_API_LEVEL
|
|
|
- print " -s\t\t\tGet stack sources using HTTPS"
|
|
|
- print " -g\t\t\tGet stack sources using GIT protocol (SSH)"
|
|
|
- print " -F\t\t\tForce mode, rebuild the Stage area"
|
|
|
- print " -r\t\t\tReset environment"
|
|
|
-
|
|
|
- print
|
|
|
- print ANSI_BOLD + ANSI_WHITE + "Profiling and Trace" + ANSI_RESET
|
|
|
- print " -A\t\t\tUse libc memory allocator instead of Jemalloc (disabled)"
|
|
|
- print " -X\t\t\tEnable Jemalloc statistics (disabled)"
|
|
|
- print " -J\t\t\tEnable Jemalloc profiling and leaks detection (disabled)"
|
|
|
- print " -T\t\t\tEnable Linux Trace Toolkit (disabled)"
|
|
|
-
|
|
|
- print
|
|
|
- print ANSI_BOLD + ANSI_WHITE + "HTTP Server Options" + ANSI_RESET
|
|
|
- print " -p TCP_PORT\t\tSet TCP port (default 2001)"
|
|
|
- print " -w WEB_SERVICE\tSpecify web service source path"
|
|
|
- print " -S\t\t\tWeb Service will run with SSL mode enabled"
|
|
|
- print " -M 'k1=v1,kn=vn'\tOverride some web server config key/value"
|
|
|
-
|
|
|
- print
|
|
|
- print ANSI_BOLD + ANSI_WHITE + "Others" + ANSI_RESET
|
|
|
- print " -h\t\t\tPrint this help"
|
|
|
- print " -u\t\t\tRedirect server output to STDOUT"
|
|
|
- print " -v\t\t\tPrint version"
|
|
|
-
|
|
|
- # it creates a configuration schema to override the values of the main
|
|
|
- # Monkey configuration file
|
|
|
- def conf_schema(self, value):
|
|
|
- if value.find(',') > 0:
|
|
|
- entries = value.split(',')
|
|
|
- if len(entries) == 0:
|
|
|
- return None
|
|
|
- else:
|
|
|
- key, val = value.split('=')
|
|
|
- if len(key) == 0 or len(val) == 0:
|
|
|
- print "Error: Invalid configuration schema '%s'" % value
|
|
|
- exit(1)
|
|
|
-
|
|
|
- return {key: val}
|
|
|
-
|
|
|
- # Lookup all entries in the value
|
|
|
- c = {}
|
|
|
- for e in entries:
|
|
|
- key, val = e.split('=')
|
|
|
- if len(key) == 0 or len(val) == 0:
|
|
|
- print "Error: Invalid configuration schema '%s'" % value
|
|
|
- exit(1)
|
|
|
- c[key] = val
|
|
|
-
|
|
|
- return c
|
|
|
-
|
|
|
- def get_arguments(self):
|
|
|
- update = None
|
|
|
- monkey_conf = None
|
|
|
- self.api_level = "dst-%i" % int(DEFAULT_API_LEVEL)
|
|
|
-
|
|
|
- # Reading command line arguments
|
|
|
- try:
|
|
|
- optlist, args = getopt.getopt(sys.argv[1:], 'V:sgFrhvSuw:p:AXJTM:')
|
|
|
- except getopt.GetoptError:
|
|
|
- self.print_help()
|
|
|
- sys.exit(2)
|
|
|
-
|
|
|
- if len(optlist) == 0:
|
|
|
- self.print_help()
|
|
|
-
|
|
|
- # Check options
|
|
|
- for op, arg in optlist:
|
|
|
- if op == '-s':
|
|
|
- update = PROTOCOL_HTTPS
|
|
|
- elif op == '-g':
|
|
|
- update = PROTOCOL_GIT
|
|
|
- elif op == '-F':
|
|
|
- self.rebuild_monkey = True
|
|
|
- elif op == '-r':
|
|
|
- self.reset()
|
|
|
- exit(0)
|
|
|
- elif op == '-V':
|
|
|
- self.api_level = arg
|
|
|
- elif op == '-S':
|
|
|
- self.SSL = True
|
|
|
- elif op == '-h':
|
|
|
- self.print_help()
|
|
|
- sys.exit(0)
|
|
|
- elif op == '-p':
|
|
|
- if not str(arg).isdigit():
|
|
|
- self.print_help()
|
|
|
- exit(1)
|
|
|
- self.port = arg
|
|
|
- elif op == '-A':
|
|
|
- self.linux_malloc = True
|
|
|
- elif op == '-X':
|
|
|
- self.jemalloc_stats = True
|
|
|
- elif op == '-J':
|
|
|
- self.jemalloc_prof = True
|
|
|
- elif op == '-M':
|
|
|
- monkey_conf = arg
|
|
|
- elif op == '-D':
|
|
|
- self.service_macros = arg
|
|
|
- elif op == '-T':
|
|
|
- self.linux_trace = True
|
|
|
- elif op == '-u':
|
|
|
- self.output_stdout = True
|
|
|
- elif op == '-v':
|
|
|
- sys.exit(0)
|
|
|
- break
|
|
|
- elif op == '-w':
|
|
|
- self.service = arg
|
|
|
- self.config_requirements()
|
|
|
-
|
|
|
- # SSL
|
|
|
- if self.SSL is True:
|
|
|
- self.monkey.SSL = True
|
|
|
-
|
|
|
- # Enable Jemalloc profiling
|
|
|
- if 'JEMALLOC_OPTS' not in os.environ:
|
|
|
- os.environ['JEMALLOC_OPTS'] = ''
|
|
|
-
|
|
|
- if self.jemalloc_prof is True:
|
|
|
- os.environ['JEMALLOC_OPTS'] += '--enable-prof'
|
|
|
- os.environ['JE_MALLOC_CONF'] = 'prof_leak:true,prof:true,prof_prefix:duda.jeprof'
|
|
|
-
|
|
|
- # More environment vars: make will use 8 jobs
|
|
|
- os.environ['MAKEFLAGS'] = '-j 8'
|
|
|
-
|
|
|
- # Linux Trace Toolkit
|
|
|
- if self.linux_trace is True:
|
|
|
- self.monkey.opts += "--linux-trace "
|
|
|
-
|
|
|
- # Use system malloc instead Jemalloc
|
|
|
- if self.linux_malloc is True:
|
|
|
- self.monkey.opts += "--malloc-libc "
|
|
|
-
|
|
|
- # Jemalloc Stats
|
|
|
- if self.linux_malloc is False and self.jemalloc_stats is True:
|
|
|
- os.environ['JEMALLOC_OPTS'] += ' --enable-stats'
|
|
|
-
|
|
|
- # Rebuild the stack ?
|
|
|
- if update is not None:
|
|
|
- if self.rebuild_monkey is True:
|
|
|
- print "Error: you cannot mix the flag -f with -g or -s"
|
|
|
- exit(1)
|
|
|
-
|
|
|
- if self.dudac_stage_path is None:
|
|
|
- self.update_framework(update)
|
|
|
- else:
|
|
|
- print_msg("DUDAC_STAGE_PATH is set")
|
|
|
-
|
|
|
- # Override Monkey configuration. It will create the configuration
|
|
|
- # schema which is used later by the run_webservice() method.
|
|
|
- if monkey_conf:
|
|
|
- mconf_schema = self.conf_schema(monkey_conf)
|
|
|
- else:
|
|
|
- mconf_schema = None
|
|
|
-
|
|
|
- # Run web service
|
|
|
- if self.service:
|
|
|
- self.run_webservice(mconf_schema)
|
|
|
-
|
|
|
- def _temp_path(self):
|
|
|
- pass
|
|
|
-
|
|
|
-def main():
|
|
|
- d = Duda()
|
|
|
-
|
|
|
-if __name__ == '__main__':
|
|
|
- main()
|