qa_utils: Factorize code for getting entity name
[ganeti-local] / lib / rapi / connector.py
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 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 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 = 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 def GetHandlers(node_name_pattern, instance_name_pattern,
92                 group_name_pattern, job_id_pattern, disk_pattern,
93                 query_res_pattern):
94   """Returns all supported resources and their handlers.
95
96   """
97   # Important note: New resources should always be added under /2. During a
98   # discussion in July 2010 it was decided that having per-resource versions
99   # is more flexible and future-compatible than versioning the whole remote
100   # API.
101   return {
102     "/": rlib2.R_root,
103     "/2": rlib2.R_2,
104
105     "/version": rlib2.R_version,
106
107     "/2/nodes": rlib2.R_2_nodes,
108     re.compile(r"^/2/nodes/(%s)$" % node_name_pattern):
109       rlib2.R_2_nodes_name,
110     re.compile(r"^/2/nodes/(%s)/powercycle$" % node_name_pattern):
111       rlib2.R_2_nodes_name_powercycle,
112     re.compile(r"^/2/nodes/(%s)/tags$" % node_name_pattern):
113       rlib2.R_2_nodes_name_tags,
114     re.compile(r"^/2/nodes/(%s)/role$" % node_name_pattern):
115       rlib2.R_2_nodes_name_role,
116     re.compile(r"^/2/nodes/(%s)/evacuate$" % node_name_pattern):
117       rlib2.R_2_nodes_name_evacuate,
118     re.compile(r"^/2/nodes/(%s)/migrate$" % node_name_pattern):
119       rlib2.R_2_nodes_name_migrate,
120     re.compile(r"^/2/nodes/(%s)/modify$" % node_name_pattern):
121       rlib2.R_2_nodes_name_modify,
122     re.compile(r"^/2/nodes/(%s)/storage$" % node_name_pattern):
123       rlib2.R_2_nodes_name_storage,
124     re.compile(r"^/2/nodes/(%s)/storage/modify$" % node_name_pattern):
125       rlib2.R_2_nodes_name_storage_modify,
126     re.compile(r"^/2/nodes/(%s)/storage/repair$" % node_name_pattern):
127       rlib2.R_2_nodes_name_storage_repair,
128
129     "/2/instances": rlib2.R_2_instances,
130     re.compile(r"^/2/instances/(%s)$" % instance_name_pattern):
131       rlib2.R_2_instances_name,
132     re.compile(r"^/2/instances/(%s)/info$" % instance_name_pattern):
133       rlib2.R_2_instances_name_info,
134     re.compile(r"^/2/instances/(%s)/tags$" % instance_name_pattern):
135       rlib2.R_2_instances_name_tags,
136     re.compile(r"^/2/instances/(%s)/reboot$" % instance_name_pattern):
137       rlib2.R_2_instances_name_reboot,
138     re.compile(r"^/2/instances/(%s)/reinstall$" % instance_name_pattern):
139       rlib2.R_2_instances_name_reinstall,
140     re.compile(r"^/2/instances/(%s)/replace-disks$" % instance_name_pattern):
141       rlib2.R_2_instances_name_replace_disks,
142     re.compile(r"^/2/instances/(%s)/shutdown$" % instance_name_pattern):
143       rlib2.R_2_instances_name_shutdown,
144     re.compile(r"^/2/instances/(%s)/startup$" % instance_name_pattern):
145       rlib2.R_2_instances_name_startup,
146     re.compile(r"^/2/instances/(%s)/activate-disks$" % instance_name_pattern):
147       rlib2.R_2_instances_name_activate_disks,
148     re.compile(r"^/2/instances/(%s)/deactivate-disks$" % instance_name_pattern):
149       rlib2.R_2_instances_name_deactivate_disks,
150     re.compile(r"^/2/instances/(%s)/recreate-disks$" % instance_name_pattern):
151       rlib2.R_2_instances_name_recreate_disks,
152     re.compile(r"^/2/instances/(%s)/prepare-export$" % instance_name_pattern):
153       rlib2.R_2_instances_name_prepare_export,
154     re.compile(r"^/2/instances/(%s)/export$" % instance_name_pattern):
155       rlib2.R_2_instances_name_export,
156     re.compile(r"^/2/instances/(%s)/migrate$" % instance_name_pattern):
157       rlib2.R_2_instances_name_migrate,
158     re.compile(r"^/2/instances/(%s)/failover$" % instance_name_pattern):
159       rlib2.R_2_instances_name_failover,
160     re.compile(r"^/2/instances/(%s)/rename$" % instance_name_pattern):
161       rlib2.R_2_instances_name_rename,
162     re.compile(r"^/2/instances/(%s)/modify$" % instance_name_pattern):
163       rlib2.R_2_instances_name_modify,
164     re.compile(r"^/2/instances/(%s)/disk/(%s)/grow$" %
165                (instance_name_pattern, disk_pattern)):
166       rlib2.R_2_instances_name_disk_grow,
167     re.compile(r"^/2/instances/(%s)/console$" % instance_name_pattern):
168       rlib2.R_2_instances_name_console,
169
170     "/2/groups": rlib2.R_2_groups,
171     re.compile(r"^/2/groups/(%s)$" % group_name_pattern):
172       rlib2.R_2_groups_name,
173     re.compile(r"^/2/groups/(%s)/modify$" % group_name_pattern):
174       rlib2.R_2_groups_name_modify,
175     re.compile(r"^/2/groups/(%s)/rename$" % group_name_pattern):
176       rlib2.R_2_groups_name_rename,
177     re.compile(r"^/2/groups/(%s)/assign-nodes$" % group_name_pattern):
178       rlib2.R_2_groups_name_assign_nodes,
179     re.compile(r"^/2/groups/(%s)/tags$" % group_name_pattern):
180       rlib2.R_2_groups_name_tags,
181
182     "/2/jobs": rlib2.R_2_jobs,
183     re.compile(r"^/2/jobs/(%s)$" % job_id_pattern):
184       rlib2.R_2_jobs_id,
185     re.compile(r"^/2/jobs/(%s)/wait$" % job_id_pattern):
186       rlib2.R_2_jobs_id_wait,
187
188     "/2/tags": rlib2.R_2_tags,
189     "/2/info": rlib2.R_2_info,
190     "/2/os": rlib2.R_2_os,
191     "/2/redistribute-config": rlib2.R_2_redist_config,
192     "/2/features": rlib2.R_2_features,
193     "/2/modify": rlib2.R_2_cluster_modify,
194     re.compile(r"^/2/query/(%s)$" % query_res_pattern): rlib2.R_2_query,
195     re.compile(r"^/2/query/(%s)/fields$" % query_res_pattern):
196       rlib2.R_2_query_fields,
197     }
198
199
200 CONNECTOR.update(GetHandlers(_NAME_PATTERN, _NAME_PATTERN, _NAME_PATTERN,
201                              constants.JOB_ID_TEMPLATE, _DISK_PATTERN,
202                              _NAME_PATTERN))