Statistics
| Branch: | Tag: | Revision:

root / lib / rapi / connector.py @ 06c2fb4a

History | View | Annotate | Download (9.2 kB)

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=C0103
26

    
27
# C0103: Invalid name, since the R_* names are not conforming
28

    
29
import re
30
import urlparse
31

    
32
from ganeti import constants
33
from ganeti import http
34
from ganeti import utils
35

    
36
from ganeti.rapi import rlib2
37

    
38

    
39
_NAME_PATTERN = r"[\w\._-]+"
40
_DISK_PATTERN = r"\d+"
41

    
42
# the connection map is created at the end of this file
43
CONNECTOR = {}
44

    
45

    
46
class Mapper:
47
  """Map resource to method.
48

49
  """
50
  def __init__(self, connector=None):
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

    
60
  def getController(self, uri):
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 = urlparse.parse_qs(query)
75
    else:
76
      path = uri
77
      query = None
78
      args = {}
79

    
80
    # Try to find handler for request path
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
def _ConvertPattern(value):
92
  """Converts URI pattern into a regular expression group.
93

94
  Used by L{_CompileHandlerPath}.
95

96
  """
97
  if isinstance(value, UriPattern):
98
    return "(%s)" % value.content
99
  else:
100
    return value
101

    
102

    
103
def _CompileHandlerPath(*args):
104
  """Compiles path for RAPI resource into regular expression.
105

106
  @return: Compiled regular expression object
107

108
  """
109
  return re.compile("^%s$" % "".join(map(_ConvertPattern, args)))
110

    
111

    
112
class UriPattern(object):
113
  __slots__ = [
114
    "content",
115
    ]
116

    
117
  def __init__(self, content):
118
    self.content = content
119

    
120

    
121
def GetHandlers(node_name_pattern, instance_name_pattern,
122
                group_name_pattern, network_name_pattern,
123
                job_id_pattern, disk_pattern,
124
                query_res_pattern,
125
                translate=None):
126
  """Returns all supported resources and their handlers.
127

128
  C{node_name_pattern} and the other C{*_pattern} parameters are wrapped in
129
  L{UriPattern} and, if used in a URI, passed to the function specified using
130
  C{translate}. C{translate} receives 1..N parameters which are either plain
131
  strings or instances of L{UriPattern} and returns a dictionary key suitable
132
  for the caller of C{GetHandlers}. The default implementation in
133
  L{_CompileHandlerPath} returns a compiled regular expression in which each
134
  pattern is a group.
135

136
  @rtype: dict
137

138
  """
139
  if translate is None:
140
    translate_fn = _CompileHandlerPath
141
  else:
142
    translate_fn = translate
143

    
144
  node_name = UriPattern(node_name_pattern)
145
  instance_name = UriPattern(instance_name_pattern)
146
  group_name = UriPattern(group_name_pattern)
147
  network_name = UriPattern(network_name_pattern)
148
  job_id = UriPattern(job_id_pattern)
149
  disk = UriPattern(disk_pattern)
150
  query_res = UriPattern(query_res_pattern)
151

    
152
  # Important note: New resources should always be added under /2. During a
153
  # discussion in July 2010 it was decided that having per-resource versions
154
  # is more flexible and future-compatible than versioning the whole remote
155
  # API.
156
  # TODO: Consider a different data structure where all keys are of the same
157
  # type. Strings are faster to look up in a dictionary than iterating and
158
  # matching regular expressions, therefore maybe two separate dictionaries
159
  # should be used.
