4 # Copyright (C) 2006, 2007, 2008 Google Inc.
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.
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.
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
21 """Remote API connection map.
28 from ganeti import constants
29 from ganeti import http
31 from ganeti.rapi import baserlib
32 from ganeti.rapi import rlib2
35 _NAME_PATTERN = r"[\w\._-]+"
37 # the connection map is created at the end of this file
42 """Map resource to method.
45 def __init__(self, connector=CONNECTOR):
46 """Resource mapper constructor.
48 @param connector: a dictionary, mapping method name with URL path regexp
51 self._connector = connector
53 def getController(self, uri):
54 """Find method for a given URI.
56 @param uri: string with URI
58 @return: None if no method is found or a tuple containing
60 - method: 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
66 (path, query) = uri.split('?', 1)
67 args = cgi.parse_qs(query)
75 for key, handler in self._connector.iteritems():
77 if hasattr(key, "match"):
80 result = (handler, list(m.groups()), args)
85 result = (handler, [], args)
91 raise http.HttpNotFound()
94 class R_root(baserlib.R_Generic):
99 """Show the list of mapped resources.
101 @return: a dictionary with 'name' and 'uri' keys for each of them.
104 root_pattern = re.compile('^R_([a-zA-Z0-9]+)$')
107 for handler in CONNECTOR.values():
108 m = root_pattern.match(handler.__name__)
112 rootlist.append(name)
114 return baserlib.BuildUriList(rootlist, "/%s")
117 def _getResources(id):
118 """Return a list of resources underneath given id.
120 This is to generalize querying of version resources lists.
122 @return: a list of resources names.
125 r_pattern = re.compile('^R_%s_([a-zA-Z0-9]+)$' % id)
128 for handler in CONNECTOR.values():
129 m = r_pattern.match(handler.__name__)
137 class R_2(baserlib.R_Generic):
138 """ /2 resource, the root of the version 2 API.
142 """Show the list of mapped resources.
144 @return: a dictionary with 'name' and 'uri' keys for each of them.
147 return baserlib.BuildUriList(_getResources("2"), "/2/%s")
150 def GetHandlers(node_name_pattern, instance_name_pattern, job_id_pattern):
151 """Returns all supported resources and their handlers.
157 "/version": rlib2.R_version,
161 "/2/nodes": rlib2.R_2_nodes,
162 re.compile(r'^/2/nodes/(%s)$' % node_name_pattern):
163 rlib2.R_2_nodes_name,
164 re.compile(r'^/2/nodes/(%s)/tags$' % node_name_pattern):
165 rlib2.R_2_nodes_name_tags,
166 re.compile(r'^/2/nodes/(%s)/role$' % node_name_pattern):
167 rlib2.R_2_nodes_name_role,
168 re.compile(r'^/2/nodes/(%s)/evacuate$' % node_name_pattern):
169 rlib2.R_2_nodes_name_evacuate,
170 re.compile(r'^/2/nodes/(%s)/migrate$' % node_name_pattern):
171 rlib2.R_2_nodes_name_migrate,
172 re.compile(r'^/2/nodes/(%s)/storage$' % node_name_pattern):
173 rlib2.R_2_nodes_name_storage,
174 re.compile(r'^/2/nodes/(%s)/storage/modify$' % node_name_pattern):
175 rlib2.R_2_nodes_name_storage_modify,
176 re.compile(r'^/2/nodes/(%s)/storage/repair$' % node_name_pattern):
177 rlib2.R_2_nodes_name_storage_repair,
179 "/2/instances": rlib2.R_2_instances,
180 re.compile(r'^/2/instances/(%s)$' % instance_name_pattern):
181 rlib2.R_2_instances_name,
182 re.compile(r'^/2/instances/(%s)/info$' % instance_name_pattern):
183 rlib2.R_2_instances_name_info,
184 re.compile(r'^/2/instances/(%s)/tags$' % instance_name_pattern):
185 rlib2.R_2_instances_name_tags,
186 re.compile(r'^/2/instances/(%s)/reboot$' % instance_name_pattern):
187 rlib2.R_2_instances_name_reboot,
188 re.compile(r'^/2/instances/(%s)/reinstall$' % instance_name_pattern):
189 rlib2.R_2_instances_name_reinstall,
190 re.compile(r'^/2/instances/(%s)/replace-disks$' % instance_name_pattern):
191 rlib2.R_2_instances_name_replace_disks,
192 re.compile(r'^/2/instances/(%s)/shutdown$' % instance_name_pattern):
193 rlib2.R_2_instances_name_shutdown,
194 re.compile(r'^/2/instances/(%s)/startup$' % instance_name_pattern):
195 rlib2.R_2_instances_name_startup,
197 "/2/jobs": rlib2.R_2_jobs,
198 re.compile(r'/2/jobs/(%s)$' % job_id_pattern):
201 "/2/tags": rlib2.R_2_tags,
202 "/2/info": rlib2.R_2_info,
203 "/2/os": rlib2.R_2_os,
204 "/2/redistribute-config": rlib2.R_2_redist_config,
208 CONNECTOR.update(GetHandlers(_NAME_PATTERN, _NAME_PATTERN,
209 constants.JOB_ID_TEMPLATE))