Adding i18n support to Syntribos
Adding i18n support to syntribos log messages and prompts. Change-Id: If9914447ccbf3ac2f9c88c3460756f4b682630ec
This commit is contained in:
parent
9fe18d5e96
commit
38eb9f2a77
|
@ -0,0 +1,3 @@
|
|||
# Extraction from Python source files
|
||||
[python: **.py]
|
||||
encoding = utf-8
|
2
pylintrc
2
pylintrc
|
@ -16,7 +16,7 @@ extension-pkg-whitelist=
|
|||
|
||||
disable=all
|
||||
|
||||
enable=bad-indentation,bad-builtin,pointless-statement,bad-continuation,unidiomatic-typecheck,method-hidden,lost-exception,attribute-defined-outside-init,expression-not-assigned,anomalous-backslash-in-string,wildcard-import,unreachable,unused-variable,blacklisted-name,logging-format-interpolation,cylic-import
|
||||
enable=bad-indentation,bad-builtin,pointless-statement,bad-continuation,unidiomatic-typecheck,method-hidden,lost-exception,attribute-defined-outside-init,expression-not-assigned,anomalous-backslash-in-string,wildcard-import,unreachable,blacklisted-name,logging-format-interpolation,cylic-import
|
||||
[REPORTS]
|
||||
output-format=text
|
||||
reports=yes
|
||||
|
|
|
@ -1,6 +1,7 @@
|
|||
# The order of packages is significant, because pip processes them in the order
|
||||
# of appearance. Changing the order has an impact on the overall integration
|
||||
# process, which may cause wedges in the gate later.
|
||||
oslo.i18n>=2.1.0 # Apache-2.0
|
||||
six>=1.9.0 # MIT
|
||||
requests!=2.12.2,!=2.13.0,>=2.10.0 # Apache-2.0
|
||||
oslo.config!=3.18.0,>=3.14.0 # Apache-2.0
|
||||
|
|
17
setup.cfg
17
setup.cfg
|
@ -36,3 +36,20 @@ oslo.config.opts =
|
|||
all_files = 1
|
||||
build-dir = doc/build
|
||||
source-dir = doc/source
|
||||
|
||||
[files]
|
||||
packages = syntribos
|
||||
|
||||
[compile_catalog]
|
||||
directory = syntribos/locale
|
||||
domain = syntribos
|
||||
|
||||
[update_catalog]
|
||||
domain = syntribos
|
||||
output_dir = syntribos/locale
|
||||
input_file = syntribos/locale/syntribos.pot
|
||||
|
||||
[extract_messages]
|
||||
keywords = _ gettext ngettext l_ lazy_gettext
|
||||
mapping_file = babel.cfg
|
||||
output_file = syntribos/locale/syntribos.pot
|
|
@ -0,0 +1,58 @@
|
|||
# Copyright 2017 Intel
|
||||
#
|
||||
# Licensed under the Apache License, Version 2.0 (the "License"); you may
|
||||
# not use this file except in compliance with the License. You may obtain
|
||||
# a copy of the License at
|
||||
#
|
||||
# http://www.apache.org/licenses/LICENSE-2.0
|
||||
#
|
||||
# Unless required by applicable law or agreed to in writing, software
|
||||
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
|
||||
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
|
||||
# License for the specific language governing permissions and limitations
|
||||
# under the License.
|
||||
|
||||
"""oslo.i18n integration module.
|
||||
|
||||
See http://docs.openstack.org/developer/oslo.i18n/usage.html .
|
||||
|
||||
"""
|
||||
|
||||
import oslo_i18n
|
||||
|
||||
DOMAIN = 'syntribos'
|
||||
|
||||
_translators = oslo_i18n.TranslatorFactory(domain=DOMAIN)
|
||||
|
||||
# The primary translation function using the well-known name "_"
|
||||
_ = _translators.primary
|
||||
|
||||
# The contextual translation function using the name "_C"
|
||||
# requires oslo.i18n >=2.1.0
|
||||
_C = _translators.contextual_form
|
||||
|
||||
# The plural translation function using the name "_P"
|
||||
# requires oslo.i18n >=2.1.0
|
||||
_P = _translators.plural_form
|
||||
|
||||
# Translators for log levels.
|
||||
#
|
||||
# The abbreviated names are meant to reflect the usual use of a short
|
||||
# name like '_'. The "L" is for "log" and the other letter comes from
|
||||
# the level.
|
||||
_LI = _translators.log_info
|
||||
_LW = _translators.log_warning
|
||||
_LE = _translators.log_error
|
||||
_LC = _translators.log_critical
|
||||
|
||||
|
||||
def enable_lazy():
|
||||
return oslo_i18n.enable_lazy()
|
||||
|
||||
|
||||
def translate(value, user_locale):
|
||||
return oslo_i18n.translate(value, user_locale)
|
||||
|
||||
|
||||
def get_available_languages():
|
||||
return oslo_i18n.get_available_languages(DOMAIN)
|
|
@ -23,6 +23,7 @@ import requests
|
|||
import six
|
||||
|
||||
import syntribos.checks.http as http_checks
|
||||
from syntribos._i18n import _, _LC, _LI # noqa
|
||||
import syntribos.signal
|
||||
from syntribos.utils import string_utils
|
||||
|
||||
|
@ -69,8 +70,9 @@ def log_http_transaction(log, level=logging.DEBUG):
|
|||
except Exception as exception:
|
||||
# Ignore all exceptions that happen in logging, then log them
|
||||
log.info(
|
||||
'Exception occurred while logging signature of calling'
|
||||
'method in http client')
|
||||
_LI(
|
||||
'Exception occurred while logging signature of calling'
|
||||
'method in http client'))
|
||||
log.exception(exception)
|
||||
|
||||
# Make the request and time its execution
|
||||
|
@ -82,11 +84,12 @@ def log_http_transaction(log, level=logging.DEBUG):
|
|||
response = func(*args, **kwargs)
|
||||
except requests.exceptions.RequestException as exc:
|
||||
signals.register(http_checks.check_fail(exc))
|
||||
log.log(level, "A call to request() failed.")
|
||||
log.log(level, _("A call to request() failed."))
|
||||
log.exception(exc)
|
||||
log.log(level, "=" * 80)
|
||||
except Exception as exc:
|
||||
log.critical('Call to Requests failed due to exception')
|
||||
log.critical(_LC(
|
||||
'Call to Requests failed due to exception'))
|
||||
log.exception(exc)
|
||||
signals.register(syntribos.signal.from_generic_exception(exc))
|
||||
raise exc
|
||||
|
@ -94,8 +97,9 @@ def log_http_transaction(log, level=logging.DEBUG):
|
|||
if len(signals) > 0 and response is None:
|
||||
no_resp_time = time() - start
|
||||
log.log(level,
|
||||
'Request failed, elapsed time....: {0:.5f} sec.\n'.
|
||||
format(no_resp_time))
|
||||
_(
|
||||
'Request failed, elapsed time....: %.6f sec.\n'
|
||||
), no_resp_time)
|
||||
return (response, signals)
|
||||
|
||||
# requests lib 1.0.0 renamed body to data in the request object
|
||||
|
@ -106,8 +110,9 @@ def log_http_transaction(log, level=logging.DEBUG):
|
|||
request_body = response.request.data
|
||||
else:
|
||||
log.info(
|
||||
"Unable to log request body, neither a 'data' nor a "
|
||||
"'body' object could be found")
|
||||
_LI(
|
||||
"Unable to log request body, neither a 'data' nor a "
|
||||
"'body' object could be found"))
|
||||
|
||||
# requests lib 1.0.4 removed params from response.request
|
||||
request_params = ''
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
# limitations under the License.
|
||||
import ast
|
||||
import copy
|
||||
from functools import reduce
|
||||
import importlib
|
||||
import json
|
||||
import re
|
||||
|
@ -27,6 +28,8 @@ import six
|
|||
from six.moves import html_parser
|
||||
from six.moves.urllib import parse as urlparse
|
||||
|
||||
from syntribos._i18n import _, _LE, _LW # noqa
|
||||
|
||||
CONF = cfg.CONF
|
||||
_iterators = {}
|
||||
_string_var_objs = {}
|
||||
|
@ -114,23 +117,25 @@ class RequestCreator(object):
|
|||
try:
|
||||
return reduce(getattr, var_obj.val.split("."), CONF)
|
||||
except AttributeError:
|
||||
print("Meta json file contains reference to the config option "
|
||||
"{0}, which does not appear to exist.".format(
|
||||
var_obj.val))
|
||||
print(_(
|
||||
"Meta json file contains reference to the config option "
|
||||
"%s, which does not appear to exist.") % var_obj.val)
|
||||
elif var_obj.var_type == 'function':
|
||||
if var_obj.function_return_value:
|
||||
return var_obj.function_return_value
|
||||
if not var_obj.val:
|
||||
print("The type of variable {0} is function, but there is no "
|
||||
"reference to the function.")
|
||||
print(_(
|
||||
"The type of variable is function, but there is no "
|
||||
"reference to the function."))
|
||||
return
|
||||
var_obj.function_return_value = cls.call_one_external_function(
|
||||
var_obj.val, var_obj.args)
|
||||
return var_obj.function_return_value
|
||||
elif var_obj.var_type == 'generator':
|
||||
if not var_obj.val:
|
||||
print("The type of variable {0} is generator, but there is no "
|
||||
"reference to the function.")
|
||||
print(_(
|
||||
"The type of variable {0} is generator, but there is no "
|
||||
"reference to the function."))
|
||||
return
|
||||
return cls.call_one_external_function(var_obj.val, var_obj.args)
|
||||
else:
|
||||
|
@ -247,7 +252,7 @@ class RequestCreator(object):
|
|||
data = ElementTree.fromstring(data)
|
||||
except Exception:
|
||||
if not re.match(postdat_regex, data):
|
||||
raise TypeError("Unknown data format")
|
||||
raise TypeError(_("Unknown data format"))
|
||||
return data
|
||||
|
||||
@classmethod
|
||||
|
@ -291,8 +296,8 @@ class RequestCreator(object):
|
|||
match = re.search(cls.FUNC_WITH_ARGS, string)
|
||||
func_string_has_args = True
|
||||
if not match:
|
||||
print("The reference to the function {0} failed to parse "
|
||||
"correctly".format(string))
|
||||
print(_("The reference to the function %s failed to parse "
|
||||
"correctly") % string)
|
||||
return
|
||||
dot_path = match.group(1)
|
||||
func_name = match.group(2)
|
||||
|
@ -320,8 +325,10 @@ class VariableObject(object):
|
|||
def __init__(self, name, var_type="", args=[], val="", fuzz=True,
|
||||
fuzz_type="", min_length=0, max_length=sys.maxsize, **kwargs):
|
||||
if var_type and var_type.lower() not in self.VAR_TYPES:
|
||||
print("The variable {0} has a type of {1} which syntribos does not"
|
||||
" recognize".format(name, var_type))
|
||||
print(_(
|
||||
"The variable %(name)s has a type of %(var)s which"
|
||||
" syntribos does not"
|
||||
" recognize") % {'name': name, 'var': var_type})
|
||||
self.name = name
|
||||
self.var_type = var_type.lower()
|
||||
self.val = val
|
||||
|
@ -338,6 +345,7 @@ class VariableObject(object):
|
|||
|
||||
class RequestHelperMixin(object):
|
||||
"""Class that helps with fuzzing requests."""
|
||||
|
||||
def __init__(self):
|
||||
self.data = ""
|
||||
self.headers = ""
|
||||
|
|
|
@ -18,6 +18,7 @@ import sys
|
|||
from oslo_config import cfg
|
||||
|
||||
import syntribos
|
||||
from syntribos._i18n import _, _LE, _LW # noqa
|
||||
from syntribos.utils.file_utils import ContentType
|
||||
from syntribos.utils.file_utils import ExistingDirType
|
||||
|
||||
|
@ -42,9 +43,9 @@ def handle_config_exception(exc):
|
|||
if CONF._args[0] == "init":
|
||||
return
|
||||
|
||||
msg = ("Configuration file specified ('{config}') wasn't "
|
||||
"found or was unreadable.").format(config=",".join(
|
||||
CONF.config_file))
|
||||
msg = (_("Configuration file specified ('%s') wasn't "
|
||||
"found or was unreadable.") % ",".join(
|
||||
CONF.config_file))
|
||||
|
||||
if msg:
|
||||
LOG.warning(msg)
|
||||
|
@ -64,42 +65,48 @@ remote_group = cfg.OptGroup(name="remote", title="Remote config")
|
|||
def sub_commands(sub_parser):
|
||||
init_parser = sub_parser.add_parser(
|
||||
"init",
|
||||
help="Initialize syntribos environment after "
|
||||
"installation. Should be run before any other "
|
||||
"commands.")
|
||||
help=_("Initialize syntribos environment after "
|
||||
"installation. Should be run before any other "
|
||||
"commands."))
|
||||
init_parser.add_argument(
|
||||
"--force", dest="force", action="store_true",
|
||||
help="Skip prompts for configurable options, force initialization "
|
||||
"even if syntribos believes it has already been initialized. If "
|
||||
"--custom_install_root isn't specified, we will use the default "
|
||||
"options. WARNING: This is potentially destructive! Use with caution.")
|
||||
help=_(
|
||||
"Skip prompts for configurable options, force initialization "
|
||||
"even if syntribos believes it has already been initialized. If "
|
||||
"--custom_install_root isn't specified, we will use the default "
|
||||
"options. WARNING: This is potentially destructive! Use with "
|
||||
"caution."))
|
||||
init_parser.add_argument(
|
||||
"--custom_install_root", dest="custom_install_root",
|
||||
help="Skip prompts for configurable options, and initialize syntribos "
|
||||
"in the specified directory. Can be combined with --force to "
|
||||
"overwrite existing files.")
|
||||
help=_("Skip prompts for configurable options, and initialize "
|
||||
"syntribos in the specified directory. Can be combined "
|
||||
"with --force to overwrite existing files."))
|
||||
init_parser.add_argument(
|
||||
"--no_downloads", dest="no_downloads", action="store_true",
|
||||
help="Disable the downloading of payload files as part of the "
|
||||
"initialization process")
|
||||
help=_("Disable the downloading of payload files as part of the "
|
||||
"initialization process"))
|
||||
|
||||
download_parser = sub_parser.add_parser(
|
||||
"download",
|
||||
help="Download payload and template files. This command is "
|
||||
"configurable according to the remote section of your config file")
|
||||
help=_(
|
||||
"Download payload and template files. This command is "
|
||||
"configurable according to the remote section of your "
|
||||
"config file"))
|
||||
download_parser.add_argument(
|
||||
"--templates", dest="templates", action="store_true",
|
||||
help="Download templates")
|
||||
help=_("Download templates"))
|
||||
download_parser.add_argument(
|
||||
"--payloads", dest="payloads", action="store_true",
|
||||
help="Download payloads")
|
||||
help=_("Download payloads"))
|
||||
|
||||
sub_parser.add_parser("list_tests",
|
||||
help="List all available tests")
|
||||
help=_("List all available tests"))
|
||||
sub_parser.add_parser("run",
|
||||
help="Run syntribos with given config options")
|
||||
help=_("Run syntribos with given config"
|
||||
"options"))
|
||||
sub_parser.add_parser("dry_run",
|
||||
help="Dry run syntribos with given config options")
|
||||
help=_("Dry run syntribos with given config"
|
||||
"options"))
|
||||
|
||||
|
||||
def list_opts():
|
||||
|
@ -140,28 +147,32 @@ def list_cli_opts():
|
|||
return [
|
||||
cfg.SubCommandOpt(name="sub_command",
|
||||
handler=sub_commands,
|
||||
help="Available commands",
|
||||
help=_("Available commands"),
|
||||
title="syntribos Commands"),
|
||||
cfg.MultiStrOpt("test-types", dest="test_types", short="t",
|
||||
default=[""], sample_default=["SQL", "XSS"],
|
||||
help="Test types to run against the target API"),
|
||||
help=_(
|
||||
"Test types to run against the target API")),
|
||||
cfg.MultiStrOpt("excluded-types", dest="excluded_types", short="e",
|
||||
default=[""], sample_default=["SQL", "XSS"],
|
||||
help="Test types to be excluded from current run"
|
||||
"against the target API"),
|
||||
help=_("Test types to be excluded from "
|
||||
"current run against the target API")),
|
||||
cfg.BoolOpt("colorize", dest="colorize", short="cl", default=False,
|
||||
help="Enable color in syntribos terminal output"),
|
||||
help=_("Enable color in syntribos terminal output")),
|
||||
cfg.StrOpt("outfile", short="o",
|
||||
sample_default="out.json", help="File to print output to"),
|
||||
sample_default="out.json", help=_("File to print "
|
||||
"output to")),
|
||||
cfg.StrOpt("format", dest="output_format", short="f", default="json",
|
||||
choices=["json"], ignore_case=True,
|
||||
help="The format for outputting results"),
|
||||
help=_("The format for outputting results")),
|
||||
cfg.StrOpt("min-severity", dest="min_severity", short="S",
|
||||
default="LOW", choices=syntribos.RANKING,
|
||||
help="Select a minimum severity for reported defects"),
|
||||
help=_("Select a minimum severity for reported "
|
||||
"defects")),
|
||||
cfg.StrOpt("min-confidence", dest="min_confidence", short="C",
|
||||
default="LOW", choices=syntribos.RANKING,
|
||||
help="Select a minimum confidence for reported defects")
|
||||
help=_("Select a minimum confidence for reported "
|
||||
"defects"))
|
||||
]
|
||||
|
||||
|
||||
|
@ -171,63 +182,77 @@ def list_syntribos_opts():
|
|||
try:
|
||||
func(*args)
|
||||
except IOError:
|
||||
print("\nCan't open a file or directory specified in the "
|
||||
"config file under the section `[syntribos]`; verify "
|
||||
"if the path exists.\nFor more information please refer "
|
||||
"the debug logs.")
|
||||
msg = _(
|
||||
"\nCan't open a file or directory specified in the "
|
||||
"config file under the section `[syntribos]`; verify "
|
||||
"if the path exists.\nFor more information please refer "
|
||||
"the debug logs.")
|
||||
print(msg)
|
||||
exit(1)
|
||||
return wrap
|
||||
return [
|
||||
cfg.StrOpt("endpoint", default="",
|
||||
sample_default="http://localhost/app",
|
||||
help="The target host to be tested"),
|
||||
help=_("The target host to be tested")),
|
||||
cfg.Opt("templates", type=ContentType("r", 0),
|
||||
default="",
|
||||
sample_default="~/.syntribos/templates",
|
||||
help="A directory of template files, or a single template "
|
||||
"file, to test on the target API"),
|
||||
help=_("A directory of template files, or a single "
|
||||
"template file, to test on the target API")),
|
||||
cfg.StrOpt("payloads", default="",
|
||||
sample_default="~/.syntribos/data",
|
||||
help="The location where we can find syntribos'"
|
||||
"payloads"),
|
||||
help=_(
|
||||
"The location where we can find syntribos'"
|
||||
"payloads")),
|
||||
cfg.MultiStrOpt("exclude_results",
|
||||
default=[""],
|
||||
sample_default=["500_errors", "length_diff"],
|
||||
help="Defect types to exclude from the "
|
||||
"results output"),
|
||||
help=_(
|
||||
"Defect types to exclude from the "
|
||||
"results output")),
|
||||
cfg.Opt("custom_root", type=wrap_try_except(ExistingDirType()),
|
||||
short="c",
|
||||
sample_default="/your/custom/root",
|
||||
help="The root directory where the subfolders that make up"
|
||||
" syntribos' environment (logs, templates, payloads, "
|
||||
"configuration files, etc.)"),
|
||||
help=_(
|
||||
"The root directory where the subfolders that make up"
|
||||
" syntribos' environment (logs, templates, payloads, "
|
||||
"configuration files, etc.)")),
|
||||
]
|
||||
|
||||
|
||||
def list_user_opts():
|
||||
return [
|
||||
cfg.StrOpt("version", default="v2.0",
|
||||
help="keystone version", choices=["v2.0", "v3"]),
|
||||
cfg.StrOpt("username", default="", help="keystone username"),
|
||||
cfg.StrOpt("password", default="", help="keystone user password",
|
||||
help=_("keystone version"), choices=["v2.0", "v3"]),
|
||||
cfg.StrOpt("username", default="",
|
||||
help=_("keystone username")),
|
||||
cfg.StrOpt("password", default="",
|
||||
help=_("keystone user password"),
|
||||
secret=True),
|
||||
cfg.StrOpt("user_id", default="",
|
||||
help="Keystone user ID", secret=True),
|
||||
cfg.StrOpt("token", default="", help="keystone auth token",
|
||||
help=_("Keystone user ID"), secret=True),
|
||||
cfg.StrOpt("token", default="", help=_("keystone auth token"),
|
||||
secret=True),
|
||||
cfg.StrOpt("endpoint", default="", help="keystone endpoint URI"),
|
||||
cfg.StrOpt("domain_name", default="", help="keystone domain name"),
|
||||
cfg.StrOpt("project_id", default="", help="keystone project id"),
|
||||
cfg.StrOpt("project_name", default="", help="keystone project name"),
|
||||
cfg.StrOpt("domain_id", default="", help="keystone domain id"),
|
||||
cfg.StrOpt("tenant_name", default="", help="keystone tenant name"),
|
||||
cfg.StrOpt("tenant_id", default="", help="keystone tenant id"),
|
||||
cfg.StrOpt("endpoint", default="",
|
||||
help=_("keystone endpoint URI")),
|
||||
cfg.StrOpt("domain_name", default="",
|
||||
help=_("keystone domain name")),
|
||||
cfg.StrOpt("project_id", default="",
|
||||
help=_("keystone project id")),
|
||||
cfg.StrOpt("project_name", default="",
|
||||
help=_("keystone project name")),
|
||||
cfg.StrOpt("domain_id", default="",
|
||||
help=_("keystone domain id")),
|
||||
cfg.StrOpt("tenant_name", default="",
|
||||
help=_("keystone tenant name")),
|
||||
cfg.StrOpt("tenant_id", default="",
|
||||
help=_("keystone tenant id")),
|
||||
cfg.StrOpt("serialize_format", default="json",
|
||||
help="Type of request body"),
|
||||
help=_("Type of request body")),
|
||||
cfg.StrOpt("deserialize_format", default="json",
|
||||
help="Type of response body"),
|
||||
help=_("Type of response body")),
|
||||
cfg.IntOpt("token_ttl", default=1800,
|
||||
help="Time to live for token in seconds")
|
||||
help=_("Time to live for token in seconds"))
|
||||
|
||||
]
|
||||
|
||||
|
@ -235,19 +260,24 @@ def list_user_opts():
|
|||
def list_test_opts():
|
||||
return [
|
||||
cfg.FloatOpt("length_diff_percent", default=1000.0,
|
||||
help="Percentage difference between initial request "
|
||||
"and test request body length to trigger a signal"),
|
||||
help=_(
|
||||
"Percentage difference between initial request "
|
||||
"and test request body length to trigger a signal")),
|
||||
cfg.FloatOpt("time_diff_percent", default=1000.0,
|
||||
help="Percentage difference between initial response "
|
||||
"time and test response time to trigger a signal"),
|
||||
help=_(
|
||||
"Percentage difference between initial response "
|
||||
"time and test response time to trigger a signal")),
|
||||
cfg.IntOpt("max_time", default=10,
|
||||
help="Maximum absolute time (in seconds) to wait for a "
|
||||
"response before triggering a timeout signal"),
|
||||
help=_(
|
||||
"Maximum absolute time (in seconds) to wait for a "
|
||||
"response before triggering a timeout signal")),
|
||||
cfg.IntOpt("max_length", default=500,
|
||||
help="Maximum length (in characters) of the response text"),
|
||||
help=_(
|
||||
"Maximum length (in characters) of the response text")),
|
||||
cfg.ListOpt("failure_keys", default="[`syntax error`]",
|
||||
help="Comma seperated list of keys for which the test "
|
||||
"would fail.")
|
||||
help=_(
|
||||
"Comma seperated list of keys for which the test "
|
||||
"would fail."))
|
||||
]
|
||||
|
||||
|
||||
|
@ -255,11 +285,14 @@ def list_logger_opts():
|
|||
# TODO(unrahul): Add log formating and verbosity options
|
||||
return [
|
||||
cfg.BoolOpt("http_request_compression", default=True,
|
||||
help="Request content compression to compress fuzz "
|
||||
"strings present in the http request content."),
|
||||
help=_(
|
||||
"Request content compression to compress fuzz "
|
||||
"strings present in the http request content.")),
|
||||
cfg.StrOpt("log_dir", default="",
|
||||
sample_default="~/.syntribos/logs",
|
||||
help="Where to save debug log files for a syntribos run")
|
||||
help=_(
|
||||
"Where to save debug log files for a syntribos run"
|
||||
))
|
||||
]
|
||||
|
||||
|
||||
|
@ -269,17 +302,18 @@ def list_remote_opts():
|
|||
cfg.StrOpt(
|
||||
"cache_dir",
|
||||
default="",
|
||||
help="Base directory where cached files can be saved"),
|
||||
help=_("Base directory where cached files can be saved")),
|
||||
cfg.StrOpt(
|
||||
"payloads_uri",
|
||||
default=("https://github.com/openstack/syntribos-payloads/"
|
||||
"archive/master.tar.gz"),
|
||||
help="Remote URI to download payloads."),
|
||||
help=_("Remote URI to download payloads.")),
|
||||
cfg.StrOpt(
|
||||
"templates_uri",
|
||||
default=("https://github.com/rahulunair/openstack-templates/"
|
||||
"archive/master.tar.gz"),
|
||||
help="Remote URI to download templates."),
|
||||
help=_("Remote URI to download templates.")),
|
||||
cfg.BoolOpt("enable_cache", default=True,
|
||||
help="Cache remote template & payload resources locally"),
|
||||
help=_(
|
||||
"Cache remote template & payload resources locally")),
|
||||
]
|
||||
|
|
|
@ -254,5 +254,5 @@ class IssueTestResult(unittest.TextTestResult):
|
|||
esuff="s" * bool(num_err - 1)))
|
||||
if test_log:
|
||||
print(syntribos.SEP)
|
||||
print("LOG PATH...: {path}".format(path=test_log))
|
||||
print(syntribos._("LOG PATH...: %s") % test_log)
|
||||
print(syntribos.SEP)
|
||||
|
|
|
@ -25,6 +25,7 @@ from six.moves import input
|
|||
|
||||
import syntribos.config
|
||||
from syntribos.formatters.json_formatter import JSONFormatter
|
||||
from syntribos._i18n import _, _LW, _LE # noqa
|
||||
import syntribos.result
|
||||
import syntribos.tests as tests
|
||||
import syntribos.tests.base
|
||||
|
@ -54,14 +55,15 @@ class Runner(object):
|
|||
@classmethod
|
||||
def list_tests(cls):
|
||||
"""Print out the list of available tests types that can be run."""
|
||||
print("List of available tests...:\n")
|
||||
print("{:<50}{}\n".format("[Test Name]", "[Description]"))
|
||||
print(_("List of available tests...:\n"))
|
||||
print("{:<50}{}\n".format(_("[Test Name]"),
|
||||
_("[Description]")))
|
||||
testdict = {name: clss.__doc__ for name, clss in cls.get_tests()}
|
||||
for test in sorted(testdict):
|
||||
if testdict[test] is None:
|
||||
raise Exception(
|
||||
("No test description provided"
|
||||
" as doc string for the test: {0}".format(test)))
|
||||
_("No test description provided"
|
||||
" as doc string for the test: %s") % test)
|
||||
else:
|
||||
test_description = testdict[test].split(".")[0]
|
||||
print("{test:<50}{desc}\r".format(
|
||||
|
@ -74,7 +76,7 @@ class Runner(object):
|
|||
|
||||
:param package: a package of tests for pkgutil to load
|
||||
"""
|
||||
for _, modname, _ in pkgutil.walk_packages(
|
||||
for i, modname, k in pkgutil.walk_packages(
|
||||
path=package.__path__,
|
||||
prefix=package.__name__ + '.',
|
||||
onerror=lambda x: None):
|
||||
|
@ -187,14 +189,16 @@ class Runner(object):
|
|||
ENV.download_wrapper()
|
||||
exit(0)
|
||||
except AttributeError:
|
||||
print("Not able to run the requested sub command, please check "
|
||||
"the debug logs for more information, exiting...")
|
||||
print(
|
||||
_(
|
||||
"Not able to run the requested sub command, please check "
|
||||
"the debug logs for more information, exiting..."))
|
||||
exit(1)
|
||||
|
||||
if not ENV.is_syntribos_initialized():
|
||||
print("Syntribos was not initialized. Please run the 'init' "
|
||||
"command or set it up manually. See the README for more "
|
||||
"information about the installation process.")
|
||||
print(_("Syntribos was not initialized. Please run the 'init'"
|
||||
" command or set it up manually. See the README for"
|
||||
" more information about the installation process."))
|
||||
exit(1)
|
||||
|
||||
cls.setup_runtime_env()
|
||||
|
@ -210,20 +214,20 @@ class Runner(object):
|
|||
dry_run_output = {"failures": [], "successes": []}
|
||||
list_of_tests = list(cls.get_tests(dry_run=True))
|
||||
|
||||
print("\nRunning Tests...:")
|
||||
print(_("\nRunning Tests...:"))
|
||||
templates_dir = CONF.syntribos.templates
|
||||
if templates_dir is None:
|
||||
print("Attempting to download templates from {}".format(
|
||||
print(_("Attempting to download templates from {}").format(
|
||||
CONF.remote.templates_uri))
|
||||
templates_path = remotes.get(CONF.remote.templates_uri)
|
||||
try:
|
||||
templates_dir = ContentType("r", 0)(templates_path)
|
||||
except IOError:
|
||||
print("Not able to open `{}`; "
|
||||
"please verify path, exiting...".format(templates_path))
|
||||
print(_("Not able to open `%s`; please verify path, "
|
||||
"exiting...") % templates_path)
|
||||
exit(1)
|
||||
|
||||
print("\nPress Ctrl-C to pause or exit...\n")
|
||||
print(_("\nPress Ctrl-C to pause or exit...\n"))
|
||||
# TODO(mdong): Make this handle inheritence and all that. For now, just
|
||||
# pass the first meta file it sees to the parser. Also, find a better
|
||||
# way to pass meta_vars
|
||||
|
@ -242,12 +246,12 @@ class Runner(object):
|
|||
LOG = cls.get_logger(file_path)
|
||||
CONF.log_opt_values(LOG, logging.DEBUG)
|
||||
if not file_path.endswith(".template"):
|
||||
LOG.debug(
|
||||
'file.......: %s (SKIPPED - not a .template file)',
|
||||
LOG.warning(
|
||||
_LW('file.....:%s (SKIPPED - not a .template file)'),
|
||||
file_path)
|
||||
continue
|
||||
|
||||
test_names = [t for (t, _) in list_of_tests]
|
||||
test_names = [t for (t, i) in list_of_tests] # noqa
|
||||
log_string = ''.join([
|
||||
'\n{0}\nTEMPLATE FILE\n{0}\n'.format('-' * 12),
|
||||
'file.......: {0}\n'.format(file_path),
|
||||
|
@ -288,20 +292,20 @@ class Runner(object):
|
|||
|
||||
:return: None
|
||||
"""
|
||||
for _, test_class in list_of_tests:
|
||||
for k, test_class in list_of_tests: # noqa
|
||||
try:
|
||||
print("\nParsing template file...")
|
||||
test_class.create_init_request(file_path, req_str, meta_vars)
|
||||
except Exception as e:
|
||||
print("Error in parsing template:\n \t{0}\n".format(
|
||||
traceback.format_exc()))
|
||||
LOG.exception("Error in parsing template:")
|
||||
LOG.error(_LE("Error in parsing template:"))
|
||||
output["failures"].append({
|
||||
"file": file_path,
|
||||
"error": e.__str__()
|
||||
})
|
||||
else:
|
||||
print("Request sucessfully generated!\n")
|
||||
print(_("Request sucessfully generated!\n"))
|
||||
output["successes"].append(file_path)
|
||||
|
||||
test_cases = list(test_class.get_test_cases(file_path, req_str))
|
||||
|
@ -319,7 +323,7 @@ class Runner(object):
|
|||
|
||||
test_log = cls.log_path
|
||||
print(syntribos.SEP)
|
||||
print("LOG PATH...: {path}".format(path=test_log))
|
||||
print(_("LOG PATH...: {path}").format(path=test_log))
|
||||
print(syntribos.SEP)
|
||||
|
||||
@classmethod
|
||||
|
@ -358,9 +362,10 @@ class Runner(object):
|
|||
try:
|
||||
test_class.send_init_request(file_path, req_str, meta_vars)
|
||||
except Exception:
|
||||
print("Error in parsing template:\n \t{0}\n".format(
|
||||
traceback.format_exc()))
|
||||
LOG.exception("Error in parsing template:")
|
||||
print(_(
|
||||
"Error in parsing template:\n %s\n"
|
||||
) % traceback.format_exc())
|
||||
LOG.error(_LE("Error in parsing template:"))
|
||||
break
|
||||
test_cases = list(
|
||||
test_class.get_test_cases(file_path, req_str))
|
||||
|
@ -390,35 +395,38 @@ class Runner(object):
|
|||
last_failures = result.stats["failures"]
|
||||
last_errors = result.stats["errors"]
|
||||
errors = cli.colorize(errors, "red")
|
||||
print(" : {0} Failure(s), {1} Error(s)\r".format(
|
||||
failures, errors))
|
||||
print(_(
|
||||
" : %(fail)s Failure(s), %(err) Error(s)\r") % {
|
||||
"fail": failures, "err": errors})
|
||||
else:
|
||||
last_failures = result.stats["failures"]
|
||||
print(" : {} Failure(s), 0 Error(s)\r".format(
|
||||
failures))
|
||||
print(
|
||||
_(
|
||||
" : %s Failure(s), 0 Error(s)\r") % failures)
|
||||
|
||||
run_time = time.time() - template_start_time
|
||||
LOG.debug("Run time: %s sec.", run_time)
|
||||
LOG.info(_("Run time: %s sec."), run_time)
|
||||
if hasattr(result, "testsRun"):
|
||||
num_tests = result.testsRun - result.testsRunSinceLastPrint
|
||||
print("\nRan {num} test(s) in {time:.3f}s\n".format(
|
||||
num=num_tests, time=run_time))
|
||||
print(_("\nRan %(num)s test(s) in %.3(time)f s\n") %
|
||||
{"num": num_tests, "time": run_time})
|
||||
result.testsRunSinceLastPrint = result.testsRun
|
||||
|
||||
except KeyboardInterrupt:
|
||||
print('\n\nPausing... Hit ENTER to continue, type quit to exit.')
|
||||
print(_(
|
||||
'\n\nPausing...Hit ENTER to continue, type quit to exit.'))
|
||||
try:
|
||||
response = input()
|
||||
if response.lower() == "quit":
|
||||
result.print_result(cls.start_time)
|
||||
cleanup.delete_temps()
|
||||
print("Exiting...")
|
||||
print(_("Exiting..."))
|
||||
exit(0)
|
||||
print('Resuming...')
|
||||
print(_('Resuming...'))
|
||||
except KeyboardInterrupt:
|
||||
result.print_result(cls.start_time)
|
||||
cleanup.delete_temps()
|
||||
print("Exiting...")
|
||||
print(_("Exiting..."))
|
||||
exit(0)
|
||||
|
||||
@classmethod
|
||||
|
|
|
@ -13,6 +13,8 @@
|
|||
# limitations under the License.
|
||||
import six
|
||||
|
||||
from syntribos._i18n import _, _LE, _LW # noqa
|
||||
|
||||
|
||||
class SignalHolder(object):
|
||||
"""SignalHolder represents a 'set' of SynSignals.
|
||||
|
@ -247,14 +249,14 @@ def from_generic_exception(exception):
|
|||
:returns: A signal describing the exception
|
||||
"""
|
||||
if not isinstance(exception, Exception):
|
||||
raise Exception("This function accepts only Exception objects")
|
||||
raise Exception(_("This function accepts only Exception objects"))
|
||||
|
||||
exc_text = str(exception)
|
||||
text = "This request raised an exception: '{0}'".format(exc_text)
|
||||
text = _("This request raised an exception: '%s'") % exc_text
|
||||
data = {
|
||||
"exception_name": exception.__class__.__name__,
|
||||
"exception_text": exc_text,
|
||||
"exception": exception
|
||||
_("exception_name"): exception.__class__.__name__,
|
||||
_("exception_text"): exc_text,
|
||||
_("exception"): exception
|
||||
}
|
||||
slug = "GENERIC_EXCEPTION_{name}".format(
|
||||
name=data["exception_name"].upper())
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
import syntribos
|
||||
from syntribos._i18n import _
|
||||
from syntribos.checks import has_string as has_string
|
||||
from syntribos.checks import time_diff as time_diff
|
||||
from syntribos.tests.fuzz import base_fuzz
|
||||
|
@ -60,10 +61,10 @@ class BufferOverflowBody(base_fuzz.BaseFuzzTestCase):
|
|||
defect_type="bof_timing",
|
||||
severity=syntribos.MEDIUM,
|
||||
confidence=syntribos.MEDIUM,
|
||||
description=("The time it took to resolve a request with a "
|
||||
"long string was too long compared to the "
|
||||
"baseline request. This could indicate a "
|
||||
"vulnerability to buffer overflow attacks"))
|
||||
description=(_("The time it took to resolve a request with a "
|
||||
"long string was too long compared to the "
|
||||
"baseline request. This could indicate a "
|
||||
"vulnerability to buffer overflow attacks")))
|
||||
|
||||
|
||||
class BufferOverflowParams(BufferOverflowBody):
|
||||
|
|
|
@ -13,6 +13,7 @@
|
|||
# limitations under the License.
|
||||
|
||||
import syntribos
|
||||
from syntribos._i18n import _
|
||||
from syntribos.checks import has_string as has_string
|
||||
from syntribos.checks import time_diff as time_diff
|
||||
from syntribos.tests.fuzz import base_fuzz
|
||||
|
@ -51,11 +52,11 @@ class CommandInjectionBody(base_fuzz.BaseFuzzTestCase):
|
|||
defect_type="command_injection",
|
||||
severity=syntribos.HIGH,
|
||||
confidence=syntribos.MEDIUM,
|
||||
description=("The time elapsed between the sending of "
|
||||
"the request and the arrival of the res"
|
||||
"ponse exceeds the expected amount of time, "
|
||||
"suggesting a vulnerability to command "
|
||||
"injection attacks."))
|
||||
description=(_("The time elapsed between the sending of "
|
||||
"the request and the arrival of the res"
|
||||
"ponse exceeds the expected amount of time, "
|
||||
"suggesting a vulnerability to command "
|
||||
"injection attacks.")))
|
||||
|
||||
|
||||
class CommandInjectionParams(CommandInjectionBody):
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
import syntribos
|
||||
from syntribos._i18n import _
|
||||
from syntribos.checks import time_diff as time_diff
|
||||
from syntribos.tests.fuzz import base_fuzz
|
||||
|
||||
|
@ -30,10 +31,10 @@ class IntOverflowBody(base_fuzz.BaseFuzzTestCase):
|
|||
defect_type="int_timing",
|
||||
severity=syntribos.MEDIUM,
|
||||
confidence=syntribos.MEDIUM,
|
||||
description=("The time it took to resolve a request with an "
|
||||
"invalid integer was too long compared to the "
|
||||
"baseline request. This could indicate a "
|
||||
"vulnerability to buffer overflow attacks"))
|
||||
description=(_("The time it took to resolve a request with an "
|
||||
"invalid integer was too long compared to the "
|
||||
"baseline request. This could indicate a "
|
||||
"vulnerability to buffer overflow attacks")))
|
||||
|
||||
|
||||
class IntOverflowParams(IntOverflowBody):
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
import syntribos
|
||||
from syntribos._i18n import _
|
||||
from syntribos.checks import has_string as has_string
|
||||
from syntribos.checks import time_diff as time_diff
|
||||
from syntribos.tests.fuzz import base_fuzz
|
||||
|
@ -56,7 +57,7 @@ class JSONDepthOverflowBody(base_fuzz.BaseFuzzTestCase):
|
|||
defect_type="json_depth_timing",
|
||||
severity=syntribos.MEDIUM,
|
||||
confidence=syntribos.MEDIUM,
|
||||
description=("The time it took to resolve a request "
|
||||
"was too long compared to the "
|
||||
"baseline request. This could indicate a "
|
||||
"vulnerability to denial of service attacks."))
|
||||
description=(_("The time it took to resolve a request "
|
||||
"was too long compared to the "
|
||||
"baseline request. This could indicate a "
|
||||
"vulnerability to denial of service attacks.")))
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
import syntribos
|
||||
from syntribos._i18n import _
|
||||
from syntribos.checks import has_string as has_string
|
||||
from syntribos.checks import time_diff as time_diff
|
||||
from syntribos.tests.fuzz import base_fuzz
|
||||
|
@ -54,10 +55,10 @@ class SQLInjectionBody(base_fuzz.BaseFuzzTestCase):
|
|||
defect_type="sql_timing",
|
||||
severity=syntribos.MEDIUM,
|
||||
confidence=syntribos.MEDIUM,
|
||||
description=("A response to one of our payload requests has "
|
||||
"taken too long compared to the baseline "
|
||||
"request. This could indicate a vulnerability "
|
||||
"to time-based SQL injection attacks"))
|
||||
description=(_("A response to one of our payload requests has "
|
||||
"taken too long compared to the baseline "
|
||||
"request. This could indicate a vulnerability "
|
||||
"to time-based SQL injection attacks")))
|
||||
|
||||
|
||||
class SQLInjectionParams(SQLInjectionBody):
|
||||
|
|
|
@ -16,6 +16,7 @@ import os
|
|||
from oslo_config import cfg
|
||||
|
||||
import syntribos
|
||||
from syntribos._i18n import _
|
||||
from syntribos.checks import has_string as has_string
|
||||
from syntribos.checks import time_diff as time_diff
|
||||
from syntribos.tests.fuzz import base_fuzz
|
||||
|
@ -66,11 +67,11 @@ class UserDefinedVulnBody(base_fuzz.BaseFuzzTestCase):
|
|||
defect_type="user_defined_string_timing",
|
||||
severity=syntribos.MEDIUM,
|
||||
confidence=syntribos.MEDIUM,
|
||||
description=("A response to one of the payload requests has "
|
||||
"taken too long compared to the baseline "
|
||||
"request. This could indicate a vulnerability "
|
||||
"to time-based injection attacks using the user "
|
||||
"provided strings."))
|
||||
description=(_("A response to one of the payload requests has "
|
||||
"taken too long compared to the baseline "
|
||||
"request. This could indicate a vulnerability "
|
||||
"to time-based injection attacks using the user"
|
||||
" provided strings.")))
|
||||
|
||||
@classmethod
|
||||
def get_test_cases(cls, filename, file_content):
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
from oslo_config import cfg
|
||||
|
||||
import syntribos
|
||||
from syntribos._i18n import _
|
||||
from syntribos.checks.header import cors
|
||||
from syntribos.clients.http import client
|
||||
from syntribos.clients.http import parser
|
||||
|
@ -59,6 +60,6 @@ class CorsHeader(base.BaseTestCase):
|
|||
severity=test_severity,
|
||||
confidence=syntribos.HIGH,
|
||||
description=(
|
||||
"CORS header vulnerability found.\n"
|
||||
"Make sure that the header is not assigned "
|
||||
"a wildcard character."))
|
||||
_("CORS header vulnerability found.\n"
|
||||
"Make sure that the header is not assigned "
|
||||
"a wildcard character.")))
|
||||
|
|
|
@ -15,6 +15,7 @@
|
|||
from oslo_config import cfg
|
||||
|
||||
import syntribos
|
||||
from syntribos._i18n import _
|
||||
from syntribos.checks.header import xst
|
||||
from syntribos.clients.http import client
|
||||
from syntribos.clients.http import parser
|
||||
|
@ -61,13 +62,14 @@ class XstHeader(base.BaseTestCase):
|
|||
xst_slugs = [
|
||||
slugs for slugs in self.test_signals.all_slugs
|
||||
if "HEADER_XST" in slugs]
|
||||
for _ in xst_slugs:
|
||||
for i in xst_slugs: # noqa
|
||||
test_severity = syntribos.LOW
|
||||
self.register_issue(
|
||||
defect_type="XST_HEADER",
|
||||
severity=test_severity,
|
||||
confidence=syntribos.HIGH,
|
||||
description=(
|
||||
"XST vulnerability found.\n"
|
||||
"Make sure that response to a TRACE request is filtered."
|
||||
))
|
||||
description=(_("XST vulnerability found.\n"
|
||||
"Make sure that response to a "
|
||||
"TRACE request is filtered."
|
||||
)
|
||||
))
|
||||
|
|
|
@ -12,6 +12,7 @@
|
|||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
import syntribos
|
||||
from syntribos._i18n import _
|
||||
from syntribos.checks import https_check
|
||||
from syntribos.tests import base
|
||||
|
||||
|
@ -28,8 +29,8 @@ class SSLTestCase(base.BaseTestCase):
|
|||
|
||||
if "HTTP_LINKS_PRESENT" in self.init_signals:
|
||||
self.register_issue(
|
||||
defect_type="SSL_ERROR",
|
||||
defect_type=_("SSL_ERROR"),
|
||||
severity=syntribos.MEDIUM,
|
||||
confidence=syntribos.HIGH,
|
||||
description=("Make sure that all the returned endpoint URIs"
|
||||
" use 'https://' and not 'http://'"))
|
||||
description=(_("Make sure that all the returned endpoint URIs"
|
||||
" use 'https://' and not 'http://'")))
|
||||
|
|
|
@ -20,7 +20,7 @@ def delete_temps():
|
|||
"""Deletes all temporary dirs used for saving cached files."""
|
||||
remote_dirs = set(syntribos.utils.remotes.remote_dirs)
|
||||
temp_dirs = set(syntribos.utils.remotes.temp_dirs)
|
||||
[delete_dir(temp_dir) for temp_dir in temp_dirs] # noqa
|
||||
[delete_dir(temp_dir) for temp_dir in temp_dirs] # noqa
|
||||
if remote_dirs - temp_dirs:
|
||||
print("All downloaded files have been saved to: {}".format(
|
||||
",".join([ele for ele in (remote_dirs - temp_dirs)])))
|
||||
|
|
|
@ -23,6 +23,7 @@ import requests
|
|||
from six.moves import input
|
||||
|
||||
import syntribos
|
||||
from syntribos._i18n import _, _LE, _LW # noqa
|
||||
from syntribos.utils import remotes
|
||||
|
||||
FOLDER = ".syntribos"
|
||||
|
@ -48,7 +49,7 @@ def get_user_home_root():
|
|||
except OSError as e:
|
||||
# Refer https://mail.python.org/pipermail/python-bugs-list/
|
||||
# 2002-July/012691.html
|
||||
LOG.error("Exception thrown in : %s", e)
|
||||
LOG.error(_LE("Exception thrown in : %s") % e)
|
||||
user = pwd.getpwuid(os.getuid())[0]
|
||||
home_path = "~{0}/{1}".format(user, FOLDER)
|
||||
return expand_path(home_path)
|
||||
|
@ -111,15 +112,17 @@ def safe_makedirs(path, force=False):
|
|||
try:
|
||||
os.makedirs(path)
|
||||
except (OSError, IOError):
|
||||
LOG.exception("Error creating folder (%s).", path)
|
||||
LOG.exception(_("Error creating folder (%s).") % path)
|
||||
elif os.path.exists(path) and force:
|
||||
try:
|
||||
shutil.rmtree(path)
|
||||
os.makedirs(path)
|
||||
except (OSError, IOError):
|
||||
LOG.exception("Error overwriting existing folder (%s).", path)
|
||||
LOG.exception(
|
||||
_("Error overwriting existing folder (%s).") % path)
|
||||
else:
|
||||
LOG.warning("Folder was already found (%s). Skipping.", path)
|
||||
LOG.warning(
|
||||
_LW("Folder was already found (%s). Skipping.") % path)
|
||||
|
||||
|
||||
def create_env_dirs(root_dir, force=False):
|
||||
|
@ -240,32 +243,37 @@ def initialize_syntribos_env():
|
|||
|
||||
payloads_dir = folders_created[1]
|
||||
if not CONF.sub_command.no_downloads:
|
||||
print("\nDownloading payload files to {0}...".format(payloads_dir))
|
||||
print(
|
||||
_("\nDownloading payload files to %s...") % payloads_dir)
|
||||
try:
|
||||
remote_path = remotes.get(CONF.remote.payloads_uri, payloads_dir)
|
||||
conf_file = create_conf_file(folders_created, remote_path)
|
||||
print("Download successful!")
|
||||
print(_("Download successful!"))
|
||||
except (requests.ConnectionError, IOError):
|
||||
print("Download failed. If you would still like to download "
|
||||
"payload files, please consult our documentation about the"
|
||||
"'syntribos download' command or do so manually.")
|
||||
print(_("Download failed. If you would still like to download"
|
||||
" payload files, please consult our documentation"
|
||||
" about the 'syntribos download' command or do so"
|
||||
" manually."))
|
||||
conf_file = create_conf_file(folders_created)
|
||||
else:
|
||||
conf_file = create_conf_file(folders_created)
|
||||
|
||||
logging.disable(logging.NOTSET)
|
||||
|
||||
print("\nSyntribos has been initialized!")
|
||||
print("Folders created:\n\t{0}".format("\n\t".join(folders_created)))
|
||||
print("Configuration file:\n\t{0}".format(conf_file))
|
||||
print("\nYou'll need to edit your configuration file to specify the "
|
||||
"endpoint to test and any other configuration options you want.")
|
||||
print("\nBy default, syntribos does not ship with any template files, "
|
||||
"which are required for syntribos to run. However, we provide a\n "
|
||||
"'syntribos download' command to fetch template files remotely. "
|
||||
"Please see our documentation for this subcommand, or run\n "
|
||||
"'syntribos download --templates' to download our default set of "
|
||||
"OpenStack templates.")
|
||||
print(_("\nSyntribos has been initialized!"))
|
||||
print(
|
||||
_("Folders created:\n\t%s") % "\n\t".join(folders_created))
|
||||
print(_("Configuration file:\n\t%s") % conf_file)
|
||||
print(_(
|
||||
"\nYou'll need to edit your configuration file to specify the "
|
||||
"endpoint to test and any other configuration options you want."))
|
||||
print(_(
|
||||
"\nBy default, syntribos does not ship with any template files, "
|
||||
"which are required for syntribos to run. However, we provide a\n "
|
||||
"'syntribos download' command to fetch template files remotely. "
|
||||
"Please see our documentation for this subcommand, or run\n "
|
||||
"'syntribos download --templates' to download our default set of "
|
||||
"OpenStack templates."))
|
||||
print(syntribos.SEP)
|
||||
|
||||
|
||||
|
@ -302,29 +310,37 @@ def download_wrapper():
|
|||
os.path.join(get_syntribos_root(), "payloads"))
|
||||
|
||||
if not CONF.sub_command.templates and not CONF.sub_command.payloads:
|
||||
print("Please specify the --templates flag and/or the --payloads flag "
|
||||
"to this command.\nNo files have been downloaded.\n")
|
||||
print(
|
||||
_(
|
||||
"Please specify the --templates flag and/or the --payloads"
|
||||
"flag to this command.\nNo files have been downloaded.\n"))
|
||||
|
||||
if CONF.sub_command.templates:
|
||||
print("Downloading template files from {0} to {1}...".format(
|
||||
templates_uri, templates_dir))
|
||||
print(_(
|
||||
"Downloading template files from %(uri)s to %(dir)s..."
|
||||
) % {"uri": templates_uri, "dir": templates_dir})
|
||||
try:
|
||||
remotes.get(templates_uri, templates_dir)
|
||||
print("Download successful! To use these templates, edit your "
|
||||
"config file to update the location of templates.")
|
||||
print(_(
|
||||
"Download successful! To use these templates, edit your "
|
||||
"config file to update the location of templates."))
|
||||
except Exception:
|
||||
print("Template download failed. Our documentation contains "
|
||||
"instructions to provide templates manually.")
|
||||
print(_(
|
||||
"Template download failed. Our documentation contains "
|
||||
"instructions to provide templates manually."))
|
||||
exit(1)
|
||||
|
||||
if CONF.sub_command.payloads:
|
||||
print("Downloading payload files from {0} to {1}...\n".format(
|
||||
payloads_uri, payloads_dir))
|
||||
print(_(
|
||||
"Downloading payload files from %(uri)s to %(dir)s...\n") % {
|
||||
"uri": payloads_uri, "dir": payloads_dir})
|
||||
try:
|
||||
remotes.get(payloads_uri, payloads_dir)
|
||||
print("Download successful! To use these payloads, edit your "
|
||||
"config file to update the location of payloads.")
|
||||
print(_(
|
||||
"Download successful! To use these payloads, edit your "
|
||||
"config file to update the location of payloads."))
|
||||
except Exception:
|
||||
print("Payload download failed. Our documentation contains "
|
||||
"instructions to provide payloads manually.")
|
||||
print(_(
|
||||
"Payload download failed. Our documentation contains "
|
||||
"instructions to provide payloads manually."))
|
||||
exit(1)
|
||||
|
|
|
@ -20,6 +20,7 @@ import tempfile
|
|||
from oslo_config import cfg
|
||||
|
||||
from syntribos.clients.http.client import SynHTTPClient
|
||||
from syntribos._i18n import _LI, _LE, _LW # noqa
|
||||
|
||||
CONF = cfg.CONF
|
||||
LOG = logging.getLogger(__name__)
|
||||
|
@ -60,8 +61,7 @@ def download(uri, cache_dir=None):
|
|||
cache_dir = tempfile.mkdtemp()
|
||||
temp_dirs.append(cache_dir)
|
||||
remote_dirs.append(cache_dir)
|
||||
log_string = "Remote file location: {}".format(remote_dirs)
|
||||
LOG.debug(log_string)
|
||||
LOG.debug(_LI("Remote file location: %s") % remote_dirs)
|
||||
resp, _ = SynHTTPClient().request("GET", uri)
|
||||
os.chdir(cache_dir)
|
||||
saved_umask = os.umask(0o77)
|
||||
|
@ -71,7 +71,7 @@ def download(uri, cache_dir=None):
|
|||
fh.write(resp.content)
|
||||
return os.path.abspath(fname)
|
||||
except IOError:
|
||||
LOG.error("IOError in writing the downloaded file to disk.")
|
||||
LOG.error(_LE("IOError in writing the downloaded file to disk."))
|
||||
finally:
|
||||
os.umask(saved_umask)
|
||||
|
||||
|
@ -100,7 +100,8 @@ def extract_tar(abs_path):
|
|||
try:
|
||||
os.mkdir("remote")
|
||||
except OSError:
|
||||
LOG.debug("path exists already, not creating remote directory.")
|
||||
LOG.error(_LE(
|
||||
"path exists already, not creating remote directory."))
|
||||
remote_path = os.path.abspath("remote")
|
||||
|
||||
def safe_paths(tar_meta):
|
||||
|
@ -137,14 +138,14 @@ def get(uri, cache_dir=None):
|
|||
temp = tempfile.TemporaryFile(dir=os.path.abspath(user_base_dir))
|
||||
temp.close()
|
||||
except OSError:
|
||||
LOG.error("Failed to write remote files to: %s",
|
||||
LOG.error(_("Failed to write remote files to: %s") %
|
||||
os.path.abspath(user_base_dir))
|
||||
exit(1)
|
||||
abs_path = download(uri, os.path.abspath(user_base_dir))
|
||||
else:
|
||||
abs_path = download(uri)
|
||||
if not file_type(abs_path) == "gz":
|
||||
msg = "Not a gz file, returning abs_path"
|
||||
msg = _("Not a gz file, returning abs_path")
|
||||
LOG.debug(msg)
|
||||
return abs_path
|
||||
return extract_tar(abs_path)
|
||||
|
|
Loading…
Reference in New Issue