~ubuntuone-pqm-team/canonical-identity-provider/trunk

« back to all changes in this revision

Viewing changes to identityprovider/views/readonly.py

  • Committer: Danny Tamez
  • Date: 2010-04-21 15:29:24 UTC
  • Revision ID: danny.tamez@canonical.com-20100421152924-lq1m92tstk2iz75a
Canonical SSO Provider (Open Source) - Initial Commit

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
# Copyright 2010 Canonical Ltd.  This software is licensed under the
 
2
# GNU Affero General Public License version 3 (see the file LICENSE).
 
3
 
 
4
from django.shortcuts import render_to_response
 
5
from django.conf import settings
 
6
from django.contrib.admin.views.decorators import staff_member_required
 
7
from django.utils import simplejson
 
8
from identityprovider.readonly import (readonly_manager,
 
9
    sync_memcached_to_db)
 
10
from django.http import HttpResponse, HttpResponseRedirect, Http404
 
11
import socket
 
12
import urllib
 
13
import urllib2
 
14
 
 
15
 
 
16
def _remote_req(server, post=None):
 
17
    """Makes a request to a specific appserver.
 
18
 
 
19
    if post is provided, it should be a sequence of 2-tuples that will be
 
20
    encoded in to POST data.
 
21
    """
 
22
    if post is None:
 
23
        post = []
 
24
    post.append(('secret', settings.READONLY_SECRET))
 
25
    post = urllib.urlencode(post)
 
26
    req = urllib2.Request('http://%s/readonlydata' % server, data=post)
 
27
    try:
 
28
        oldtimeout = socket.getdefaulttimeout()
 
29
        socket.setdefaulttimeout(5)
 
30
        datafile = urllib2.urlopen(req)
 
31
        data = datafile.read()
 
32
        socket.setdefaulttimeout(oldtimeout)
 
33
    except urllib2.URLError:
 
34
        data = None
 
35
    return data
 
36
 
 
37
 
 
38
@staff_member_required
 
39
def readonly_admin(request):
 
40
    atts = get_server_atts(settings.APP_SERVERS)
 
41
    return render_to_response('admin/readonly.html', atts)
 
42
 
 
43
 
 
44
def get_server_atts(servers):
 
45
    """Provides a report about readonly status of all app servers."""
 
46
    appservers = []
 
47
    set_all_readonly = False
 
48
    clear_all_readonly = False
 
49
    for server in servers:
 
50
        datastr = _remote_req(server)
 
51
        if datastr is None:
 
52
            data = {'reachable': False}
 
53
        else:
 
54
            try:
 
55
                data = simplejson.loads(datastr)
 
56
            except ValueError:
 
57
                # This is probably caused by the remote database being out
 
58
                # of sync with our current database
 
59
                data = {'reachable': False}
 
60
            else:
 
61
                data['reachable'] = True
 
62
            if data.get('readonly'):
 
63
                clear_all_readonly = True
 
64
            else:
 
65
                set_all_readonly = True
 
66
        data['name'] = server
 
67
        appservers.append(data)
 
68
    atts = {'appservers': appservers,
 
69
            'admin_media_prefix': settings.ADMIN_MEDIA_PREFIX,
 
70
            'clear_all_readonly': clear_all_readonly,
 
71
            'set_all_readonly': set_all_readonly,
 
72
            }
 
73
    return atts
 
74
 
 
75
 
 
76
@staff_member_required
 
77
def readonly_confirm(request, action, appserver=None, conn=None):
 
78
    if request.method == 'POST':
 
79
        update_server(action, appserver, conn)
 
80
        return HttpResponseRedirect('/readonly')
 
81
    atts = {'appserver': appserver,
 
82
            'action': action,
 
83
            'conn': conn,
 
84
           }
 
85
    return render_to_response('admin/readonly_confirm.html', atts)
 
86
 
 
87
 
 
88
def update_server(action, appserver=None, conn=None):
 
89
    if appserver is None:
 
90
        appservers = settings.APP_SERVERS
 
91
    else:
 
92
        appservers = [appserver]
 
93
    for server in appservers:
 
94
        post = [('action', action),
 
95
                ('conn', conn),
 
96
               ]
 
97
        datastr = _remote_req(server, post)
 
98
    # If we're leaving readonly mode across all appservers,
 
99
    # try to sync up data back from memcached to the DB.
 
100
    if appserver is None and action == 'clear':
 
101
        sync_memcached_to_db()
 
102
 
 
103
 
 
104
def readonly_data(request):
 
105
    """Provides data about the readonly status of this app server."""
 
106
    if request.method != 'POST':
 
107
        raise Http404()
 
108
    secret = request.POST.get('secret')
 
109
    if secret != settings.READONLY_SECRET:
 
110
        raise Http404()
 
111
    action = request.POST.get('action')
 
112
    conn = request.POST.get('conn')
 
113
    if action == 'set':
 
114
        readonly_manager.set_readonly()
 
115
    elif action == 'clear':
 
116
        readonly_manager.clear_readonly()
 
117
    elif action == 'enable':
 
118
        readonly_manager.clear_failed(conn)
 
119
    elif action == 'disable':
 
120
        readonly_manager.mark_failed(conn)
 
121
    result = {'readonly': readonly_manager.is_readonly()}
 
122
    dbs = []
 
123
    for conn in readonly_manager.connections:
 
124
        dbid = conn['DATABASE_ID']
 
125
        dbs.append({'id': dbid,
 
126
                    'failed': readonly_manager.is_failed(dbid),
 
127
                   })
 
128
    result['connections'] = dbs
 
129
    return HttpResponse(simplejson.dumps(result))