Skip to content

Commit fd6fd8a

Browse files
committed
Merge pull request #33 from al4/master
Bugfix and pre-0.2 release
2 parents 951df57 + b3d8410 commit fd6fd8a

File tree

9 files changed

+147
-88
lines changed

9 files changed

+147
-88
lines changed

Vagrantfile

Lines changed: 23 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -71,34 +71,41 @@ Vagrant.configure(2) do |config|
7171
# SHELL
7272
config.vm.provision "shell", inline: <<-SHELL
7373
# sudo sed -i 's/archive.ubuntu.com/nl.archive.ubuntu.com/g' /etc/apt/sources.list
74-
sudo apt-get update
75-
sudo apt-get -y install python-pip python-dev postgresql postgresql-server-dev-all
74+
apt-get update
75+
apt-get -y install python-pip python-dev postgresql postgresql-server-dev-all
7676
echo "CREATE USER orlo WITH PASSWORD 'password'; CREATE DATABASE orlo OWNER orlo; " \
7777
| sudo -u postgres -i psql
7878
7979
# python-ldap dependencies
80-
sudo apt-get install -y python-dev libldap2-dev libsasl2-dev libssl-dev
80+
apt-get install -y python-dev libldap2-dev libsasl2-dev libssl-dev
8181
8282
# Build tools
83-
sudo apt-get -y install build-essential git-buildpackage debhelper python-dev dh-systemd python-virtualenv
83+
apt-get -y install build-essential git-buildpackage debhelper python-dev dh-systemd python-virtualenv
8484
wget -P /tmp/ \
8585
'https://launchpad.net/ubuntu/+archive/primary/+files/dh-virtualenv_0.11-1_all.deb'
8686
dpkg -i /tmp/dh-virtualenv_0.11-1_all.deb
87+
apt-get -f install -y
8788
88-
sudo pip install --upgrade pip
89-
sudo pip install sphinx sphinxcontrib-httpdomain
90-
sudo pip install git+https://github.com/jarus/flask-testing.git
89+
pip install --upgrade pip
90+
pip install virtualenv
9191
92-
cd /vagrant/
93-
# why do we need to do this twice?
94-
sudo python /vagrant/setup.py install
95-
sudo python /vagrant/setup.py install
92+
# Virtualenv is to avoid conflict with Debian's python-six
93+
virtualenv /home/vagrant/virtualenv/orlo
94+
source /home/vagrant/virtualenv/orlo/bin/activate
95+
echo "source ~/virtualenv/orlo/bin/activate" >> /home/vagrant/.profile
9696
97-
python /vagrant/create_db.py
98-
sudo pip install -r /vagrant/requirements.txt
99-
sudo pip install pytest Flask-Testing
97+
pip install -r /vagrant/requirements.txt
98+
pip install -r /vagrant/requirements_testing.txt
99+
pip install -r /vagrant/docs/requirements.txt
100+
101+
# Flask-Testing hasn't been released to pip in ages :(
102+
pip install --upgrade git+https://github.com/jarus/flask-testing.git
100103
101-
# For deployer.rb
102-
sudo apt-get install ruby-rest-client ruby-json
104+
sudo chown -R vagrant:vagrant /home/vagrant/virtualenv
105+
106+
# Create the database
107+
python /vagrant/create_db.py
108+
mkdir /etc/orlo
109+
chown vagrant:root /etc/orlo
103110
SHELL
104111
end

bin/orlo

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,9 @@
11
#!/bin/bash
22

3-
/usr/share/python/orlo/bin/python /usr/share/python/orlo/lib/python2.7/site-packages/orlo/cli.py $@
3+
# This script is for DEBIAN packaging only.
4+
# The bin/orlo script referenced below is generated by setuptools (see entry_points in setup.py).
45

6+
# For the actual logic that is run by the script below, see orlo/cli.py
7+
8+
/usr/share/python/orlo/bin/orlo $@
59

debian/preinst

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,5 +9,8 @@ else
99
fi
1010

1111
mkdir -p /var/{lib,log}/orlo
12-
chown orlo:orlo /var/{lib,log}/orlo
12+
touch /var/log/orlo/app.log
13+
14+
chown -R orlo:orlo /var/{lib,log}/orlo
1315
chmod 755 /var/{lib,log}/orlo
16+
chmod 664 /var/log/orlo/app.log

deployer.py

Lines changed: 30 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -23,19 +23,16 @@ class DeployerError(Exception):
2323
def __init__(self, message):
2424
self.message = message
2525
error(message)
26-
raise SystemExit(1)
2726

2827

2928
def get_params():
3029
parser = argparse.ArgumentParser(description="Orlo Test Deployer")
3130
parser.add_argument('packages', choices=None, const=None, nargs='*',
32-
help="Packages to deploy, in format package_name=version, "
33-
"e.g test-package=1.0.0")
31+
help="Packages to deploy, in format "
32+
"package_name=version, e.g test-package=1.0.0")
3433
args, unknown = parser.parse_known_args()
3534

