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 from ganeti import utils
35
36 from ganeti.rapi import baserlib
37 from ganeti.rapi import rlib2
38
39
40 _NAME_PATTERN = r"[\w\._-]+"
41 _DISK_PATTERN = r"\d+"
42
43
44 CONNECTOR = {}
48 """Map resource to method.
49
50 """
52 """Resource mapper constructor.
53
54 @param connector: a dictionary, mapping method name with URL path regexp
55
56 """
57 if connector is None:
58 connector = CONNECTOR
59 self._connector = connector
60
62 """Find method for a given URI.
63
64 @param uri: string with URI
65
66 @return: None if no method is found or a tuple containing
67 the following fields:
68 - method: name of method mapped to URI
69 - items: a list of variable intems in the path
70 - args: a dictionary with additional parameters from URL
71
72 """
73 if "?" in uri:
74 (path, query) = uri.split("?", 1)
75 args = cgi.parse_qs(query)
76 else:
77 path = uri
78 query = None
79 args = {}
80
81
82 result = utils.FindMatch(self._connector, path)
83
84 if result is None:
85 raise http.HttpNotFound()
86
87 (handler, groups) = result
88
89 return (handler, groups, args)
90
91
92 -class R_root(baserlib.R_Generic):
93 """/ resource.
94
95 """
96 _ROOT_PATTERN = re.compile("^R_([a-zA-Z0-9]+)$")
97
98 @classmethod
100 """Show the list of mapped resources.
101
102 @return: a dictionary with 'name' and 'uri' keys for each of them.
103
104 """
105 rootlist = []
106 for handler in CONNECTOR.values():
107 m = cls._ROOT_PATTERN.match(handler.__name__)
108 if m:
109 name = m.group(1)
110 if name != "root":
111 rootlist.append(name)
112
113 return baserlib.BuildUriList(rootlist, "/%s")
114
117 """Return a list of resources underneath given id.
118
119 This is to generalize querying of version resources lists.
120
121 @return: a list of resources names.
122
123 """
124 r_pattern = re.compile("^R_%s_([a-zA-Z0-9]+)$" % id_)
125
126 rlist = []
127 for handler in CONNECTOR.values():
128 m = r_pattern.match(handler.__name__)
129 if m:
130 name = m.group(1)
131 rlist.append(name)
132
133 return rlist
134
135
136 -class R_2(baserlib.R_Generic):
137 """/2 resource.
138
139 This is the root of the version 2 API.
140
141 """
142 @staticmethod
144 """Show the list of mapped resources.
145
146 @return: a dictionary with 'name' and 'uri' keys for each of them.
147
148 """
149 return baserlib.BuildUriList(_getResources("2"), "/2/%s")
150
151
152 -def GetHandlers(node_name_pattern, instance_name_pattern,
153 group_name_pattern, job_id_pattern, disk_pattern,
154 query_res_pattern):
155 """Returns all supported resources and their handlers.
156
157 """
158
159
160
161
162 return {
163 "/": R_root,
164
165 "/version": rlib2.R_version,
166
167 "/2": R_2,
168
169 "/2/nodes": rlib2.R_2_nodes,
170 re.compile(r"^/2/nodes/(%s)$" % node_name_pattern):
171 rlib2.R_2_nodes_name,
172 re.compile(r"^/2/nodes/(%s)/tags$" % node_name_pattern):
173 rlib2.R_2_nodes_name_tags,
174 re.compile(r"^/2/nodes/(%s)/role$" % node_name_pattern):
175 rlib2.R_2_nodes_name_role,
176 re.compile(r"^/2/nodes/(%s)/evacuate$" % node_name_pattern):
177 rlib2.R_2_nodes_name_evacuate,
178 re.compile(r"^/2/nodes/(%s)/migrate$" % node_name_pattern):
179 rlib2.R_2_nodes_name_migrate,
180 re.compile(r"^/2/nodes/(%s)/storage$" % node_name_pattern):
181 rlib2.R_2_nodes_name_storage,
182 re.compile(r"^/2/nodes/(%s)/storage/modify$" % node_name_pattern):
183 rlib2.R_2_nodes_name_storage_modify,
184 re.compile(r"^/2/nodes/(%s)/storage/repair$" % node_name_pattern):
185 rlib2.R_2_nodes_name_storage_repair,
186
187 "/2/instances": rlib2.R_2_instances,
188 re.compile(r"^/2/instances/(%s)$" % instance_name_pattern):
189 rlib2.R_2_instances_name,
190 re.compile(r"^/2/instances/(%s)/info$" % instance_name_pattern):
191 rlib2.R_2_instances_name_info,
192 re.compile(r"^/2/instances/(%s)/tags$" % instance_name_pattern):
193 rlib2.R_2_instances_name_tags,
194 re.compile(r"^/2/instances/(%s)/reboot$" % instance_name_pattern):
195 rlib2.R_2_instances_name_reboot,
196 re.compile(r"^/2/instances/(%s)/reinstall$" % instance_name_pattern):
197 rlib2.R_2_instances_name_reinstall,
198 re.compile(r"^/2/instances/(%s)/replace-disks$" % instance_name_pattern):
199 rlib2.R_2_instances_name_replace_disks,
200 re.compile(r"^/2/instances/(%s)/shutdown$" % instance_name_pattern):
201 rlib2.R_2_instances_name_shutdown,
202 re.compile(r"^/2/instances/(%s)/startup$" % instance_name_pattern):
203 rlib2.R_2_instances_name_startup,
204 re.compile(r"^/2/instances/(%s)/activate-disks$" % instance_name_pattern):
205 rlib2.R_2_instances_name_activate_disks,
206 re.compile(r"^/2/instances/(%s)/deactivate-disks$" % instance_name_pattern):
207 rlib2.R_2_instances_name_deactivate_disks,
208 re.compile(r"^/2/instances/(%s)/prepare-export$" % instance_name_pattern):
209 rlib2.R_2_instances_name_prepare_export,
210 re.compile(r"^/2/instances/(%s)/export$" % instance_name_pattern):
211 rlib2.R_2_instances_name_export,
212 re.compile(r"^/2/instances/(%s)/migrate$" % instance_name_pattern):
213 rlib2.R_2_instances_name_migrate,
214 re.compile(r"^/2/instances/(%s)/failover$" % instance_name_pattern):
215 rlib2.R_2_instances_name_failover,
216 re.compile(r"^/2/instances/(%s)/rename$" % instance_name_pattern):
217 rlib2.R_2_instances_name_rename,
218 re.compile(r"^/2/instances/(%s)/modify$" % instance_name_pattern):
219 rlib2.R_2_instances_name_modify,
220 re.compile(r"^/2/instances/(%s)/disk/(%s)/grow$" %
221 (instance_name_pattern, disk_pattern)):
222 rlib2.R_2_instances_name_disk_grow,
223 re.compile(r"^/2/instances/(%s)/console$" % instance_name_pattern):
224 rlib2.R_2_instances_name_console,
225
226 "/2/groups": rlib2.R_2_groups,
227 re.compile(r"^/2/groups/(%s)$" % group_name_pattern):
228 rlib2.R_2_groups_name,
229 re.compile(r"^/2/groups/(%s)/modify$" % group_name_pattern):
230 rlib2.R_2_groups_name_modify,
231 re.compile(r"^/2/groups/(%s)/rename$" % group_name_pattern):
232 rlib2.R_2_groups_name_rename,
233 re.compile(r"^/2/groups/(%s)/assign-nodes$" % group_name_pattern):
234 rlib2.R_2_groups_name_assign_nodes,
235 re.compile(r"^/2/groups/(%s)/tags$" % group_name_pattern):
236 rlib2.R_2_groups_name_tags,
237
238 "/2/jobs": rlib2.R_2_jobs,
239 re.compile(r"^/2/jobs/(%s)$" % job_id_pattern):
240 rlib2.R_2_jobs_id,
241 re.compile(r"^/2/jobs/(%s)/wait$" % job_id_pattern):
242 rlib2.R_2_jobs_id_wait,
243
244 "/2/tags": rlib2.R_2_tags,
245 "/2/info": rlib2.R_2_info,
246 "/2/os": rlib2.R_2_os,
247 "/2/redistribute-config": rlib2.R_2_redist_config,
248 "/2/features": rlib2.R_2_features,
249 "/2/modify": rlib2.R_2_cluster_modify,
250 re.compile(r"^/2/query/(%s)$" % query_res_pattern): rlib2.R_2_query,
251 re.compile(r"^/2/query/(%s)/fields$" % query_res_pattern):
252 rlib2.R_2_query_fields,
253 }
254
255
256 CONNECTOR.update(GetHandlers(_NAME_PATTERN, _NAME_PATTERN, _NAME_PATTERN,
257 constants.JOB_ID_TEMPLATE, _DISK_PATTERN,
258 _NAME_PATTERN))
259