Friday, December 18, 2009

Django Middleware Fun

I have a Django app that lets users create and manage 'requests'. There are a few views that display and manipulate requests, and in each view I need to ensure that -
  • the current user is of the correct type to access that view
  • the current user has access to the request(s) she's trying to view - the request id's are part of the url
Pretty simple, right? So I have a piece of boilerplate code stuck in the front of my views that does the following:
  • get the logged in user
    • redirect to login page if no user or anonymous user
  • get the logged in users' profile, and from that get their account id/object
    • if the user doesn't have a profile, they shouldn't be here at all so fail with an 'access denied' message
    • if the user doesn't have an account, they may be an admin - check for admin privs (is_staff)
      • if they're not an admin and don't have an account, their user/account is invalid and support needs to fix them - tell them that before logging them out.
These steps basically validate the user has access to the app. Based on whether we're in a 'view/edit' or 'list/browse' type context, one of the following happens next:
  • To ensure they have access to the 'current' order, we lookup the orderid in the set associated with their account. 
    • If it's not there, it's probably somebody else's order and we give them an 'access-denied', unless
    • they are staff members, in which case they are granted access based on a class level permissions system.
  • To discover the set of orders the user has access to, we do an account based database query, unless the user is staff, in which case we just list everything
Over time the boilerplate starts to smell. Small variations arise from method to method based on specific stuff I need to do, or I figure a better, more elegant way to do the same thing and don't bother changing all the other boilerplates. Worse, when something global changes - for example, the emergence of 'staff' users - I have to make the same change in a lot of places, possibly in slightly different ways. 

My answer to this? Middleware!

Since I basically always need the account of the logged in user, I created a middleware class to set that in the current request when it was available.  This class also validates the current user is valid and permitted application access based on their 'role' or account type, so each view just has to handle the variant behaviour based on the staff/not staff dichotomy.  Since this logic may vary depending on the view, I think its appropriate to leave the view this work.

Simple stuff, probably, but cool anyway.

Wednesday, December 16, 2009

Not Quite Daily...

Ok. Well..
So about that 'daily blogging'...

Anyway -

I just finished recompiling Postgresql 8.4 on my big machine after upgrading to Snow Leopard a few weeks back. It was surprisingly easy - make clean; make; sudo make install. Cake.

On my laptop I took the MacPorts approach, and while that might seem simpler, it took about ten times as long since it had to download half the open-source world before it saw fit to actually compile PSQL. Once it did however, everything worked well - I have yet to test my homemade incarnation of PSQL, so there may be a shoe waiting to drop here.

Sunday, December 13, 2009

Blogging Daily

To get into the habit, I'm making a committment to myself to blog daily for thirty days. Every day, I will create at least a paragraph or two of original content. For example, I just posted a cool python recipe I found on the net to my tumblr, but that won't count. This entry, on the other hand, does.

Today I'm completing my RT installation. We're installing RT to help us manage the support process as well as to support the design request workflow and interactions with service providers and consumers.  I'm finding it a little difficult to focus, and the docs seem to lack polish which is probably more discouraging than warranted.

The interesting part of this project is the process automation aspect.
  1. Our customers send us requests through any one of a variety of means - email, fax, file upload and telephone support are all valid options (although the phone option is a rare special case). 
  2. Once the order is received it is examined and 'cleaned' - a preprocessing step we perform to ensure requests sent to service providers meet a minimum quality and completeness standard. It's possible at this step cannot be completed without contacting the submitter to gather additional information, or clarify some ambiguity. 
  3. Cleaned orders are then submitted to a service provider who fulfills that order, returning a completed 'design package'. During the course of creating the package, the service provider may have questions that need clarification as well - these questions are passed to the submitter and processing will halt until the proper clarification is recieved.
  4. Orders completed by the service provider are validated by our customer service staff prior to delievery back to the requestor. Failed validation here can result in additional clarification interactions with the service provider as well.
  5. Finally the verified, completed order is returned to the submittor for final acceptance. The existence of errors in the design will trigger a correction cycle where the service provider will be required to address the issues and return an updated design package.
