Statistics
| Branch: | Tag: | Revision:

root / lib / rapi / connector.py @ 7e950d31

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

    
35
from ganeti.rapi import baserlib
36
from ganeti.rapi import rlib2
37

    
38

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

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

    
44

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

48
  """
49
  def __init__(self, connector=CONNECTOR):
50
    """Resource mapper constructor.
51

52
    @param connector: a dictionary, mapping method name with URL path regexp
53

54
    """
55
    self._connector = connector
56

    
57
  def getController(self, uri):
58
    """Find method for a given URI.
59

60
    @param uri: string with URI
61

62
    @return: None if no method is found or a tuple containing
63
        the following fields:
64
            - method: name of method mapped to URI
65
            - items: a list of variable intems in the path
66
            - args: a dictionary with additional parameters from URL
67

68
    """
69
    if '?' in uri:
70
      (path, query) = uri.split('?', 1)
71
      args = cgi.parse_qs(query)
72
    else:
73
      path = uri
74
      query = None
75
      args = {}
76

    
77
    result = None
78

    
79
    for key, handler in self._connector.iteritems():
80
      # Regex objects
81
      if hasattr(key, "match"):
82
        m = key.match(path)
83
        if m:
84
          result = (handler, list(m.groups()), args)
85
          break
86

    
87
      # String objects
88
      elif key == path:
89
        result = (handler, [], args)
90
        break
91

    
92
    if result:
93
      return result
94
    else:
95
      raise http.HttpNotFound()
96

    
97

    
98
class R_root(baserlib.R_Generic):
99
  """/ resource.
100

101
  """
102
  @staticmethod
103
  def GET():
104
    """Show the list of mapped resources.
105

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

108
    """
109
    root_pattern = re.compile('^R_([a-zA-Z0-9]+)$')
110

    
111
    rootlist = []
112
    for handler in CONNECTOR.values():
113
      m = root_pattern.match(handler.__name__)
114
      if m:
115
        name = m.group(1)
116
        if name != 'root':
117
          rootlist.append(name)
118

    
119
    return baserlib.BuildUriList(rootlist, "/%s")
120

    
121

    
122
def _getResources(id_):
123
  """Return a list of resources underneath given id.
124

125
  This is to generalize querying of version resources lists.
126

127
  @return: a list of resources names.
128

129
  """
130
  r_pattern = re.compile('^R_%s_([a-zA-Z0-9]+)$' % id_)
131

    
132
  rlist = []
133
  for handler in CONNECTOR.values():
134
    m = r_pattern.match(handler.__name__)
135
    if m:
136
      name = m.group(1)
137
      rlist.append(name)
138

    
139
  return rlist
140

    
141

    
142
class R_2(baserlib.R_Generic):
143
  """ /2 resource, the root of the version 2 API.
144

145
  """
146
  @staticmethod
147
  def GET():
148
    """Show the list of mapped resources.
149

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

152
    """
153
    return baserlib.BuildUriList(_getResources("2"), "/2/%s")
154

    
155

    
156
def GetHandlers(node_name_pattern, instance_name_pattern, job_id_pattern):
157
  """Returns all supported resources and their handlers.
158

159
  """
160
  return {
161
    "/": R_root,
162

    
163
    "/version": rlib2.R_version,
164

    
165
    "/2": R_2,
166

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

    
185
    "/2/instances": rlib2.R_2_instances,
186
    re.compile(r'^/2/instances/(%s)$' % instance_name_pattern):
187
      rlib2.R_2_instances_name,
188
    re.compile(r'^/2/instances/(%s)/info$' % instance_name_pattern):
189
      rlib2.R_2_instances_name_info,
190
    re.compile(r'^/2/instances/(%s)/tags$' % instance_name_pattern):
191
      rlib2.R_2_instances_name_tags,
192
    re.compile(r'^/2/instances/(%s)/reboot$' % instance_name_pattern):
193
      rlib2.R_2_instances_name_reboot,
194
    re.compile(r'^/2/instances/(%s)/reinstall$' % instance_name_pattern):
195
      rlib2.R_2_instances_name_reinstall,
196
    re.compile(r'^/2/instances/(%s)/replace-disks$' % instance_name_pattern):
197
      rlib2.R_2_instances_name_replace_disks,
198
    re.compile(r'^/2/instances/(%s)/shutdown$' % instance_name_pattern):
199
      rlib2.R_2_instances_name_shutdown,
200
    re.compile(r'^/2/instances/(%s)/startup$' % instance_name_pattern):
201
      rlib2.R_2_instances_name_startup,
202

    
203
    "/2/jobs": rlib2.R_2_jobs,
204
    re.compile(r'/2/jobs/(%s)$' % job_id_pattern):
205
      rlib2.R_2_jobs_id,
206

    
207
    "/2/tags": rlib2.R_2_tags,
208
    "/2/info": rlib2.R_2_info,
209
    "/2/os": rlib2.R_2_os,
210
    "/2/redistribute-config": rlib2.R_2_redist_config,
211
    }
212

    
213

    
214
CONNECTOR.update(GetHandlers(_NAME_PATTERN, _NAME_PATTERN,
215
                             constants.JOB_ID_TEMPLATE))