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 """Returns all supported resources and their handlers.
155
156 """
157
158
159
160
161 return {
162 "/": R_root,
163
164 "/version": rlib2.R_version,
165
166 "/2": R_2,
167
168 "/2/nodes": rlib2.R_2_nodes,
169 re.compile(r'^/2/nodes/(%s)$' % node_name_pattern):
170 rlib2.R_2_nodes_name,
171 re.compile(r'^/2/nodes/(%s)/tags$' % node_name_pattern):
172 rlib2.R_2_nodes_name_tags,
173 re.compile(r'^/2/nodes/(%s)/role$' % node_name_pattern):
174 rlib2.R_2_nodes_name_role,
175 re.compile(r'^/2/nodes/(%s)/evacuate$' % node_name_pattern):
176 rlib2.R_2_nodes_name_evacuate,
177 re.compile(r'^/2/nodes/(%s)/migrate$' % node_name_pattern):
178 rlib2.R_2_nodes_name_migrate,
179 re.compile(r'^/2/nodes/(%s)/storage$' % node_name_pattern):
180 rlib2.R_2_nodes_name_storage,
181 re.compile(r'^/2/nodes/(%s)/storage/modify$' % node_name_pattern):
182 rlib2.R_2_nodes_name_storage_modify,
183 re.compile(r'^/2/nodes/(%s)/storage/repair$' % node_name_pattern):
184 rlib2.R_2_nodes_name_storage_repair,
185
186 "/2/instances": rlib2.R_2_instances,
187 re.compile(r'^/2/instances/(%s)$' % instance_name_pattern):
188 rlib2.R_2_instances_name,
189 re.compile(r'^/2/instances/(%s)/info$' % instance_name_pattern):
190 rlib2.R_2_instances_name_info,
191 re.compile(r'^/2/instances/(%s)/tags$' % instance_name_pattern):
192 rlib2.R_2_instances_name_tags,
193 re.compile(r'^/2/instances/(%s)/reboot$' % instance_name_pattern):
194 rlib2.R_2_instances_name_reboot,
195 re.compile(r'^/2/instances/(%s)/reinstall$' % instance_name_pattern):
196 rlib2.R_2_instances_name_reinstall,
197 re.compile(r'^/2/instances/(%s)/replace-disks$' % instance_name_pattern):
198 rlib2.R_2_instances_name_replace_disks,
199 re.compile(r'^/2/instances/(%s)/shutdown$' % instance_name_pattern):
200 rlib2.R_2_instances_name_shutdown,
201 re.compile(r'^/2/instances/(%s)/startup$' % instance_name_pattern):
202 rlib2.R_2_instances_name_startup,
203 re.compile(r'^/2/instances/(%s)/activate-disks$' % instance_name_pattern):
204 rlib2.R_2_instances_name_activate_disks,
205 re.compile(r'^/2/instances/(%s)/deactivate-disks$' % instance_name_pattern):
206 rlib2.R_2_instances_name_deactivate_disks,
207 re.compile(r'^/2/instances/(%s)/prepare-export$' % instance_name_pattern):
208 rlib2.R_2_instances_name_prepare_export,
209 re.compile(r'^/2/instances/(%s)/export$' % instance_name_pattern):
210 rlib2.R_2_instances_name_export,
211 re.compile(r'^/2/instances/(%s)/migrate$' % instance_name_pattern):
212 rlib2.R_2_instances_name_migrate,
213 re.compile(r'^/2/instances/(%s)/rename$' % instance_name_pattern):
214 rlib2.R_2_instances_name_rename,
215 re.compile(r'^/2/instances/(%s)/modify$' % instance_name_pattern):
216 rlib2.R_2_instances_name_modify,
217 re.compile(r"^/2/instances/(%s)/disk/(%s)/grow$" %
218 (instance_name_pattern, disk_pattern)):
219 rlib2.R_2_instances_name_disk_grow,
220 re.compile(r'^/2/instances/(%s)/console$' % instance_name_pattern):
221 rlib2.R_2_instances_name_console,
222
223 "/2/groups": rlib2.R_2_groups,
224 re.compile(r'^/2/groups/(%s)$' % group_name_pattern):
225 rlib2.R_2_groups_name,
226 re.compile(r'^/2/groups/(%s)/modify$' % group_name_pattern):
227 rlib2.R_2_groups_name_modify,
228 re.compile(r'^/2/groups/(%s)/rename$' % group_name_pattern):
229 rlib2.R_2_groups_name_rename,
230 re.compile(r'^/2/groups/(%s)/assign-nodes$' % group_name_pattern):
231 rlib2.R_2_groups_name_assign_nodes,
232
233 "/2/jobs": rlib2.R_2_jobs,
234 re.compile(r"^/2/jobs/(%s)$" % job_id_pattern):
235 rlib2.R_2_jobs_id,
236 re.compile(r"^/2/jobs/(%s)/wait$" % job_id_pattern):
237 rlib2.R_2_jobs_id_wait,
238
239 "/2/tags": rlib2.R_2_tags,
240 "/2/info": rlib2.R_2_info,
241 "/2/os": rlib2.R_2_os,
242 "/2/redistribute-config": rlib2.R_2_redist_config,
243 "/2/features": rlib2.R_2_features,
244 "/2/modify": rlib2.R_2_cluster_modify,
245 }
246
247
248 CONNECTOR.update(GetHandlers(_NAME_PATTERN, _NAME_PATTERN, _NAME_PATTERN,
249 constants.JOB_ID_TEMPLATE, _DISK_PATTERN))
250