6. fab deploy
from fabric.api import run, roles, executedef deploy():
execute(migrate)
execute(update)
migrate on db1
migrate on db2
update on web1
update on web2
update on web3
7. $ fab deploy:app or $ fab deploy:db
from fabric.api import run, execute, task# For example, code talking to an HTTP API, or a database, or ...from mylib import
external_datastore# This is the actual algorithm involved. It does not care about host# lists at all.def do_work():
run("something interesting on a host")# This is the user-facing task invoked on the command line.
@taskdef deploy(lookup_param):
# This is the magic you don't get with @hosts or @roles.
# Even lazy-loading roles require you to declare available roles
# beforehand. Here, the sky is the limit.
host_list = external_datastore.query(lookup_param)
# Put this dynamically generated host list together with the work to be
# done.
execute(do_work, hosts=host_list)
8. $ fab set_hosts:app do_work
from fabric.api import run, taskfrom mylib import external_datastore# Marked as a publicly visible task, but otherwise unchanged:
still just# "do the work, let somebody else worry about what hosts to run on".
@taskdef do_work():
run("something interesting on a host")
@taskdef set_hosts(lookup_param):
# Update env.hosts instead of calling execute()
env.hosts = external_datastore.query(lookup_param)
10. $ fab -H host1,host2,host3
runs_in_parallel runs_serially
from fabric.api import *
@paralleldef runs_in_parallel():
passdef runs_serially():
pass
runs_in_parallel on host1, host2, and host3
runs_serially on host1
runs_serially on host2
runs_serially on host3
11. $ fab -P -z 5 heavy_task
from fabric.api import *
@parallel(pool_size=5)def heavy_task():
# lots of heavy local lifting or lots of IO here
14. Class Task
class MyTask(Task):
name = "deploy"
def run(self, environment, domain="whatever.com"):
run("git clone foo")
sudo("service apache2 restart")
instance = MyTask()
VS
@taskdef deploy(environment, domain="whatever.com"):
run("git clone foo")
sudo("service apache2 restart")
15. Colors
from fabric.colors import greenprint(green("This text is green!"))
fabric.colors.blue(text, bold=False)
fabric.colors.cyan(text, bold=False)
fabric.colors.green(text, bold=False)
fabric.colors.magenta(text, bold=False)
fabric.colors.red(text, bold=False)
fabric.colors.white(text, bold=False)
fabric.colors.yellow(text, bold=False)
16. Context managers
def mytask():
with cd('/path/to/app'), prefix('workon myvenv'):
run('./manage.py syncdb')
run('./manage.py loaddata myfixture')
with cd('/var/www'):
run('ls') # cd /var/www && ls
with cd('website1'):
run('ls') # cd /var/www/website1 && ls
with hide('running', 'stdout', 'stderr'):
run('ls /var/www')
# Map localhost:6379 on the server to localhost:6379 on the client,
# so that the remote 'redis-cli' program ends up speaking to the local
# redis-server.
with remote_tunnel(6379):
run("redis-cli -i")
26. fab cleanup_nexus:10.0.2-RC2
@taskdef cleanup_nexus(version):
for module in [
"core-api",
"core-client-rest",
"core-manual",
"core-web"]:
local("curl -X DELETE -u user:rootme
http://nexus.example.com:8180/nexus/service/local/repositories/releases/content/
example/%s/%s/" % (module, version))
27. LOCK_FILE = "~/.lockfile.release.core.lock"class Lock():
def __enter__(self):
if os.access(os.path.expanduser(LOCK_FILE), os.F_OK):
pidfile = open(os.path.expanduser(LOCK_FILE), "r")
pidfile.seek(0)
old_pid = pidfile.readline()
print "There is an already a process running with pid: %s," % old_pid
sys.exit(1)
pidfile = open(os.path.expanduser(LOCK_FILE), "w")
pidfile.write("%s" % os.getpid())
pidfile.close
def __exit__(self, type, value, traceback):
os.remove(os.path.expanduser(LOCK_FILE))
Locks
28. fab send_email_candidate:2.12,me@...
@taskdef send_mail_candidate(version, *receivers):
sender = 'development@geniusbytes.com'
body = """From: Core Team <noreply@example.com>To: Development
<development@example.com>Subject: New Release CANDIDATE %(version)snNew Release
CANDIDATE %(version)savailable on: * smb://example.com/myproject/%(version)s
""" % dict(version=version)
try:
message = smtplib.SMTP('example.com')
message.sendmail(sender, receivers, body)
print "Successfully sent email"
except smtplib.SMTPException:
print "Error: unable to send email"
29. XML parser
@taskdef get_pom_version():
src=os.path.dirname(__file__)
pom_file=os.path.abspath(os.path.join(src, 'pom.xml'))
from xml.dom.minidom import parse
pom = parse(pom_file)
version = pom.getElementsByTagName("version")[1].firstChild.nodeValue
find = re.compile(r'^d+.d+.d+-([a-zA-Z-]+)d*-SNAPSHOT$').findall(version)
if not find:
abort(version + " is not a valid development version")
versions = re.compile(r'd+').findall(version)
if len(versions) is 3:
versions.append(1)
if len(versions) is not 4:
abort(version + " is not a valid development version")
versions.extend(find)
return versions
36. EC2 Testing with 200 micro server
EC2 + Fabric + Funkload
● EC2 use all ubuntu standard AMI
● Fabric as remote control, move files, aggregate.
● Funkload in order to stress an internet application. (not on
EC2)
38. Testing phases
I. Prepare Monitoring
II.Prepare Cloud
1. Start Monitoring
2. Start Parallel Testing
3. Collecting Test Results
4. Collecting Perf Results
5. ReportingTarge
t
Cloud
CTRL
Tester
Targe
tTarge
t
FunkLoa
d
Fabric
(nmon+pefmon)
Fabric +
EC2
Fabric +
EC2
39. Testing Console
fab prepare_monitoring
fab prepare_cloud
fab start_monitoring
fab start_testing:ciccio,100,5000
fab collecting_test_results:ciccio
fab collecting_perf_results:ciccio
fab reporting:ciccio