From e3166c91026cf3c6a28859a1455dfcbc4e4023fe Mon Sep 17 00:00:00 2001 From: Andrew Hutchings <andrew@linuxjedi.co.uk> Date: Mon, 30 Jan 2012 13:57:37 +0000 Subject: [PATCH] Add lodgeit to puppet Will automatically install paste.drizzle.org and paste.openstack.org onto a server Change-Id: Ia2c1e37892f3ae8e3d4034e38ddfaa01c6a92a54 --- manifests/site.pp | 14 ++ modules/lodgeit/files/database.py | 202 ++++++++++++++++++++++ modules/lodgeit/files/header-bg2.png | Bin 0 -> 3670 bytes modules/lodgeit/manifests/init.pp | 52 ++++++ modules/lodgeit/manifests/site.pp | 66 +++++++ modules/lodgeit/templates/layout.html.erb | 91 ++++++++++ modules/lodgeit/templates/manage.py.erb | 38 ++++ modules/lodgeit/templates/nginx.erb | 10 ++ modules/lodgeit/templates/upstart.erb | 8 + 9 files changed, 481 insertions(+) create mode 100644 modules/lodgeit/files/database.py create mode 100644 modules/lodgeit/files/header-bg2.png create mode 100644 modules/lodgeit/manifests/init.pp create mode 100644 modules/lodgeit/manifests/site.pp create mode 100644 modules/lodgeit/templates/layout.html.erb create mode 100644 modules/lodgeit/templates/manage.py.erb create mode 100644 modules/lodgeit/templates/nginx.erb create mode 100644 modules/lodgeit/templates/upstart.erb diff --git a/manifests/site.pp b/manifests/site.pp index b8da8b413e..3b1a77c072 100644 --- a/manifests/site.pp +++ b/manifests/site.pp @@ -194,6 +194,20 @@ node "docs.openstack.org" { include doc_server } +node "paste.openstack.org" { + include openstack_server + include lodgeit + lodgeit::site { "openstack": + port => "5000", + image => "header-bg2.png" + } + + lodgeit::site { "drizzle": + port => "5001" + } + +} + node "devstack-oneiric.template.openstack.org" { include openstack_template include devstack_host diff --git a/modules/lodgeit/files/database.py b/modules/lodgeit/files/database.py new file mode 100644 index 0000000000..ce4718756c --- /dev/null +++ b/modules/lodgeit/files/database.py @@ -0,0 +1,202 @@ +# -*- coding: utf-8 -*- +""" + lodgeit.database + ~~~~~~~~~~~~~~~~ + + Database fun :) + + :copyright: 2007-2008 by Armin Ronacher, Christopher Grebs. + :license: BSD +""" +import time +import difflib +from datetime import datetime +from werkzeug import cached_property +from sqlalchemy import MetaData, Integer, Text, DateTime, ForeignKey, \ + String, Boolean, Table, Column, select, and_, func +from sqlalchemy.orm import scoped_session, create_session, backref, relation +from sqlalchemy.orm.scoping import ScopedSession +from lodgeit import local +from lodgeit.utils import generate_paste_hash +from lodgeit.lib.highlighting import highlight, preview_highlight, LANGUAGES + +from sqlalchemy.orm import mapper as sqla_mapper + +def session_mapper(scoped_session): + def mapper(cls, *arg, **kw): + cls.query = scoped_session.query_property() + return sqla_mapper(cls, *arg, **kw) + return mapper + +session = scoped_session(lambda: create_session(local.application.engine), + scopefunc=local._local_manager.get_ident) + +metadata = MetaData() + +pastes = Table('pastes', metadata, + Column('paste_id', Integer, primary_key=True), + Column('code', Text), + Column('parent_id', Integer, ForeignKey('pastes.paste_id'), + nullable=True), + Column('pub_date', DateTime), + Column('language', String(30)), + Column('user_hash', String(40), nullable=True), + Column('handled', Boolean, nullable=False), + Column('private_id', String(40), unique=True, nullable=True) +) + + +class Paste(object): + """Represents a paste.""" + + def __init__(self, code, language, parent=None, user_hash=None, + private=False): + if language not in LANGUAGES: + language = 'text' + self.code = u'\n'.join(code.splitlines()) + self.language = language + if isinstance(parent, Paste): + self.parent = parent + elif parent is not None: + self.parent_id = parent + self.pub_date = datetime.now() + self.handled = False + self.user_hash = user_hash + self.private = private + + @staticmethod + def get(identifier): + """Return the paste for an identifier. Private pastes must be loaded + with their unique hash and public with the paste id. + """ + if isinstance(identifier, basestring) and not identifier.isdigit(): + return Paste.query.filter(Paste.private_id == identifier).first() + return Paste.query.filter( + (Paste.paste_id == int(identifier)) & + (Paste.private_id == None) + ).first() + + @staticmethod + def find_all(): + """Return a query for all public pastes ordered by the id in reverse + order. + """ + return Paste.query.filter(Paste.private_id == None) \ + .order_by(Paste.paste_id.desc()) + + @staticmethod + def count(): + """Count all pastes.""" + s = select([func.count(pastes.c.paste_id)]) + return session.execute(s).fetchone()[0] + + @staticmethod + def resolve_root(identifier): + """Find the root paste for a paste tree.""" + paste = Paste.get(identifier) + if paste is None: + return + while paste.parent_id is not None: + paste = paste.parent + return paste + + @staticmethod + def fetch_replies(): + """Get the new replies for the ower of a request and flag them + as handled. + """ + s = select([pastes.c.paste_id], + Paste.user_hash == local.request.user_hash + ) + + paste_list = Paste.query.filter(and_( + Paste.parent_id.in_(s), + Paste.handled == False, + Paste.user_hash != local.request.user_hash, + )).order_by(pastes.c.paste_id.desc()).all() + + to_mark = [p.paste_id for p in paste_list] + session.execute(pastes.update(pastes.c.paste_id.in_(to_mark), + values={'handled': True})) + return paste_list + + def _get_private(self): + return self.private_id is not None + + def _set_private(self, value): + if not value: + self.private_id = None + return + if self.private_id is None: + while 1: + self.private_id = generate_paste_hash() + paste = Paste.query.filter(Paste.private_id == + self.private_id).first() + if paste is None: + break + private = property(_get_private, _set_private, doc=''' + The private status of the paste. If the paste is private it gets + a unique hash as identifier, otherwise an integer. + ''') + del _get_private, _set_private + + @property + def identifier(self): + """The paste identifier. This is a string, the same the `get` + method accepts. + """ + if self.private: + return self.private_id + return str(self.paste_id) + + @property + def url(self): + """The URL to the paste.""" + return '/show/%s/' % self.identifier + + def compare_to(self, other, context_lines=4, template=False): + """Compare the paste with another paste.""" + udiff = u'\n'.join(difflib.unified_diff( + self.code.splitlines(), + other.code.splitlines(), + fromfile='Paste #%s' % self.identifier, + tofile='Paste #%s' % other.identifier, + lineterm='', + n=context_lines + )) + if template: + from lodgeit.lib.diff import prepare_udiff + diff, info = prepare_udiff(udiff) + return diff and diff[0] or None + return udiff + + @cached_property + def parsed_code(self): + """The paste as rendered code.""" + return highlight(self.code, self.language) + + def to_xmlrpc_dict(self): + """Convert the paste into a dict for XMLRCP.""" + return { + 'paste_id': self.paste_id, + 'code': self.code, + 'parsed_code': self.parsed_code, + 'pub_date': int(time.mktime(self.pub_date.timetuple())), + 'language': self.language, + 'parent_id': self.parent_id, + 'url': self.url + } + + def render_preview(self, num=5): + """Render a preview for this paste.""" + return preview_highlight(self.code, self.language, num) + +mapper= session_mapper(session) + +mapper(Paste, pastes, properties={ + 'children': relation(Paste, + primaryjoin=pastes.c.parent_id==pastes.c.paste_id, + cascade='all', + backref=backref('parent', remote_side=[pastes.c.paste_id]) + ) +}) diff --git a/modules/lodgeit/files/header-bg2.png b/modules/lodgeit/files/header-bg2.png new file mode 100644 index 0000000000000000000000000000000000000000..146faec5cfe3773824f4caf39e4480e4974d10df GIT binary patch literal 3670 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 literal 0 HcmV?d00001 diff --git a/modules/lodgeit/manifests/init.pp b/modules/lodgeit/manifests/init.pp new file mode 100644 index 0000000000..f25a500636 --- /dev/null +++ b/modules/lodgeit/manifests/init.pp @@ -0,0 +1,52 @@ +class lodgeit { + $packages = [ "nginx", + "python-imaging", + "python-pip", + "python-jinja2", + "python-pybabel", + "python-werkzeug", + "python-simplejson", + "python-pygments", + "mercurial", + "drizzle", + "python-mysqldb" ] + + package { $packages: ensure => latest } + + package { 'SQLAlchemy': + provider => pip, + ensure => present, + require => Package[python-pip] + } + + file { '/srv/lodgeit': + ensure => directory + } + + service { 'drizzle': + ensure => running, + hasrestart => true + } + + +# if we already have the mercurial repo the pull updates + + exec { "update_lodgeit": + command => "hg pull /tmp/lodgeit-main", + path => "/bin:/usr/bin", + onlyif => "test -d /tmp/lodgeit-main" + } + +# otherwise get a new clone of it + + exec { "get_lodgeit": + command => "hg clone http://dev.pocoo.org/hg/lodgeit-main /tmp/lodgeit-main", + path => "/bin:/usr/bin", + onlyif => "test ! -d /tmp/lodgeit-main" + } + + service { 'nginx': + ensure => running, + hasrestart => true + } +} diff --git a/modules/lodgeit/manifests/site.pp b/modules/lodgeit/manifests/site.pp new file mode 100644 index 0000000000..7a4b56b41d --- /dev/null +++ b/modules/lodgeit/manifests/site.pp @@ -0,0 +1,66 @@ +define lodgeit::site($port, $image="") { + + file { "/etc/nginx/sites-available/${name}": + ensure => 'present', + content => template("lodgeit/nginx.erb"), + replace => 'true', + require => Package[nginx] + } + + file { "/etc/nginx/sites-enabled/${name}": + ensure => link, + target => "/etc/nginx/sites-available/${name}", + require => Package[nginx] + } + + file { "/etc/init/${name}-paste.conf": + ensure => 'present', + content => template("lodgeit/upstart.erb"), + replace => 'true', + require => Package[nginx] + } + + file { "/srv/lodgeit/${name}": + ensure => directory, + recurse => true, + source => "/tmp/lodgeit-main" + } + + if $image != '' { + file { "/srv/lodgeit/${name}/lodgeit/static/${image}": + ensure => present, + source => "puppet:///lodgeit/${image}" + } + } + +# Database file needs replacing to be compatible with SQLAlchemy 0.7 + + file { "/srv/lodgeit/${name}/lodgeit/database.py": + replace => true, + source => 'puppet:///modules/lodgeit/database.py' + } + + file { "/srv/lodgeit/${name}/manage.py": + mode => 755, + replace => true, + content => template("lodgeit/manage.py.erb") + } + + file { "/srv/lodgeit/${name}/lodgeit/views/layout.html": + replace => true, + content => template("lodgeit/layout.html.erb") + } + + exec { "create_database_${name}": + command => "drizzle --user=root -e \"create database if not exists ${name};\"", + path => "/bin:/usr/bin", + require => Service["drizzle"] + } + + service { "${name}-paste": + provider => upstart, + ensure => running, + require => [Service["drizzle", "nginx"], Exec["create_database_${name}"]] + } + +} diff --git a/modules/lodgeit/templates/layout.html.erb b/modules/lodgeit/templates/layout.html.erb new file mode 100644 index 0000000000..0838fb948c --- /dev/null +++ b/modules/lodgeit/templates/layout.html.erb @@ -0,0 +1,91 @@ +<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" + "http://www.w3.org/TR/html4/loose.dtd"> +<html> + <head> + <title>{{ page_title|e }} | LodgeIt!</title> + <link rel="stylesheet" href="/static/style.css" type="text/css"> + <link rel="stylesheet" href="/static/print.css" type="text/css" media="print"> + <script type="text/javascript" src="/static/jquery.js"></script> + <script type="text/javascript" src="/static/cookie.js"></script> + <script type="text/javascript" src="/static/lodgeit.js"></script> + {%- if css %} + <style type="text/css"> + {{ css|e }} + </style> + {%- endif %} + </head> + <body> + <div class="page"> + <div id="header"> + <h1> + <% if has_variable?("image") then %> + <img src="/static/<%= image %>" style="padding-bottom: 10px; margin-left: 10px;" alt="<%= name.capitalize %> Pastebin" /> + <% else %> + <%= name.capitalize %> Pastebin + <% end %> + </h1></div> + <ul id="navigation"> + {%- for href, id, caption in [ + ('/', 'new', _('New')), + ('/all/', 'all', _('All')), + ('/about/', 'about', _('About')), + ('/help/', 'help', '?') + ] %} + <li{% if active_page == id %} class="active"{% endif %}> + <a href="{{ href|e }}">{{ caption|e }}</a> + </li> + {%- endfor %} + </ul> + {# <ul id="languages"> + {% for lang, name in i18n_languages %} + <li{% if request.locale.language == lang %} class="active"{% endif %}> + <a href="{{ '/language/%s'|format(lang) }}"><img alt="{{ lang }}" src="{{ '/static/flags/%s.png'|format(lang) }}"></a> + </li> + {% endfor %} + </ul> #} + <div class="content"> + <h2>{{ page_title|e }}</h2> + {%- if new_replies %} + <div class="notification"> + <h3>{% trans %}Someone Replied To Your Paste{% endtrans %}</h3> + {% for paste in new_replies %} + <p>{% trans date=paste.pub_date|datetimeformat, parent=paste.parent.paste_id, + paste=paste.paste_id, paste_url=paste.url|e, parent_url=paste.parent.url|e %} + on {{ date }} someone replied to your paste + <a href="{{ parent_url }}">#{{ parent }}</a>, + in paste <a href="{{ paste_url }}">#{{ paste }}</a>. Click here to + <a href="/compare/{{ paste }}/{{ parent }}/">compare + those two pastes</a>.{% endtrans %} + </p> + {% endfor %} + <p><a href="javascript:LodgeIt.hideNotification()">{% trans %}hide this notification{% endtrans %}</a></p> + </div> + {% elif request.first_visit %} + <div class="notification"> + <h3>{% trans %}Welcome On LodgeIt{% endtrans %}</h3> + <p>{%- trans -%} + Welcome to the LodgeIt pastebin. In order to use the notification feature + a 31 day cookie with an unique ID was created for you. The lodgeit database + does not store any information about you, it's just used for an advanced + pastebin experience :-). Read more on the <a href="/about/#privacy">about + lodgeit</a> page. Have fun :-){%- endtrans -%} + </p> + <p><a href="javascript:LodgeIt.hideNotification()">{% trans %}hide this notification{% endtrans %}</a></p> + </div> + {% endif -%} + {% block body %}{% endblock -%} + <div class="footer"></div> + </div> + </div> + <script type="text/javascript"> + var _gaq = _gaq || []; + _gaq.push(['_setAccount', 'UA-27485426-1']); + _gaq.push(['_trackPageview']); + (function() { + var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true; + ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js'; + var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s); + })(); + </script> + </body> +</html> diff --git a/modules/lodgeit/templates/manage.py.erb b/modules/lodgeit/templates/manage.py.erb new file mode 100644 index 0000000000..a17a318cd1 --- /dev/null +++ b/modules/lodgeit/templates/manage.py.erb @@ -0,0 +1,38 @@ +import os + +from werkzeug import script, create_environ, run_wsgi_app +from werkzeug.serving import run_simple + +from lodgeit import local +from lodgeit.application import make_app +from lodgeit.database import session + +#dburi = 'sqlite:////tmp/lodgeit.db' +dburi = 'drizzle://127.0.0.1:4427/<%= name %>' + +SECRET_KEY = 'no secret key' + + +def run_app(app, path='/'): + env = create_environ(path, SECRET_KEY) + return run_wsgi_app(app, env) + +action_runserver = script.make_runserver( + lambda: make_app(dburi, SECRET_KEY), + use_reloader=True) + +action_shell = script.make_shell( + lambda: { + 'app': make_app(dburi, SECRET_KEY, False, True), + 'local': local, + 'session': session, + 'run_app': run_app + }, + ('\nWelcome to the interactive shell environment of LodgeIt!\n' + '\n' + 'You can use the following predefined objects: app, local, session.\n' + 'To run the application (creates a request) use *run_app*.') +) + +if __name__ == '__main__': + script.run() diff --git a/modules/lodgeit/templates/nginx.erb b/modules/lodgeit/templates/nginx.erb new file mode 100644 index 0000000000..13223fd032 --- /dev/null +++ b/modules/lodgeit/templates/nginx.erb @@ -0,0 +1,10 @@ +server { + listen 80; + server_name paste.<%= name %>.org; + root /srv/lodgeit/<%= name %>; + + location / { + proxy_pass http://localhost:<%= port %>/; + } +} + diff --git a/modules/lodgeit/templates/upstart.erb b/modules/lodgeit/templates/upstart.erb new file mode 100644 index 0000000000..4b2cb47956 --- /dev/null +++ b/modules/lodgeit/templates/upstart.erb @@ -0,0 +1,8 @@ +description "<%= name %> Lodgeit server" +author "Andrew Hutchings <andrew@linuxjedi.co.uk>" + +start on (local-filesystems and net-device-up) +stop on runlevel [!2345] + +exec python /srv/lodgeit/<%= name %>/manage.py runserver -h 127.0.0.1 -p <%= port %> +