'File exists' validator and Utils class for validators
Change-Id: I43451ae5a79618cd7d8b60a98e9904052b242276
This commit is contained in:
parent
d32b2d5f2b
commit
4925b5692e
@ -67,7 +67,7 @@
|
|||||||
MuranoPackages.import_and_list_packages:
|
MuranoPackages.import_and_list_packages:
|
||||||
-
|
-
|
||||||
args:
|
args:
|
||||||
package: "/home/jenkins/.rally/extra/murano/applications/HelloReporter/io.murano.apps.HelloReporter/"
|
package: "~/.rally/extra/murano/applications/HelloReporter/io.murano.apps.HelloReporter/"
|
||||||
runner:
|
runner:
|
||||||
type: "constant"
|
type: "constant"
|
||||||
times: 10
|
times: 10
|
||||||
@ -81,7 +81,7 @@
|
|||||||
max: 0
|
max: 0
|
||||||
-
|
-
|
||||||
args:
|
args:
|
||||||
package: "/home/jenkins/.rally/extra/murano/applications/HelloReporter/io.murano.apps.HelloReporter.zip"
|
package: "~/.rally/extra/murano/applications/HelloReporter/io.murano.apps.HelloReporter.zip"
|
||||||
runner:
|
runner:
|
||||||
type: "constant"
|
type: "constant"
|
||||||
times: 1
|
times: 1
|
||||||
@ -97,7 +97,7 @@
|
|||||||
MuranoPackages.import_and_delete_package:
|
MuranoPackages.import_and_delete_package:
|
||||||
-
|
-
|
||||||
args:
|
args:
|
||||||
package: "/home/jenkins/.rally/extra/murano/applications/HelloReporter/io.murano.apps.HelloReporter/"
|
package: "~/.rally/extra/murano/applications/HelloReporter/io.murano.apps.HelloReporter/"
|
||||||
runner:
|
runner:
|
||||||
type: "constant"
|
type: "constant"
|
||||||
times: 10
|
times: 10
|
||||||
@ -113,7 +113,7 @@
|
|||||||
MuranoPackages.import_and_filter_applications:
|
MuranoPackages.import_and_filter_applications:
|
||||||
-
|
-
|
||||||
args:
|
args:
|
||||||
package: "/home/jenkins/.rally/extra/murano/applications/HelloReporter/io.murano.apps.HelloReporter/"
|
package: "~/.rally/extra/murano/applications/HelloReporter/io.murano.apps.HelloReporter/"
|
||||||
filter_query: {"category" : "Web"}
|
filter_query: {"category" : "Web"}
|
||||||
runner:
|
runner:
|
||||||
type: "constant"
|
type: "constant"
|
||||||
@ -130,7 +130,7 @@
|
|||||||
MuranoPackages.package_lifecycle:
|
MuranoPackages.package_lifecycle:
|
||||||
-
|
-
|
||||||
args:
|
args:
|
||||||
package: "/home/jenkins/.rally/extra/murano/applications/HelloReporter/io.murano.apps.HelloReporter/"
|
package: "~/.rally/extra/murano/applications/HelloReporter/io.murano.apps.HelloReporter/"
|
||||||
body: {"categories": ["Web"]}
|
body: {"categories": ["Web"]}
|
||||||
operation: "add"
|
operation: "add"
|
||||||
runner:
|
runner:
|
||||||
|
@ -737,7 +737,7 @@
|
|||||||
context:
|
context:
|
||||||
image_command_customizer:
|
image_command_customizer:
|
||||||
command:
|
command:
|
||||||
local_path: "/home/jenkins/.rally/extra/install_benchmark.sh"
|
local_path: "~/.rally/extra/install_benchmark.sh"
|
||||||
remote_path: "./install_benchmark.sh"
|
remote_path: "./install_benchmark.sh"
|
||||||
flavor:
|
flavor:
|
||||||
name: "m1.tiny"
|
name: "m1.tiny"
|
||||||
|
@ -255,7 +255,7 @@
|
|||||||
hooks:
|
hooks:
|
||||||
- name: sys_call
|
- name: sys_call
|
||||||
description: Run script
|
description: Run script
|
||||||
args: sh /home/jenkins/.rally/extra/hook_example_script.sh
|
args: sh ~/.rally/extra/hook_example_script.sh
|
||||||
trigger:
|
trigger:
|
||||||
name: event
|
name: event
|
||||||
args:
|
args:
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
# Copyright 2017: Mirantis Inc.
|
|
||||||
# All Rights Reserved.
|
# All Rights Reserved.
|
||||||
#
|
#
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
@ -14,6 +13,7 @@
|
|||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
import inspect
|
import inspect
|
||||||
|
import os
|
||||||
|
|
||||||
import jsonschema
|
import jsonschema
|
||||||
import six
|
import six
|
||||||
@ -24,6 +24,23 @@ from rally.common import validation
|
|||||||
LOG = logging.getLogger(__name__)
|
LOG = logging.getLogger(__name__)
|
||||||
|
|
||||||
|
|
||||||
|
class ValidatorUtils(object):
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _file_access_ok(filename, mode, param_name, required=True):
|
||||||
|
if not filename:
|
||||||
|
return validation.ValidationResult(
|
||||||
|
not required,
|
||||||
|
"Parameter %s required" % param_name)
|
||||||
|
if not os.access(os.path.expanduser(filename), mode):
|
||||||
|
return validation.ValidationResult(
|
||||||
|
False, "Could not open %(filename)s with mode %(mode)s "
|
||||||
|
"for parameter %(param_name)s"
|
||||||
|
% {"filename": filename, "mode": mode,
|
||||||
|
"param_name": param_name})
|
||||||
|
return validation.ValidationResult(True)
|
||||||
|
|
||||||
|
|
||||||
@validation.configure(name="jsonschema")
|
@validation.configure(name="jsonschema")
|
||||||
class JsonSchemaValidator(validation.Validator):
|
class JsonSchemaValidator(validation.Validator):
|
||||||
"""JSON schema validator"""
|
"""JSON schema validator"""
|
||||||
@ -294,8 +311,7 @@ class RequiredContextsValidator(validation.Validator):
|
|||||||
return self.fail(msg)
|
return self.fail(msg)
|
||||||
|
|
||||||
|
|
||||||
@validation.configure(name="required_param_or_context",
|
@validation.configure(name="required_param_or_context")
|
||||||
namespace="openstack")
|
|
||||||
class RequiredParamOrContextValidator(validation.Validator):
|
class RequiredParamOrContextValidator(validation.Validator):
|
||||||
|
|
||||||
def __init__(self, param_name, ctx_name):
|
def __init__(self, param_name, ctx_name):
|
||||||
@ -318,3 +334,36 @@ class RequiredParamOrContextValidator(validation.Validator):
|
|||||||
if self.param_name in config.get("args", {}):
|
if self.param_name in config.get("args", {}):
|
||||||
return
|
return
|
||||||
return self.fail(msg)
|
return self.fail(msg)
|
||||||
|
|
||||||
|
|
||||||
|
@validation.configure(name="file_exists")
|
||||||
|
class FileExistsValidator(validation.Validator):
|
||||||
|
|
||||||
|
def __init__(self, param_name, mode=os.R_OK, required=True):
|
||||||
|
"""Validator checks parameter is proper path to file with proper mode.
|
||||||
|
|
||||||
|
Ensure a file exists and can be accessed with the specified mode.
|
||||||
|
Note that path to file will be expanded before access checking.
|
||||||
|
|
||||||
|
:param param_name: Name of parameter to validate
|
||||||
|
:param mode: Access mode to test for. This should be one of:
|
||||||
|
* os.F_OK (file exists)
|
||||||
|
* os.R_OK (file is readable)
|
||||||
|
* os.W_OK (file is writable)
|
||||||
|
* os.X_OK (file is executable)
|
||||||
|
|
||||||
|
If multiple modes are required they can be added, eg:
|
||||||
|
mode=os.R_OK+os.W_OK
|
||||||
|
:param required: Boolean indicating whether this argument is required.
|
||||||
|
"""
|
||||||
|
super(FileExistsValidator, self).__init__()
|
||||||
|
|
||||||
|
self.param_name = param_name
|
||||||
|
self.mode = mode
|
||||||
|
self.required = required
|
||||||
|
|
||||||
|
def validate(self, config, credentials, plugin_cls, plugin_cfg):
|
||||||
|
|
||||||
|
return ValidatorUtils._file_access_ok(
|
||||||
|
config.get("args", {}).get(self.param_name),
|
||||||
|
self.mode, self.param_name, self.required)
|
||||||
|
@ -13,7 +13,6 @@
|
|||||||
# License for the specific language governing permissions and limitations
|
# License for the specific language governing permissions and limitations
|
||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
|
|
||||||
from oslo_config import cfg
|
from oslo_config import cfg
|
||||||
import requests
|
import requests
|
||||||
|
|
||||||
|
@ -51,7 +51,7 @@ class ListExecutions(utils.MistralScenario):
|
|||||||
sort_keys=sort_keys, sort_dirs=sort_dirs)
|
sort_keys=sort_keys, sort_dirs=sort_dirs)
|
||||||
|
|
||||||
|
|
||||||
@validation.file_exists("definition")
|
@validation.add("file_exists", param_name="definition")
|
||||||
@types.convert(definition={"type": "file"})
|
@types.convert(definition={"type": "file"})
|
||||||
@types.convert(params={"type": "file"})
|
@types.convert(params={"type": "file"})
|
||||||
@types.convert(wf_input={"type": "file"})
|
@types.convert(wf_input={"type": "file"})
|
||||||
|
@ -38,7 +38,7 @@ class ListWorkbooks(utils.MistralScenario):
|
|||||||
self._list_workbooks()
|
self._list_workbooks()
|
||||||
|
|
||||||
|
|
||||||
@validation.file_exists("definition")
|
@validation.add("file_exists", param_name="definition")
|
||||||
@types.convert(definition={"type": "file"})
|
@types.convert(definition={"type": "file"})
|
||||||
@validation.add("required_platform", platform="openstack", users=True)
|
@validation.add("required_platform", platform="openstack", users=True)
|
||||||
@validation.add("required_services",
|
@validation.add("required_services",
|
||||||
|
@ -25,7 +25,7 @@ from rally.task import validation
|
|||||||
"""Scenarios for Murano packages."""
|
"""Scenarios for Murano packages."""
|
||||||
|
|
||||||
|
|
||||||
@validation.file_exists(param_name="package", mode=os.F_OK)
|
@validation.add("file_exists", param_name="package", mode=os.F_OK)
|
||||||
@validation.add("required_services", services=[consts.Service.MURANO])
|
@validation.add("required_services", services=[consts.Service.MURANO])
|
||||||
@validation.add("required_platform", platform="openstack", users=True)
|
@validation.add("required_platform", platform="openstack", users=True)
|
||||||
@scenario.configure(context={"cleanup": ["murano.packages"]},
|
@scenario.configure(context={"cleanup": ["murano.packages"]},
|
||||||
@ -55,7 +55,7 @@ class ImportAndListPackages(utils.MuranoScenario):
|
|||||||
os.remove(package_path)
|
os.remove(package_path)
|
||||||
|
|
||||||
|
|
||||||
@validation.file_exists(param_name="package", mode=os.F_OK)
|
@validation.add("file_exists", param_name="package", mode=os.F_OK)
|
||||||
@validation.add("required_services", services=[consts.Service.MURANO])
|
@validation.add("required_services", services=[consts.Service.MURANO])
|
||||||
@validation.add("required_platform", platform="openstack", users=True)
|
@validation.add("required_platform", platform="openstack", users=True)
|
||||||
@scenario.configure(context={"cleanup": ["murano.packages"]},
|
@scenario.configure(context={"cleanup": ["murano.packages"]},
|
||||||
@ -82,7 +82,7 @@ class ImportAndDeletePackage(utils.MuranoScenario):
|
|||||||
os.remove(package_path)
|
os.remove(package_path)
|
||||||
|
|
||||||
|
|
||||||
@validation.file_exists(param_name="package", mode=os.F_OK)
|
@validation.add("file_exists", param_name="package", mode=os.F_OK)
|
||||||
@validation.add("required_services", services=[consts.Service.MURANO])
|
@validation.add("required_services", services=[consts.Service.MURANO])
|
||||||
@validation.add("required_platform", platform="openstack", users=True)
|
@validation.add("required_platform", platform="openstack", users=True)
|
||||||
@scenario.configure(context={"cleanup": ["murano.packages"]},
|
@scenario.configure(context={"cleanup": ["murano.packages"]},
|
||||||
@ -118,7 +118,7 @@ class PackageLifecycle(utils.MuranoScenario):
|
|||||||
os.remove(package_path)
|
os.remove(package_path)
|
||||||
|
|
||||||
|
|
||||||
@validation.file_exists(param_name="package", mode=os.F_OK)
|
@validation.add("file_exists", param_name="package", mode=os.F_OK)
|
||||||
@validation.add("required_services", services=[consts.Service.MURANO])
|
@validation.add("required_services", services=[consts.Service.MURANO])
|
||||||
@validation.add("required_platform", platform="openstack", users=True)
|
@validation.add("required_platform", platform="openstack", users=True)
|
||||||
@scenario.configure(context={"cleanup": ["murano.packages"]},
|
@scenario.configure(context={"cleanup": ["murano.packages"]},
|
||||||
|
@ -124,8 +124,9 @@ class VMScenario(nova_utils.NovaScenario):
|
|||||||
"or list type")
|
"or list type")
|
||||||
cmd.extend(remote_path)
|
cmd.extend(remote_path)
|
||||||
if command.get("local_path"):
|
if command.get("local_path"):
|
||||||
ssh.put_file(command["local_path"], remote_path[-1],
|
ssh.put_file(os.path.expanduser(
|
||||||
mode=self.USER_RWX_OTHERS_RX_ACCESS_MODE)
|
command["local_path"]), remote_path[-1],
|
||||||
|
mode=self.USER_RWX_OTHERS_RX_ACCESS_MODE)
|
||||||
|
|
||||||
if command.get("script_file"):
|
if command.get("script_file"):
|
||||||
stdin = open(os.path.expanduser(command["script_file"]), "rb")
|
stdin = open(os.path.expanduser(command["script_file"]), "rb")
|
||||||
|
@ -115,30 +115,6 @@ def _file_access_ok(filename, mode, param_name, required=True):
|
|||||||
return ValidationResult(True)
|
return ValidationResult(True)
|
||||||
|
|
||||||
|
|
||||||
@validator
|
|
||||||
def file_exists(config, clients, deployment, param_name, mode=os.R_OK,
|
|
||||||
required=True):
|
|
||||||
"""Validator checks parameter is proper path to file with proper mode.
|
|
||||||
|
|
||||||
Ensure a file exists and can be accessed with the specified mode.
|
|
||||||
Note that path to file will be expanded before access checking.
|
|
||||||
|
|
||||||
:param param_name: Name of parameter to validate
|
|
||||||
:param mode: Access mode to test for. This should be one of:
|
|
||||||
* os.F_OK (file exists)
|
|
||||||
* os.R_OK (file is readable)
|
|
||||||
* os.W_OK (file is writable)
|
|
||||||
* os.X_OK (file is executable)
|
|
||||||
|
|
||||||
If multiple modes are required they can be added, eg:
|
|
||||||
mode=os.R_OK+os.W_OK
|
|
||||||
:param required: Boolean indicating whether this argument is required.
|
|
||||||
"""
|
|
||||||
|
|
||||||
return _file_access_ok(config.get("args", {}).get(param_name), mode,
|
|
||||||
param_name, required)
|
|
||||||
|
|
||||||
|
|
||||||
def check_command_dict(command):
|
def check_command_dict(command):
|
||||||
"""Check command-specifying dict `command', raise ValueError on error."""
|
"""Check command-specifying dict `command', raise ValueError on error."""
|
||||||
|
|
||||||
@ -409,3 +385,5 @@ required_param_or_context = deprecated_validator("required_param_or_context",
|
|||||||
volume_type_exists = deprecated_validator("volume_type_exists",
|
volume_type_exists = deprecated_validator("volume_type_exists",
|
||||||
"volume_type_exists",
|
"volume_type_exists",
|
||||||
"0.10.0")
|
"0.10.0")
|
||||||
|
|
||||||
|
file_exists = deprecated_validator("file_exists", "file_exists", "0.10.0")
|
||||||
|
@ -1,4 +1,3 @@
|
|||||||
# Copyright 2017: Mirantis Inc.
|
|
||||||
# All Rights Reserved.
|
# All Rights Reserved.
|
||||||
#
|
#
|
||||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||||
@ -15,7 +14,11 @@
|
|||||||
|
|
||||||
import ddt
|
import ddt
|
||||||
import mock
|
import mock
|
||||||
|
import os
|
||||||
|
import shutil
|
||||||
|
import tempfile
|
||||||
|
|
||||||
|
import rally
|
||||||
from rally.common.plugin import plugin
|
from rally.common.plugin import plugin
|
||||||
from rally.common import validation
|
from rally.common import validation
|
||||||
from rally.plugins.common import validators
|
from rally.plugins.common import validators
|
||||||
@ -340,3 +343,38 @@ class RequiredParamOrContextValidatorTestCase(test.TestCase):
|
|||||||
self.assertEqual(err_msg, result.msg)
|
self.assertEqual(err_msg, result.msg)
|
||||||
else:
|
else:
|
||||||
self.assertIsNone(result)
|
self.assertIsNone(result)
|
||||||
|
|
||||||
|
|
||||||
|
class FileExistsValidatorTestCase(test.TestCase):
|
||||||
|
rally_jobs_path = os.path.join(
|
||||||
|
os.path.dirname(rally.__file__), "..", "rally-jobs")
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super(FileExistsValidatorTestCase, self).setUp()
|
||||||
|
self.validator = validators.FileExistsValidator(param_name="p",
|
||||||
|
required=False)
|
||||||
|
self.credentials = dict(openstack={"admin": mock.MagicMock(),
|
||||||
|
"users": [mock.MagicMock()], })
|
||||||
|
self.tmp_dir = tempfile.mkdtemp()
|
||||||
|
os.makedirs(os.path.join(self.tmp_dir, ".rally"))
|
||||||
|
shutil.copytree(os.path.join(self.rally_jobs_path, "extra"),
|
||||||
|
os.path.join(self.tmp_dir, ".rally", "extra"))
|
||||||
|
|
||||||
|
self.original_home = os.environ["HOME"]
|
||||||
|
os.environ["HOME"] = self.tmp_dir
|
||||||
|
|
||||||
|
def return_home():
|
||||||
|
os.environ["HOME"] = self.original_home
|
||||||
|
self.addCleanup(shutil.rmtree, self.tmp_dir)
|
||||||
|
|
||||||
|
self.addCleanup(return_home)
|
||||||
|
|
||||||
|
@mock.patch("rally.plugins.common.validators."
|
||||||
|
"ValidatorUtils._file_access_ok")
|
||||||
|
def test_file_exists(self, mock__file_access_ok):
|
||||||
|
mock__file_access_ok.return_value = "foobar"
|
||||||
|
result = self.validator.validate({"args": {"p": "test_file"}},
|
||||||
|
self.credentials, None, None)
|
||||||
|
self.assertEqual("foobar", result)
|
||||||
|
mock__file_access_ok.assert_called_once_with(
|
||||||
|
"test_file", os.R_OK, "p", False)
|
||||||
|
@ -13,6 +13,8 @@
|
|||||||
# under the License.
|
# under the License.
|
||||||
|
|
||||||
import os
|
import os
|
||||||
|
import shutil
|
||||||
|
import tempfile
|
||||||
import traceback
|
import traceback
|
||||||
|
|
||||||
import mock
|
import mock
|
||||||
@ -30,6 +32,22 @@ class RallyJobsTestCase(test.TestCase):
|
|||||||
rally_jobs_path = os.path.join(
|
rally_jobs_path = os.path.join(
|
||||||
os.path.dirname(rally.__file__), "..", "rally-jobs")
|
os.path.dirname(rally.__file__), "..", "rally-jobs")
|
||||||
|
|
||||||
|
def setUp(self):
|
||||||
|
super(RallyJobsTestCase, self).setUp()
|
||||||
|
self.tmp_dir = tempfile.mkdtemp()
|
||||||
|
os.makedirs(os.path.join(self.tmp_dir, ".rally"))
|
||||||
|
shutil.copytree(os.path.join(self.rally_jobs_path, "extra"),
|
||||||
|
os.path.join(self.tmp_dir, ".rally", "extra"))
|
||||||
|
|
||||||
|
self.original_home = os.environ["HOME"]
|
||||||
|
os.environ["HOME"] = self.tmp_dir
|
||||||
|
|
||||||
|
def return_home():
|
||||||
|
os.environ["HOME"] = self.original_home
|
||||||
|
self.addCleanup(shutil.rmtree, self.tmp_dir)
|
||||||
|
|
||||||
|
self.addCleanup(return_home)
|
||||||
|
|
||||||
def test_schema_is_valid(self):
|
def test_schema_is_valid(self):
|
||||||
discover.load_plugins(os.path.join(self.rally_jobs_path, "plugins"))
|
discover.load_plugins(os.path.join(self.rally_jobs_path, "plugins"))
|
||||||
|
|
||||||
|
@ -192,17 +192,6 @@ class ValidatorsTestCase(test.TestCase):
|
|||||||
"foobar", os.R_OK, "p", False)
|
"foobar", os.R_OK, "p", False)
|
||||||
self.assertFalse(result.is_valid, result.msg)
|
self.assertFalse(result.is_valid, result.msg)
|
||||||
|
|
||||||
@mock.patch(MODULE + "_file_access_ok")
|
|
||||||
def test_file_exists(self, mock__file_access_ok):
|
|
||||||
mock__file_access_ok.return_value = "foobar"
|
|
||||||
validator = self._unwrap_validator(validation.file_exists,
|
|
||||||
param_name="p",
|
|
||||||
required=False)
|
|
||||||
result = validator({"args": {"p": "test_file"}}, None, None)
|
|
||||||
self.assertEqual("foobar", result)
|
|
||||||
mock__file_access_ok.assert_called_once_with(
|
|
||||||
"test_file", os.R_OK, "p", False)
|
|
||||||
|
|
||||||
@ddt.data({"raises_message": "Command must be a dictionary"},
|
@ddt.data({"raises_message": "Command must be a dictionary"},
|
||||||
{"command": "foo",
|
{"command": "foo",
|
||||||
"raises_message": "Command must be a dictionary"},
|
"raises_message": "Command must be a dictionary"},
|
||||||
|
Loading…
Reference in New Issue
Block a user