1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21 """Remote API connection map.
22
23 """
24
25
26
27
28
29 import cgi
30 import re
31
32 from ganeti import constants
33 from ganeti import http
34
35 from ganeti.rapi import baserlib
36 from ganeti.rapi import rlib2
37
38
39 _NAME_PATTERN = r"[\w\._-]+"
40
41
42 CONNECTOR = {}
46 """Map resource to method.
47
48 """
50 """Resource mapper constructor.
51
52 @param connector: a dictionary, mapping method name with URL path regexp
53
54 """
55 if connector is None:
56 connector = CONNECTOR
57 self._connector = connector
58
60 """Find method for a given URI.
61
62 @param uri: string with URI
63
64 @return: None if no method is found or a tuple containing
65 the following fields:
66 - method: name of method mapped to URI
67 - items: a list of variable intems in the path
68 - args: a dictionary with additional parameters from URL
69
70 """
71 if '?' in uri:
72 (path, query) = uri.split('?', 1)
73 args = cgi.parse_qs(query)
74 else:
75 path = uri
76 query = None
77 args = {}
78
79 result = None
80
81 for key, handler in self._connector.iteritems():
82
83 if hasattr(key, "match"):
84 m = key.match(path)
85 if m:
86 result = (handler, list(m.groups()), args)
87 break
88
89
90 elif key == path:
91 result = (handler, [], args)
92 break
93
94 if result:
95 return result
96 else:
97 raise http.HttpNotFound()
98
99
100 -class R_root(baserlib.R_Generic):
101 """/ resource.
102
103 """
104 @staticmethod
106 """Show the list of mapped resources.
107
108 @return: a dictionary with 'name' and 'uri' keys for each of them.
109
110 """
111 root_pattern = re.compile('^R_([a-zA-Z0-9]+)$')
112
113 rootlist = []
114 for handler in CONNECTOR.values():
115 m = root_pattern.match(handler.__name__)
116 if m:
117 name = m.group(1)
118 if name != 'root':
119 rootlist.append(name)
120
121 return baserlib.BuildUriList(rootlist, "/%s")
122
125 """Return a list of resources underneath given id.
126
127 This is to generalize querying of version resources lists.
128
129 @return: a list of resources names.
130
131 """
132 r_pattern = re.compile('^R_%s_([a-zA-Z0-9]+)$' % id_)
133
134 rlist = []
135 for handler in CONNECTOR.values():
136 m = r_pattern.match(handler.__name__)
137 if m:
138 name = m.group(1)
139 rlist.append(name)
140
141 return rlist
142
143
144 -class R_2(baserlib.R_Generic):
145 """ /2 resource, the root of the version 2 API.
146
147 """
148 @staticmethod
150 """Show the list of mapped resources.
151
152 @return: a dictionary with 'name' and 'uri' keys for each of them.
153
154 """
155 return baserlib.BuildUriList(_getResources("2"), "/2/%s")
156
157
158 -def GetHandlers(node_name_pattern, instance_name_pattern, job_id_pattern):
159 """Returns all supported resources and their handlers.
160
161 """
162
163
164
165
166 return {
167 "/": R_root,
168
169 "/version": rlib2.R_version,
170
171 "/2": R_2,
172
173 "/2/nodes": rlib2.R_2_nodes,
174 re.compile(r'^/2/nodes/(%s)$' % node_name_pattern):
175 rlib2.R_2_nodes_name,
176 re.compile(r'^/2/nodes/(%s)/tags$' % node_name_pattern):
177 rlib2.R_2_nodes_name_tags,
178 re.compile(r'^/2/nodes/(%s)/role$' % node_name_pattern):
179 rlib2.R_2_nodes_name_role,
180 re.compile(r'^/2/nodes/(%s)/evacuate$' % node_name_pattern):
181 rlib2.R_2_nodes_name_evacuate,
182 re.compile(r'^/2/nodes/(%s)/migrate$' % node_name_pattern):
183 rlib2.R_2_nodes_name_migrate,
184 re.compile(r'^/2/nodes/(%s)/storage$' % node_name_pattern):
185 rlib2.R_2_nodes_name_storage,
186 re.compile(r'^/2/nodes/(%s)/storage/modify$' % node_name_pattern):
187 rlib2.R_2_nodes_name_storage_modify,
188 re.compile(r'^/2/nodes/(%s)/storage/repair$' % node_name_pattern):
189 rlib2.R_2_nodes_name_storage_repair,
190
191 "/2/instances": rlib2.R_2_instances,
192 re.compile(r'^/2/instances/(%s)$' % instance_name_pattern):
193 rlib2.R_2_instances_name,
194 re.compile(r'^/2/instances/(%s)/info$' % instance_name_pattern):
195 rlib2.R_2_instances_name_info,
196 re.compile(r'^/2/instances/(%s)/tags$' % instance_name_pattern):
197 rlib2.R_2_instances_name_tags,
198 re.compile(r'^/2/instances/(%s)/reboot$' % instance_name_pattern):
199 rlib2.R_2_instances_name_reboot,
200 re.compile(r'^/2/instances/(%s)/reinstall$' % instance_name_pattern):
201 rlib2.R_2_instances_name_reinstall,
202 re.compile(r'^/2/instances/(%s)/replace-disks$' % instance_name_pattern):
203 rlib2.R_2_instances_name_replace_disks,
204 re.compile(r'^/2/instances/(%s)/shutdown$' % instance_name_pattern):
205 rlib2.R_2_instances_name_shutdown,
206 re.compile(r'^/2/instances/(%s)/startup$' % instance_name_pattern):
207 rlib2.R_2_instances_name_startup,
208 re.compile(r'^/2/instances/(%s)/activate-disks$' % instance_name_pattern):
209 rlib2.R_2_instances_name_activate_disks,
210 re.compile(r'^/2/instances/(%s)/deactivate-disks$' % instance_name_pattern):
211 rlib2.R_2_instances_name_deactivate_disks,
212 re.compile(r'^/2/instances/(%s)/prepare-export$' % instance_name_pattern):
213 rlib2.R_2_instances_name_prepare_export,
214 re.compile(r'^/2/instances/(%s)/export$' % instance_name_pattern):
215 rlib2.R_2_instances_name_export,
216 re.compile(r'^/2/instances/(%s)/migrate$' % instance_name_pattern):
217 rlib2.R_2_instances_name_migrate,
218 re.compile(r'^/2/instances/(%s)/rename$' % instance_name_pattern):
219 rlib2.R_2_instances_name_rename,
220 re.compile(r'^/2/instances/(%s)/modify$' % instance_name_pattern):
221 rlib2.R_2_instances_name_modify,
222
223 "/2/jobs": rlib2.R_2_jobs,
224 re.compile(r"^/2/jobs/(%s)$" % job_id_pattern):
225 rlib2.R_2_jobs_id,
226 re.compile(r"^/2/jobs/(%s)/wait$" % job_id_pattern):
227 rlib2.R_2_jobs_id_wait,
228
229 "/2/tags": rlib2.R_2_tags,
230 "/2/info": rlib2.R_2_info,
231 "/2/os": rlib2.R_2_os,
232 "/2/redistribute-config": rlib2.R_2_redist_config,
233 "/2/features": rlib2.R_2_features,
234 }
235
236
237 CONNECTOR.update(GetHandlers(_NAME_PATTERN, _NAME_PATTERN,
238 constants.JOB_ID_TEMPLATE))
239