3635
_packages = OrderedDict()
37-
if not args.packages:
38-
raise DeployerError("No packages to deploy, see help")
3936

4037
for pkg in args.packages:
4138
package, version = pkg.split('=')
@@ -62,13 +59,14 @@ def deploy(package, meta=None):
6259
:param dict meta: Dictionary of metadata (unused in this dummy function)
6360
:return:
6461
"""
62+
info("Package start - {}:{}".format(package.name, package.version))
6563
orlo_client.package_start(package)
6664

67-
# Do the deploy...
68-
65+
# Do stuff
6966
# Determining success status is up to you
7067
success = True
7168

69+
info("Package stop - {}:{}".format(package.name, package.version))
7270
orlo_client.package_stop(package, success=success)
7371

7472
return success
@@ -79,33 +77,45 @@ def deploy(package, meta=None):
7977
orlo_url = os.environ['ORLO_URL']
8078
else:
8179
# This deployer is only every supposed to accept releases from Orlo
82-
# Other deployers could use this to detect whether they are being invoked by Orlo
80+
# Other deployers could use this to detect whether they are being
81+
# invoked by Orlo
8382
raise DeployerError("Could not detect ORLO_URL from environment")
8483

8584
if os.getenv('ORLO_RELEASE'):
86-
orlo_release = os.environ['ORLO_RELEASE']
85+
orlo_release_id = os.environ['ORLO_RELEASE']
8786
else:
8887
raise DeployerError("Could not detect ORLO_RELEASE in environment")
8988

89+
logging.info(
90+
"Environment: \n" +
91+
json.dumps(os.environ, indent=2, default=lambda o: o.__dict__))
92+
93+
# Fetch packages and metadata. Packages is not used, it is just to
94+
# demonstrate they are passed as arguments
9095
packages, metadata = get_params()
9196

97+
logging.info("Stdin: \n" + str(metadata))
98+
99+
# Create an instance of the Orlo client
92100
orlo_client = OrloClient(uri=orlo_url)
93-
# The release is created in Orlo before being handed to the deployer
94-
# So fetch it here
95-
release = orlo_client.get_release(orlo_release)
96101

97-
# TODO - using package info from arguments makes no sense when we could fetch from Orlo
98-
orlo_packages = []
99-
for p, v in packages.items():
100-
info("Creating Package {}:{}".format(p, v))
101-
pkg = orlo_client.create_package(release, p, v)
102-
orlo_packages.append(pkg)
102+
# The release is created in Orlo before the deployer is invoked, so fetch
103+
# it here. If you prefer, you can to do the release creation within your
104+
# deployer and use Orlo only for receiving data
105+
release = orlo_client.get_release(orlo_release_id)
106+
107+
# While we fetch Packages using the Orlo client, they are passed on the
108+
# CLI as well, which is useful for non-python deployers
109+
info("Fetching packages from Orlo")
110+
if not release.packages:
111+
raise DeployerError("No packages to deploy")
103112

104113
info("Starting Release")
105-
for pkg in orlo_packages:
114+
for pkg in release.packages:
106115
info("Deploying {}".format(pkg.name))
107116
deploy(pkg, meta=metadata)
108-
info("Finishing Release")
109117

118+
info("Finishing Release")
110119
orlo_client.release_stop(release)
120+
111121
info("Done.")

orlo/cli.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,11 @@ def run_server(args):
7171
app.run(host=args.host, port=args.port, debug=True, use_reloader=True)
7272

7373

74-
if __name__ == '__main__':
74+
def main():
75+
# Referenced by entry_points in setup.py
7576
args = parse_args()
7677
args.func(args)
78+
79+
80+
if __name__ == '__main__':
81+
main()

orlo/config.py

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,6 @@
1313
config.set('main', 'strict_slashes', 'false')
1414
config.set('main', 'base_url', 'http://localhost:8080')
1515

16-
1716
config.add_section('security')
1817
config.set('security', 'enabled', 'false')
1918
config.set('security', 'passwd_file', os.path.dirname(__file__) + '/../etc/passwd')
@@ -33,12 +32,11 @@
3332
config.set('logging', 'debug', 'false')
3433
config.set('logging', 'file', 'disabled')
3534

36-
config.read('/etc/orlo/orlo.ini')
37-
3835
config.add_section('deploy')
3936
config.set('deploy', 'timeout', '3600') # How long to timeout external deployer calls
4037

4138
config.add_section('deploy_shell')
4239
config.set('deploy_shell', 'command_path', os.path.dirname(os.path.abspath(__file__)) +
4340
'/../deployer.py')
4441

42+
config.read('/etc/orlo/orlo.ini')

orlo/deploy.py

Lines changed: 48 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -2,49 +2,14 @@
22
import json
33
import subprocess
44
from threading import Timer
5+
from orlo import app
56
from orlo.config import config
67
from orlo.exceptions import OrloError
78

89

910
__author__ = 'alforbes'
1011

1112

12-
# Stolen from http://stackoverflow.com/questions/1191374
13-
def run(args, env, in_data, timeout_sec=3600):
14-
"""
15-
Run a command in a separate thread
16-
17-
:param env: Dict of environment variables
18-
:param in_data: String to pass to stdin
19-
:param args: List of arguments
20-
:param timeout_sec: Timeout in seconds, 1 hour by default
21-
:return:
22-
"""
23-
proc = subprocess.Popen(
24-
args,
25-
env=env,
26-
stdin=subprocess.PIPE,
27-
stdout=subprocess.PIPE,
28-
stderr=subprocess.PIPE,
29-
)
30-
31-
timer = Timer(timeout_sec, proc.kill)
32-
out = err = " "
33-
try:
34-
timer.start()
35-
out, err = proc.communicate(in_data)
36-
finally:
37-
timer.cancel()
38-
print("Out:\n{}".format(out))
39-
print("Err:\n{}".format(err))
40-
41-
if proc.returncode is not 0:
42-
raise OrloError("Subprocess exited with code {}".format(
43-
proc.returncode
44-
))
45-
print("end run")
46-
47-
4813
class BaseDeploy(object):
4914
"""
5015
A Deploy task
@@ -90,16 +55,20 @@ def start(self):
9055
pass
9156

