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