RAPI: Switch from opcodes to no native 2.0 queries.
[ganeti-local] / lib / rapi / connector.py
1 #
2 #
3
4 # Copyright (C) 2006, 2007, 2008 Google Inc.
5 #
6 # This program is free software; you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by
8 # the Free Software Foundation; either version 2 of the License, or
9 # (at your option) any later version.
10 #
11 # This program is distributed in the hope that it will be useful, but
12 # WITHOUT ANY WARRANTY; without even the implied warranty of
13 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 # General Public License for more details.
15 #
16 # You should have received a copy of the GNU General Public License
17 # along with this program; if not, write to the Free Software
18 # Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
19 # 02110-1301, USA.
20
21 """Remote API connection map.
22
23 """
24
25 import cgi
26 import re
27
28 from ganeti import constants
29 from ganeti import http
30
31 from ganeti.rapi import baserlib
32 from ganeti.rapi import rlib1
33 from ganeti.rapi import rlib2
34
35 # the connection map is created at the end of this file
36 CONNECTOR = {}
37
38
39 class Mapper:
40   """Map resource to method.
41
42   """
43   def __init__(self, connector=CONNECTOR):
44     """Resource mapper constructor.
45
46     Args:
47       con: a dictionary, mapping method name with URL path regexp
48
49     """
50     self._connector = connector
51
52   def getController(self, uri):
53     """Find method for a given URI.
54
55     Args:
56       uri: string with URI
57
58     Returns:
59       None if no method is found or a tuple containing the following fields:
60         methd: name of method mapped to URI
61         items: a list of variable intems in the path
62         args: a dictionary with additional parameters from URL
63
64     """
65     if '?' in uri:
66       (path, query) = uri.split('?', 1)
67       args = cgi.parse_qs(query)
68     else:
69       path = uri
70       query = None
71       args = {}
72
73     result = None
74
75     for key, handler in self._connector.iteritems():
76       # Regex objects
77       if hasattr(key, "match"):
78         m = key.match(path)
79         if m:
80           result = (handler, list(m.groups()), args)
81           break
82
83       # String objects
84       elif key == path:
85         result = (handler, [], args)
86         break
87
88     if result:
89       return result
90     else:
91       raise http.HTTPNotFound()
92
93
94 class R_root(baserlib.R_Generic):
95   """/ resource.
96
97   """
98   DOC_URI = "/"
99
100   def GET(self):
101     """Show the list of mapped resources.
102
103     Returns:
104       A dictionary with 'name' and 'uri' keys for each of them.
105
106     """
107     root_pattern = re.compile('^R_([a-zA-Z0-9]+)$')
108
109     rootlist = []
110     for handler in CONNECTOR.values():
111       m = root_pattern.match(handler.__name__)
112       if m:
113         name = m.group(1)
114         if name != 'root':
115           rootlist.append(name)
116
117     return baserlib.BuildUriList(rootlist, "/%s")
118
119
120 CONNECTOR.update({
121   "/": R_root,
122
123   "/version": rlib1.R_version,
124
125   "/tags": rlib1.R_tags,
126   "/info": rlib1.R_info,
127
128   "/nodes": rlib2.R_2_nodes,
129   re.compile(r'^/nodes/([\w\._-]+)$'): rlib1.R_nodes_name,
130   re.compile(r'^/nodes/([\w\._-]+)/tags$'): rlib1.R_nodes_name_tags,
131
132   "/instances": rlib2.R_2_instances,
133   re.compile(r'^/instances/([\w\._-]+)$'): rlib1.R_instances_name,
134   re.compile(r'^/instances/([\w\._-]+)/tags$'): rlib1.R_instances_name_tags,
135
136   "/os": rlib1.R_os,
137
138   "/2/jobs": rlib2.R_2_jobs,
139   "/2/nodes": rlib2.R_2_nodes,
140   "/2/instances": rlib2.R_2_instances,
141   re.compile(r'^/2/instances/([\w\._-]+)$'): rlib1.R_instances_name,
142   re.compile(r'^/2/instances/([\w\._-]+)/tags$'): rlib2.R_2_instances_name_tags,
143   re.compile(r'^/2/instances/([\w\._-]+)/reboot$'):
144       rlib2.R_2_instances_name_reboot,
145   re.compile(r'^/2/instances/([\w\._-]+)/shutdown$'):
146       rlib2.R_2_instances_name_shutdown,
147   re.compile(r'^/2/instances/([\w\._-]+)/startup$'):
148       rlib2.R_2_instances_name_startup,
149   re.compile(r'/2/jobs/(%s)$' % constants.JOB_ID_TEMPLATE): rlib2.R_2_jobs_id,
150   })