9257
def kill(self):
93-
pass
58+
raise NotImplementedError("No kill method for HTTP deploys")
9459

9560

9661
class ShellDeploy(BaseDeploy):
9762
"""
9863
Deployment by shell command
9964
100-
meta {} => stdin
101-
deployer pkg1=1
102-
capture stdout,
65+
Data is passed to the shell command given in 3 ways:
66+
67+
* ORLO_URL, ORLO_RELEASE (the ID), and other Release attributes
68+
are set as environment variables (all prefixed by ORLO_)
69+
* The package and version sets are passed as arguments, e.g.
70+
package-name=1.0.0
71+
* The metadata dictionary is passed to stdin
10372
"""
10473

10574
def __init__(self, release):
@@ -130,10 +99,48 @@ def start(self):
13099
metadata.update(m.to_dict())
131100
in_data = json.dumps(metadata)
132101

133-
run(args, env, in_data, timeout_sec=config.getint('deploy', 'timeout'))
102+
self.run_command(args, env, in_data,
103+
timeout_sec=config.getint('deploy', 'timeout'))
134104

135105
def kill(self):
136106
"""
137107
Kill a deploy in progress
138108
"""
139109
raise NotImplementedError
110+
111+
@staticmethod
112+
def run_command(args, env, in_data, timeout_sec=3600):
113+
"""
114+
Run a command in a separate thread
115+
116+
Adapted from http://stackoverflow.com/questions/1191374
117+
118+
:param env: Dict of environment variables
119+
:param in_data: String to pass to stdin
120+
:param args: List of arguments
121+
:param timeout_sec: Timeout in seconds, 1 hour by default
122+
:return:
123+
"""
124+
proc = subprocess.Popen(
125+
args,
126+
env=env,
127+
stdin=subprocess.PIPE,
128+
stdout=subprocess.PIPE,
129+
stderr=subprocess.PIPE,
130+
)
131+
132+
timer = Timer(timeout_sec, proc.kill)
133+
out = err = " "
134+
try:
135+
timer.start()
136+
out, err = proc.communicate(in_data)
137+
finally:
138+
timer.cancel()
139+
print("Out:\n{}".format(out))
140+
print("Err:\n{}".format(err))
141+
142+
if proc.returncode is not 0:
143+
raise OrloError("Subprocess exited with code {}".format(
144+
proc.returncode), status_code=500)
145+
print("end run")
146+

setup.py

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,10 +3,12 @@
33
# from distutils.core import setup
44
from setuptools import setup
55
import multiprocessing # nopep8
6+
import os
67

78

8-
VERSION = '0.1.1-1'
9-
version_file = open('./orlo/_version.py', 'w')
9+
VERSION = '0.2.0-pre1'
10+
my_path = os.path.dirname(os.path.realpath(__file__))
11+
version_file = open('{}/orlo/_version.py'.format(my_path), 'w')
1012
version_file.write("__version__ = '{}'".format(VERSION))
1113
version_file.close()
1214

@@ -42,4 +44,8 @@
4244
'orloclient>=0.1.1',
4345
],
4446
test_suite='tests',
47+
# Creates a script in /usr/local/bin
48+
entry_points={
49+
'console_scripts': ['orlo=orlo.cli:main']
50+
}
4551
)

0 commit comments

Comments
 (0)