Package ganeti :: Package rapi :: Module connector
[hide private]
[frames] | no frames]

Source Code for Module ganeti.rapi.connector

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