Convert AddOSToInstance to (status, data)
[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     @param connector: a dictionary, mapping method name with URL path regexp
47
48     """
49     self._connector = connector
50
51   def getController(self, uri):
52     """Find method for a given URI.
53
54     @param uri: string with URI
55
56     @return: None if no method is found or a tuple containing
57         the following fields:
58             - method: name of method mapped to URI
59             - items: a list of variable intems in the path
60             - args: a dictionary with additional parameters from URL
61
62     """
63     if '?' in uri:
64       (path, query) = uri.split('?', 1)
65       args = cgi.parse_qs(query)
66     else:
67       path = uri
68       query = None
69       args = {}
70
71     result = None
72
73     for key, handler in self._connector.iteritems():
74       # Regex objects
75       if hasattr(key, "match"):
76         m = key.match(path)
77         if m:
78           result = (handler, list(m.groups()), args)
79           break
80
81       # String objects
82       elif key == path:
83         result = (handler, [], args)
84         break
85
86     if result:
87       return result
88     else:
89       raise http.HttpNotFound()
90
91
92 class R_root(baserlib.R_Generic):
93   """/ resource.
94
95   """
96   DOC_URI = "/"
97
98   def GET(self):
99     """Show the list of mapped resources.
100
101     @return: a dictionary with 'name' and 'uri' keys for each of them.
102
103     """
104     root_pattern = re.compile('^R_([a-zA-Z0-9]+)$')
105
106     rootlist = []
107     for handler in CONNECTOR.values():
108       m = root_pattern.match(handler.__name__)
109       if m:
110         name = m.group(1)
111         if name != 'root':
112           rootlist.append(name)
113
114     return baserlib.BuildUriList(rootlist, "/%s")
115
116
117 CONNECTOR.update({
118   "/": R_root,
119
120   "/version": rlib1.R_version,
121
122   "/tags": rlib1.R_tags,
123   "/info": rlib1.R_info,
124
125   "/nodes": rlib2.R_nodes,
126   re.compile(r'^/nodes/([\w\._-]+)$'): rlib1.R_nodes_name,
127   re.compile(r'^/nodes/([\w\._-]+)/tags$'): rlib1.R_nodes_name_tags,
128
129   "/instances": rlib2.R_instances,
130   re.compile(r'^/instances/([\w\._-]+)$'): rlib1.R_instances_name,
131   re.compile(r'^/instances/([\w\._-]+)/tags$'): rlib1.R_instances_name_tags,
132
133   "/os": rlib1.R_os,
134
135   "/2/jobs": rlib2.R_2_jobs,
136   "/2/nodes": rlib2.R_2_nodes,
137   "/2/instances": rlib2.R_2_instances,
138   re.compile(r'^/2/instances/([\w\._-]+)$'): rlib1.R_instances_name,
139   re.compile(r'^/2/instances/([\w\._-]+)/tags$'): rlib2.R_2_instances_name_tags,
140   re.compile(r'^/2/instances/([\w\._-]+)/reboot$'):
141       rlib2.R_2_instances_name_reboot,
142   re.compile(r'^/2/instances/([\w\._-]+)/shutdown$'):
143       rlib2.R_2_instances_name_shutdown,
144   re.compile(r'^/2/instances/([\w\._-]+)/startup$'):
145       rlib2.R_2_instances_name_startup,
146   re.compile(r'/2/jobs/(%s)$' % constants.JOB_ID_TEMPLATE): rlib2.R_2_jobs_id,
147   })