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  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 @staticmethod
96 - def GET():
97 """Show the list of mapped resources. 98 99 @return: a dictionary with 'name' and 'uri' keys for each of them. 100 101 """ 102 root_pattern = re.compile('^R_([a-zA-Z0-9]+)$') 103 104 rootlist = [] 105 for handler in CONNECTOR.values(): 106 m = 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, job_id_pattern):
150 """Returns all supported resources and their handlers. 151 152 """ 153 # Important note: New resources should always be added under /2. During a 154 # discussion in July 2010 it was decided that having per-resource versions 155 # is more flexible and future-compatible than versioning the whole remote 156 # API. 157 return { 158 "/": R_root, 159 160 "/version": rlib2.R_version, 161 162 "/2": R_2, 163 164 "/2/nodes": rlib2.R_2_nodes, 165 re.compile(r'^/2/nodes/(%s)$' % node_name_pattern): 166 rlib2.R_2_nodes_name, 167 re.compile(r'^/2/nodes/(%s)/tags$' % node_name_pattern): 168 rlib2.R_2_nodes_name_tags, 169 re.compile(r'^/2/nodes/(%s)/role$' % node_name_pattern): 170 rlib2.R_2_nodes_name_role, 171 re.compile(r'^/2/nodes/(%s)/evacuate$' % node_name_pattern): 172 rlib2.R_2_nodes_name_evacuate, 173 re.compile(r'^/2/nodes/(%s)/migrate$' % node_name_pattern): 174 rlib2.R_2_nodes_name_migrate, 175 re.compile(r'^/2/nodes/(%s)/storage$' % node_name_pattern): 176 rlib2.R_2_nodes_name_storage, 177 re.compile(r'^/2/nodes/(%s)/storage/modify$' % node_name_pattern): 178 rlib2.R_2_nodes_name_storage_modify, 179 re.compile(r'^/2/nodes/(%s)/storage/repair$' % node_name_pattern): 180 rlib2.R_2_nodes_name_storage_repair, 181 182 "/2/instances": rlib2.R_2_instances, 183 re.compile(r'^/2/instances/(%s)$' % instance_name_pattern): 184 rlib2.R_2_instances_name, 185 re.compile(r'^/2/instances/(%s)/info$' % instance_name_pattern): 186 rlib2.R_2_instances_name_info, 187 re.compile(r'^/2/instances/(%s)/tags$' % instance_name_pattern): 188 rlib2.R_2_instances_name_tags, 189 re.compile(r'^/2/instances/(%s)/reboot$' % instance_name_pattern): 190 rlib2.R_2_instances_name_reboot, 191 re.compile(r'^/2/instances/(%s)/reinstall$' % instance_name_pattern): 192 rlib2.R_2_instances_name_reinstall, 193 re.compile(r'^/2/instances/(%s)/replace-disks$' % instance_name_pattern): 194 rlib2.R_2_instances_name_replace_disks, 195 re.compile(r'^/2/instances/(%s)/shutdown$' % instance_name_pattern): 196 rlib2.R_2_instances_name_shutdown, 197 re.compile(r'^/2/instances/(%s)/startup$' % instance_name_pattern): 198 rlib2.R_2_instances_name_startup, 199 re.compile(r'^/2/instances/(%s)/activate-disks$' % instance_name_pattern): 200 rlib2.R_2_instances_name_activate_disks, 201 re.compile(r'^/2/instances/(%s)/deactivate-disks$' % instance_name_pattern): 202 rlib2.R_2_instances_name_deactivate_disks, 203 re.compile(r'^/2/instances/(%s)/prepare-export$' % instance_name_pattern): 204 rlib2.R_2_instances_name_prepare_export, 205 re.compile(r'^/2/instances/(%s)/export$' % instance_name_pattern): 206 rlib2.R_2_instances_name_export, 207 re.compile(r'^/2/instances/(%s)/migrate$' % instance_name_pattern): 208 rlib2.R_2_instances_name_migrate, 209 re.compile(r'^/2/instances/(%s)/rename$' % instance_name_pattern): 210 rlib2.R_2_instances_name_rename, 211 re.compile(r'^/2/instances/(%s)/modify$' % instance_name_pattern): 212 rlib2.R_2_instances_name_modify, 213 214 "/2/jobs": rlib2.R_2_jobs, 215 re.compile(r"^/2/jobs/(%s)$" % job_id_pattern): 216 rlib2.R_2_jobs_id, 217 re.compile(r"^/2/jobs/(%s)/wait$" % job_id_pattern): 218 rlib2.R_2_jobs_id_wait, 219 220 "/2/tags": rlib2.R_2_tags, 221 "/2/info": rlib2.R_2_info, 222 "/2/os": rlib2.R_2_os, 223 "/2/redistribute-config": rlib2.R_2_redist_config, 224 "/2/features": rlib2.R_2_features, 225 }
226 227 228 CONNECTOR.update(GetHandlers(_NAME_PATTERN, _NAME_PATTERN, 229 constants.JOB_ID_TEMPLATE)) 230