disk wiping: fix bug in chunk size computation
[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 # pylint: disable-msg=C0103
26
27 # C0103: Invalid name, since the R_* names are not conforming
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 # the connection map is created at the end of this file
44 CONNECTOR = {}
45
46
47 class Mapper:
48   """Map resource to method.
49
50   """
51   def __init__(self, connector=None):
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
61   def getController(self, uri):
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     # Try to find handler for request path
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
99   def GET(cls):
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
115
116 def _getResources(id_):
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
143   def GET():
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   # Important note: New resources should always be added under /2. During a
158   # discussion in July 2010 it was decided that having per-resource versions
159   # is more flexible and future-compatible than versioning the whole remote
160   # API.
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))