160
  return {
161
    "/": rlib2.R_root,
162
    "/2": rlib2.R_2,
163

    
164
    "/version": rlib2.R_version,
165

    
166
    "/2/nodes": rlib2.R_2_nodes,
167

    
168
    translate_fn("/2/nodes/", node_name):
169
      rlib2.R_2_nodes_name,
170
    translate_fn("/2/nodes/", node_name, "/powercycle"):
171
      rlib2.R_2_nodes_name_powercycle,
172
    translate_fn("/2/nodes/", node_name, "/tags"):
173
      rlib2.R_2_nodes_name_tags,
174
    translate_fn("/2/nodes/", node_name, "/role"):
175
      rlib2.R_2_nodes_name_role,
176
    translate_fn("/2/nodes/", node_name, "/evacuate"):
177
      rlib2.R_2_nodes_name_evacuate,
178
    translate_fn("/2/nodes/", node_name, "/migrate"):
179
      rlib2.R_2_nodes_name_migrate,
180
    translate_fn("/2/nodes/", node_name, "/modify"):
181
      rlib2.R_2_nodes_name_modify,
182
    translate_fn("/2/nodes/", node_name, "/storage"):
183
      rlib2.R_2_nodes_name_storage,
184
    translate_fn("/2/nodes/", node_name, "/storage/modify"):
185
      rlib2.R_2_nodes_name_storage_modify,
186
    translate_fn("/2/nodes/", node_name, "/storage/repair"):
187
      rlib2.R_2_nodes_name_storage_repair,
188

    
189
    "/2/instances": rlib2.R_2_instances,
190
    translate_fn("/2/instances/", instance_name):
191
      rlib2.R_2_instances_name,
192
    translate_fn("/2/instances/", instance_name, "/info"):
193
      rlib2.R_2_instances_name_info,
194
    translate_fn("/2/instances/", instance_name, "/tags"):
195
      rlib2.R_2_instances_name_tags,
196
    translate_fn("/2/instances/", instance_name, "/reboot"):
197
      rlib2.R_2_instances_name_reboot,
198
    translate_fn("/2/instances/", instance_name, "/reinstall"):
199
      rlib2.R_2_instances_name_reinstall,
200
    translate_fn("/2/instances/", instance_name, "/snapshot"):
201
      rlib2.R_2_instances_name_snapshot,
202
    translate_fn("/2/instances/", instance_name, "/replace-disks"):
203
      rlib2.R_2_instances_name_replace_disks,
204
    translate_fn("/2/instances/", instance_name, "/shutdown"):
205
      rlib2.R_2_instances_name_shutdown,
206
    translate_fn("/2/instances/", instance_name, "/startup"):
207
      rlib2.R_2_instances_name_startup,
208
    translate_fn("/2/instances/", instance_name, "/activate-disks"):
209
      rlib2.R_2_instances_name_activate_disks,
210
    translate_fn("/2/instances/", instance_name, "/deactivate-disks"):
211
      rlib2.R_2_instances_name_deactivate_disks,
212
    translate_fn("/2/instances/", instance_name, "/recreate-disks"):
213
      rlib2.R_2_instances_name_recreate_disks,
214
    translate_fn("/2/instances/", instance_name, "/prepare-export"):
215
      rlib2.R_2_instances_name_prepare_export,
216
    translate_fn("/2/instances/", instance_name, "/export"):
217
      rlib2.R_2_instances_name_export,
218
    translate_fn("/2/instances/", instance_name, "/migrate"):
219
      rlib2.R_2_instances_name_migrate,
220
    translate_fn("/2/instances/", instance_name, "/failover"):
221
      rlib2.R_2_instances_name_failover,
222
    translate_fn("/2/instances/", instance_name, "/rename"):
223
      rlib2.R_2_instances_name_rename,
224
    translate_fn("/2/instances/", instance_name, "/modify"):
225
      rlib2.R_2_instances_name_modify,
226
    translate_fn("/2/instances/", instance_name, "/disk/", disk, "/grow"):
227
      rlib2.R_2_instances_name_disk_grow,
228
    translate_fn("/2/instances/", instance_name, "/console"):
229
      rlib2.R_2_instances_name_console,
230

    
231
    "/2/networks": rlib2.R_2_networks,
232
    translate_fn("/2/networks/", network_name):
233
      rlib2.R_2_networks_name,
234
    translate_fn("/2/networks/", network_name, "/connect"):
235
      rlib2.R_2_networks_name_connect,
236
    translate_fn("/2/networks/", network_name, "/disconnect"):
237
      rlib2.R_2_networks_name_disconnect,
238
    translate_fn("/2/networks/", network_name, "/modify"):
239
      rlib2.R_2_networks_name_modify,
240
    translate_fn("/2/networks/", network_name, "/tags"):
241
      rlib2.R_2_networks_name_tags,
242

    
243
    "/2/groups": rlib2.R_2_groups,
244
    translate_fn("/2/groups/", group_name):
245
      rlib2.R_2_groups_name,
246
    translate_fn("/2/groups/", group_name, "/modify"):
247
      rlib2.R_2_groups_name_modify,
248
    translate_fn("/2/groups/", group_name, "/rename"):
249
      rlib2.R_2_groups_name_rename,
250
    translate_fn("/2/groups/", group_name, "/assign-nodes"):
251
      rlib2.R_2_groups_name_assign_nodes,
252
    translate_fn("/2/groups/", group_name, "/tags"):
253
      rlib2.R_2_groups_name_tags,
254

    
255
    "/2/jobs": rlib2.R_2_jobs,
256
    translate_fn("/2/jobs/", job_id):
257
      rlib2.R_2_jobs_id,
258
    translate_fn("/2/jobs/", job_id, "/wait"):
259
      rlib2.R_2_jobs_id_wait,
260

    
261
    "/2/instances-multi-alloc": rlib2.R_2_instances_multi_alloc,
262
    "/2/tags": rlib2.R_2_tags,
263
    "/2/info": rlib2.R_2_info,
264
    "/2/os": rlib2.R_2_os,
265
    "/2/redistribute-config": rlib2.R_2_redist_config,
266
    "/2/features": rlib2.R_2_features,
267
    "/2/modify": rlib2.R_2_cluster_modify,
268

    
269
    translate_fn("/2/query/", query_res):
270
      rlib2.R_2_query,
271
    translate_fn("/2/query/", query_res, "/fields"):
272
      rlib2.R_2_query_fields,
273
    }
274

    
275

    
276
CONNECTOR.update(GetHandlers(_NAME_PATTERN, _NAME_PATTERN,
277
                             _NAME_PATTERN, _NAME_PATTERN,
278
                             constants.JOB_ID_TEMPLATE, _DISK_PATTERN,
279
                             _NAME_PATTERN))