These steps are in fact a simplification of the actual process, and there are points of flexbility in the process that I don't bother to note, but there are some common requirements that apply across all of the possible scenarios -
  • Traceability -  every significant action in the lifecycle of an order must be logged.
  • Visibility - it should be easy to see the current status of all orders, to access their history, and to be notified of changes in an orders status. This visibility should be available to all stakeholders of a particular issue (e.g. submitted-by for submitters, serviced-by for service-providers, and by account for service-reps)
  • Accountability - the system should provide a basis for measuring performance, and helping stakeholders to meet committed goals - e.g. 24 or 48 hour turnaround times.
  • Flexibility - the system should not lock us into a particular workflow, or prevent us from modifying the workflow unreasonably. For example, workflows will vary as the process matures, and workflows may differ based on submitter or service provider (or the two combined).
Our initial plan was to build this workflow into the system, but on second thought this didn't seem to be a great use of our time and resources.  The advantage of going with something like RT is that it has most of what we need out of the box. The disadvantages are yet to be cataloged (which is itself a disadvatage) but will probably include some necessary integration pain, and possible limitations related to integration.

Wish me luck - I'm off!

Python Monkeypatching recipies

I found these on comp.lang.python, posted by Guido -
I ran into the need of monkeypatching a large number of classes (for
what I think are very good reasons :-) and invented two new recipes.
These don't depend on Py3k, and the second one actually works all the
way back to Python 2.2. Neither of these allows monkeypatching
built-in types like list. If you don't know what monkeypatching is,
see see http://en.wikipedia.org/wiki/Monkey_patch.

I think it's useful to share these recipes, if only to to establish
whether they have been discovered before, or to decide whether they
are worthy of a place in the standard library. I didn't find any
relevant hits on the ASPN Python cookbook.

First, a decorator to add a single method to an existing class:

def monkeypatch_method(cls):
    def decorator(func):
        setattr(cls, func.__name__, func)
        return func
    return decorator

To use:

from  import 

@monkeypatch_method()
def (self, args):
    return 

This adds  to 

Second, a "metaclass" to add a number of methods (or other attributes)
to an existing class, using a convenient class notation:

def monkeypatch_class(name, bases, namespace):
    assert len(bases) == 1, "Exactly one base class required"
    base = bases[0]
    for name, value in namespace.iteritems():
        if name != "__metaclass__":
            setattr(base, name, value)
    return base

To use:

from  import 

class ():
    __metaclass__ = monkeypatch_class
    def (...): ...
    def (...): ...
    ...

This adds , , etc. to , and makes
 a local alias for .

Saturday, December 12, 2009

Managed Hosting?

I just sent an email to a company that specializes in Linux consulting but also offers 'managed' VPS hosting.  I've been thinking about making the switch from self-managed VPS for a while now, and installing RT (my current project) is making my think about it again.

In the process of writing the email I think I ended up creating a pretty good argument for switching, so I'm including the text of the email below.


I'm a developer building an application which I currently host on a slicehost VPS. I'm considering a move to managed hosting to reduce the time I spend doing sysadm tasks and improve the results. 

I see you offer managed hosting, VPS hosting, and sysadmin consulting, but it's not clear to me where the lines are between these. For example -
Are any/all of your VPS plans 'managed'? 
What's included in managed hosting and what types of tasks would escalate to chargeable consulting.

For context, here's my situation -
  1. Application is a Python/Django app using a Postgres database
  2. Mail is handled by a google apps domain, but we have a server we maintain to manage application messaging - notifications, primarily.
  3. We're implementing a ticketing system (RT probably) to handle part of our business process as well, which will also need to be integrated with our application and mail setup
  4. We have what are probably fairly standard, but critical requirements for network security since we process financial information.
  5. We need to be able to monitor and track application uptime, performance and system utilization for app components such as web, database and mail servers as well as general system utilization.
  6. While we currently use our hosts domain management tools there might at some point be some utility in hosting our domain ourselves, or at least getting more flexibility with respect to how it is managed and setup.
  7. We need fairly unrestricted access to the machine - ssh and root access - although not all developers will have this level of access.
  8. We need a backup / recovery plan that would -
    • ensure we never lose more then a few hours of business data
    • limit downtime in the case of disaster or hardware failure to less than 12 hours
  9. As our business picks up, #8 would be strengthened...

The first four things on that list have been implemented, the rest are in various partial states.

In addition, I would expect there are requirements I'm forgetting in this quick rundown that you're familiar with from experience with similar customers.

The question is, I guess, how much of this is part of 'managed' and how much requires consulting?

I wonder what their response will be? How much 'management' is typically included in a managed hosting plan?