Populate OS variants if an api >= 15 is present
[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 rlib2
33
34
35 _NAME_PATTERN = r"[\w\._-]+"
36
37 # the connection map is created at the end of this file
38 CONNECTOR = {}
39
40
41 class Mapper:
42   """Map resource to method.
43
44   """
45   def __init__(self, connector=CONNECTOR):
46     """Resource mapper constructor.
47
48     @param connector: a dictionary, mapping method name with URL path regexp
49
50     """
51     self._connector = connector
52
53   def getController(self, uri):
54     """Find method for a given URI.
55
56     @param uri: string with URI
57
58     @return: None if no method is found or a tuple containing
59         the following fields:
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
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   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 def _getResources(id):
118   """Return a list of resources underneath given id.
119
120   This is to generalize querying of version resources lists.
121
122   @return: a list of resources names.
123
124   """
125   r_pattern = re.compile('^R_%s_([a-zA-Z0-9]+)$' % id)
126
127   rlist = []
128   for handler in CONNECTOR.values():
129     m = r_pattern.match(handler.__name__)
130     if m:
131       name = m.group(1)
132       rlist.append(name)
133
134   return rlist
135
136
137 class R_2(baserlib.R_Generic):
138   """ /2 resource, the root of the version 2 API.
139
140   """
141   def GET(self):
142     """Show the list of mapped resources.
143
144     @return: a dictionary with 'name' and 'uri' keys for each of them.
145
146     """
147     return baserlib.BuildUriList(_getResources("2"), "/2/%s")
148
149
150 def GetHandlers(node_name_pattern, instance_name_pattern, job_id_pattern):
151   """Returns all supported resources and their handlers.
152
153   """
154   return {
155     "/": R_root,
156
157     "/version": rlib2.R_version,
158
159     "/2": R_2,
160
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,
178
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,
196
197     "/2/jobs": rlib2.R_2_jobs,
198     re.compile(r'/2/jobs/(%s)$' % job_id_pattern):
199       rlib2.R_2_jobs_id,
200
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,
205     }
206
207
208 CONNECTOR.update(GetHandlers(_NAME_PATTERN, _NAME_PATTERN,
209                              constants.JOB_ID_TEMPLATE))