Statistics
| Branch: | Tag: | Revision:

root / lib / rapi / connector.py @ 0dbaa9ca

History | View | Annotate | Download (7.1 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-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

    
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 = cgi.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
class R_root(baserlib.R_Generic):
92
  """/ resource.
93

94
  """
95
  _ROOT_PATTERN = re.compile("^R_([a-zA-Z0-9]+)$")
96

    
97
  @classmethod
98
  def GET(cls):
99
    """Show the list of mapped resources.
100

101
    @return: a dictionary with 'name' and 'uri' keys for each of them.
102

103
    """
104
    rootlist = []
105
    for handler in CONNECTOR.values():
106
      m = cls._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

    
114

    
115
def _getResources(id_):
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
140
  def GET():
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,
150
                group_name_pattern, job_id_pattern):
151
  """Returns all supported resources and their handlers.
152

153
  """
154
  # Important note: New resources should always be added under /2. During a
155
  # discussion in July 2010 it was decided that having per-resource versions
156
  # is more flexible and future-compatible than versioning the whole remote
157
  # API.
158
  return {
159
    "/": R_root,
160

    
161
    "/version": rlib2.R_version,
162

    
163
    "/2": R_2,
164

    
165
    "/2/nodes": rlib2.R_2_nodes,
166
    re.compile(r'^/2/nodes/(%s)$' % node_name_pattern):
167
      rlib2.R_2_nodes_name,
168
    re.compile(r'^/2/nodes/(%s)/tags$' % node_name_pattern):
169
      rlib2.R_2_nodes_name_tags,
170
    re.compile(r'^/2/nodes/(%s)/role$' % node_name_pattern):
171
      rlib2.R_2_nodes_name_role,
172
    re.compile(r'^/2/nodes/(%s)/evacuate$' % node_name_pattern):
173
      rlib2.R_2_nodes_name_evacuate,
174
    re.compile(r'^/2/nodes/(%s)/migrate$' % node_name_pattern):
175
      rlib2.R_2_nodes_name_migrate,
176
    re.compile(r'^/2/nodes/(%s)/storage$' % node_name_pattern):
177
      rlib2.R_2_nodes_name_storage,
178
    re.compile(r'^/2/nodes/(%s)/storage/modify$' % node_name_pattern):
179
      rlib2.R_2_nodes_name_storage_modify,
180
    re.compile(r'^/2/nodes/(%s)/storage/repair$' % node_name_pattern):
181
      rlib2.R_2_nodes_name_storage_repair,
182

    
183
    "/2/instances": rlib2.R_2_instances,
184
    re.compile(r'^/2/instances/(%s)$' % instance_name_pattern):
185
      rlib2.R_2_instances_name,
186
    re.compile(r'^/2/instances/(%s)/info$' % instance_name_pattern):
187
      rlib2.R_2_instances_name_info,
188
    re.compile(r'^/2/instances/(%s)/tags$' % instance_name_pattern):
189
      rlib2.R_2_instances_name_tags,
190
    re.compile(r'^/2/instances/(%s)/reboot$' % instance_name_pattern):
191
      rlib2.R_2_instances_name_reboot,
192
    re.compile(r'^/2/instances/(%s)/reinstall$' % instance_name_pattern):
193
      rlib2.R_2_instances_name_reinstall,
194
    re.compile(r'^/2/instances/(%s)/replace-disks$' % instance_name_pattern):
195
      rlib2.R_2_instances_name_replace_disks,
196
    re.compile(r'^/2/instances/(%s)/shutdown$' % instance_name_pattern):
197
      rlib2.R_2_instances_name_shutdown,
198
    re.compile(r'^/2/instances/(%s)/startup$' % instance_name_pattern):
199
      rlib2.R_2_instances_name_startup,
200
    re.compile(r'^/2/instances/(%s)/activate-disks$' % instance_name_pattern):
201
      rlib2.R_2_instances_name_activate_disks,
202
    re.compile(r'^/2/instances/(%s)/deactivate-disks$' % instance_name_pattern):
203
      rlib2.R_2_instances_name_deactivate_disks,
204
    re.compile(r'^/2/instances/(%s)/prepare-export$' % instance_name_pattern):
205
      rlib2.R_2_instances_name_prepare_export,
206
    re.compile(r'^/2/instances/(%s)/export$' % instance_name_pattern):
207
      rlib2.R_2_instances_name_export,
208
    re.compile(r'^/2/instances/(%s)/migrate$' % instance_name_pattern):
209
      rlib2.R_2_instances_name_migrate,
210
    re.compile(r'^/2/instances/(%s)/rename$' % instance_name_pattern):
211
      rlib2.R_2_instances_name_rename,
212
    re.compile(r'^/2/instances/(%s)/modify$' % instance_name_pattern):
213
      rlib2.R_2_instances_name_modify,
214

    
215
    "/2/groups": rlib2.R_2_groups,
216
    re.compile(r'^/2/groups/(%s)$' % group_name_pattern):
217
      rlib2.R_2_groups_name,
218
    re.compile(r'^/2/groups/(%s)/rename$' % group_name_pattern):
219
      rlib2.R_2_groups_name_rename,
220

    
221
    "/2/jobs": rlib2.R_2_jobs,
222
    re.compile(r"^/2/jobs/(%s)$" % job_id_pattern):
223
      rlib2.R_2_jobs_id,
224
    re.compile(r"^/2/jobs/(%s)/wait$" % job_id_pattern):
225
      rlib2.R_2_jobs_id_wait,
226

    
227
    "/2/tags": rlib2.R_2_tags,
228
    "/2/info": rlib2.R_2_info,
229
    "/2/os": rlib2.R_2_os,
230
    "/2/redistribute-config": rlib2.R_2_redist_config,
231
    "/2/features": rlib2.R_2_features,
232
    }
233

    
234

    
235
CONNECTOR.update(GetHandlers(_NAME_PATTERN, _NAME_PATTERN, _NAME_PATTERN,
236
                             constants.JOB_ID_TEMPLATE))