add a function get_param_as_set for handler
It's a common task to get list of something from URL,
so let's add this get_param_as_set function and use
it where possible.
Backport of commit c179e5d0b4
from master.
Change-Id: I9bf4a24d908eca9593beb39453e2b088e81e5a66
Partial-Bug: #1593751
This commit is contained in:
parent
1428c80b46
commit
ecef951437
|
@ -250,6 +250,25 @@ class BaseHandler(object):
|
|||
|
||||
raise self.http(status, objects.Task.to_json(task))
|
||||
|
||||
@staticmethod
|
||||
def get_param_as_set(param_name, delimiter=',', default=None):
|
||||
"""Parse array param from web.input()
|
||||
|
||||
:param param_name: parameter name in web.input()
|
||||
:type param_name: str
|
||||
:param delimiter: delimiter
|
||||
:type delimiter: str
|
||||
:returns: list of items
|
||||
:rtype: set of str or None
|
||||
"""
|
||||
if param_name in web.input():
|
||||
return set(six.moves.map(
|
||||
six.text_type.strip,
|
||||
getattr(web.input(), param_name).split(delimiter))
|
||||
)
|
||||
else:
|
||||
return default
|
||||
|
||||
|
||||
def content_json(func, cls, *args, **kwargs):
|
||||
json_resp = lambda data: (
|
||||
|
|
|
@ -13,7 +13,6 @@
|
|||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
import web
|
||||
|
||||
from nailgun.api.v1.handlers import base
|
||||
from nailgun.api.v1.handlers.base import content
|
||||
|
@ -41,10 +40,9 @@ class DeploymentHistoryCollectionHandler(base.CollectionHandler):
|
|||
objects.Transaction, transaction_id)
|
||||
|
||||
# process input parameters
|
||||
nodes_ids = web.input(nodes=None).nodes
|
||||
statuses = web.input(statuses=None).statuses
|
||||
tasks_names = web.input(tasks_names=None).tasks_names
|
||||
|
||||
nodes_ids = self.get_param_as_set('nodes_ids')
|
||||
statuses = self.get_param_as_set('statuses')
|
||||
tasks_names = self.get_param_as_set('tasks_names')
|
||||
try:
|
||||
self.validator.validate_query(nodes_ids=nodes_ids,
|
||||
statuses=statuses,
|
||||
|
@ -52,13 +50,6 @@ class DeploymentHistoryCollectionHandler(base.CollectionHandler):
|
|||
except errors.ValidationException as exc:
|
||||
raise self.http(400, exc.message)
|
||||
|
||||
if nodes_ids:
|
||||
nodes_ids = set(nodes_ids.strip().split(','))
|
||||
if statuses:
|
||||
statuses = set(statuses.strip().split(','))
|
||||
if tasks_names:
|
||||
tasks_names = set(tasks_names.strip().split(','))
|
||||
|
||||
# fetch and serialize history
|
||||
return self.collection.get_history(transaction=transaction,
|
||||
nodes_ids=nodes_ids,
|
||||
|
|
|
@ -139,9 +139,10 @@ class NodeCollectionHandler(CollectionHandler):
|
|||
"""
|
||||
# TODO(pkaminski): web.py does not support parsing of array arguments
|
||||
# in the queryset so we specify the input as comma-separated list
|
||||
node_ids = self.get_param_as_set('ids', default=[])
|
||||
node_ids = self.checked_data(
|
||||
validate_method=self.validator.validate_collection_delete,
|
||||
data=web.input().get('ids', '')
|
||||
validate_method=self.validator.validate_ids_list,
|
||||
data=node_ids
|
||||
)
|
||||
|
||||
nodes = self.get_objects_list_or_404(self.collection, node_ids)
|
||||
|
|
|
@ -59,15 +59,15 @@ class NodesFilterMixin(object):
|
|||
|
||||
else return default nodes
|
||||
"""
|
||||
nodes = web.input(nodes=None).nodes
|
||||
if nodes:
|
||||
node_ids = self.checked_data(data=nodes)
|
||||
return self.get_objects_list_or_404(
|
||||
objects.NodeCollection,
|
||||
node_ids
|
||||
)
|
||||
nodes = self.get_param_as_set('nodes', default=[])
|
||||
if not nodes:
|
||||
return self.get_default_nodes(cluster) or []
|
||||
|
||||
return self.get_default_nodes(cluster) or []
|
||||
node_ids = self.checked_data(data=nodes)
|
||||
return self.get_objects_list_or_404(
|
||||
objects.NodeCollection,
|
||||
node_ids
|
||||
)
|
||||
|
||||
|
||||
class DefaultOrchestratorInfo(NodesFilterMixin, BaseHandler):
|
||||
|
@ -363,14 +363,14 @@ class TaskDeployGraph(BaseHandler):
|
|||
tasks = objects.Cluster.get_deployment_tasks(cluster, graph_type)
|
||||
graph = orchestrator_graph.GraphSolver(tasks)
|
||||
|
||||
tasks = web.input(tasks=None).tasks
|
||||
tasks = self.get_param_as_set('tasks', default=[])
|
||||
parents_for = web.input(parents_for=None).parents_for
|
||||
remove = web.input(remove=None).remove
|
||||
remove = self.get_param_as_set('remove')
|
||||
|
||||
if tasks:
|
||||
tasks = self.checked_data(
|
||||
self.validator.validate,
|
||||
data=tasks,
|
||||
data=list(tasks),
|
||||
cluster=cluster,
|
||||
graph_type=graph_type)
|
||||
logger.debug('Tasks used in dot graph %s', tasks)
|
||||
|
@ -383,7 +383,7 @@ class TaskDeployGraph(BaseHandler):
|
|||
logger.debug('Graph with predecessors for %s', parents_for)
|
||||
|
||||
if remove:
|
||||
remove = list(set(remove.split(',')))
|
||||
remove = list(remove)
|
||||
remove = self.checked_data(
|
||||
self.validator.validate_tasks_types,
|
||||
data=remove)
|
||||
|
@ -417,9 +417,8 @@ class SerializedTasksHandler(NodesFilterMixin, BaseHandler):
|
|||
nodes = self.get_nodes(cluster)
|
||||
self.checked_data(self.validator.validate_placement,
|
||||
data=nodes, cluster=cluster)
|
||||
tasks = web.input(tasks=None).tasks
|
||||
graph_type = web.input(graph_type=None).graph_type
|
||||
task_ids = [t.strip() for t in tasks.split(',')] if tasks else None
|
||||
task_ids = self.get_param_as_set('tasks')
|
||||
|
||||
try:
|
||||
if objects.Release.is_lcm_supported(cluster.release):
|
||||
|
|
|
@ -122,6 +122,25 @@ class BasicValidator(object):
|
|||
"from Fuel Master node, please check '/etc/puppet' "
|
||||
"directory.".format(cluster.release.name))
|
||||
|
||||
@classmethod
|
||||
def validate_ids_list(cls, data):
|
||||
"""Validate list of integer identifiers.
|
||||
|
||||
:param data: ids list to be validated and converted
|
||||
:type data: iterable of strings
|
||||
:returns: converted and verified data
|
||||
:rtype: list of integers
|
||||
"""
|
||||
try:
|
||||
ret = [int(d) for d in data]
|
||||
except ValueError:
|
||||
raise errors.InvalidData('Comma-separated numbers list expected',
|
||||
log_message=True)
|
||||
|
||||
cls.validate_schema(ret, base_types.IDS_ARRAY)
|
||||
|
||||
return ret
|
||||
|
||||
|
||||
class BaseDefferedTaskValidator(BasicValidator):
|
||||
|
||||
|
|
|
@ -21,10 +21,11 @@ class DeploymentHistoryValidator(BasicValidator):
|
|||
|
||||
@classmethod
|
||||
def validate_query(cls, nodes_ids, statuses, tasks_names):
|
||||
if statuses:
|
||||
statuses = set(statuses.strip().split(','))
|
||||
if not statuses.issubset(set(consts.HISTORY_TASK_STATUSES)):
|
||||
raise errors.ValidationException(
|
||||
"Statuses parameter could be only: {}".format(
|
||||
", ".join(consts.HISTORY_TASK_STATUSES))
|
||||
)
|
||||
if not statuses:
|
||||
return
|
||||
|
||||
if not statuses.issubset(set(consts.HISTORY_TASK_STATUSES)):
|
||||
raise errors.ValidationException(
|
||||
"Statuses parameter could be only: {}".format(
|
||||
", ".join(consts.HISTORY_TASK_STATUSES))
|
||||
)
|
||||
|
|
|
@ -16,7 +16,6 @@
|
|||
import six
|
||||
|
||||
from nailgun.api.v1.validators import base
|
||||
from nailgun.api.v1.validators.json_schema import base_types
|
||||
from nailgun.api.v1.validators.json_schema import node_schema
|
||||
from nailgun.api.v1.validators.orchestrator_graph import \
|
||||
TaskDeploymentValidator
|
||||
|
@ -303,36 +302,12 @@ class NodeValidator(base.BasicValidator):
|
|||
cls.validate_update(nd)
|
||||
return d
|
||||
|
||||
@classmethod
|
||||
def validate_collection_delete(cls, data):
|
||||
try:
|
||||
d = map(int, data.split(','))
|
||||
except ValueError:
|
||||
raise errors.InvalidData('Comma-separated number list expected',
|
||||
log_message=True)
|
||||
|
||||
cls.validate_schema(d, base_types.IDS_ARRAY)
|
||||
|
||||
return d
|
||||
|
||||
|
||||
class NodesFilterValidator(base.BasicValidator):
|
||||
|
||||
@classmethod
|
||||
def validate(cls, nodes):
|
||||
"""Used for filtering nodes
|
||||
|
||||
:param nodes: list of ids in string representation.
|
||||
Example: "1,99,3,4"
|
||||
|
||||
:returns: list of integers
|
||||
"""
|
||||
try:
|
||||
node_ids = set(map(int, nodes.split(',')))
|
||||
except ValueError:
|
||||
raise errors.InvalidData('Provided id is not integer')
|
||||
|
||||
return node_ids
|
||||
return super(NodesFilterValidator, cls).validate_ids_list(nodes)
|
||||
|
||||
@classmethod
|
||||
def validate_placement(cls, nodes, cluster):
|
||||
|
|
|
@ -92,8 +92,7 @@ class GraphSolverVisualizationValidator(TaskDeploymentValidator):
|
|||
:returns: list of tasks
|
||||
:rtype: list[dict]
|
||||
"""
|
||||
tasks = list(set(data.split(',')))
|
||||
return cls.validate_tasks(tasks, cluster, graph_type)
|
||||
return cls.validate_tasks(data, cluster, graph_type)
|
||||
|
||||
@classmethod
|
||||
def validate_task_presence(cls, task, graph):
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
# under the License.
|
||||
|
||||
import json
|
||||
import urllib
|
||||
|
||||
import web
|
||||
|
||||
|
@ -142,3 +143,20 @@ class TestHandlers(BaseIntegrationTest):
|
|||
('Content-Type', 'application/json'),
|
||||
web.ctx.headers
|
||||
)
|
||||
|
||||
def test_get_param_as_set(self):
|
||||
urls = ("/hello", "hello")
|
||||
|
||||
class hello(object):
|
||||
def GET(self_inner):
|
||||
web.header('Content-Type', 'application/json')
|
||||
data = BaseHandler.get_param_as_set('test_param',
|
||||
delimiter=';')
|
||||
return json.dumps(list(data))
|
||||
|
||||
app = web.application(urls, {'hello': hello})
|
||||
url = '/hello?test_param=' + urllib.quote('1;4 ; 777; 4;x ')
|
||||
resp = app.request(url)
|
||||
|
||||
self.assertEqual(set(json.loads(resp.data)),
|
||||
set(['1', '4', '777', 'x']))
|
||||
|
|
Loading…
Reference in New Issue