├── .gitignore ├── .pylintrc ├── .testing.pylintrc ├── ChangeLog.md ├── LICENSE ├── README.md ├── docs ├── Makefile ├── _static │ ├── favicon.ico │ └── salt-logo.pdf ├── _themes │ └── saltstack │ │ ├── layout.html │ │ ├── static │ │ ├── base-salt.css │ │ ├── css │ │ │ ├── bootstrap-responsive.css │ │ │ ├── bootstrap-responsive.min.css │ │ │ ├── bootstrap.css │ │ │ ├── bootstrap.min.css │ │ │ └── main.css │ │ ├── images │ │ │ ├── SaltStack-Logo.png │ │ │ ├── footerBG.jpg │ │ │ ├── socialFB.png │ │ │ ├── socialG+.png │ │ │ ├── socialGitHub.png │ │ │ ├── socialLI.png │ │ │ └── socialTW.png │ │ ├── img │ │ │ ├── carouselLeft.png │ │ │ ├── carouselRight.png │ │ │ ├── glyphicons-halflings-white.png │ │ │ ├── glyphicons-halflings.png │ │ │ └── navCurrentArrow.png │ │ └── js │ │ │ ├── main.js │ │ │ └── vendor │ │ │ ├── bootstrap.js │ │ │ ├── bootstrap.min.js │ │ │ ├── jquery-1.9.1.js │ │ │ ├── modernizr-2.6.2-respond-1.1.0.js │ │ │ └── modernizr-2.6.2-respond-1.1.0.min.js │ │ └── theme.conf ├── conf.py ├── images │ ├── RaetMetaphor.pdf │ ├── RaetMetaphor.png │ ├── RaetSaltAlphaArchitecture.pdf │ └── RaetSaltAlphaArchitecture.png ├── index.rst ├── make.bat └── topics │ ├── Salt_Raet.rst │ ├── examples_lane.py │ ├── examples_road.py │ ├── installation.rst │ ├── introduction.rst │ └── tutorial.rst ├── pkg ├── rpm │ └── python-raet.spec └── suse │ ├── python-raet.changes │ └── python-raet.spec ├── raet ├── __init__.py ├── __metadata__.py ├── abiding.py ├── encoding.py ├── flo │ ├── __init__.py │ ├── behaving.py │ ├── plan │ │ ├── lanetest.flo │ │ ├── managetest.flo │ │ ├── master.flo │ │ ├── masterminion1.flo │ │ ├── masterminion2.flo │ │ ├── minion.flo │ │ ├── minion1.flo │ │ ├── minion2.flo │ │ ├── roadtest.flo │ │ └── routetest.flo │ └── test │ │ ├── __init__.py │ │ └── test_behaving.py ├── keeping.py ├── lane │ ├── __init__.py │ ├── paging.py │ ├── stacking.py │ ├── test │ │ ├── __init__.py │ │ ├── test_paging.py │ │ └── test_stacking.py │ └── yarding.py ├── lotting.py ├── nacling.py ├── raeting.py ├── road │ ├── __init__.py │ ├── estating.py │ ├── keeping.py │ ├── packeting.py │ ├── stacking.py │ ├── test │ │ ├── __init__.py │ │ ├── test_estating.py │ │ ├── test_joining.py │ │ ├── test_keeping.py │ │ ├── test_messaging.py │ │ ├── test_packeting.py │ │ ├── test_presenting.py │ │ └── test_stacking.py │ └── transacting.py ├── stacking.py └── test │ ├── __init__.py │ ├── test_nacling.py │ └── test_template.py ├── scripts └── raetflo ├── setup.py └── systest ├── __init__.py ├── lib ├── __init__.py ├── data.py ├── mp_helper.py └── netem.py └── load ├── test_road_highload.py ├── test_road_network.py └── testing.py /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | *.DS_Store 3 | *~ 4 | */log/* 5 | */*/log/* 6 | */*/*/log/* 7 | dist/*/* 8 | dist 9 | dist/ 10 | raet.egg-info 11 | raet.egg-info/ 12 | raet.egg-info/* 13 | raet.egg-info/*.* 14 | raet.egg-info* 15 | raet.egg-info/PKG-INFO 16 | docs/_build 17 | .eggs 18 | .eggs/ 19 | .eggs/* 20 | .eggs/*.* 21 | -------------------------------------------------------------------------------- /.pylintrc: -------------------------------------------------------------------------------- 1 | [MASTER] 2 | 3 | # Specify a configuration file. 4 | #rcfile= 5 | 6 | # Python code to execute, usually for sys.path manipulation such as 7 | # pygtk.require(). 8 | init-hook=" 9 | exec 'aW1wb3J0IG9zLCBzeXMKCmlmICdWSVJUVUFMX0VOVicgaW4gb3MuZW52aXJvbjoKCiAgICB2ZV9k \ 10 | aXIgPSBvcy5lbnZpcm9uWydWSVJUVUFMX0VOViddCiAgICB2ZV9kaXIgaW4gc3lzLnBhdGggb3Ig \ 11 | c3lzLnBhdGguaW5zZXJ0KDAsIHZlX2RpcikKICAgIGFjdGl2YXRlX3RoaXMgPSBvcy5wYXRoLmpv \ 12 | aW4ob3MucGF0aC5qb2luKHZlX2RpciwgJ2JpbicpLCAnYWN0aXZhdGVfdGhpcy5weScpCgogICAg \ 13 | IyBGaXggZm9yIHdpbmRvd3MKICAgIGlmIG5vdCBvcy5wYXRoLmV4aXN0cyhhY3RpdmF0ZV90aGlz \ 14 | KToKICAgICAgICBhY3RpdmF0ZV90aGlzID0gb3MucGF0aC5qb2luKG9zLnBhdGguam9pbih2ZV9k \ 15 | aXIsICdTY3JpcHRzJyksICdhY3RpdmF0ZV90aGlzLnB5JykKCiAgICBleGVjZmlsZShhY3RpdmF0 \ 16 | ZV90aGlzLCBkaWN0KF9fZmlsZV9fPWFjdGl2YXRlX3RoaXMpKQo='.decode('base64')" 17 | 18 | 19 | # Profiled execution. 20 | profile=no 21 | 22 | # Add files or directories to the blacklist. They should be base names, not 23 | # paths. 24 | ignore=CVS 25 | 26 | # Pickle collected data for later comparisons. 27 | persistent=yes 28 | 29 | # List of plugins (as comma separated values of python modules names) to load, 30 | # usually to register additional checkers. 31 | load-plugins=salttesting.pylintplugins.pep8,salttesting.pylintplugins.pep263,salttesting.pylintplugins.strings 32 | 33 | 34 | [MESSAGES CONTROL] 35 | 36 | # Enable the message, report, category or checker with the given id(s). You can 37 | # either give multiple identifier separated by comma (,) or put this option 38 | # multiple time. See also the "--disable" option for examples. 39 | #enable= 40 | 41 | # Disable the message, report, category or checker with the given id(s). You 42 | # can either give multiple identifiers separated by comma (,) or put this 43 | # option multiple times (only on the command line, not in the configuration 44 | # file where it should appear only once).You can also use "--disable=all" to 45 | # disable everything first and then reenable specific checks. For example, if 46 | # you want to run only the similarities checker, you can use "--disable=all 47 | # --enable=similarities". If you want to run only the classes checker, but have 48 | # no Warning level messages displayed, use"--disable=all --enable=classes 49 | # --disable=W" 50 | disable=C0330 51 | 52 | # Disabled Checks 53 | # C0330 (bad-continuation) 54 | 55 | 56 | [REPORTS] 57 | 58 | # Set the output format. Available formats are text, parseable, colorized, msvs 59 | # (visual studio) and html. You can also give a reporter class, eg 60 | # mypackage.mymodule.MyReporterClass. 61 | output-format=text 62 | 63 | # Put messages in a separate file for each module / package specified on the 64 | # command line instead of printing them on stdout. Reports (if any) will be 65 | # written in a file name "pylint_global.[txt|html]". 66 | files-output=no 67 | 68 | # Tells whether to display a full report or only the messages 69 | reports=yes 70 | 71 | # Python expression which should return a note less than 10 (10 is the highest 72 | # note). You have access to the variables errors warning, statement which 73 | # respectively contain the number of errors / warnings messages and the total 74 | # number of statements analyzed. This is used by the global evaluation report 75 | # (RP0004). 76 | evaluation=10.0 - ((float(5 * error + warning + refactor + convention) / statement) * 10) 77 | 78 | # Add a comment according to your evaluation note. This is used by the global 79 | # evaluation report (RP0004). 80 | comment=no 81 | 82 | # Template used to display messages. This is a python new-style format string 83 | # used to format the message information. See doc for all details 84 | msg-template='{path}:{line}: [{msg_id}({symbol}), {obj}] {msg}' 85 | 86 | 87 | [VARIABLES] 88 | 89 | # Tells whether we should check for unused import in __init__ files. 90 | init-import=no 91 | 92 | # A regular expression matching the name of dummy variables (i.e. expectedly 93 | # not used). 94 | dummy-variables-rgx=_|dummy 95 | 96 | # List of additional names supposed to be defined in builtins. Remember that 97 | # you should avoid to define new builtins when possible. 98 | #additional-builtins= 99 | 100 | 101 | [FORMAT] 102 | 103 | # Maximum number of characters on a single line. 104 | max-line-length=100 105 | 106 | # Regexp for a line that is allowed to be longer than the limit. 107 | ignore-long-lines=^\s*(# )??$ 108 | 109 | # Allow the body of an if to be on the same line as the test if there is no 110 | # else. 111 | single-line-if-stmt=no 112 | 113 | # List of optional constructs for which whitespace checking is disabled 114 | #no-space-check=trailing-comma,dict-separator 115 | 116 | # Maximum number of lines in a module 117 | max-module-lines=3000 118 | 119 | # String used as indentation unit. This is usually " " (4 spaces) or "\t" (1 120 | # tab). 121 | indent-string=' ' 122 | 123 | # Number of spaces of indent required inside a hanging or continued line. 124 | indent-after-paren=4 125 | 126 | 127 | [LOGGING] 128 | 129 | # Logging modules to check that the string format arguments are in logging 130 | # function parameter format 131 | logging-modules=logging 132 | 133 | 134 | [TYPECHECK] 135 | 136 | # Tells whether missing members accessed in mixin class should be ignored. A 137 | # mixin class is detected if its name ends with "mixin" (case insensitive). 138 | ignore-mixin-members=yes 139 | 140 | # List of module names for which member attributes should not be checked 141 | # (useful for modules/projects where namespaces are manipulated during runtime 142 | # and thus extisting member attributes cannot be deduced by static analysis 143 | ignored-modules= 144 | 145 | # List of classes names for which member attributes should not be checked 146 | # (useful for classes with attributes dynamically set). 147 | ignored-classes=SQLObject 148 | 149 | # When zope mode is activated, add a predefined set of Zope acquired attributes 150 | # to generated-members. 151 | zope=no 152 | 153 | # List of members which are set dynamically and missed by pylint inference 154 | # system, and so shouldn't trigger E0201 when accessed. Python regular 155 | # expressions are accepted. 156 | generated-members=REQUEST,acl_users,aq_parent 157 | 158 | 159 | [MISCELLANEOUS] 160 | 161 | # List of note tags to take in consideration, separated by a comma. 162 | notes=FIXME,FIX,XXX,TODO 163 | 164 | 165 | [SIMILARITIES] 166 | 167 | # Minimum lines number of a similarity. 168 | min-similarity-lines=4 169 | 170 | # Ignore comments when computing similarities. 171 | ignore-comments=yes 172 | 173 | # Ignore docstrings when computing similarities. 174 | ignore-docstrings=yes 175 | 176 | # Ignore imports when computing similarities. 177 | ignore-imports=no 178 | 179 | 180 | [BASIC] 181 | 182 | # Required attributes for module, separated by a comma 183 | required-attributes= 184 | 185 | # List of builtins function names that should not be used, separated by a comma 186 | bad-functions=map,filter,apply,input 187 | 188 | # Good variable names which should always be accepted, separated by a comma 189 | #good-names=i,j,k,ex,Run,_,log 190 | good-names=pk,vk,sk,_,log,nacl 191 | 192 | # Bad variable names which should always be refused, separated by a comma 193 | bad-names=foo,bar,baz,toto,tutu,tata 194 | 195 | # Colon-delimited sets of names that determine each other's naming style when 196 | # the name regexes allow several styles. 197 | name-group= 198 | 199 | # Include a hint for the correct naming format with invalid-name 200 | include-naming-hint=no 201 | 202 | # Regular expression matching correct function names 203 | function-rgx=[a-z_][a-zA-Z0-9]{2,30}$ 204 | 205 | # Naming hint for function names 206 | function-name-hint=[a-z_][a-zA-Z0-9]{2,30}$ 207 | 208 | # Regular expression matching correct variable names 209 | variable-rgx=[a-z]([a-zA-Z0-9]|[a-z0-9_]){2,30}$ 210 | 211 | # Naming hint for variable names 212 | variable-name-hint=[a-z]([a-zA-Z0-9]|[a-z0-9_]){2,30}$ 213 | 214 | # Regular expression matching correct constant names 215 | const-rgx=((([A-Z_][A-Z0-9_]*|[a-z0-9_]*))|(__.*__))$ 216 | 217 | # Naming hint for constant names 218 | const-name-hint=((([A-Z_][A-Z0-9_]*|[a-z0-9_]*))|(__.*__))$ 219 | 220 | # Regular expression matching correct attribute names 221 | attr-rgx=[a-z_][a-z0-9_]{2,30}$ 222 | 223 | # Naming hint for attribute names 224 | attr-name-hint=[a-z_][a-z0-9_]{2,30}$ 225 | 226 | # Regular expression matching correct argument names 227 | argument-rgx=[a-z][a-zA-Z0-9]*$ 228 | 229 | # Naming hint for argument names 230 | argument-name-hint=[a-z][a-zA-Z0-9]{2,30}$ 231 | 232 | # Regular expression matching correct class attribute names 233 | class-attribute-rgx=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$ 234 | 235 | # Naming hint for class attribute names 236 | class-attribute-name-hint=([A-Za-z_][A-Za-z0-9_]{2,30}|(__.*__))$ 237 | 238 | # Regular expression matching correct inline iteration names 239 | inlinevar-rgx=[A-Za-z_][A-Za-z0-9_]*$ 240 | 241 | # Naming hint for inline iteration names 242 | inlinevar-name-hint=[A-Za-z_][A-Za-z0-9_]*$ 243 | 244 | # Regular expression matching correct class names 245 | class-rgx=[A-Z][a-zA-Z0-9]+$ 246 | 247 | # Naming hint for class names 248 | class-name-hint=[A-Z][a-zA-Z0-9]+$ 249 | 250 | # Regular expression matching correct module names 251 | module-rgx=(([a-z][a-z0-9]*)|([A-Z][a-zA-Z0-9]+))$ 252 | 253 | # Naming hint for module names 254 | module-name-hint=(([a-z][a-z0-9]*)|([A-Z][a-zA-Z0-9]+))$ 255 | 256 | # Regular expression matching correct method names 257 | method-rgx=[a-z_][a-zA-Z0-9]{2,30}$ 258 | 259 | # Naming hint for method names 260 | method-name-hint=[a-z_][a-zA-Z0-9]{2,30}$ 261 | 262 | # Regular expression which should only match function or class names that do 263 | # not require a docstring. 264 | no-docstring-rgx=__.*__ 265 | 266 | # Minimum line length for functions/classes that require docstrings, shorter 267 | # ones are exempt. 268 | docstring-min-length=-1 269 | 270 | 271 | [CLASSES] 272 | 273 | # List of interface methods to ignore, separated by a comma. This is used for 274 | # instance to not check methods defines in Zope's Interface base class. 275 | ignore-iface-methods=isImplementedBy,deferred,extends,names,namesAndDescriptions,queryDescriptionFor,getBases,getDescriptionFor,getDoc,getName,getTaggedValue,getTaggedValueTags,isEqualOrExtendedBy,setTaggedValue,isImplementedByInstancesOf,adaptWith,is_implemented_by 276 | 277 | # List of method names used to declare (i.e. assign) instance attributes. 278 | defining-attr-methods=__init__,__new__,setUp 279 | 280 | # List of valid names for the first argument in a class method. 281 | valid-classmethod-first-arg=cls 282 | 283 | # List of valid names for the first argument in a metaclass class method. 284 | valid-metaclass-classmethod-first-arg=mcs 285 | 286 | 287 | [IMPORTS] 288 | 289 | # Deprecated modules which should not be used, separated by a comma 290 | deprecated-modules=regsub,string,TERMIOS,Bastion,rexec 291 | 292 | # Create a graph of every (i.e. internal and external) dependencies in the 293 | # given file (report RP0402 must not be disabled) 294 | import-graph= 295 | 296 | # Create a graph of external dependencies in the given file (report RP0402 must 297 | # not be disabled) 298 | ext-import-graph= 299 | 300 | # Create a graph of internal dependencies in the given file (report RP0402 must 301 | # not be disabled) 302 | int-import-graph= 303 | 304 | 305 | [DESIGN] 306 | 307 | # Maximum number of arguments for function / method 308 | max-args=35 309 | 310 | # Argument names that match this expression will be ignored. Default to name 311 | # with leading underscore 312 | ignored-argument-names=_.* 313 | 314 | # Maximum number of locals for function / method body 315 | max-locals=40 316 | 317 | # Maximum number of return / yield for function / method body 318 | max-returns=6 319 | 320 | # Maximum number of branch for function / method body 321 | max-branches=12 322 | 323 | # Maximum number of statements in function / method body 324 | max-statements=100 325 | 326 | # Maximum number of parents for a class (see R0901). 327 | max-parents=7 328 | 329 | # Maximum number of attributes for a class (see R0902). 330 | max-attributes=7 331 | 332 | # Minimum number of public methods for a class (see R0903). 333 | min-public-methods=2 334 | 335 | # Maximum number of public methods for a class (see R0904). 336 | max-public-methods=20 337 | 338 | 339 | [EXCEPTIONS] 340 | 341 | # Exceptions that will emit a warning when being caught. Defaults to 342 | # "Exception" 343 | overgeneral-exceptions=Exception 344 | -------------------------------------------------------------------------------- /.testing.pylintrc: -------------------------------------------------------------------------------- 1 | [MASTER] 2 | 3 | # Specify a configuration file. 4 | rcfile=.pylintrc 5 | 6 | [MESSAGES CONTROL] 7 | 8 | # Disable the message, report, category or checker with the given id(s). You 9 | # can either give multiple identifiers separated by comma (,) or put this 10 | # option multiple times (only on the command line, not in the configuration 11 | # file where it should appear only once).You can also use "--disable=all" to 12 | # disable everything first and then reenable specific checks. For example, if 13 | # you want to run only the similarities checker, you can use "--disable=all 14 | # --enable=similarities". If you want to run only the classes checker, but have 15 | # no Warning level messages displayed, use"--disable=all --enable=classes 16 | # --disable=W" 17 | disable=R, 18 | I0011, 19 | I0013, 20 | E1101, 21 | E1103, 22 | C0102, 23 | C0103, 24 | C0111, 25 | C0203, 26 | C0204, 27 | C0301, 28 | C0302, 29 | C0330, 30 | W0110, 31 | W0122, 32 | W0142, 33 | W0201, 34 | W0212, 35 | W0404, 36 | W0511, 37 | W0603, 38 | W0612, 39 | W0613, 40 | W0621, 41 | W0622, 42 | W0631, 43 | W0704, 44 | F0220, 45 | F0401, 46 | E8501, 47 | E8121, 48 | E8122, 49 | E8123, 50 | E8124, 51 | E8125, 52 | E8126, 53 | E8127, 54 | E8128 55 | 56 | [REPORTS] 57 | 58 | # Tells whether to display a full report or only the messages 59 | reports=no 60 | 61 | # Set the output format. Available formats are text, parseable, colorized, msvs 62 | # (visual studio) and html 63 | # output-format=parseable 64 | msg-template='{path}:{line}: [{msg_id}({symbol}), {obj}] {msg}' 65 | 66 | # Put messages in a separate file for each module / package specified on the 67 | # command line instead of printing them on stdout. Reports (if any) will be 68 | # written in a file name "pylint_global.[txt|html]". 69 | files-output=no 70 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | RAET - The Reliable Asynchronous Event Transport 2 | 3 | Copyright 2015 Samuel M Smith 4 | Copyright 2014 SaltStack Team 5 | 6 | Licensed under the Apache License, Version 2.0 (the "License"); 7 | you may not use this files in this repository except in compliance with the License. 8 | You may obtain a copy of the License at 9 | 10 | http://www.apache.org/licenses/LICENSE-2.0 11 | 12 | Unless required by applicable law or agreed to in writing, software 13 | distributed under the License is distributed on an "AS IS" BASIS, 14 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 15 | See the License for the specific language governing permissions and 16 | limitations under the License. 17 | -------------------------------------------------------------------------------- /docs/Makefile: -------------------------------------------------------------------------------- 1 | # Makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line. 5 | SPHINXOPTS = 6 | SPHINXBUILD = sphinx-build 7 | PAPER = 8 | BUILDDIR = _build 9 | 10 | # User-friendly check for sphinx-build 11 | ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) 12 | $(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) 13 | endif 14 | 15 | # Internal variables. 16 | PAPEROPT_a4 = -D latex_paper_size=a4 17 | PAPEROPT_letter = -D latex_paper_size=letter 18 | ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . 19 | # the i18n builder cannot share the environment and doctrees with the others 20 | I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . 21 | 22 | .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext 23 | 24 | help: 25 | @echo "Please use \`make ' where is one of" 26 | @echo " html to make standalone HTML files" 27 | @echo " dirhtml to make HTML files named index.html in directories" 28 | @echo " singlehtml to make a single large HTML file" 29 | @echo " pickle to make pickle files" 30 | @echo " json to make JSON files" 31 | @echo " htmlhelp to make HTML files and a HTML help project" 32 | @echo " qthelp to make HTML files and a qthelp project" 33 | @echo " devhelp to make HTML files and a Devhelp project" 34 | @echo " epub to make an epub" 35 | @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" 36 | @echo " latexpdf to make LaTeX files and run them through pdflatex" 37 | @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" 38 | @echo " text to make text files" 39 | @echo " man to make manual pages" 40 | @echo " texinfo to make Texinfo files" 41 | @echo " info to make Texinfo files and run them through makeinfo" 42 | @echo " gettext to make PO message catalogs" 43 | @echo " changes to make an overview of all changed/added/deprecated items" 44 | @echo " xml to make Docutils-native XML files" 45 | @echo " pseudoxml to make pseudoxml-XML files for display purposes" 46 | @echo " linkcheck to check all external links for integrity" 47 | @echo " doctest to run all doctests embedded in the documentation (if enabled)" 48 | 49 | clean: 50 | rm -rf $(BUILDDIR)/* 51 | 52 | html: 53 | $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html 54 | @echo 55 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." 56 | 57 | dirhtml: 58 | $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml 59 | @echo 60 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." 61 | 62 | singlehtml: 63 | $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml 64 | @echo 65 | @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." 66 | 67 | pickle: 68 | $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle 69 | @echo 70 | @echo "Build finished; now you can process the pickle files." 71 | 72 | json: 73 | $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json 74 | @echo 75 | @echo "Build finished; now you can process the JSON files." 76 | 77 | htmlhelp: 78 | $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp 79 | @echo 80 | @echo "Build finished; now you can run HTML Help Workshop with the" \ 81 | ".hhp project file in $(BUILDDIR)/htmlhelp." 82 | 83 | qthelp: 84 | $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp 85 | @echo 86 | @echo "Build finished; now you can run "qcollectiongenerator" with the" \ 87 | ".qhcp project file in $(BUILDDIR)/qthelp, like this:" 88 | @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/Raet.qhcp" 89 | @echo "To view the help file:" 90 | @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/Raet.qhc" 91 | 92 | devhelp: 93 | $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp 94 | @echo 95 | @echo "Build finished." 96 | @echo "To view the help file:" 97 | @echo "# mkdir -p $$HOME/.local/share/devhelp/Raet" 98 | @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/Raet" 99 | @echo "# devhelp" 100 | 101 | epub: 102 | $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub 103 | @echo 104 | @echo "Build finished. The epub file is in $(BUILDDIR)/epub." 105 | 106 | latex: 107 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 108 | @echo 109 | @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." 110 | @echo "Run \`make' in that directory to run these through (pdf)latex" \ 111 | "(use \`make latexpdf' here to do that automatically)." 112 | 113 | latexpdf: 114 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 115 | @echo "Running LaTeX files through pdflatex..." 116 | $(MAKE) -C $(BUILDDIR)/latex all-pdf 117 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." 118 | 119 | latexpdfja: 120 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 121 | @echo "Running LaTeX files through platex and dvipdfmx..." 122 | $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja 123 | @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." 124 | 125 | text: 126 | $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text 127 | @echo 128 | @echo "Build finished. The text files are in $(BUILDDIR)/text." 129 | 130 | man: 131 | $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man 132 | @echo 133 | @echo "Build finished. The manual pages are in $(BUILDDIR)/man." 134 | 135 | texinfo: 136 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo 137 | @echo 138 | @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." 139 | @echo "Run \`make' in that directory to run these through makeinfo" \ 140 | "(use \`make info' here to do that automatically)." 141 | 142 | info: 143 | $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo 144 | @echo "Running Texinfo files through makeinfo..." 145 | make -C $(BUILDDIR)/texinfo info 146 | @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." 147 | 148 | gettext: 149 | $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale 150 | @echo 151 | @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." 152 | 153 | changes: 154 | $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes 155 | @echo 156 | @echo "The overview file is in $(BUILDDIR)/changes." 157 | 158 | linkcheck: 159 | $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck 160 | @echo 161 | @echo "Link check complete; look for any errors in the above output " \ 162 | "or in $(BUILDDIR)/linkcheck/output.txt." 163 | 164 | doctest: 165 | $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest 166 | @echo "Testing of doctests in the sources finished, look at the " \ 167 | "results in $(BUILDDIR)/doctest/output.txt." 168 | 169 | xml: 170 | $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml 171 | @echo 172 | @echo "Build finished. The XML files are in $(BUILDDIR)/xml." 173 | 174 | pseudoxml: 175 | $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml 176 | @echo 177 | @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." 178 | -------------------------------------------------------------------------------- /docs/_static/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RaetProtocol/raet/659c5615694ab0ed595e1e8354196f615086aeb8/docs/_static/favicon.ico -------------------------------------------------------------------------------- /docs/_static/salt-logo.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RaetProtocol/raet/659c5615694ab0ed595e1e8354196f615086aeb8/docs/_static/salt-logo.pdf -------------------------------------------------------------------------------- /docs/_themes/saltstack/layout.html: -------------------------------------------------------------------------------- 1 | {%- block doctype -%} 2 | 3 | {%- endblock %} 4 | 5 | {%- set reldelim1 = reldelim1 is not defined and ' »' or reldelim1 %} 6 | {%- set reldelim2 = reldelim2 is not defined and ' |' or reldelim2 %} 7 | {%- set render_sidebar = (not embedded) and (not theme_nosidebar|tobool) and (sidebars != []) %} 8 | {%- set url_root = pathto('', 1) %} 9 | {# XXX necessary? #} 10 | {%- if url_root == '#' %}{% set url_root = '' %}{% endif %} 11 | {%- if not embedded and docstitle %} 12 | {%- set titlesuffix = " — "|safe + docstitle|e %} 13 | {%- else %} 14 | {%- set titlesuffix = "" %} 15 | {%- endif %} 16 | 17 | {# Remove old version of jQuery #} 18 | {% set js_blacklist = [ 19 | '_static/jquery.js', 20 | ] %} 21 | 22 | {# Add to top of the list #} 23 | {% set script_files = [ 24 | '_static/js/vendor/jquery-1.9.1.js', 25 | '_static/js/vendor/bootstrap.min.js', 26 | ] + script_files %} 27 | 28 | {%- macro relbar() %} 29 | 51 | {%- endmacro %} 52 | 53 | {%- macro sidebar() %} 54 | {%- if render_sidebar %} 55 |
56 |
57 | {%- block sidebarlogo %}{%- endblock %} 58 | 59 | {%- for sidebartemplate in sidebars|default(html_default_sidebars, true) %} 60 | {%- include sidebartemplate %} 61 | {%- endfor %} 62 |
63 |
64 | {%- endif %} 65 | {%- endmacro %} 66 | 67 | {%- macro script() %} 68 | 77 | {%- for scriptfile in script_files %} 78 | {% if scriptfile not in js_blacklist %} 79 | 80 | {% endif %} 81 | {%- endfor %} 82 | {%- endmacro %} 83 | 84 | {%- macro css() %} 85 | {% if style %} 86 | 87 | {% endif %} 88 | 89 | 90 | 91 | 92 | 95 | 96 | 97 | {%- endmacro %} 98 | 99 | 100 | 101 | 102 | 103 | 104 | 105 | {{ metatags }} 106 | 107 | 108 | {%- block htmltitle %} 109 | {{ title|striptags|e }}{{ titlesuffix }} 110 | {%- endblock %} 111 | 112 | 113 | 114 | 115 | 116 | {{ css() }} 117 | 118 | {%- if not embedded %} 119 | {{ script() }} 120 | {%- if use_opensearch %} 121 | 124 | {%- endif %} 125 | 126 | {%- if favicon %} 127 | 128 | {%- endif %} 129 | {%- endif %} 130 | 131 | {%- block linktags %} 132 | {%- if hasdoc('about') %} 133 | 134 | {%- endif %} 135 | {%- if hasdoc('genindex') %} 136 | 137 | {%- endif %} 138 | {%- if hasdoc('search') %} 139 | 140 | {%- endif %} 141 | {%- if hasdoc('copyright') %} 142 | 143 | {%- endif %} 144 | 145 | {%- if parents %} 146 | 147 | {%- endif %} 148 | {%- if next %} 149 | 150 | {%- endif %} 151 | {%- if prev %} 152 | 153 | {%- endif %} 154 | {%- endblock %} 155 | 156 | {%- block extrahead %} {% endblock %} 157 | 158 | 159 | 160 | {%- block analytics %} 161 | {% endblock %} 162 | 163 | 164 | 165 | 168 | 169 | 170 | 171 | {% block header %} 172 | 187 | {% endblock %} 188 | 189 | 190 | {%- block content %} 191 | 192 | {%- block sidebar1 %}{% endblock %} 193 | 194 |
195 |
196 |
197 |
198 | {%- block document %} 199 | {% block body %} {% endblock %} 200 | {%- endblock %} 201 |
202 | 203 | {%- block sidebar2 %}{{ sidebar() }}{% endblock %} 204 |
205 |
206 |
207 | {%- endblock %} 208 | 209 | {%- block relbar2 %} 210 | 213 | {% endblock %} 214 | 215 | {%- block footer %} 216 | 255 | {%- endblock %} 256 | 257 | 258 | 259 | 265 | 266 | 267 | -------------------------------------------------------------------------------- /docs/_themes/saltstack/static/base-salt.css: -------------------------------------------------------------------------------- 1 | body { 2 | background-color: #eeeeec; 3 | font-size: 100%; line-height: 1.25; text-align: center; } 4 | 5 | .container { 6 | background-color: #fff; 7 | width: 60.5em; min-height: 57.25em; 8 | text-align: left; margin: 0 auto; } 9 | 10 | .content { 11 | margin-bottom: 5em; 12 | text-align: justify; display: inline-block; } 13 | 14 | .document { 15 | float: left; 16 | width: 36.8em; margin-right: 2.5em; } 17 | 18 | .document a, .footer a { 19 | text-decoration: underline; } 20 | 21 | .sidebar { 22 | float: left; width: 18em; 23 | text-align: left; } 24 | 25 | .related { overflow: hidden; } 26 | 27 | .related h3 { 28 | font-size: 1px; text-indent: -9999999em; } 29 | 30 | .related ul { margin: 0; } 31 | 32 | .related li { 33 | display: inline; list-style-type: none; } 34 | 35 | .rel-main { float: left; } 36 | .rel-extra { float: right; } 37 | 38 | .header, 39 | .related, 40 | .content, 41 | .footer { 42 | margin-left: 1.5em; margin-right: 1.5em; } 43 | 44 | .header { 45 | border-bottom: 3px solid #2e3436; } 46 | 47 | .header h1 { margin: 0; } 48 | 49 | .footer { 50 | padding-top: 2em; text-align: right; 51 | border-top: 4px solid #babdb6; } 52 | 53 | /* 54 | * http://lamb.cc/typograph/ 55 | */ 56 | 57 | h1, h2, h3, h4 { 58 | color: #3465a4; font-family: georgia; font-weight: normal; } 59 | 60 | h1 { font-size: 1.75em; margin: 1.51786em 0; color: #204a87; } 61 | h2 { 62 | border-bottom: 1px solid #3465a4; 63 | font-size: 1.5em; margin: 1.45833em 0; } 64 | h3 { font-size: 1.33333em; margin: 1.25em 0; } 65 | h4 { font-size: 1.16667em; margin: 1.51786em 0; } 66 | 67 | a { 68 | color: #ce5c00; } 69 | 70 | .headerlink { 71 | visibility: hidden; color: #dddddd; padding-left: .3em; } 72 | 73 | h1:hover > .headerlink, 74 | h2:hover > .headerlink, 75 | h3:hover > .headerlink, 76 | h4:hover > .headerlink, 77 | h5:hover > .headerlink, 78 | h6:hover > .headerlink, 79 | dt:hover > .headerlink { visibility: visible; } 80 | 81 | img { 82 | border: 0; } 83 | 84 | dt:target, .highlighted { 85 | background-color: #fbe54e; } 86 | 87 | /* 88 | * http://www.blueprintcss.org/ 89 | */ 90 | 91 | .small { font-size: .8em; margin-bottom: 1.875em; line-height: 1.875em; } 92 | .large { font-size: 1.2em; line-height: 2.5em; margin-bottom: 1.25em; } 93 | .hide { display: none; } 94 | 95 | .quiet { color: #666; } 96 | .loud { color: #000; } 97 | .highlight { background: #ff0; } 98 | .added { background: #060; color: #fff; } 99 | .removed { background: #900; color: #fff; } 100 | 101 | .first { margin-left: 0; padding-left: 0; } 102 | .last { margin-right: 0; padding-right: 0; } 103 | .top { margin-top: 0; padding-top: 0; } 104 | .bottom { margin-bottom: 0; padding-bottom: 0; } 105 | 106 | /* 107 | * 108 | */ 109 | 110 | .doc-link, 111 | .feat-link { 112 | margin-left: 0; text-align: left; } 113 | 114 | .doc-link dd, 115 | .feat-link dd { 116 | margin-left: 0; font-style: italic; } 117 | 118 | .feat-link dt { 119 | color: #3465a4; font-weight: bold; } 120 | 121 | .doc-link { 122 | width: 44%; height: 6em; float: left; 123 | margin-right: 2em; } 124 | 125 | /* 126 | * 127 | */ 128 | 129 | .sidebar .toctree-l1.current a { 130 | border-right: 5px solid #fcaf3e; } 131 | 132 | .line-block { 133 | display: block; 134 | margin-top: 1em; 135 | margin-bottom: 1em; 136 | } 137 | 138 | .line-block .line-block { 139 | margin-top: 0; 140 | margin-bottom: 0; 141 | margin-left: 1.5em; 142 | } 143 | 144 | div.header div.rel a { 145 | color: #fcaf3e; 146 | letter-spacing: .1em; 147 | text-transform: uppercase; 148 | } 149 | 150 | .highlight { 151 | padding: 3px; 152 | background-color: #eeeeec; 153 | border-top: 2px solid #dddddd; 154 | border-bottom: 2px solid #dddddd; 155 | margin-top: .8em; 156 | margin-bottom: .8em; 157 | } 158 | 159 | .descname { 160 | font-weight: bold; } 161 | 162 | .literal { 163 | background-color: #eeeeec; } 164 | 165 | blockquote { 166 | margin: 1em; } 167 | 168 | .footer, .footer a { 169 | color: #888a85; } 170 | 171 | div.admonition { 172 | font-size: 0.9em; 173 | margin: 1em 0 1em 0; 174 | padding: 0.5em 1em 0.5em 1em; 175 | border: 1px solid #ddd; } 176 | 177 | div.admonition p.admonition-title { 178 | font-weight: bold; color: #3465a4; } 179 | 180 | div.warning { 181 | border-color: #940000; } 182 | 183 | div.warning p.admonition-title { 184 | color: #940000; } 185 | 186 | div.viewcode-block:target { 187 | background-color: #f4debf; 188 | border-top: 1px solid #ac9; 189 | border-bottom: 1px solid #ac9; 190 | } 191 | 192 | /* Styles copied from basic theme */ 193 | 194 | img.align-left, .figure.align-left, object.align-left { 195 | clear: left; float: left; margin-right: 1em; } 196 | 197 | img.align-right, .figure.align-right, object.align-right { 198 | clear: right; float: right; margin-left: 1em; } 199 | 200 | img.align-center, .figure.align-center, object.align-center { 201 | display: block; margin-left: auto; margin-right: auto; } 202 | 203 | .align-left { text-align: left; } 204 | .align-center { text-align: center; } 205 | .align-right { text-align: right; } 206 | 207 | ul.keywordmatches li.goodmatch a { 208 | font-weight: bold; } 209 | 210 | /* -- index page ------------------------------------------------------------ */ 211 | 212 | table.contentstable { 213 | width: 90%; 214 | } 215 | 216 | table.contentstable p.biglink { 217 | line-height: 150%; 218 | } 219 | 220 | a.biglink { 221 | font-size: 1.3em; 222 | } 223 | 224 | span.linkdescr { 225 | font-style: italic; 226 | padding-top: 5px; 227 | font-size: 90%; 228 | } 229 | 230 | /* -- general index --------------------------------------------------------- */ 231 | 232 | table.indextable td { 233 | text-align: left; 234 | vertical-align: top; 235 | } 236 | 237 | table.indextable dl, table.indextable dd { 238 | margin-top: 0; 239 | margin-bottom: 0; 240 | } 241 | 242 | table.indextable tr.pcap { 243 | height: 10px; 244 | } 245 | 246 | table.indextable tr.cap { 247 | margin-top: 10px; 248 | background-color: #f2f2f2; 249 | } 250 | 251 | img.toggler { 252 | margin-right: 3px; 253 | margin-top: 3px; 254 | cursor: pointer; 255 | } 256 | 257 | /* -- viewcode extension ---------------------------------------------------- */ 258 | 259 | .viewcode-link { 260 | float: right; 261 | } 262 | 263 | .viewcode-back { 264 | float: right; 265 | } 266 | 267 | div.viewcode-block:target { 268 | margin: -1px -3px; 269 | padding: 0 3px; 270 | background-color: #f4debf; 271 | border-top: 1px solid #ac9; 272 | border-bottom: 1px solid #ac9; 273 | } 274 | -------------------------------------------------------------------------------- /docs/_themes/saltstack/static/css/main.css: -------------------------------------------------------------------------------- 1 | 2 | 3 | /* ========================================================================== 4 | Author's custom styles 5 | ========================================================================== */ 6 | html, body, div, span, applet, object, iframe, h1, h2, h3, h4, h5, h6, p, blockquote, pre, a, abbr, acronym, address, big, cite, code, del, dfn, em, font, img, ins, kbd, q, s, samp, small, strike, strong, sub, sup, tt, var, b, u, i, center, dl, dt, dd, ol, ul, li, fieldset, form, label, legend, table, caption, tbody, tfoot, thead, tr, th, td { 7 | -webkit-transition: all 0.2s ease; 8 | -moz-transition: all 0.2s ease; 9 | -ms-transition: all 0.2s ease; 10 | -o-transition: all 0.2s ease; 11 | transition: all 0.2s ease; 12 | } 13 | .navbar .nav { 14 | float:right; 15 | margin: 0; 16 | padding-top: 18px; 17 | } 18 | .navbar-inverse .brand, .navbar-inverse .nav > li > a { 19 | color: #484c51; 20 | font: 14px/24px 'Open Sans Light'; 21 | } 22 | .navbar .nav li.currentNav { 23 | background: url(../img/navCurrentArrow.png) center 32px no-repeat; 24 | } 25 | .hero-unit { 26 | margin-bottom: 0; 27 | } 28 | .shaded { 29 | background: #f7f9f8; 30 | } 31 | .shaded img { 32 | margin: 8px 12px; 33 | } 34 | .articleCredits { 35 | padding-left: 12px; 36 | font: 12px/24px 'Open Sans Light'; 37 | white-space: pre; 38 | } 39 | .fullwidth { 40 | padding: 30px; 41 | } 42 | body.contact .shaded img { 43 | margin: 0; 44 | } 45 | .map img { 46 | margin-top: 30px; 47 | float: left; 48 | } 49 | body.index .success, body.index .clients { 50 | margin-top: 0; 51 | } 52 | .success h2 { 53 | margin-top: 25px; 54 | } 55 | .testimonialAuthor { 56 | display: block; 57 | margin-bottom: 30px; 58 | font: 12px/24px 'Open Sans Extrabold'; 59 | color: #aa2b39; 60 | text-transform: uppercase; 61 | } 62 | .success hr, .events hr, .productnews hr { 63 | margin-top: 0; 64 | } 65 | .clients { 66 | background-color: #415a72; 67 | } 68 | .clients img { 69 | margin: 15px 21px; 70 | } 71 | .news { 72 | margin-bottom: 40px; 73 | } 74 | h2.homeSecTitles { 75 | color: #8d9caa; 76 | font-family: 'Open Sans Extrabold Italic'; 77 | text-transform: capitalize; 78 | margin-bottom: 0; 79 | } 80 | .success h3 { 81 | font: 18px/30px 'Open Sans Light Italic'; color: #4f575b; margin: 25px 0; 82 | } 83 | .success img { 84 | margin: 30px 10px 10px 80px; 85 | } 86 | .about img { 87 | margin-bottom: 21px; 88 | } 89 | .carousel-inner { 90 | max-height: 387px; 91 | } 92 | .carousel-control { 93 | opacity: 1; 94 | background: none; 95 | border: none; 96 | border-radius: 0; 97 | } 98 | .carousel-caption h1 { 99 | text-transform:uppercase; 100 | margin-top: 20px; 101 | display:none; 102 | } 103 | .carousel-caption p { 104 | margin-top: 25px; 105 | font: 16px/24px 'Open Sans Light'; 106 | color: #000; 107 | display: none; 108 | } 109 | .carousel-caption img { 110 | margin-top: 10px; 111 | } 112 | #myCarousel img { 113 | width: 100%; 114 | height: auto; 115 | } 116 | #myCarousel .carousel-control img { 117 | width: auto; 118 | } 119 | 120 | h1, h2, h3, h4, h5, h6 { 121 | font-family: 'Open Sans Light'; 122 | font-weight: normal; 123 | } 124 | 125 | h2 { 126 | font: 18px/28px 'Open Sans Extrabold'; 127 | text-transform: uppercase; 128 | color: #373e4b; 129 | margin-bottom: 0; 130 | } 131 | h3 { 132 | font-size: 16px; line-height:26px; 133 | } 134 | p { 135 | font-size: 14px; line-height: 24px; color: #313131; 136 | } 137 | .lede { 138 | text-align: center; 139 | margin-bottom:20px; 140 | max-width: 80%; 141 | margin-left: 10%; 142 | } 143 | body.services .lede { 144 | max-width: 95%; 145 | margin-left: 2.5%; 146 | margin-top: 30px; 147 | } 148 | body.products .lede { 149 | margin-top: 30px; 150 | } 151 | .lede h3 { 152 | font: 24px/30px 'Open Sans Light'; 153 | color: #aa2b39; 154 | } 155 | .lede h4 { 156 | font: 20px/30px 'Open Sans Light Italic'; 157 | color: #373e4b; 158 | } 159 | body.services .lede h4 { 160 | font-size: 16px; 161 | line-height: 150%; 162 | } 163 | body.services .lede { 164 | margin-bottom: 30px; 165 | } 166 | body.about h1, body.services h1, body.contact h1 { 167 | font: 20px/30px 'Open Sans Extrabold Italic'; 168 | color: #4f575b; 169 | margin-top: 0; 170 | } 171 | .row-fluid { 172 | margin-top: 50px; 173 | } 174 | body.about h6 { 175 | margin: 0; 176 | font-family: 'Open Sans Light Italic'; 177 | text-transform: uppercase; 178 | line-height: 80%; 179 | margin-bottom: 10px; 180 | color: #AA2B39; 181 | } 182 | body.services table { 183 | margin: 0; 184 | padding: 0; 185 | table-layout: fixed; 186 | } 187 | body.services table th, body.services table td { 188 | padding: 10px 0; 189 | text-align: left; 190 | } 191 | body.services table td { 192 | color: #373e4b; 193 | font-family: 'Open Sans Light Italic'; 194 | width: 206px; 195 | } 196 | body.services table tr:last-child th, body.services table tr:last-child td { 197 | border-bottom: none; 198 | } 199 | body.services table tr:nth-child(even) { 200 | background: #eff3f1; 201 | } 202 | body.services table td:first-child { 203 | padding-left: 30px; 204 | } 205 | body.services table td.tableCenter { 206 | text-align: center; 207 | } 208 | .singleProduct ul { 209 | margin-left: 15px; 210 | } 211 | .singleProduct li { 212 | padding: 5px 0; 213 | } 214 | .btn-red { 215 | display:block; 216 | padding: 5px 0; 217 | background: #aa2b39; 218 | color: #FFF; 219 | font-family: 'Open Sans Light'; 220 | text-shadow: none; 221 | font-weight: normal; 222 | border: none; 223 | border-radius: 0; 224 | box-shadow: none; 225 | width: 100px; 226 | margin-left: 75px; 227 | } 228 | .btn-red:hover, .bth-red:focus { 229 | background-color: #9B1C2E; 230 | color: white; 231 | } 232 | body.contact .btn-red { 233 | margin-left: 0; margin-top: 5px; 234 | } 235 | #myCarousel .btn-red { 236 | margin-left: 12px; margin-top:-7px; 237 | } 238 | .map { 239 | border: 0; border-right: 1px solid #eee; 240 | } 241 | .map h2, .connect h2 { 242 | margin: 0; 243 | } 244 | .map img { 245 | padding-right: 30px; 246 | } 247 | .connect a { 248 | margin: 0 8px 0 0; display: block; float: left; 249 | } 250 | .connect a img:hover { 251 | margin-top: -5px; 252 | -webkit-transition: margin 0.2s ease-out; 253 | -moz-transition: margin 0.2s ease-out; 254 | -o-transition: margin 0.2s ease-out; 255 | transition: margin 0.2s ease-out; 256 | } 257 | 258 | footer { 259 | background: url(../images/footerBG.jpg) 50% 0 no-repeat; 260 | min-height: 340px; 261 | margin-top: 50px; 262 | position:relative; 263 | -webkit-background-size: cover; /*for webKit*/ 264 | -moz-background-size: cover; /*Mozilla*/ 265 | -o-background-size: cover; /*opera*/ 266 | background-size: cover; /*generic*/ 267 | } 268 | footer p, footer a { 269 | color: #FFF; 270 | font: 12px 'Open Sans Light'; 271 | } 272 | footer a { 273 | display:block; 274 | float: left; 275 | margin: 0 0 6px 0; 276 | clear: left; 277 | } 278 | footer .row-fluid { 279 | margin-top: 30px; 280 | } 281 | .footerCol { 282 | width: 20%; 283 | float:left; 284 | } 285 | .footerCol h4 { 286 | color: #FFF; 287 | font: 14px/24px 'Open Sans Extrabold'; 288 | text-transform: uppercase; 289 | margin-bottom: 0; 290 | } 291 | footer .social a { 292 | clear: none; 293 | margin: 0 4px; 294 | } 295 | footer .social img:hover { 296 | margin-top: -5px; 297 | -webkit-transition: margin 0.2s ease-out; 298 | -moz-transition: margin 0.2s ease-out; 299 | -o-transition: margin 0.2s ease-out; 300 | transition: margin 0.2s ease-out; 301 | } 302 | body.contact footer, body.index footer { 303 | margin-top: 0; 304 | } 305 | .news img { 306 | max-width: 275px; 307 | height: auto; 308 | } 309 | .news h2, .news p, .events hr { 310 | max-width: 275px; 311 | } 312 | .productnews hr { 313 | max-width: 595px; 314 | } 315 | 316 | /* ========================================================================== 317 | Sphinx custom styles 318 | ========================================================================== */ 319 | 320 | h1:hover > .headerlink, 321 | h2:hover > .headerlink, 322 | h3:hover > .headerlink, 323 | h4:hover > .headerlink, 324 | h5:hover > .headerlink, 325 | h6:hover > .headerlink, 326 | dt:hover > .headerlink { visibility: visible; } 327 | 328 | .sidebar .toctree-l1.current a { 329 | border-right: 5px solid #fcaf3e; } 330 | 331 | .line-block { 332 | display: block; 333 | margin-top: 1em; 334 | margin-bottom: 1em; 335 | } 336 | 337 | .line-block .line-block { 338 | margin-top: 0; 339 | margin-bottom: 0; 340 | margin-left: 1.5em; 341 | } 342 | 343 | div.header div.rel a { 344 | color: #fcaf3e; 345 | letter-spacing: .1em; 346 | text-transform: uppercase; 347 | } 348 | 349 | .descname { 350 | font-weight: bold; } 351 | 352 | .literal { 353 | background-color: #eeeeec; } 354 | 355 | blockquote { 356 | margin: 1em; } 357 | 358 | .footer, .footer a { 359 | color: #888a85; } 360 | 361 | div.admonition { 362 | font-size: 0.9em; 363 | margin: 1em 0 1em 0; 364 | padding: 0.5em 1em 0.5em 1em; 365 | border: 1px solid #ddd; } 366 | 367 | div.admonition p.admonition-title { 368 | font-weight: bold; color: #3465a4; } 369 | 370 | div.warning { 371 | border-color: #940000; } 372 | 373 | div.warning p.admonition-title { 374 | color: #940000; } 375 | 376 | div.viewcode-block:target { 377 | background-color: #f4debf; 378 | border-top: 1px solid #ac9; 379 | border-bottom: 1px solid #ac9; 380 | } 381 | 382 | /* ========================================================================== 383 | SaltStack custom styles 384 | ========================================================================== */ 385 | 386 | .lit-docs { 387 | list-style-type: none; 388 | margin: 0; 389 | } 390 | 391 | .lit-item { 392 | padding-bottom: 2em; 393 | } 394 | 395 | .lit-annotation, 396 | .lit-content { 397 | display: inline-block; 398 | vertical-align: top; 399 | } 400 | 401 | .lit-annotation { 402 | width: 40.42553191489362%; /* span-5 */ 403 | } 404 | 405 | .lit-content { 406 | width: 57.44680851063829%; /* span-7 */ 407 | } 408 | 409 | /* Override a few Bootstrap-isms */ 410 | .lit-annotation pre, 411 | .lit-content pre { 412 | word-break: normal; 413 | word-wrap: normal; 414 | white-space: pre; 415 | overflow-x: auto; 416 | } 417 | 418 | .lit-content pre { 419 | border: none; 420 | } 421 | 422 | .lit-container { 423 | position: relative; 424 | } 425 | 426 | .lit-background { 427 | position: absolute; 428 | top: -1px; 429 | bottom: 0; 430 | right: 1.1em; 431 | width: 57.44680851063829%; /* span-7 */ 432 | 433 | z-index: -1; 434 | background-color: #f5f5f5; 435 | 436 | border: 1px solid #e5e5ee; 437 | border: 1px solid rgba(0, 0, 0, 0.15); 438 | -webkit-border-radius: 4px; 439 | -moz-border-radius: 4px; 440 | border-radius: 4px; 441 | } 442 | -------------------------------------------------------------------------------- /docs/_themes/saltstack/static/images/SaltStack-Logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RaetProtocol/raet/659c5615694ab0ed595e1e8354196f615086aeb8/docs/_themes/saltstack/static/images/SaltStack-Logo.png -------------------------------------------------------------------------------- /docs/_themes/saltstack/static/images/footerBG.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RaetProtocol/raet/659c5615694ab0ed595e1e8354196f615086aeb8/docs/_themes/saltstack/static/images/footerBG.jpg -------------------------------------------------------------------------------- /docs/_themes/saltstack/static/images/socialFB.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RaetProtocol/raet/659c5615694ab0ed595e1e8354196f615086aeb8/docs/_themes/saltstack/static/images/socialFB.png -------------------------------------------------------------------------------- /docs/_themes/saltstack/static/images/socialG+.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RaetProtocol/raet/659c5615694ab0ed595e1e8354196f615086aeb8/docs/_themes/saltstack/static/images/socialG+.png -------------------------------------------------------------------------------- /docs/_themes/saltstack/static/images/socialGitHub.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RaetProtocol/raet/659c5615694ab0ed595e1e8354196f615086aeb8/docs/_themes/saltstack/static/images/socialGitHub.png -------------------------------------------------------------------------------- /docs/_themes/saltstack/static/images/socialLI.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RaetProtocol/raet/659c5615694ab0ed595e1e8354196f615086aeb8/docs/_themes/saltstack/static/images/socialLI.png -------------------------------------------------------------------------------- /docs/_themes/saltstack/static/images/socialTW.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RaetProtocol/raet/659c5615694ab0ed595e1e8354196f615086aeb8/docs/_themes/saltstack/static/images/socialTW.png -------------------------------------------------------------------------------- /docs/_themes/saltstack/static/img/carouselLeft.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RaetProtocol/raet/659c5615694ab0ed595e1e8354196f615086aeb8/docs/_themes/saltstack/static/img/carouselLeft.png -------------------------------------------------------------------------------- /docs/_themes/saltstack/static/img/carouselRight.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RaetProtocol/raet/659c5615694ab0ed595e1e8354196f615086aeb8/docs/_themes/saltstack/static/img/carouselRight.png -------------------------------------------------------------------------------- /docs/_themes/saltstack/static/img/glyphicons-halflings-white.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RaetProtocol/raet/659c5615694ab0ed595e1e8354196f615086aeb8/docs/_themes/saltstack/static/img/glyphicons-halflings-white.png -------------------------------------------------------------------------------- /docs/_themes/saltstack/static/img/glyphicons-halflings.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RaetProtocol/raet/659c5615694ab0ed595e1e8354196f615086aeb8/docs/_themes/saltstack/static/img/glyphicons-halflings.png -------------------------------------------------------------------------------- /docs/_themes/saltstack/static/img/navCurrentArrow.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RaetProtocol/raet/659c5615694ab0ed595e1e8354196f615086aeb8/docs/_themes/saltstack/static/img/navCurrentArrow.png -------------------------------------------------------------------------------- /docs/_themes/saltstack/static/js/main.js: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /docs/_themes/saltstack/theme.conf: -------------------------------------------------------------------------------- 1 | [theme] 2 | inherit = default 3 | stylesheet = css/main.css 4 | -------------------------------------------------------------------------------- /docs/conf.py: -------------------------------------------------------------------------------- 1 | # coding: utf-8 2 | # pylint: disable=C0103,W0622 3 | ''' 4 | Sphinx documentation for Raet 5 | ''' 6 | import sys 7 | import os 8 | 9 | from sphinx.directives import TocTree 10 | 11 | # pylint: disable=R0903 12 | class Mock(object): 13 | ''' 14 | Mock out specified imports 15 | 16 | This allows autodoc to do it's thing without having oodles of req'd 17 | installed libs. This doesn't work with ``import *`` imports. 18 | 19 | http://read-the-docs.readthedocs.org/en/latest/faq.html#i-get-import-errors-on-libraries-that-depend-on-c-modules 20 | ''' 21 | def __init__(self, *args, **kwargs): 22 | pass 23 | 24 | def __call__(self, *args, **kwargs): 25 | return Mock() 26 | 27 | @classmethod 28 | def __getattr__(self, name): 29 | if name in ('__file__', '__path__'): 30 | return '/dev/null' 31 | else: 32 | return Mock() 33 | # pylint: enable=R0903 34 | 35 | MOCK_MODULES = [ 36 | 'importlib', 37 | ] 38 | 39 | for mod_name in MOCK_MODULES: 40 | sys.modules[mod_name] = Mock() 41 | 42 | ### Add a few directories to the Python path 43 | try: 44 | docs_basepath = os.path.abspath(os.path.dirname(__file__)) 45 | except NameError: 46 | # sphinx-intl and six execute some code which will raise this NameError 47 | # assume we're in the doc/ directory 48 | docs_basepath = os.path.abspath(os.path.dirname('.')) 49 | 50 | addtl_paths = ( 51 | os.pardir, # raet itself (for autodoc) 52 | '_ext', # custom Sphinx extensions 53 | ) 54 | 55 | for path in addtl_paths: 56 | sys.path.insert(0, os.path.abspath(os.path.join(docs_basepath, path))) 57 | 58 | # We're now able to import raet 59 | from raet import __version__ 60 | 61 | project = 'Raet' 62 | document_title = 'Raet Documentation' 63 | copyright = '2014 SaltStack, Inc.' 64 | author = ['SaltStack, Inc.'] 65 | 66 | master_doc = 'index' 67 | 68 | version = __version__ 69 | release = version 70 | 71 | language = 'en' 72 | locale_dirs = [ 73 | '_locale', 74 | ] 75 | gettext_compact = False 76 | 77 | extensions = [ 78 | 'sphinx.ext.autodoc', 79 | 'sphinx.ext.autosummary', 80 | 'sphinx.ext.intersphinx', 81 | ] 82 | 83 | intersphinx_mapping = { 84 | 'salt': ('http://docs.saltstack.com/en/latest/', None), 85 | } 86 | 87 | 88 | ### HTML options 89 | html_theme = 'saltstack' 90 | html_theme_path = ['_themes'] 91 | html_title = None 92 | html_short_title = project 93 | 94 | html_static_path = ['_static'] 95 | html_logo = None # specfied in the theme layout.html 96 | html_favicon = 'favicon.ico' 97 | html_use_smartypants = False 98 | 99 | html_default_sidebars = [ 100 | 'localtoc.html', 101 | 'relations.html', 102 | 'sourcelink.html', 103 | 'searchbox.html', 104 | ] 105 | 106 | html_context = { 107 | 'html_default_sidebars': html_default_sidebars, 108 | } 109 | 110 | 111 | ### Latex options 112 | latex_logo = '_static/salt-logo.pdf' 113 | latex_documents = [ 114 | ('contents', 'Raet.tex', document_title, author, 'manual'), 115 | ] 116 | 117 | 118 | ### Manpage options 119 | man_pages = [ 120 | ('index', 'raet', document_title, [author], 1), 121 | ] 122 | 123 | 124 | ### epub options 125 | epub_title = document_title 126 | epub_author = author 127 | epub_publisher = author 128 | epub_copyright = copyright 129 | 130 | epub_scheme = 'URL' 131 | epub_identifier = 'http://raet.docs.saltstack.org/' 132 | 133 | 134 | def _normalize_version(args): 135 | _, path = args 136 | return '.'.join([x.zfill(4) for x in (path.split('/')[-1].split('.'))]) 137 | 138 | class ReleasesTree(TocTree): 139 | option_spec = dict(TocTree.option_spec) 140 | 141 | def run(self): 142 | rst = super(ReleasesTree, self).run() 143 | entries = rst[0][0]['entries'][:] 144 | entries.sort(key=_normalize_version, reverse=True) 145 | rst[0][0]['entries'][:] = entries 146 | return rst 147 | 148 | 149 | def setup(app): 150 | app.add_directive('releasestree', ReleasesTree) 151 | -------------------------------------------------------------------------------- /docs/images/RaetMetaphor.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RaetProtocol/raet/659c5615694ab0ed595e1e8354196f615086aeb8/docs/images/RaetMetaphor.pdf -------------------------------------------------------------------------------- /docs/images/RaetMetaphor.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RaetProtocol/raet/659c5615694ab0ed595e1e8354196f615086aeb8/docs/images/RaetMetaphor.png -------------------------------------------------------------------------------- /docs/images/RaetSaltAlphaArchitecture.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RaetProtocol/raet/659c5615694ab0ed595e1e8354196f615086aeb8/docs/images/RaetSaltAlphaArchitecture.pdf -------------------------------------------------------------------------------- /docs/images/RaetSaltAlphaArchitecture.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/RaetProtocol/raet/659c5615694ab0ed595e1e8354196f615086aeb8/docs/images/RaetSaltAlphaArchitecture.png -------------------------------------------------------------------------------- /docs/index.rst: -------------------------------------------------------------------------------- 1 | ==== 2 | RAET 3 | ==== 4 | by SaltStack 5 | ============ 6 | 7 | .. rubric:: Reliable Asynchronous Event Transport Protocol 8 | 9 | Contents: 10 | 11 | .. toctree:: 12 | :maxdepth: 1 13 | 14 | topics/introduction 15 | topics/installation 16 | 17 | Motivation 18 | ========== 19 | 20 | Modern large scale distributed application architectures where components are 21 | distributed across the internet on multiple hosts and multiple CPU cores are 22 | often based on a messaging or event bus that allows the various distributed 23 | components to communicate asynchronously with each other. Typically the 24 | messaging bus is some form of messaging queue service such as AMQP or ZeroMQ. 25 | The message bus supports what is commonly referred to as a publish/subscribe 26 | methodology for information exchange. 27 | 28 | While there are many advantages to a full featured message queuing service, one 29 | of the disadvantagesis the inability to manage performance at scale. 30 | 31 | A message queuing service performs two distinct but complementary functions. 32 | 33 | - The first is asynchronous transport of messages over the internet. 34 | 35 | - The second is message queue management, that is, the identification, 36 | tracking, storage, and distribution of messages between publishers and 37 | subscribers via queues. 38 | 39 | One of the advantages of a message queuing service for many applications is 40 | that the service hides the complexities of queue management from the clients 41 | behind an API. The disadvantage is that at scale where the volume of messages, 42 | the timing of messages, and the associated demands on memory, network, and cpu 43 | capacity become critical, the client has little ability to tune the service for 44 | performance. Often MQ services become bottlenecks for the distributed 45 | application. The more complicated MQ services like AMQP tend to be unreliable 46 | under load. 47 | 48 | Separating the asynchrounous event over network transport function from the 49 | message queue management allows independant tuning at scale of each function. 50 | 51 | Moreover, most if not all of the MQ services that we are familiar with are 52 | based on TCP/IP which due to the way it handles connection setup and teardown 53 | as well as failed connections in order to support streams tends to add high 54 | latency to the network communications and is not therefore not well suited for 55 | the asynchronous nature of distibuted event driven application communications. 56 | 57 | Because UDP/IP has lower latency and is connectionless, it scales better, but 58 | it has the serious drawback that it is not reliable. What it needed is a tuned 59 | transport protocol adds reliability to UDP/IP without sacrificing latency and 60 | scalability. A transactioned protocol, is much more appropriate for providing 61 | reliablity to asynchronous event transport than a streaming protocol. 62 | 63 | In addition, because most MQ services are based on TCP/IP they tend to also use 64 | HTTP and therefore TLS/SSL for secure communications. While using HTTP provides 65 | easy integration with web based systems, it is problematic for high performant 66 | systems and TLS is also problematic as a security system both from performance 67 | and vulnerabilty aspects. Elliptic Curve Cryptography provides increases in 68 | security with lower performance requires over other approaches. LibSodium 69 | provides an open source Elliptic Curve Cryptographic library with support for 70 | both authentication and encryption. The CurveCP protocol is based on LibSodium 71 | and provides a handshake protocol for bootstrapping secure network exchanges of 72 | information. 73 | 74 | Finally, one of the best ways to manage and fine tune processor resources (cpu, 75 | memory, network) in distrubted concurrent event driven applications is to use 76 | something called micro-threads. A microthread is typically and in-language 77 | feature that allows logical concurrency with no more overhead than a function 78 | call. Micro threading uses cooperative multi-tasking instead of threads and/or 79 | processes and avoids many of the complexities of resource contention, context 80 | switching, and interprocess communications while providing much higher total 81 | performance. 82 | 83 | The main limitation of a micro-threaded application is that it is constrained 84 | to one CPU core because it runs in one process. To enable full utilization of 85 | all CPU cores, the application needs to be able to run at least one process per 86 | CPU core. This requires on host inter-process communications. But instead of 87 | one process per logical concurrent function which is the conventional approach 88 | to multi-processing, A micro-threaded multi-process application has one 89 | micro-thread per logical concurrent function and the total number of 90 | micro-threads is distributed amoungst the minimum number of processes, no more 91 | than the number of cpu cores. This optimizes the use of the cpu power while 92 | minimizes the overhead of process context switching. 93 | 94 | An example of a framework that uses this type of micro-threaded but 95 | multi-process architecture is Erlang. Indeed, Erlang provided confirmation that 96 | the approach to RAET could be viable. Unfortunately, the Erlang ecosystem is 97 | somewhat limited and the language itself uses what one might describe as a very 98 | unfortunate syntax. Since we have extensive background in Python we wanted to 99 | leverage the richness of the Python ecosystem but still be able to develop 100 | distributed applications on a micro-threaded multi-process capable framework. 101 | 102 | 103 | RAET is designed to provide secure reliable scalable asynchronous message/event 104 | transport over the internet in a micro-threaded multi-process application 105 | framework that uses UDP for interhost communication and LibSodium for 106 | authentication, encryption and the CurveCP handshake for secure bootstrap. 107 | 108 | The queue management and micro-threaded application support is provided by 109 | Ioflo. RAET is a complementary project to Ioflo in that RAET enables multiple 110 | Ioflo applications to work together over a network as part of a distributed 111 | application. 112 | 113 | The primary use case and motivating problem that resulted in the development of 114 | RAET was the need to enable SaltStack to scale better. SaltStack is a remote 115 | execution and configuration management platform written in Python. SaltStack 116 | uses ZeroMQ (0MQ) as is message bug or message queuing service. ZeroMQ is based 117 | on 118 | 119 | Indices and tables 120 | ================== 121 | 122 | * :ref:`genindex` 123 | * :ref:`modindex` 124 | * :ref:`search` 125 | 126 | -------------------------------------------------------------------------------- /docs/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | REM Command file for Sphinx documentation 4 | 5 | if "%SPHINXBUILD%" == "" ( 6 | set SPHINXBUILD=sphinx-build 7 | ) 8 | set BUILDDIR=_build 9 | set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% . 10 | set I18NSPHINXOPTS=%SPHINXOPTS% . 11 | if NOT "%PAPER%" == "" ( 12 | set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% 13 | set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS% 14 | ) 15 | 16 | if "%1" == "" goto help 17 | 18 | if "%1" == "help" ( 19 | :help 20 | echo.Please use `make ^` where ^ is one of 21 | echo. html to make standalone HTML files 22 | echo. dirhtml to make HTML files named index.html in directories 23 | echo. singlehtml to make a single large HTML file 24 | echo. pickle to make pickle files 25 | echo. json to make JSON files 26 | echo. htmlhelp to make HTML files and a HTML help project 27 | echo. qthelp to make HTML files and a qthelp project 28 | echo. devhelp to make HTML files and a Devhelp project 29 | echo. epub to make an epub 30 | echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter 31 | echo. text to make text files 32 | echo. man to make manual pages 33 | echo. texinfo to make Texinfo files 34 | echo. gettext to make PO message catalogs 35 | echo. changes to make an overview over all changed/added/deprecated items 36 | echo. xml to make Docutils-native XML files 37 | echo. pseudoxml to make pseudoxml-XML files for display purposes 38 | echo. linkcheck to check all external links for integrity 39 | echo. doctest to run all doctests embedded in the documentation if enabled 40 | goto end 41 | ) 42 | 43 | if "%1" == "clean" ( 44 | for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i 45 | del /q /s %BUILDDIR%\* 46 | goto end 47 | ) 48 | 49 | 50 | %SPHINXBUILD% 2> nul 51 | if errorlevel 9009 ( 52 | echo. 53 | echo.The 'sphinx-build' command was not found. Make sure you have Sphinx 54 | echo.installed, then set the SPHINXBUILD environment variable to point 55 | echo.to the full path of the 'sphinx-build' executable. Alternatively you 56 | echo.may add the Sphinx directory to PATH. 57 | echo. 58 | echo.If you don't have Sphinx installed, grab it from 59 | echo.http://sphinx-doc.org/ 60 | exit /b 1 61 | ) 62 | 63 | if "%1" == "html" ( 64 | %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html 65 | if errorlevel 1 exit /b 1 66 | echo. 67 | echo.Build finished. The HTML pages are in %BUILDDIR%/html. 68 | goto end 69 | ) 70 | 71 | if "%1" == "dirhtml" ( 72 | %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml 73 | if errorlevel 1 exit /b 1 74 | echo. 75 | echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. 76 | goto end 77 | ) 78 | 79 | if "%1" == "singlehtml" ( 80 | %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml 81 | if errorlevel 1 exit /b 1 82 | echo. 83 | echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. 84 | goto end 85 | ) 86 | 87 | if "%1" == "pickle" ( 88 | %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle 89 | if errorlevel 1 exit /b 1 90 | echo. 91 | echo.Build finished; now you can process the pickle files. 92 | goto end 93 | ) 94 | 95 | if "%1" == "json" ( 96 | %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json 97 | if errorlevel 1 exit /b 1 98 | echo. 99 | echo.Build finished; now you can process the JSON files. 100 | goto end 101 | ) 102 | 103 | if "%1" == "htmlhelp" ( 104 | %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp 105 | if errorlevel 1 exit /b 1 106 | echo. 107 | echo.Build finished; now you can run HTML Help Workshop with the ^ 108 | .hhp project file in %BUILDDIR%/htmlhelp. 109 | goto end 110 | ) 111 | 112 | if "%1" == "qthelp" ( 113 | %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp 114 | if errorlevel 1 exit /b 1 115 | echo. 116 | echo.Build finished; now you can run "qcollectiongenerator" with the ^ 117 | .qhcp project file in %BUILDDIR%/qthelp, like this: 118 | echo.^> qcollectiongenerator %BUILDDIR%\qthelp\Raet.qhcp 119 | echo.To view the help file: 120 | echo.^> assistant -collectionFile %BUILDDIR%\qthelp\Raet.ghc 121 | goto end 122 | ) 123 | 124 | if "%1" == "devhelp" ( 125 | %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp 126 | if errorlevel 1 exit /b 1 127 | echo. 128 | echo.Build finished. 129 | goto end 130 | ) 131 | 132 | if "%1" == "epub" ( 133 | %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub 134 | if errorlevel 1 exit /b 1 135 | echo. 136 | echo.Build finished. The epub file is in %BUILDDIR%/epub. 137 | goto end 138 | ) 139 | 140 | if "%1" == "latex" ( 141 | %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex 142 | if errorlevel 1 exit /b 1 143 | echo. 144 | echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. 145 | goto end 146 | ) 147 | 148 | if "%1" == "latexpdf" ( 149 | %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex 150 | cd %BUILDDIR%/latex 151 | make all-pdf 152 | cd %BUILDDIR%/.. 153 | echo. 154 | echo.Build finished; the PDF files are in %BUILDDIR%/latex. 155 | goto end 156 | ) 157 | 158 | if "%1" == "latexpdfja" ( 159 | %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex 160 | cd %BUILDDIR%/latex 161 | make all-pdf-ja 162 | cd %BUILDDIR%/.. 163 | echo. 164 | echo.Build finished; the PDF files are in %BUILDDIR%/latex. 165 | goto end 166 | ) 167 | 168 | if "%1" == "text" ( 169 | %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text 170 | if errorlevel 1 exit /b 1 171 | echo. 172 | echo.Build finished. The text files are in %BUILDDIR%/text. 173 | goto end 174 | ) 175 | 176 | if "%1" == "man" ( 177 | %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man 178 | if errorlevel 1 exit /b 1 179 | echo. 180 | echo.Build finished. The manual pages are in %BUILDDIR%/man. 181 | goto end 182 | ) 183 | 184 | if "%1" == "texinfo" ( 185 | %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo 186 | if errorlevel 1 exit /b 1 187 | echo. 188 | echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo. 189 | goto end 190 | ) 191 | 192 | if "%1" == "gettext" ( 193 | %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale 194 | if errorlevel 1 exit /b 1 195 | echo. 196 | echo.Build finished. The message catalogs are in %BUILDDIR%/locale. 197 | goto end 198 | ) 199 | 200 | if "%1" == "changes" ( 201 | %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes 202 | if errorlevel 1 exit /b 1 203 | echo. 204 | echo.The overview file is in %BUILDDIR%/changes. 205 | goto end 206 | ) 207 | 208 | if "%1" == "linkcheck" ( 209 | %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck 210 | if errorlevel 1 exit /b 1 211 | echo. 212 | echo.Link check complete; look for any errors in the above output ^ 213 | or in %BUILDDIR%/linkcheck/output.txt. 214 | goto end 215 | ) 216 | 217 | if "%1" == "doctest" ( 218 | %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest 219 | if errorlevel 1 exit /b 1 220 | echo. 221 | echo.Testing of doctests in the sources finished, look at the ^ 222 | results in %BUILDDIR%/doctest/output.txt. 223 | goto end 224 | ) 225 | 226 | if "%1" == "xml" ( 227 | %SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml 228 | if errorlevel 1 exit /b 1 229 | echo. 230 | echo.Build finished. The XML files are in %BUILDDIR%/xml. 231 | goto end 232 | ) 233 | 234 | if "%1" == "pseudoxml" ( 235 | %SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml 236 | if errorlevel 1 exit /b 1 237 | echo. 238 | echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml. 239 | goto end 240 | ) 241 | 242 | :end 243 | -------------------------------------------------------------------------------- /docs/topics/Salt_Raet.rst: -------------------------------------------------------------------------------- 1 | ============ 2 | Salt with RAET 3 | ============ 4 | 5 | The current version of Salt using Raet is a hybrid architecture due to the amount 6 | of work it would have taken to convert all of Salt to a RAET-Ioflo style architecture. 7 | Mostly the changes were made to replace Zero-MQ with RAET but not change everything 8 | else to a micro-threaded architecture. The following figure shows notionally how 9 | Salt works on top of RAET. At some point in the future more of Salt will be migrated 10 | to a micro-threaded architecture as feasible. The constraint being that Salt must 11 | still support ZeroMQ. 12 | 13 | .. figure:: /images/RaetSaltAlphaArchitecture.png 14 | :alt: RAET Salt archtecture diagram 15 | 16 | The archtecture of Salt when using RAET. 17 | 18 | 19 | 20 | -------------------------------------------------------------------------------- /docs/topics/examples_lane.py: -------------------------------------------------------------------------------- 1 | ''' 2 | RAET Tutorial Examples for LaneStack 3 | ''' 4 | 5 | import os 6 | import shutil 7 | import time 8 | import tempfile 9 | 10 | import ioflo 11 | from ioflo.base.consoling import getConsole 12 | 13 | import raet 14 | 15 | console = getConsole() 16 | console.reinit(verbosity=console.Wordage.concise) 17 | 18 | def serviceStacks(stacks, duration=0.5, period=0.1): 19 | ''' 20 | Utility method to service queues. Call from test method. 21 | ''' 22 | store = ioflo.base.storing.Store(stamp=0.0) 23 | timer = ioflo.aid.timing.StoreTimer(store=store, duration=duration) 24 | while not timer.expired: 25 | for stack in stacks: 26 | stack.serviceAll() 27 | stack.store.advanceStamp(period) 28 | 29 | store.advanceStamp(period) 30 | time.sleep(period) 31 | 32 | def example1(): 33 | tempDirpath = tempfile.mkdtemp(prefix="raet", suffix="base", dir='/tmp') 34 | baseDirpath = os.path.join(tempDirpath, 'lane') 35 | 36 | alpha = raet.lane.stacking.LaneStack(name='alpha', 37 | uid=1, 38 | lanename='zeus', 39 | sockdirpath=baseDirpath) 40 | 41 | beta = raet.lane.stacking.LaneStack(name='beta', 42 | uid=1, 43 | lanename='zeus', 44 | sockdirpath=baseDirpath) 45 | 46 | stacks = [alpha, beta] 47 | 48 | for stack in stacks: 49 | console.terse("LaneStack '{0}': UXD socket ha = '{1}'\n".format(stack.name, stack.ha)) 50 | 51 | remote = raet.lane.yarding.RemoteYard(stack=alpha, ha=beta.ha) 52 | alpha.addRemote(remote) 53 | 54 | msg = dict(content="Hello this is a message from alpha to beta") 55 | alpha.transmit(msg, remote.uid) 56 | serviceStacks(stacks) 57 | 58 | while beta.rxMsgs: 59 | rxMsg, source = beta.rxMsgs.popleft() 60 | console.terse("Beta received from {0} message = '{1}'\n".format(source, rxMsg)) 61 | 62 | remote = beta.remotes.values()[0] 63 | console.terse("Beta remotes has '{0}' at '{1}'\n".format(remote.name, remote.ha)) 64 | 65 | remote = alpha.remotes.values()[0] 66 | console.terse("Alpha remotes has '{0}' at '{1}'\n".format(remote.name, remote.ha)) 67 | 68 | beta.transmit(dict(content = "Hi from beta")) 69 | beta.transmit(dict(content = "Hi again from beta")) 70 | beta.transmit(dict(content = "Hi yet again from beta")) 71 | 72 | alpha.transmit(dict(content = "Hello from alpha")) 73 | alpha.transmit(dict(content = "Hello again from alpha")) 74 | alpha.transmit(dict(content = "Hello yet again from alpha")) 75 | 76 | serviceStacks(stacks) 77 | 78 | for stack in stacks: 79 | while stack.rxMsgs: 80 | rxMsg, source = stack.rxMsgs.popleft() 81 | console.terse("LaneStack {0} received from {1} message = '{2}'\n".format(stack.name, source, rxMsg)) 82 | 83 | 84 | 85 | for stack in stacks: 86 | stack.server.close() 87 | 88 | shutil.rmtree(tempDirpath) 89 | 90 | print("Finished\n") 91 | 92 | 93 | 94 | if __name__ == "__main__": 95 | example1() 96 | 97 | -------------------------------------------------------------------------------- /docs/topics/examples_road.py: -------------------------------------------------------------------------------- 1 | ''' 2 | RAET Tutorial Examples for RoadStack 3 | ''' 4 | import time 5 | 6 | import ioflo 7 | from ioflo.base.consoling import getConsole 8 | 9 | 10 | import raet 11 | from raet import raeting 12 | from raet.raeting import AutoMode 13 | 14 | console = getConsole() 15 | console.reinit(verbosity=console.Wordage.concise) 16 | 17 | def serviceStacks(stacks, duration=1.0, period=0.1): 18 | ''' 19 | Utility method to service queues. Call from test method. 20 | ''' 21 | store = ioflo.base.storing.Store(stamp=0.0) 22 | timer = ioflo.aid.timing.StoreTimer(store=store, duration=duration) 23 | while not timer.expired: 24 | for stack in stacks: 25 | stack.serviceAll() 26 | stack.store.advanceStamp(period) 27 | 28 | store.advanceStamp(period) 29 | if all([not stack.transactions for stack in stacks]): 30 | break 31 | time.sleep(period) 32 | console.concise("Perceived service duration = {0} seconds\n".format(timer.elapsed)) 33 | 34 | def example1(): 35 | alpha = raet.road.stacking.RoadStack(name='alpha', 36 | ha=('0.0.0.0', 7531), 37 | auto=AutoMode.always.value) 38 | 39 | beta = raet.road.stacking.RoadStack(name='beta', 40 | ha=('0.0.0.0', 7532), 41 | main=True, 42 | auto=AutoMode.always.value) 43 | 44 | remote = raet.road.estating.RemoteEstate(stack=alpha, 45 | ha=beta.ha) 46 | 47 | alpha.addRemote(remote) 48 | 49 | alpha.join(uid=remote.uid, cascade=True) 50 | 51 | stacks = [alpha, beta] 52 | while True: 53 | for stack in stacks: 54 | stack.serviceAll() 55 | stack.store.advanceStamp(0.1) 56 | if all([not stack.transactions for stack in stacks]): 57 | break 58 | time.sleep(0.1) 59 | 60 | for stack in stacks: 61 | stack.server.close() # close the UDP socket 62 | stack.keep.clearAllDir() # clear persisted data 63 | 64 | print("Finished\n") 65 | 66 | 67 | def example2(): 68 | alpha = raet.road.stacking.RoadStack(name='alpha', 69 | ha=('0.0.0.0', 7531), 70 | auto=AutoMode.always.value) 71 | 72 | beta = raet.road.stacking.RoadStack(name='beta', 73 | ha=('0.0.0.0', 7532), 74 | main=True, 75 | auto=AutoMode.always.value) 76 | 77 | remote = raet.road.estating.RemoteEstate(stack=alpha, 78 | ha=beta.ha) 79 | 80 | alpha.addRemote(remote) 81 | 82 | alpha.join(uid=remote.uid, cascade=True) 83 | 84 | stacks = [alpha, beta] 85 | while True: 86 | for stack in stacks: 87 | stack.serviceAll() 88 | stack.store.advanceStamp(0.1) 89 | if all([not stack.transactions for stack in stacks]): 90 | break 91 | time.sleep(0.1) 92 | 93 | print("Finished Handshake\n") 94 | 95 | msg = {'subject': 'Example message alpha to beta', 96 | 'content': 'The dict keys in this dict are not special any dict will do.',} 97 | 98 | alpha.transmit(msg, remote.uid) 99 | while True: 100 | for stack in stacks: 101 | stack.serviceAll() 102 | stack.store.advanceStamp(0.1) 103 | if all([not stack.transactions for stack in stacks]): 104 | break 105 | time.sleep(0.1) 106 | 107 | rx = beta.rxMsgs.popleft() 108 | print("{0}\n".format(rx)) 109 | print("Finished Message alpha to beta\n") 110 | 111 | msg = {'subject': 'Example message beta to alpha', 112 | 'content': 'Messages are the core of raet.',} 113 | 114 | beta.transmit(msg, remote.uid) 115 | while True: 116 | for stack in stacks: 117 | stack.serviceAll() 118 | stack.store.advanceStamp(0.1) 119 | if all([not stack.transactions for stack in stacks]): 120 | break 121 | time.sleep(0.1) 122 | 123 | rx = alpha.rxMsgs.popleft() 124 | print("{0}\n".format(rx)) 125 | print("Finished Message beta to alpha\n") 126 | 127 | for stack in stacks: 128 | stack.server.close() # close the UDP socket 129 | stack.keep.clearAllDir() # clear persisted data 130 | 131 | print("Finished\n") 132 | 133 | def example3(): 134 | alpha = raet.road.stacking.RoadStack(name='alpha', 135 | ha=('0.0.0.0', 7531), 136 | main=True, 137 | auto=AutoMode.always.value) 138 | 139 | beta = raet.road.stacking.RoadStack(name='beta', 140 | ha=('0.0.0.0', 7532), 141 | main=True, 142 | auto=AutoMode.always.value) 143 | 144 | gamma = raet.road.stacking.RoadStack(name='gamma', 145 | ha=('0.0.0.0', 7533), 146 | main=True, 147 | auto=AutoMode.always.value) 148 | 149 | remote = raet.road.estating.RemoteEstate(stack=alpha, 150 | name=beta.name, 151 | ha=beta.ha) 152 | alpha.addRemote(remote) 153 | alpha.join(uid=remote.uid, cascade=True) 154 | 155 | remote = raet.road.estating.RemoteEstate(stack=alpha, 156 | name=gamma.name, 157 | ha=gamma.ha) 158 | alpha.addRemote(remote) 159 | alpha.join(uid=remote.uid, cascade=True) 160 | 161 | remote = raet.road.estating.RemoteEstate(stack=beta, 162 | name=gamma.name, 163 | ha=gamma.ha) 164 | beta.addRemote(remote) 165 | beta.join(uid=remote.uid, cascade=True) 166 | 167 | stacks = [alpha, beta, gamma] 168 | serviceStacks(stacks) 169 | print("Finished Handshakes\n") 170 | 171 | msg = {'subject': 'Example message alpha to whoever', 172 | 'content': 'Hi',} 173 | for remote in alpha.remotes.values(): 174 | alpha.transmit(msg, remote.uid) 175 | 176 | msg = {'subject': 'Example message beta to whoever', 177 | 'content': 'Hello.',} 178 | for remote in beta.remotes.values(): 179 | beta.transmit(msg, remote.uid) 180 | 181 | msg = {'subject': 'Example message gamma to whoever', 182 | 'content': 'Good Day',} 183 | for remote in gamma.remotes.values(): 184 | gamma.transmit(msg, remote.uid) 185 | 186 | serviceStacks(stacks) 187 | print("Finished Messages\n") 188 | 189 | for stack in stacks: 190 | print("Stack {0} received:\n".format(stack.name)) 191 | while stack.rxMsgs: 192 | msg, source = stack.rxMsgs.popleft() 193 | print("source = '{0}'.\nmsg= {1}\n".format(source, msg)) 194 | 195 | 196 | for stack in stacks: 197 | stack.server.close() # close the UDP socket 198 | stack.keep.clearAllDir() # clear persisted data 199 | 200 | print("Finished\n") 201 | 202 | 203 | if __name__ == "__main__": 204 | example1() 205 | example2() 206 | example3() 207 | -------------------------------------------------------------------------------- /docs/topics/installation.rst: -------------------------------------------------------------------------------- 1 | ============ 2 | Installation 3 | ============ 4 | 5 | Current RAET is provided as a PyPi package. 6 | 7 | To install on a UNIX based system use pip: 8 | 9 | .. code-block:: bash 10 | 11 | $ pip install raet 12 | 13 | On OS X: 14 | 15 | .. code-block:: bash 16 | 17 | $ sudo pip install raet 18 | -------------------------------------------------------------------------------- /docs/topics/introduction.rst: -------------------------------------------------------------------------------- 1 | ============ 2 | Introduction 3 | ============ 4 | 5 | Currently RAET supports two types of communication. 6 | 7 | - Host to host communication over UDP/IP sockets 8 | - Same host interprocess communication over Unix Domain (UXD) Sockets 9 | 10 | .. figure:: /images/RaetMetaphor.png 11 | :alt: RAET application archtecture diagram 12 | 13 | The archtecture of a RAET based application. 14 | 15 | Details 16 | ======= 17 | 18 | Production UDP/IP Ports for Raet 19 | -------------------------------- 20 | 21 | Manor Estate 4505 22 | Other Estates 4510 23 | 24 | Packet Data Format 25 | ------------------ 26 | 27 | The data used to initialize a packet is an ordered dict with several fields 28 | most of the fields are shared with the header data format below so only the 29 | unique fields are shown here. 30 | 31 | Unique Packet data fields 32 | ------------------------- 33 | 34 | :: 35 | 36 | sh: source host ip address (ipv4) 37 | sp: source ip port 38 | dh: destination host ip address (ipv4) 39 | dp: destination host ip port 40 | 41 | Header Data Format 42 | ------------------ 43 | 44 | The .data in the packet header is an ordered dict which is used to either 45 | create a packet to transmit 46 | or holds the field from a received packet. 47 | What fields are included in a header is dependent on the header kind. 48 | 49 | Header encoding 50 | --------------- 51 | 52 | There are three header encoding formats currently supported. 53 | 54 | - RAET Native. This is an minimized ascii test format that optimizes the 55 | tradeoff between easy readability and size. This is the default. 56 | 57 | - JSON. This is the most verbose format but has the advantage of compatibility. 58 | 59 | - Binary. This is not yet implemented. Once the protocol reaches a more mature 60 | state and its not likely that there will be any header changes (or very 61 | infrequent) then a binary format that minimizes size will be provided. 62 | 63 | When the head kind is json = 0, then certain optimizations are used to minimize 64 | the header length. 65 | 66 | - The header field keys are two bytes long 67 | - If a header field value is the default then the field is not included 68 | - Lengths are encoded as hex strings 69 | - The flags are encoded as a double char hex string in field 'fg' 70 | 71 | 72 | Header Data Fields 73 | ------------------ 74 | 75 | :: 76 | 77 | ri: raet id Default 'RAET' 78 | vn: Version (Version) Default 0 79 | pk: Packet Kind (PcktKind) 80 | pl: Packet Length (PcktLen) 81 | hk: Header kind (HeadKind) Default 0 82 | hl: Header length (HeadLen) Default 0 83 | 84 | se: Source Estate ID (SEID) 85 | de: Destination Estate ID (DEID) 86 | cf: Correspondent Flag (CrdtFlag) Default 0 87 | bf: BroadCast Flag (BcstFlag) Default 0 88 | 89 | si: Session ID (SID) Default 0 90 | ti: Transaction ID (TID) Default 0 91 | tk: Transaction Kind (TrnsKind) 92 | 93 | dt: Datetime Stamp (Datetime) Default 0 94 | oi: Order index (OrdrIndx) Default 0 95 | 96 | wf: Waiting Ack Flag (WaitFlag) Default 0 97 | Next segment or ordered packet is waiting for ack to this packet 98 | ml: Message Length (MsgLen) Default 0 99 | Length of message only (unsegmented) 100 | sn: Segment Number (SgmtNum) Default 0 101 | sc: Segment Count (SgmtCnt) Default 1 102 | sf: Segment Flag (SgmtFlag) Default 0 103 | This packet is part of a segmented message 104 | af: All Flag (AllFlag) Default 0 105 | Resend all segments not just one 106 | 107 | bk: Body kind (BodyKind) Default 0 108 | ck: Coat kind (CoatKind) Default 0 109 | fk: Footer kind (FootKind) Default 0 110 | fl: Footer length (FootLen) Default 0 111 | 112 | fg: flags packed (Flags) Default '00' hs 113 | 2 char Hex string with bits (0, 0, af, sf, 0, wf, bf, cf) 114 | Zeros are TBD flags 115 | 116 | 117 | Body Data Format 118 | ---------------- 119 | 120 | The Body .data is a Mapping that is serialized using either JSON or MSGPACK 121 | 122 | Packet Parts 123 | ------------ 124 | 125 | Each packet has 4 parts some of which may be empty. These are: 126 | 127 | - Head 128 | - Body 129 | - Coat 130 | - Tail 131 | 132 | The Head is manditory and provides the header fields that are needed to process 133 | the packet. 134 | 135 | The Tail provides the authentication signature that is used to verify the 136 | source of the packet and that its contents have not been tampered with. 137 | 138 | The Body is the contents of the packet. Some packets such as Acks and Nacks 139 | don't need a body. The Body is a serialized Python dictionary typically and 140 | ordered dictionary so that parsing and debugging has a consistent view of the 141 | ordering of the fields in the body. 142 | 143 | The Coat is the encrypted version of the body. The encryption type is CurveCP 144 | based. If the Coat is provided then the Body is encapsulated within the Coat 145 | Part. 146 | 147 | 148 | 149 | Header Details 150 | -------------- 151 | 152 | JSON Encoding 153 | ````````````` 154 | 155 | Header is the ASCII Safe JSON encoding of a Python ordered dictionary. Header 156 | termination is an empty line given by double pair of carriage-return linefeed 157 | characters:: 158 | 159 | /r/n/r/n 160 | 10 13 10 13 161 | ADAD 162 | 1010 1101 1010 1101 163 | 164 | Carriage-return and newline characters cannot appear in a JSON encoded string 165 | unless they are escaped with backslash, so the 4 byte combination is illegal in 166 | valid JSON that does not have multi-byte unicode characters so it makes it a 167 | uniquely identifiable header termination. 168 | 169 | These means the header must be ascii safe so no multibyte utf-8 strings are 170 | allowed in the header. 171 | 172 | Native Encoding 173 | ``````````````` 174 | 175 | The header consists of newline delimited lines. Each header line consists of a 176 | two character field identifier followed by a space followed by the value of the 177 | field as ascii hex encoded binary followed by newline. The Header end is 178 | indicated by a blank line, that is, a double newline character. Example 179 | 180 | Binary Encoding 181 | ``````````````` 182 | 183 | The header consists of defined set of fixed length fields 184 | 185 | 186 | Session 187 | ``````` 188 | 189 | Session is important for security. Want one session opened and then multiple 190 | transactions within session:: 191 | 192 | Session ID 193 | SID 194 | sid 195 | si 196 | 197 | 198 | Session Bootstrap 199 | ----------------- 200 | 201 | 202 | 203 | Layering 204 | -------- 205 | 206 | OSI Layers 207 | 208 | == == 209 | 7: Application: Format: Data (Stack to Application interface buffering etc) 210 | 6: Presentation: Format: Data (Encrypt-Decrypt convert to machine independent format) 211 | 5: Session: Format: Data (Interhost communications. Authentication. Groups) 212 | 4: Transport: Format: Segments (Reliable delivery of Message, Transactions, Segmentation, Error checking) 213 | 3: Network: Format: Packets/Datagrams (Addressing Routing) 214 | 2: Link: Format: Frames ( Reliable per frame communications connection, Media access controller ) 215 | 1: Physical: Bits (Transciever communication connection not reliable) 216 | == == 217 | 218 | - Link is hidden from Raet 219 | 220 | - Network is IP host address and UDP Port 221 | 222 | - Transport is Raet transaction and packet authentication vis tail signature 223 | that provide reliable transport. 224 | 225 | - Session is session id key exchange for signing. Grouping is Road 226 | 227 | - Presentation is Encrypt-Decrypt Body and Serialize-Deserialize Body 228 | 229 | - Application is Body data dictionary 230 | 231 | Packet signing could technically be in either the Transport or Session layers. 232 | -------------------------------------------------------------------------------- /pkg/rpm/python-raet.spec: -------------------------------------------------------------------------------- 1 | %if ! (0%{?rhel} >= 6 || 0%{?fedora} > 12) 2 | %global with_python26 1 3 | %define pybasever 2.6 4 | %define __python_ver 26 5 | %define __python %{_bindir}/python%{?pybasever} 6 | %endif 7 | 8 | %{!?python_sitelib: %global python_sitelib %(%{__python} -c "from distutils.sysconfig import get_python_lib; print(get_python_lib())")} 9 | %{!?python_sitearch: %global python_sitearch %(%{__python} -c "from distutils.sysconfig import get_python_lib; print(get_python_lib(1))")} 10 | %{!?pythonpath: %global pythonpath %(%{__python} -c "import os, sys; print(os.pathsep.join(x for x in sys.path if x))")} 11 | 12 | %global srcname raet 13 | 14 | Name: python-%{srcname} 15 | Version: 0.2.12 16 | Release: 3%{?dist} 17 | Summary: Reliable Asynchronous Event Transport Protocol 18 | 19 | License: ASL 2.0 20 | URL: https://github.com/RaetProtocol/raet 21 | Source0: http://pypi.python.org/packages/source/r/%{srcname}/%{srcname}-%{version}.tar.gz 22 | 23 | BuildRequires: python-setuptools 24 | BuildRequires: python-six 25 | BuildRequires: python-importlib 26 | BuildRequires: python-ioflo >= 0.9.39 27 | Requires: python-importlib 28 | Requires: python-libnacl >= 1.3.3 29 | Requires: python-six 30 | Requires: python-simplejson 31 | Requires: python-ioflo >= 0.9.39 32 | BuildArch: noarch 33 | 34 | # We don't want to provide private python extension libs 35 | %{?filter_setup: 36 | %filter_provides_in %{python2_sitearch}/.*\.so$ 37 | %filter_setup 38 | } 39 | 40 | %description 41 | A high level, stack based communication protocol for network and IPC communication 42 | 43 | %prep 44 | %setup -q -n %{srcname}-%{version} 45 | 46 | %install 47 | %{__python} setup.py install --root %{buildroot} 48 | 49 | %files 50 | %{_bindir}/raetflo 51 | %{python_sitelib}/%{srcname}/ 52 | %{python_sitelib}/%{srcname}*.egg-info 53 | -------------------------------------------------------------------------------- /pkg/suse/python-raet.changes: -------------------------------------------------------------------------------- 1 | ------------------------------------------------------------------- 2 | Wed Jul 2 18:25:59 UTC 2014 - aboe76@gmail.com 3 | 4 | - Major release 0.1.0 5 | - Minor fixup prepping for release with SaltStack Release Candidate 6 | 7 | ------------------------------------------------------------------- 8 | Tue Jul 1 18:56:32 UTC 2014 - aboe76@gmail.com 9 | 10 | - Updated to version 0.0.31: 11 | - Fixed roadstack .manage method to used aliveds 12 | - From versions in between 13 | - No longer removes rejected remotes out of band or future presence expire mechanism is needed to 14 | remove rejected remotes 0.0.30 15 | - Fixed a bug on renew in Joiner transaction 0.0.29 16 | - Fixed some race conditions 0.0.28 17 | - Support for reaping and restoring dead remotes on main estate road stack Support for saving and 18 | resending stale messages when session changes on rejoin or reallow Some other fixes 0.0.27 19 | - RoadStack.manage now provide underlying support needed for presence events and filtering of remote 20 | targets based on availabilty (allowed) status 0.0.26 21 | 22 | ------------------------------------------------------------------- 23 | Sat Jun 21 07:12:41 UTC 2014 - aboe76@gmail.com 24 | 25 | - Updated to version 0.0.25 26 | fix install_requirements error 27 | 28 | ------------------------------------------------------------------- 29 | Fri Jun 20 08:33:21 UTC 2014 - aboe76@gmail.com 30 | 31 | - updated to version 0.0.23 32 | 33 | ------------------------------------------------------------------- 34 | Wed Jun 18 19:52:44 UTC 2014 - aboe76@gmail.com 35 | 36 | - Update to version 0.0.19 37 | 38 | ------------------------------------------------------------------- 39 | Mon Jun 9 10:05:11 UTC 2014 - aboe76@gmail.com 40 | 41 | - Initial package version 0.0.18 42 | 43 | -------------------------------------------------------------------------------- /pkg/suse/python-raet.spec: -------------------------------------------------------------------------------- 1 | # 2 | # spec file for package python-raet 3 | # 4 | # Copyright (c) 2014 SUSE LINUX Products GmbH, Nuernberg, Germany. 5 | # 6 | # All modifications and additions to the file contributed by third parties 7 | # remain the property of their copyright owners, unless otherwise agreed 8 | # upon. The license for this file, and modifications and additions to the 9 | # file, is the same license as for the pristine package itself (unless the 10 | # license for the pristine package is not an Open Source License, in which 11 | # case the license is the MIT License). An "Open Source License" is a 12 | # license that conforms to the Open Source Definition (Version 1.9) 13 | # published by the Open Source Initiative. 14 | 15 | # Please submit bugfixes or comments via http://bugs.opensuse.org/ 16 | # 17 | 18 | Name: python-raet 19 | Version: 0.1.0 20 | Release: 0 21 | License: Apache-2.0 22 | Summary: Reliable Asynchronous Event Transport protocol 23 | Url: https://github.com/saltstack/raet 24 | Group: Development/Languages/Python 25 | Source0: https://pypi.python.org/packages/source/r/raet/raet-%{version}.tar.gz 26 | BuildRoot: %{_tmppath}/raet-%{version}-build 27 | 28 | BuildRequires: python-setuptools 29 | BuildRequires: python-devel 30 | BuildRequires: python-six 31 | BuildRequires: python-ioflo 32 | BuildRequires: python-libnacl 33 | BuildRequires: fdupes 34 | BuildRequires: libsodium-devel 35 | Requires: python-libnacl 36 | Requires: python-ioflo 37 | 38 | BuildRoot: %{_tmppath}/%{name}-%{version}-build 39 | %if 0%{?suse_version} && 0%{?suse_version} <= 1110 40 | %{!?python_sitelib: %global python_sitelib %(python -c "from distutils.sysconfig import get_python_lib; print get_python_lib()")} 41 | BuildRequires: python-importlib 42 | Requires: python-importlib 43 | BuildRequires: python 44 | Requires: python 45 | %else 46 | BuildArch: noarch 47 | %endif 48 | 49 | %description 50 | Raet is a Python library for raet protocol which stands for 51 | Reliable Asynchronous Event Transport protocol. 52 | 53 | %prep 54 | %setup -q -n raet-%{version} 55 | 56 | %build 57 | python setup.py build 58 | 59 | %install 60 | python setup.py install --prefix=%{_prefix} --root=%{buildroot} --optimize=1 61 | %fdupes %{buildroot}%{_prefix} 62 | 63 | %files 64 | %defattr(-,root,root) 65 | %{python_sitelib}/* 66 | %{_bindir}/raetflo 67 | 68 | %changelog -------------------------------------------------------------------------------- /raet/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | ''' 3 | raet modules 4 | 5 | __init__.py file for raet package 6 | ''' 7 | 8 | __all__ = ['raeting', 'nacling', 'keeping', 'lotting', 'stacking', 'road', 'lane'] 9 | 10 | import importlib 11 | for m in __all__: 12 | importlib.import_module(".{0}".format(m), package='raet') 13 | 14 | # Load the package metadata 15 | from raet.__metadata__ import * # pylint: disable=wildcard-import 16 | -------------------------------------------------------------------------------- /raet/__metadata__.py: -------------------------------------------------------------------------------- 1 | ''' 2 | Raet package metadata 3 | ''' 4 | 5 | __version_info__ = (0, 6, 9) 6 | __version__ = '{0}.{1}.{2}'.format(*__version_info__) 7 | __author__ = "Samuel M. Smith" 8 | __license__ = "Apache2" 9 | 10 | __all__ = ['__version_info__', '__version__', '__author__', '__license__'] 11 | -------------------------------------------------------------------------------- /raet/abiding.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | ''' 3 | Globals to be used with from abiding import * 4 | 5 | Python 2 to 3 Support 6 | ''' 7 | 8 | # pylint: skip-file 9 | # pylint: disable=C0103 10 | 11 | # Import python libs 12 | import sys 13 | 14 | # Python2to3 support 15 | if sys.version > '3': # Python3 16 | long = int 17 | basestring = (str, bytes) 18 | unicode = str 19 | xrange = range 20 | 21 | def ns2b(x): 22 | """ 23 | Converts from native str type to native bytes type 24 | """ 25 | return x.encode('ISO-8859-1') 26 | 27 | def ns2u(x): 28 | """ 29 | Converts from native str type to native unicode type 30 | """ 31 | return x 32 | 33 | else: # Python2 34 | # long = long 35 | # basestring = basestring 36 | # unicode = unicode 37 | 38 | def ns2b(x): 39 | """ 40 | Converts from native str type to native bytes type 41 | """ 42 | return x 43 | 44 | def ns2u(x): 45 | """ 46 | Converts from native str type to native unicode type 47 | """ 48 | return unicode(x) 49 | -------------------------------------------------------------------------------- /raet/encoding.py: -------------------------------------------------------------------------------- 1 | # Copyright 2013 Donald Stufft and individual contributors 2 | # 3 | # Licensed under the Apache License, Version 2.0 (the "License"); 4 | # you may not use this file except in compliance with the License. 5 | # You may obtain a copy of the License at 6 | # 7 | # http://www.apache.org/licenses/LICENSE-2.0 8 | # 9 | # Unless required by applicable law or agreed to in writing, software 10 | # distributed under the License is distributed on an "AS IS" BASIS, 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | # See the License for the specific language governing permissions and 13 | # limitations under the License. 14 | import base64 15 | import binascii 16 | 17 | 18 | class RawEncoder(object): 19 | 20 | @staticmethod 21 | def encode(data): 22 | return data 23 | 24 | @staticmethod 25 | def decode(data): 26 | return data 27 | 28 | 29 | class HexEncoder(object): 30 | 31 | @staticmethod 32 | def encode(data): 33 | return binascii.hexlify(data) 34 | 35 | @staticmethod 36 | def decode(data): 37 | return binascii.unhexlify(data) 38 | 39 | 40 | class Base16Encoder(object): 41 | 42 | @staticmethod 43 | def encode(data): 44 | return base64.b16encode(data) 45 | 46 | @staticmethod 47 | def decode(data): 48 | return base64.b16decode(data) 49 | 50 | 51 | class Base32Encoder(object): 52 | 53 | @staticmethod 54 | def encode(data): 55 | return base64.b32encode(data) 56 | 57 | @staticmethod 58 | def decode(data): 59 | return base64.b32decode(data) 60 | 61 | 62 | class Base64Encoder(object): 63 | 64 | @staticmethod 65 | def encode(data): 66 | return base64.b64encode(data) 67 | 68 | @staticmethod 69 | def decode(data): 70 | return base64.b64decode(data) 71 | 72 | 73 | class Encodable(object): 74 | 75 | def encode(self, encoder=RawEncoder): 76 | return encoder.encode(bytes(self)) 77 | -------------------------------------------------------------------------------- /raet/flo/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | ''' 3 | raet.flo package 4 | modules associated with running raet with ioflo 5 | ''' 6 | 7 | __all__ = ['behaving'] 8 | 9 | import importlib 10 | for m in __all__: 11 | importlib.import_module(".{0}".format(m), package='raet.flo') 12 | -------------------------------------------------------------------------------- /raet/flo/plan/lanetest.flo: -------------------------------------------------------------------------------- 1 | # Raet Test FloScript 2 | 3 | house master 4 | 5 | init .raet.lane.stack.local to name "lord" lane "ash" sockdirpath "/tmp/raet/test/lane/" 6 | init .raet.lane.stack.dest to "serf" 7 | 8 | framer bossuxdstack be active first start 9 | frame start 10 | do raet lane stack per inode ".raet.lane.stack" 11 | exit 12 | do raet lane stack closer per inode ".raet.lane.stack." 13 | timeout 5 14 | 15 | frame abort 16 | bid stop all 17 | 18 | framer uxdreceiver be active first start 19 | frame start 20 | do raet lane stack printer per inode ".raet.lane.stack." 21 | 22 | framer setupuxdyard be active first start 23 | frame start 24 | enter 25 | do raet lane stack yard add to lane "ash" name "serf" 26 | timeout 1 27 | 28 | frame send 29 | enter 30 | do raet lane stack transmit to stuff "Lord says Hello" \ 31 | per inode ".raet.lane.stack." 32 | 33 | 34 | house serf 35 | 36 | init .raet.lane.stack.local to name "serf" lane "ash" sockdirpath "/tmp/raet/test/lane/" 37 | init .raet.lane.stack.dest to "lord" 38 | 39 | framer serfuxdstack be active first start 40 | frame start 41 | do raet lane stack per inode ".raet.lane.stack" 42 | exit 43 | do raet lane stack closer per inode ".raet.lane.stack." 44 | timeout 5 45 | 46 | frame abort 47 | bid stop all 48 | 49 | framer uxdreceiver be active first start 50 | frame start 51 | do raet lane stack printer per inode ".raet.lane.stack." 52 | 53 | 54 | framer setupuxdyard be active first start 55 | frame start 56 | enter 57 | do raet lane stack yard add to lane "ash" name "lord" 58 | timeout 1 59 | 60 | frame send 61 | enter 62 | do raet lane stack transmit to stuff "Serf says Hello" \ 63 | per inode ".raet.lane.stack." 64 | 65 | 66 | -------------------------------------------------------------------------------- /raet/flo/plan/managetest.flo: -------------------------------------------------------------------------------- 1 | # Mange Test FloScript 2 | 3 | house master 4 | 5 | init .raet.road.stack.local to uid 1 name "master" host "" port 7530 \ 6 | basedirpath "/tmp/raet/test/keep/" main True auto True 7 | 8 | 9 | framer masterroadstack be active first start 10 | frame start 11 | enter 12 | do salt raet road cleanup per inode ".raet.road.stack" 13 | do raet road stack setup per inode ".raet.road.stack" 14 | do raet road stack manager immediate per inode ".raet.road.stack" 15 | exit 16 | do raet road stack closer per inode ".raet.road.stack." 17 | 18 | framer servicerx be active first start 19 | frame start 20 | do raet road stack rx servicer per inode ".raet.road.stack" 21 | 22 | 23 | framer manage be active first start 24 | frame start 25 | print Managing Master... 26 | do raet road stack printer per inode ".raet.road.stack." 27 | do raet road stack manager per inode ".raet.road.stack." 28 | timeout 10 29 | 30 | frame abort 31 | bid stop all 32 | 33 | framer servicetx be active first start 34 | frame start 35 | do raet road stack tx servicer per inode ".raet.road.stack" 36 | 37 | house minion1 38 | 39 | init .raet.road.stack.local to uid 0 name "minion1" host "" port 7531 \ 40 | basedirpath "/tmp/raet/test/keep/" main False auto True 41 | 42 | 43 | framer minionudpstack be active first start 44 | frame start 45 | do raet road stack setup per inode ".raet.road.stack" 46 | exit 47 | do raet road stack closer per inode ".raet.road.stack." 48 | 49 | framer servicerx be active first start 50 | frame start 51 | do raet road stack rx servicer per inode ".raet.road.stack" 52 | 53 | framer bootstrap be active first checkjoin 54 | 55 | frame checkjoin 56 | print Checking Join Minion1... 57 | enter 58 | do raet road stack joined per inode ".raet.road.stack." 59 | 60 | go alreadyjoined if joined in .raet.road.stack.status 61 | go join 62 | 63 | frame alreadyjoined 64 | print Already Joined Minion1... 65 | go checkallow 66 | 67 | frame join 68 | print Joining Minion1... 69 | enter 70 | do raet road stack joiner per inode ".raet.road.stack." 71 | recur 72 | do raet road stack joined per inode ".raet.road.stack." 73 | 74 | go next if joined in .raet.road.stack.status 75 | go abort if elapsed >= 2 76 | 77 | frame joined 78 | print Joined Minion1... 79 | go next 80 | 81 | frame checkallow 82 | print Checking allow Minion1... 83 | enter 84 | do raet road stack allowed per inode ".raet.road.stack." 85 | 86 | go alreadyallowed if allowed in .raet.road.stack.status 87 | go allow 88 | 89 | frame alreadyallowed 90 | print Already allowed Minion1... 91 | go message 92 | 93 | frame allow 94 | print Allowing Minion1... 95 | enter 96 | do raet road stack allower per inode ".raet.road.stack." 97 | recur 98 | do raet road stack allowed per inode ".raet.road.stack." 99 | 100 | go next if allowed in .raet.road.stack.status 101 | go abort if elapsed >= 2 102 | 103 | frame allowed 104 | print Allowed Minion1... 105 | go next 106 | 107 | frame message 108 | print Messaging Minion1... 109 | enter 110 | do raet road stack messenger to contents "Minion 1 Hello" code 15 \ 111 | per inode ".raet.road.stack." 112 | go next 113 | 114 | frame manage 115 | print Managing Minion1... 116 | do raet road stack manager per inode ".raet.road.stack." 117 | go next if elapsed >= 5 118 | 119 | frame idle 120 | print Idling Minion1... 121 | do raet road stack idled per inode ".raet.road.stack." 122 | go abort if idled in .raet.road.stack.status 123 | 124 | frame abort 125 | bid stop all 126 | 127 | framer servicetx be active first start 128 | frame start 129 | do raet road stack tx servicer per inode ".raet.road.stack" 130 | 131 | house minion2 132 | 133 | init .raet.road.stack.local to uid 0 name "minion2" host "" port 7532 \ 134 | basedirpath "/tmp/raet/test/keep/" main False auto True 135 | 136 | 137 | framer minionudpstack be active first start 138 | frame start 139 | do raet road stack setup per inode ".raet.road.stack" 140 | exit 141 | do raet road stack closer per inode ".raet.road.stack." 142 | 143 | framer servicerx be active first start 144 | frame start 145 | do raet road stack rx servicer per inode ".raet.road.stack" 146 | 147 | 148 | framer bootstrap be active first checkjoin 149 | frame checkjoin 150 | print Checking Join Minion2... 151 | enter 152 | do raet road stack joined per inode ".raet.road.stack." 153 | 154 | go alreadyjoined if joined in .raet.road.stack.status 155 | go join 156 | 157 | frame alreadyjoined 158 | print Already Joined Minion2... 159 | go checkallow 160 | 161 | frame join 162 | print Joining Minion2... 163 | enter 164 | do raet road stack joiner per inode ".raet.road.stack." 165 | recur 166 | do raet road stack joined per inode ".raet.road.stack." 167 | 168 | go next if joined in .raet.road.stack.status 169 | go abort if elapsed >= 5 170 | 171 | frame joined 172 | print Joined Minion2... 173 | go next 174 | 175 | frame checkallow 176 | print Checking allow Minion2... 177 | enter 178 | do raet road stack allowed per inode ".raet.road.stack." 179 | 180 | go alreadyallowed if allowed in .raet.road.stack.status 181 | go allow 182 | 183 | frame alreadyallowed 184 | print Already allowed Minion2... 185 | go message 186 | 187 | frame allow 188 | print Allowing Minion2... 189 | enter 190 | do raet road stack allower per inode ".raet.road.stack." 191 | recur 192 | do raet road stack allowed per inode ".raet.road.stack." 193 | 194 | go next if allowed in .raet.road.stack.status 195 | go abort if elapsed >= 5 196 | 197 | frame allowed 198 | print Allowed Minion2... 199 | go next 200 | 201 | frame message 202 | print Messaging Minion2... 203 | enter 204 | do raet road stack messenger to contents "Minion 2 Hello" code 15 \ 205 | per inode ".raet.road.stack." 206 | go next 207 | 208 | frame manage 209 | print Managing Minion2... 210 | do raet road stack manager per inode ".raet.road.stack." 211 | go next if elapsed >= 7 212 | 213 | frame idle 214 | print Idling Minion2... 215 | do raet road stack idled per inode ".raet.road.stack." 216 | go abort if idled in .raet.road.stack.status 217 | 218 | frame abort 219 | bid stop all 220 | 221 | framer servicetx be active first start 222 | frame start 223 | do raet road stack tx servicer per inode ".raet.road.stack" 224 | -------------------------------------------------------------------------------- /raet/flo/plan/master.flo: -------------------------------------------------------------------------------- 1 | # Raet Test FloScript 2 | 3 | house master 4 | 5 | init .raet.road.stack.local to uid 1 name "master" host "" port 7530 6 | 7 | 8 | framer masterudpstack be active first start 9 | frame start 10 | do raet road stack per inode ".raet.road.stack" 11 | exit 12 | do raet road stack closer per inode ".raet.road.stack." 13 | 14 | framer receiver be active first start 15 | frame start 16 | do raet road stack printer per inode ".raet.road.stack." 17 | timeout 5 18 | 19 | frame abort 20 | bid stop all 21 | -------------------------------------------------------------------------------- /raet/flo/plan/masterminion1.flo: -------------------------------------------------------------------------------- 1 | # Raet Test FloScript 2 | 3 | house master 4 | 5 | init .raet.road.stack.local to uid 1 name "master" host "" port 7530 \ 6 | basedirpath "/tmp/raet/test/keep/" main True auto True 7 | 8 | 9 | framer masterudpstack be active first start 10 | frame start 11 | do raet road stack per inode ".raet.road.stack" 12 | exit 13 | do raet road stack closer per inode ".raet.road.stack." 14 | 15 | framer receiver be active first start 16 | frame start 17 | do raet road stack printer per inode ".raet.road.stack." 18 | timeout 5 19 | 20 | frame abort 21 | bid stop all 22 | 23 | 24 | 25 | house minion1 26 | 27 | init .raet.road.stack.local to uid 0 name "minion1" host "" port 7531 \ 28 | basedirpath "/tmp/raet/test/keep/" 29 | 30 | 31 | framer minionudpstack be active first start 32 | frame start 33 | do raet road stack per inode ".raet.road.stack" 34 | exit 35 | do raet road stack closer per inode ".raet.road.stack." 36 | 37 | framer bootstrap be active first join 38 | frame join 39 | print Joining Minion1... 40 | enter 41 | do raet road stack joiner per inode ".raet.road.stack." 42 | recur 43 | do raet road stack joined per inode ".raet.road.stack." 44 | 45 | go next if joined in .raet.road.stack.status 46 | go abort if elapsed >= 5 47 | 48 | frame joined 49 | print Joined Minion1 50 | go next 51 | 52 | frame allow 53 | print Allowing Minion1... 54 | enter 55 | do raet road stack allower per inode ".raet.road.stack." 56 | recur 57 | do raet road stack allowed per inode ".raet.road.stack." 58 | 59 | go next if allowed in .raet.road.stack.status 60 | go abort if elapsed >= 5 61 | 62 | 63 | frame allowed 64 | print Allowed Minion1 65 | go next 66 | 67 | frame message 68 | print Messaging Minion1... 69 | enter 70 | do raet road stack messenger to contents "Minion 1 Hello" code 15 \ 71 | per inode ".raet.road.stack." 72 | go next 73 | 74 | frame idle 75 | print Idling Minion1... 76 | do raet road stack idled per inode ".raet.road.stack." 77 | go abort if idled in .raet.road.stack.status 78 | 79 | frame abort 80 | bid stop all 81 | 82 | -------------------------------------------------------------------------------- /raet/flo/plan/masterminion2.flo: -------------------------------------------------------------------------------- 1 | # Raet Test FloScript 2 | 3 | house master 4 | 5 | init .raet.road.stack.local to uid 1 name "master" host "" port 7530 \ 6 | basedirpath "/tmp/raet/test/keep/" main True auto True 7 | 8 | 9 | framer masterudpstack be active first start 10 | frame start 11 | do raet road stack per inode ".raet.road.stack" 12 | exit 13 | do raet road stack closer per inode ".raet.road.stack." 14 | 15 | framer receiver be active first start 16 | frame start 17 | do raet road stack printer per inode ".raet.road.stack." 18 | timeout 5 19 | 20 | frame abort 21 | bid stop all 22 | 23 | 24 | 25 | house minion2 26 | 27 | init .raet.road.stack.local to uid 0 name "minion2" host "" port 7532 \ 28 | basedirpath "/tmp/raet/test/keep/" 29 | 30 | 31 | framer minionudpstack be active first start 32 | frame start 33 | do raet road stack per inode ".raet.road.stack" 34 | exit 35 | do raet road stack closer per inode ".raet.road.stack." 36 | 37 | framer bootstrap be active first join 38 | frame join 39 | print Joining Minion2... 40 | enter 41 | do raet road stack joiner per inode ".raet.road.stack." 42 | recur 43 | do raet road stack joined per inode ".raet.road.stack." 44 | 45 | go next if joined in .raet.road.stack.status 46 | go abort if elapsed >= 5 47 | 48 | frame joined 49 | print Joined Minion2 50 | go next 51 | 52 | frame allow 53 | print Allowing Minion2... 54 | enter 55 | do raet road stack allower per inode ".raet.road.stack." 56 | recur 57 | do raet road stack allowed per inode ".raet.road.stack." 58 | 59 | go next if allowed in .raet.road.stack.status 60 | go abort if elapsed >= 5 61 | 62 | 63 | frame allowed 64 | print Allowed Minion2 65 | go next 66 | 67 | frame message 68 | print Messaging Minion2... 69 | enter 70 | do raet road stack messenger to contents "Minion 2 Hello" code 15 \ 71 | per inode ".raet.road.stack." 72 | go next 73 | 74 | frame idle 75 | print Idling Minion2... 76 | do raet road stack idled per inode ".raet.road.stack." 77 | go abort if idled in .raet.road.stack.status 78 | 79 | frame abort 80 | bid stop all 81 | -------------------------------------------------------------------------------- /raet/flo/plan/minion.flo: -------------------------------------------------------------------------------- 1 | # Raet Test FloScript 2 | 3 | house minion 4 | 5 | init .raet.road.stack.local to uid 0 name "minion" host "" port 7531 \ 6 | basedirpath "/tmp/raet/test/keep/" 7 | 8 | 9 | framer minionudpstack be active first start 10 | frame start 11 | do raet road stack per inode ".raet.road.stack" 12 | exit 13 | do raet road stack closer per inode ".raet.road.stack." 14 | 15 | framer bootstrap be active first join 16 | frame join 17 | print Joining... 18 | enter 19 | do raet road stack joiner per inode ".raet.road.stack." 20 | recur 21 | do raet road stack joined per inode ".raet.road.stack." 22 | 23 | go next if joined in .raet.road.stack.status 24 | go abort if elapsed >= 5 25 | 26 | frame joined 27 | print Joined 28 | go next 29 | 30 | frame allow 31 | print Allowing... 32 | enter 33 | do raet road stack allower per inode ".raet.road.stack." 34 | recur 35 | do raet road stack allowed per inode ".raet.road.stack." 36 | 37 | go next if allowed in .raet.road.stack.status 38 | go abort if elapsed >= 5 39 | 40 | 41 | frame allowed 42 | print Allowed 43 | go next 44 | 45 | frame message 46 | print Messaging... 47 | enter 48 | do raet road stack messenger to contents "Minion 1 Hello" code 15 \ 49 | per inode ".raet.road.stack." 50 | go next 51 | 52 | frame idle 53 | print Idling... 54 | do raet road stack idled per inode ".raet.road.stack." 55 | go abort if idled in .raet.road.stack.status 56 | 57 | frame abort 58 | bid stop all 59 | 60 | -------------------------------------------------------------------------------- /raet/flo/plan/minion1.flo: -------------------------------------------------------------------------------- 1 | # Raet Test FloScript 2 | 3 | house minion1 4 | 5 | init .raet.road.stack.local to uid 0 name "minion1" host "" port 7531 \ 6 | basedirpath "/tmp/raet/test/keep/" 7 | 8 | 9 | framer minionudpstack be active first start 10 | frame start 11 | do raet road stack per inode ".raet.road.stack" 12 | exit 13 | do raet road stack closer per inode ".raet.road.stack." 14 | 15 | framer bootstrap be active first join 16 | frame join 17 | print Joining... 18 | enter 19 | do raet road stack joiner per inode ".raet.road.stack." 20 | recur 21 | do raet road stack joined per inode ".raet.road.stack." 22 | 23 | go next if joined in .raet.road.stack.status 24 | go abort if elapsed >= 5 25 | 26 | frame joined 27 | print Joined 28 | go next 29 | 30 | frame allow 31 | print Allowing... 32 | enter 33 | do raet road stack allower per inode ".raet.road.stack." 34 | recur 35 | do raet road stack allowed per inode ".raet.road.stack." 36 | 37 | go next if allowed in .raet.road.stack.status 38 | go abort if elapsed >= 5 39 | 40 | 41 | frame allowed 42 | print Allowed 43 | go next 44 | 45 | frame message 46 | print Messaging... 47 | enter 48 | do raet road stack messenger to contents "Minion 1 Hello" code 15 \ 49 | per inode ".raet.road.stack." 50 | go next 51 | 52 | frame idle 53 | print Idling... 54 | do raet road stack idled per inode ".raet.road.stack." 55 | go abort if idled in .raet.road.stack.status 56 | 57 | frame abort 58 | bid stop all 59 | 60 | -------------------------------------------------------------------------------- /raet/flo/plan/minion2.flo: -------------------------------------------------------------------------------- 1 | # Raet Test FloScript 2 | 3 | 4 | house minion2 5 | 6 | init .raet.road.stack.local to uid 0 name "minion2" host "" port 7532 \ 7 | basedirpath "/tmp/raet/test/keep/" 8 | 9 | 10 | framer minionudpstack be active first start 11 | frame start 12 | do raet road stack per inode ".raet.road.stack" 13 | exit 14 | do raet road stack closer per inode ".raet.road.stack." 15 | 16 | framer bootstrap be active first join 17 | frame join 18 | print Joining... 19 | enter 20 | do raet road stack joiner per inode ".raet.road.stack." 21 | recur 22 | do raet road stack joined per inode ".raet.road.stack." 23 | 24 | go next if joined in .raet.road.stack.status 25 | go abort if elapsed >= 5 26 | 27 | frame joined 28 | print Joined 29 | go next 30 | 31 | frame allow 32 | print Allowing... 33 | enter 34 | do raet road stack allower per inode ".raet.road.stack." 35 | recur 36 | do raet road stack allowed per inode ".raet.road.stack." 37 | 38 | go next if allowed in .raet.road.stack.status 39 | go abort if elapsed >= 5 40 | 41 | 42 | frame allowed 43 | print Allowed 44 | go next 45 | 46 | frame message 47 | print Messaging... 48 | enter 49 | do raet road stack messenger to contents "Minion 2 Hello" code 15 \ 50 | per inode ".raet.road.stack." 51 | go next 52 | 53 | frame idle 54 | print Idling... 55 | do raet road stack idled per inode ".raet.road.stack." 56 | go abort if idled in .raet.road.stack.status 57 | 58 | frame abort 59 | bid stop all 60 | -------------------------------------------------------------------------------- /raet/flo/plan/roadtest.flo: -------------------------------------------------------------------------------- 1 | # Raet Test FloScript 2 | 3 | house master 4 | 5 | init .raet.road.stack.local to name "master" host "" port 7530 \ 6 | basedirpath "/tmp/raet/test/keep/" main True auto True 7 | 8 | 9 | framer masterroadstack be active first start 10 | frame start 11 | enter 12 | do salt raet road cleanup per inode ".raet.road.stack" 13 | do raet road stack setup per inode ".raet.road.stack" 14 | exit 15 | do raet road stack closer per inode ".raet.road.stack." 16 | 17 | framer servicerx be active first start 18 | frame start 19 | do raet road stack rx servicer per inode ".raet.road.stack" 20 | 21 | 22 | framer receiver be active first start 23 | frame start 24 | do raet road stack printer per inode ".raet.road.stack." 25 | timeout 5 26 | 27 | frame abort 28 | bid stop all 29 | 30 | framer servicetx be active first start 31 | frame start 32 | do raet road stack tx servicer per inode ".raet.road.stack" 33 | 34 | house minion1 35 | 36 | init .raet.road.stack.local to name "minion1" host "" port 7531 \ 37 | basedirpath "/tmp/raet/test/keep/" main False auto True \ 38 | masterhost "127.0.0.1" masterport 7530 39 | 40 | 41 | framer minionudpstack be active first start 42 | frame start 43 | enter 44 | do raet road stack setup per inode ".raet.road.stack" 45 | 46 | exit 47 | do raet road stack closer per inode ".raet.road.stack." 48 | 49 | framer servicerx be active first start 50 | frame start 51 | do raet road stack rx servicer per inode ".raet.road.stack" 52 | 53 | framer bootstrap be active first join 54 | frame join 55 | print Joining Minion1... 56 | enter 57 | do raet road stack joiner per inode ".raet.road.stack." 58 | recur 59 | do raet road stack joined per inode ".raet.road.stack." 60 | 61 | go next if joined in .raet.road.stack.status 62 | go abort if elapsed >= 5 63 | 64 | frame joined 65 | print Joined Minion1 66 | go next 67 | 68 | frame allow 69 | print Allowing Minion1... 70 | enter 71 | do raet road stack allower per inode ".raet.road.stack." 72 | recur 73 | do raet road stack allowed per inode ".raet.road.stack." 74 | 75 | go next if allowed in .raet.road.stack.status 76 | go abort if elapsed >= 5 77 | 78 | 79 | frame allowed 80 | print Allowed Minion1 81 | go next 82 | 83 | frame message 84 | print Messaging Minion1... 85 | enter 86 | do raet road stack messenger to contents "Minion 1 Hello" code 15 \ 87 | per inode ".raet.road.stack." 88 | go next 89 | 90 | frame idle 91 | print Idling Minion1... 92 | do raet road stack idled per inode ".raet.road.stack." 93 | go abort if idled in .raet.road.stack.status 94 | 95 | frame abort 96 | bid stop all 97 | 98 | framer servicetx be active first start 99 | frame start 100 | do raet road stack tx servicer per inode ".raet.road.stack" 101 | 102 | house minion2 103 | 104 | init .raet.road.stack.local to name "minion2" host "" port 7532 \ 105 | basedirpath "/tmp/raet/test/keep/" main False auto True \ 106 | masterhost "127.0.0.1" masterport 7530 107 | 108 | 109 | framer minionudpstack be active first start 110 | frame start 111 | enter 112 | do raet road stack setup per inode ".raet.road.stack" 113 | 114 | exit 115 | do raet road stack closer per inode ".raet.road.stack." 116 | 117 | framer servicerx be active first start 118 | frame start 119 | do raet road stack rx servicer per inode ".raet.road.stack" 120 | 121 | framer bootstrap be active first join 122 | frame join 123 | print Joining Minion2... 124 | enter 125 | do raet road stack joiner per inode ".raet.road.stack." 126 | recur 127 | do raet road stack joined per inode ".raet.road.stack." 128 | 129 | go next if joined in .raet.road.stack.status 130 | go abort if elapsed >= 5 131 | 132 | frame joined 133 | print Joined Minion2 134 | go next 135 | 136 | frame allow 137 | print Allowing Minion2... 138 | enter 139 | do raet road stack allower per inode ".raet.road.stack." 140 | recur 141 | do raet road stack allowed per inode ".raet.road.stack." 142 | 143 | go next if allowed in .raet.road.stack.status 144 | go abort if elapsed >= 5 145 | 146 | 147 | frame allowed 148 | print Allowed Minion2 149 | go next 150 | 151 | frame message 152 | print Messaging Minion2... 153 | enter 154 | do raet road stack messenger to contents "Minion 2 Hello" code 15 \ 155 | per inode ".raet.road.stack." 156 | go next 157 | 158 | frame idle 159 | print Idling Minion2... 160 | do raet road stack idled per inode ".raet.road.stack." 161 | go abort if idled in .raet.road.stack.status 162 | 163 | frame abort 164 | bid stop all 165 | 166 | framer servicetx be active first start 167 | frame start 168 | do raet road stack tx servicer per inode ".raet.road.stack" 169 | -------------------------------------------------------------------------------- /raet/flo/plan/routetest.flo: -------------------------------------------------------------------------------- 1 | # Raet Test FloScript 2 | 3 | house master 4 | 5 | init .raet.road.stack.local to name "master" host "" port 7530 \ 6 | basedirpath "/tmp/raet/test/keep/" main True auto True 7 | init .raet.lane.stack.local to name "boss" lane "ash" \ 8 | basedirpath "/tmp/raet/test/lane/keep/" 9 | 10 | framer masterudpstack be active first start 11 | frame start 12 | do raet road stack per inode ".raet.road.stack" 13 | exit 14 | do raet road stack closer per inode ".raet.road.stack." 15 | 16 | framer receiver be active first start 17 | frame start 18 | do raet road stack printer per inode ".raet.road.stack." 19 | timeout 5 20 | 21 | frame abort 22 | bid stop all 23 | 24 | framer bossuxdstack be active first start 25 | frame start 26 | do raet lane stack per inode ".raet.lane.stack" 27 | exit 28 | do raet lane stack closer per inode ".raet.lane.stack." 29 | 30 | framer uxdreceiver be active first start 31 | frame start 32 | do raet lane stack printer per inode ".raet.road.stack." 33 | timeout 5 34 | 35 | frame abort 36 | bid stop me 37 | 38 | framer setupuxdyard be active first start 39 | frame start 40 | enter 41 | do raet lane stack yard add to lane "ash" name "yard1" 42 | 43 | frame send 44 | enter 45 | do raet lane stack transmit to stuff "Lord Hello" \ 46 | per inode ".raet.lane.stack." 47 | 48 | frame stop 49 | bid stop me 50 | 51 | 52 | house serf 53 | 54 | init .raet.lane.stack.local to name "serf" lane "ash" name "yard1" \ 55 | basedirpath "/tmp/raet/test/lane/keep/" 56 | 57 | framer serfuxdstack be active first start 58 | frame start 59 | do raet lane stack per inode ".raet.lane.stack" 60 | exit 61 | do raet lane stack closer per inode ".raet.lane.stack." 62 | 63 | framer uxdreceiver be active first start 64 | frame start 65 | do raet lane stack printer per inode ".raet.road.stack." 66 | timeout 5 67 | 68 | frame abort 69 | bid stop me 70 | 71 | 72 | framer setupuxdyard be active first start 73 | frame start 74 | enter 75 | do raet lane stack yard add to lane "ash" name "boss" 76 | timeout 0.5 77 | 78 | frame send 79 | enter 80 | do raet lane stack transmit to stuff "Serf Hello" \ 81 | per inode ".raet.lane.stack." 82 | 83 | frame stop 84 | bid stop me 85 | 86 | 87 | house minion1 88 | 89 | init .raet.road.stack.local to name "minion1" host "" port 7531 \ 90 | basedirpath "/tmp/raet/test/keep/" 91 | 92 | 93 | framer minionudpstack be active first start 94 | frame start 95 | do raet road stack per inode ".raet.road.stack" 96 | exit 97 | do raet road stack closer per inode ".raet.road.stack." 98 | 99 | framer bootstrap be active first join 100 | frame join 101 | print Joining Minion1... 102 | enter 103 | do raet road stack joiner per inode ".raet.road.stack." 104 | recur 105 | do raet road stack joined per inode ".raet.road.stack." 106 | 107 | go next if joined in .raet.road.stack.status 108 | go abort if elapsed >= 5 109 | 110 | frame joined 111 | print Joined Minion1 112 | go next 113 | 114 | frame allow 115 | print Allowing Minion1... 116 | enter 117 | do raet road stack allower per inode ".raet.road.stack." 118 | recur 119 | do raet road stack allowed per inode ".raet.road.stack." 120 | 121 | go next if allowed in .raet.road.stack.status 122 | go abort if elapsed >= 5 123 | 124 | 125 | frame allowed 126 | print Allowed Minion1 127 | go next 128 | 129 | frame message 130 | print Messaging Minion1... 131 | enter 132 | do raet road stack messenger to contents "Minion 1 Hello" code 15 \ 133 | per inode ".raet.road.stack." 134 | go next 135 | 136 | frame idle 137 | print Idling Minion1... 138 | do raet road stack idled per inode ".raet.road.stack." 139 | go abort if idled in .raet.road.stack.status 140 | 141 | frame abort 142 | bid stop all 143 | 144 | -------------------------------------------------------------------------------- /raet/flo/test/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | ''' 3 | raet.flo unit test package 4 | ''' 5 | import sys 6 | if sys.version_info < (2, 7): 7 | import unittest2 as unittest 8 | else: 9 | import unittest 10 | import os 11 | 12 | from ioflo import test 13 | from ioflo.base.consoling import getConsole 14 | console = getConsole() 15 | console.reinit(verbosity=console.Wordage.concise) 16 | 17 | top = os.path.dirname(os.path.abspath(sys.modules.get(__name__).__file__)) 18 | 19 | if __name__ == "__main__": 20 | test.run(top) 21 | -------------------------------------------------------------------------------- /raet/flo/test/test_behaving.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | """ 3 | Raet Ioflo Behavior Unittests 4 | """ 5 | 6 | import sys 7 | if sys.version_info < (2, 7): 8 | import unittest2 as unittest 9 | else: 10 | import unittest 11 | 12 | from collections import deque 13 | 14 | from ioflo.test import testing 15 | from ioflo.base.consoling import getConsole 16 | console = getConsole() 17 | 18 | # Import raet libs 19 | from raet.abiding import * # import globals 20 | from raet.road import stacking 21 | from raet.flo import behaving 22 | 23 | def setUpModule(): 24 | console.reinit(verbosity=console.Wordage.concise) 25 | 26 | 27 | def tearDownModule(): 28 | pass 29 | 30 | 31 | class BasicTestCase(testing.FrameIofloTestCase): 32 | """ 33 | Example TestCase 34 | """ 35 | 36 | def setUp(self): 37 | """ 38 | Call super if override so House Framer and Frame are setup correctly 39 | """ 40 | super(BasicTestCase, self).setUp() 41 | 42 | def tearDown(self): 43 | """ 44 | Call super if override so House Framer and Frame are torn down correctly 45 | """ 46 | super(BasicTestCase, self).tearDown() 47 | 48 | def testRaetRoadStack(self): 49 | """ 50 | Test RaetRoadStack Behavior 51 | """ 52 | console.terse("{0}\n".format(self.testRaetRoadStack.__doc__)) 53 | act = self.addEnterDeed("RaetRoadStack") 54 | self.assertIn(act, self.frame.enacts) 55 | self.assertEqual(act.actor, "RaetRoadStack") 56 | 57 | self.resolve() # resolve House, Framer, Frame, Acts, Actors 58 | self.assertDictEqual(act.actor.Ioinits, 59 | { 60 | 'txmsgs': {'ipath': 'txmsgs', 'ival': deque([])}, 61 | 'local': {'ipath': 'local', 'ival': {'uid': None, 62 | 'auto': 1, 'basedirpath': '/tmp/raet/keep', 63 | 'host': '0.0.0.0', 'sigkey': None, 64 | 'mutable': True, 'prikey': None, 65 | 'main': False, 'port': 7530, 'name': 'master'}}, 66 | 'rxmsgs': {'ipath': 'rxmsgs', 'ival': deque([])}, 67 | 'inode': 'raet.road.stack.', 68 | 'stack': 'stack'}) 69 | 70 | self.assertTrue(hasattr(act.actor, 'local')) 71 | self.assertTrue(hasattr(act.actor, 'txmsgs')) 72 | self.assertTrue(hasattr(act.actor, 'rxmsgs')) 73 | self.assertTrue(hasattr(act.actor, 'inode')) 74 | self.assertTrue(hasattr(act.actor, 'stack')) 75 | self.assertEqual(act.actor.inode.name, 'raet.road.stack') 76 | self.assertIsInstance(act.actor.stack.value, stacking.RoadStack) 77 | 78 | self.frame.enter() # run in frame 79 | self.assertIs(len(act.actor.txmsgs.value), 0) 80 | act.actor.stack.value.server.close() 81 | 82 | 83 | def runOne(test): 84 | ''' 85 | Unittest Runner 86 | ''' 87 | test = BasicTestCase(test) 88 | suite = unittest.TestSuite([test]) 89 | unittest.TextTestRunner(verbosity=2).run(suite) 90 | 91 | 92 | def runSome(): 93 | """ Unittest runner """ 94 | tests = [] 95 | names = ['testRaetRoadStack', ] 96 | tests.extend(map(BasicTestCase, names)) # pylint: disable=bad-builtin 97 | suite = unittest.TestSuite(tests) 98 | unittest.TextTestRunner(verbosity=2).run(suite) 99 | 100 | 101 | def runAll(): 102 | """ Unittest runner """ 103 | suite = unittest.TestSuite() 104 | suite.addTest(unittest.TestLoader().loadTestsFromTestCase(BasicTestCase)) 105 | unittest.TextTestRunner(verbosity=2).run(suite) 106 | 107 | if __name__ == '__main__' and __package__ is None: 108 | 109 | #console.reinit(verbosity=console.Wordage.concise) 110 | 111 | runAll() # run all unittests 112 | 113 | #runSome() # only run some 114 | 115 | #runOne('testBasic') 116 | -------------------------------------------------------------------------------- /raet/lane/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | ''' 3 | raet.lane package 4 | modules associated with unix domain socket (UXD) communications 5 | ''' 6 | 7 | __all__ = ['yarding', 'paging', 'stacking'] 8 | 9 | import importlib 10 | for m in __all__: 11 | importlib.import_module(".{0}".format(m), package='raet.lane') 12 | -------------------------------------------------------------------------------- /raet/lane/stacking.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | ''' 3 | stacking.py raet protocol stacking classes 4 | ''' 5 | # pylint: skip-file 6 | # pylint: disable=W0611 7 | 8 | # Import python libs 9 | import socket 10 | import sys 11 | import os 12 | import errno 13 | 14 | from collections import deque, Mapping 15 | try: 16 | import simplejson as json 17 | except ImportError: 18 | import json 19 | 20 | try: 21 | import msgpack 22 | except ImportError: 23 | mspack = None 24 | 25 | # Import ioflo libs 26 | from ioflo.aid.odicting import odict 27 | from ioflo.base import nonblocking 28 | 29 | # Import raet libs 30 | from ..abiding import * # import globals 31 | from .. import raeting, nacling, stacking 32 | from . import paging, yarding 33 | from ..raeting import PackKind 34 | 35 | from ioflo.base.consoling import getConsole 36 | console = getConsole() 37 | 38 | class LaneStack(stacking.Stack): 39 | ''' 40 | RAET protocol UXD (unix domain) socket stack object 41 | ''' 42 | Count = 0 43 | Uid = 0 44 | Pk = PackKind.json.value # serialization pack kind of Uxd message 45 | Accept = True # accept any uxd messages if True from yards not already in lanes 46 | 47 | def __init__(self, 48 | local=None, #passed up from subclass 49 | name='', 50 | puid=None, 51 | uid=None, 52 | lanename='lane', 53 | sockdirpath='', 54 | ha='', 55 | bufcnt=100, 56 | accept=None, 57 | **kwa 58 | ): 59 | ''' 60 | Setup LaneStack instance 61 | ''' 62 | if getattr(self, 'puid', None) is None: 63 | self.puid = puid if puid is not None else self.Uid 64 | 65 | local = local or yarding.Yard(stack=self, 66 | name=name, 67 | uid=uid, 68 | ha=ha, 69 | dirpath=sockdirpath, 70 | lanename=lanename) 71 | 72 | super(LaneStack, self).__init__(puid=puid, 73 | local=local, 74 | bufcnt=bufcnt, 75 | **kwa) 76 | 77 | self.haRemotes = odict() # remotes indexed by ha host address 78 | self.accept = self.Accept if accept is None else accept #accept uxd msg if not in lane 79 | 80 | def serverFromLocal(self): 81 | ''' 82 | Create local listening server for stack 83 | ''' 84 | 85 | if not sys.platform == 'win32': 86 | server = nonblocking.SocketUxdNb(ha=self.ha, 87 | bufsize=raeting.UXD_MAX_PACKET_SIZE * self.bufcnt) 88 | else: 89 | server = nonblocking.WinMailslotNb(ha=self.ha, 90 | bufsize=raeting.UXD_MAX_PACKET_SIZE * self.bufcnt) 91 | return server 92 | 93 | def addRemote(self, remote): 94 | ''' 95 | Add a remote to indexes 96 | ''' 97 | if remote.ha in self.haRemotes or remote.ha == self.local.ha: 98 | emsg = "Cannot add remote at ha '{0}', alreadys exists".format(remote.ha) 99 | raise raeting.StackError(emsg) 100 | super(LaneStack, self).addRemote(remote) 101 | self.haRemotes[remote.ha] = remote 102 | 103 | def removeRemote(self, remote): 104 | ''' 105 | Remove remote from all remotes dicts 106 | ''' 107 | super(LaneStack, self).removeRemote(remote) 108 | del self.haRemotes[remote.ha] 109 | 110 | def _handleOneRx(self): 111 | ''' 112 | Handle on message from .rxes deque 113 | Assumes that there is a message on the .rxes deque 114 | ''' 115 | raw, sa = self.rxes.popleft() 116 | console.verbose("{0} received raw message \n{1}\n".format(self.name, raw)) 117 | page = paging.RxPage(packed=raw) 118 | 119 | try: 120 | page.head.parse() 121 | except raeting.PageError as ex: 122 | console.terse(str(ex) + '\n') 123 | self.incStat('invalid_page_header') 124 | 125 | dn = page.data['dn'] # destination yard name 126 | if dn != self.local.name: 127 | emsg = "Invalid destination yard name = {0}. Dropping packet...\n".format(dn) 128 | console.concise( emsg) 129 | self.incStat('invalid_destination') 130 | 131 | sn = page.data['sn'] # source yard name 132 | if sn not in self.nameRemotes: 133 | if not self.accept: 134 | emsg = "Unaccepted source yard name = {0}. Dropping packet...\n".format(sn) 135 | console.terse(emsg) 136 | self.incStat('unaccepted_source_yard') 137 | return 138 | 139 | # sa is None on Windows, Mailslots don't convey their source addresses 140 | # So we need to construct a compatible source address from the local's dirpath 141 | # and lanename. Use the yarding.Yard.computeHa utility function for this. 142 | if sa is None: 143 | sa, haDirpath = yarding.Yard.computeHa(self.local.dirpath, self.local.lanename, sn) 144 | 145 | try: 146 | self.addRemote(yarding.RemoteYard(stack=self, ha=sa)) # sn and sa are assume compat 147 | except raeting.StackError as ex: 148 | console.terse(str(ex) + '\n') 149 | self.incStat('invalid_source_yard') 150 | return 151 | 152 | remote = self.nameRemotes[sn] 153 | si = page.data['si'] 154 | 155 | if si != remote.rsid: 156 | remote.rsid = si 157 | remote.removeStaleBooks() 158 | 159 | self.processRx(page, remote) 160 | 161 | def serviceRxes(self): 162 | ''' 163 | Process all messages in .rxes deque 164 | ''' 165 | while self.rxes: 166 | self._handleOneRx() 167 | 168 | def serviceRxOnce(self): 169 | ''' 170 | Process one messages in .rxes deque 171 | ''' 172 | if self.rxes: 173 | self._handleOneRx() 174 | 175 | def processRx(self, received, remote): 176 | ''' 177 | Retrieve next page from stack receive queue if any and parse 178 | Assumes received header has been parsed 179 | ''' 180 | console.verbose("{0} received page header\n{1}\n".format(self.name, received.data)) 181 | console.verbose("{0} received page index = '{1}'\n".format(self.name, received.index)) 182 | 183 | if received.paginated: 184 | index = received.index #(received.data['si'], received.data['bi']) 185 | book = remote.books.get(index) 186 | if not book: 187 | if received.data['pn'] != 0: # not first page to missed first page 188 | emsg = "Missed page prior to '{0}' from remote {1}\n".format( 189 | received.data['pn'], remote.name) 190 | console.terse(emsg) 191 | self.incStat('missed_page') 192 | return 193 | book = paging.RxBook(stack=self) 194 | remote.addBook(index, book) 195 | book.parse(received) 196 | if not book.complete: 197 | return 198 | remote.removeBook(index) 199 | body = book.body 200 | else: 201 | received.body.parse() 202 | body = received.body.data 203 | 204 | self.rxMsgs.append((body, remote.name)) 205 | 206 | def _handleOneTxMsg(self): 207 | ''' 208 | Take one message from .txMsgs deque and handle it 209 | Assumes there is a message on the deque 210 | ''' 211 | body, uid = self.txMsgs.popleft() # duple (body dict, destination name) 212 | self.message(body, uid=uid) 213 | console.verbose("{0} sending to {1}\n{2}\n".format(self.name, uid, body)) 214 | 215 | def _handleOneTx(self, laters, blocks): 216 | ''' 217 | Handle one message on .txes deque 218 | Assumes there is a message 219 | laters is deque of messages to try again later 220 | blocks is list of blocked destination address so put all associated into laters 221 | ''' 222 | tx, ta = self.txes.popleft() # duple = (packet, destination address) 223 | 224 | if ta in blocks: # already blocked on this iteration 225 | laters.append((tx, ta)) # keep sequential 226 | return 227 | 228 | try: 229 | self.server.send(tx, ta) 230 | except Exception as ex: 231 | console.concise("Error sending to '{0}' from '{1}: {2}\n".format( 232 | ta, self.ha, ex)) 233 | err = raeting.get_exception_error(ex) 234 | if err == errno.ECONNREFUSED or err == errno.ENOENT: 235 | self.incStat("stale_transmit_yard") 236 | yard = self.haRemotes.get(ta) 237 | if yard: 238 | self.removeRemote(yard) 239 | console.terse("Reaped yard {0}\n".format(yard.name)) 240 | elif err in [errno.EAGAIN, errno.EWOULDBLOCK, errno.ENOBUFS]: 241 | self.incStat("busy_transmit_yard") 242 | #busy with last message save it for later 243 | laters.append((tx, ta)) 244 | blocks.append(ta) 245 | 246 | else: 247 | self.incStat("error_transmit_yard") 248 | raise 249 | 250 | def message(self, body, uid=None): 251 | ''' 252 | Sends message body to yard given by uid and manages paging of long messages 253 | ''' 254 | if uid is None: 255 | if not self.remotes: 256 | emsg = "No yard to send to\n" 257 | console.terse(emsg) 258 | self.incStat("invalid_destination") 259 | return 260 | uid = self.remotes.values()[0].uid 261 | if uid not in self.remotes: 262 | emsg = "Invalid destination yard '{0}'\n".format(uid) 263 | console.terse(emsg) 264 | self.incStat("invalid_destination") 265 | return 266 | remote = self.remotes[uid] 267 | data = odict(pk=self.Pk, 268 | sn=self.local.name, 269 | dn=remote.name, 270 | si=remote.sid, 271 | bi=remote.nextBid()) 272 | book = paging.TxBook(data=data, body=body) 273 | try: 274 | book.pack() 275 | except raeting.PageError as ex: 276 | console.terse(str(ex) + '\n') 277 | self.incStat("packing_error") 278 | return 279 | 280 | for page in book.pages: 281 | self.txes.append((page.packed, remote.ha)) 282 | 283 | 284 | -------------------------------------------------------------------------------- /raet/lane/test/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | ''' 3 | raet.lane unit test package 4 | ''' 5 | import sys 6 | if sys.version_info < (2, 7): 7 | import unittest2 as unittest 8 | else: 9 | import unittest 10 | import os 11 | 12 | from ioflo import test 13 | from ioflo.base.consoling import getConsole 14 | console = getConsole() 15 | console.reinit(verbosity=console.Wordage.concise) 16 | 17 | top = os.path.dirname(os.path.abspath(sys.modules.get(__name__).__file__)) 18 | 19 | if __name__ == "__main__": 20 | test.run(top) 21 | -------------------------------------------------------------------------------- /raet/lane/test/test_paging.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | ''' 3 | Tests to try out paging. Potentially ephemeral 4 | 5 | ''' 6 | # pylint: skip-file 7 | import sys 8 | if sys.version_info < (2, 7): 9 | import unittest2 as unittest 10 | else: 11 | import unittest 12 | 13 | import os 14 | import time 15 | from collections import deque 16 | 17 | from ioflo.aid.odicting import odict 18 | from ioflo.aid.timing import Timer, StoreTimer 19 | from ioflo.base.storing import Store 20 | 21 | from ioflo.base.consoling import getConsole 22 | console = getConsole() 23 | 24 | # Import raet libs 25 | from raet.abiding import * # import globals 26 | from raet import raeting, nacling 27 | from raet.lane import paging, yarding, stacking 28 | 29 | def setUpModule(): 30 | console.reinit(verbosity=console.Wordage.concise) 31 | 32 | def tearDownModule(): 33 | pass 34 | 35 | 36 | class BasicTestCase(unittest.TestCase): 37 | """""" 38 | 39 | def setUp(self): 40 | self.store = Store(stamp=0.0) 41 | self.timer = StoreTimer(store=self.store, duration=1.0) 42 | 43 | def tearDown(self): 44 | pass 45 | 46 | def testPackParseJson(self): 47 | ''' 48 | Test basic page pack and parse 49 | ''' 50 | console.terse("{0}\n".format(self.testPackParseJson.__doc__)) 51 | data = odict(pk=raeting.PackKind.json.value) 52 | src = ['mayor', 'main', None] 53 | dst = ['citizen', 'other', None] 54 | route = odict([('src', src), ('dst', dst)]) 55 | 56 | body = odict([('route', route), ('content', "Hello all yards.")]) 57 | page0 = paging.TxPage(data=data, embody=body) 58 | self.assertDictEqual(page0.body.data, body) 59 | page0.pack() 60 | self.assertEqual(len(page0.packed), 169) 61 | self.assertEqual(page0.packed, b'ri RAET\nvn 0\npk 0\nsn \ndn \nsi 000000000000000000\nbi 0\npn 0000\npc 0001\n\n{"route":{"src":["mayor","main",null],"dst":["citizen","other",null]},"content":"Hello all yards."}') 62 | page1 = paging.RxPage(packed=page0.packed) 63 | page1.parse() 64 | self.assertDictEqual(page1.body.data, body) 65 | 66 | stuff = [] 67 | for i in range(10000): 68 | stuff.append(str(i).rjust(10, " ")) 69 | stuff = "".join(stuff) 70 | body = odict(msg=stuff) 71 | page0 = paging.TxPage(data=data, embody=body) 72 | self.assertRaises(raeting.PageError, page0.pack) 73 | 74 | sid = nacling.uuid(size=18) 75 | data.update(odict(sn="boy", dn='girl', si=sid, bi=1)) 76 | book0 = paging.TxBook(data=data, body=body) 77 | book0.pack() 78 | self.assertEqual(len(book0.pages), 2) 79 | self.assertEqual(book0.packed, page0.body.packed) 80 | self.assertDictEqual(book0.pages[0].data, {'ri': 'RAET', 81 | 'vn': 0, 82 | 'pk': 0, 83 | 'sn': 'boy', 84 | 'dn': 'girl', 85 | 'si': sid, 86 | 'bi': 1, 87 | 'pn': 0, 88 | 'pc': 2}) 89 | self.assertEqual(len(book0.pages[0].packed), 65533) 90 | self.assertDictEqual(book0.pages[1].data, {'ri': 'RAET', 91 | 'vn': 0, 92 | 'pk': 0, 93 | 'sn': 'boy', 94 | 'dn': 'girl', 95 | 'si': sid, 96 | 'bi': 1, 97 | 'pn': 1, 98 | 'pc': 2}) 99 | self.assertEqual(len(book0.pages[1].packed), 34631) 100 | self.assertEqual(book0.index, ('boy', 'girl', sid, 1)) 101 | 102 | book1 = paging.RxBook() 103 | for page in book0.pages: 104 | page = paging.RxPage(packed=page.packed) # simulate received packed 105 | page.head.parse() #parse head to get data 106 | book1.parse(page) 107 | 108 | self.assertDictEqual(body, book1.body) 109 | self.assertDictEqual(book1.data, {'ri': 'RAET', 110 | 'vn': 0, 111 | 'pk': 0, 112 | 'sn': 'boy', 113 | 'dn': 'girl', 114 | 'si': sid, 115 | 'bi': 1, 116 | 'pn': 0, 117 | 'pc': 2}) 118 | self.assertEqual(book1.index, ('girl', 'boy', sid, 1)) 119 | 120 | def testPackParseMsgpack(self): 121 | ''' 122 | Test basic page pack and parse 123 | ''' 124 | console.terse("{0}\n".format(self.testPackParseMsgpack.__doc__)) 125 | data = odict(pk=raeting.PackKind.pack.value) 126 | sid = nacling.uuid(size=18) 127 | data.update(odict(sn="boy", dn='girl', si=sid, bi=1)) 128 | src = ['mayor', 'main', None] 129 | dst = ['citizen', 'other', None] 130 | route = odict([('src', src), ('dst', dst)]) 131 | 132 | body = odict([('route', route), ('content', "Hello all yards.")]) 133 | page0 = paging.TxPage(data=data, embody=body) 134 | self.assertDictEqual(page0.body.data, body) 135 | page0.pack() 136 | self.assertEqual(len(page0.packed), 147) 137 | self.assertEqual(page0.packed, ns2b('ri RAET\nvn 0\npk 1\nsn boy\ndn girl\nsi {0:.18s}\nbi 1\npn 0000\npc 0001\n\n\x82\xa5route\x82\xa3src\x93\xa5mayor\xa4main\xc0\xa3dst\x93\xa7citizen\xa5other\xc0\xa7content\xb0Hello all yards.'.format(sid))) 138 | page1 = paging.RxPage(packed=page0.packed) 139 | page1.parse() 140 | self.assertDictEqual(page1.body.data, body) 141 | 142 | def testSectionedJson(self): 143 | ''' 144 | Test sectioned pack and parse json packing 145 | ''' 146 | console.terse("{0}\n".format(self.testSectionedJson.__doc__)) 147 | data = odict(pk=raeting.PackKind.json.value) 148 | sid = nacling.uuid(size=18) 149 | data.update(odict(sn="boy", dn='girl', si=sid, bi=1)) 150 | src = ['mayor', 'main', None] 151 | dst = ['citizen', 'other', None] 152 | route = odict([('src', src), ('dst', dst)]) 153 | 154 | stuff = [] 155 | for i in range(10000): 156 | stuff.append(str(i).rjust(10, " ")) 157 | stuff = "".join(stuff) 158 | self.assertEqual(len(stuff), 100000) 159 | self.assertTrue(len(stuff) > raeting.UXD_MAX_PACKET_SIZE) 160 | 161 | body = odict([('route', route), ('content', stuff)]) 162 | page0 = paging.TxPage(data=data, embody=body) 163 | self.assertDictEqual(page0.body.data, body) 164 | self.assertRaises(raeting.PageError, page0.pack) 165 | 166 | book0 = paging.TxBook(data=data, body=body) 167 | book0.pack() 168 | self.assertEqual(len(book0.packed), 100083) 169 | self.assertEqual(len(book0.pages), 2) 170 | self.assertEqual(book0.index, ('boy', 'girl', sid, 1)) 171 | 172 | book1 = paging.RxBook() 173 | for page in book0.pages: 174 | page = paging.RxPage(packed=page.packed) 175 | page.head.parse() #parse head to get data 176 | book1.parse(page) 177 | 178 | self.assertEqual(book1.index, ('girl', 'boy', sid, 1)) 179 | self.assertDictEqual(book1.body, body) 180 | self.assertEqual(book1.data['sn'], 'boy') 181 | self.assertEqual(book1.data['dn'], 'girl') 182 | self.assertEqual(book1.data['si'], sid) 183 | self.assertEqual(book1.data['bi'], 1) 184 | 185 | def testSectionedMsgpack(self): 186 | ''' 187 | Test sectioned pack and parse msgpack packing 188 | ''' 189 | console.terse("{0}\n".format(self.testSectionedMsgpack.__doc__)) 190 | data = odict(pk=raeting.PackKind.pack.value) 191 | sid = nacling.uuid(size=18) 192 | data.update(odict(sn="boy", dn='girl', si=sid, bi=1)) 193 | src = ['mayor', 'main', None] 194 | dst = ['citizen', 'other', None] 195 | route = odict([('src', src), ('dst', dst)]) 196 | 197 | stuff = [] 198 | for i in range(10000): 199 | stuff.append(str(i).rjust(10, " ")) 200 | stuff = "".join(stuff) 201 | self.assertEqual(len(stuff), 100000) 202 | self.assertTrue(len(stuff) > raeting.UXD_MAX_PACKET_SIZE) 203 | 204 | body = odict([('route', route), ('content', stuff)]) 205 | page0 = paging.TxPage(data=data, embody=body) 206 | self.assertDictEqual(page0.body.data, body) 207 | self.assertRaises(raeting.PageError, page0.pack) 208 | 209 | book0 = paging.TxBook(data=data, body=body) 210 | book0.pack() 211 | self.assertEqual(len(book0.packed), 100058) 212 | self.assertEqual(len(book0.pages), 2) 213 | self.assertEqual(book0.index, ('boy', 'girl', sid, 1)) 214 | 215 | book1 = paging.RxBook() 216 | for page in book0.pages: 217 | page = paging.RxPage(packed=page.packed) 218 | page.head.parse() #parse head to get data 219 | book1.parse(page) 220 | 221 | self.assertEqual(book1.index, ('girl', 'boy', sid, 1)) 222 | self.assertDictEqual(book1.body, body) 223 | self.assertEqual(book1.data['sn'], 'boy') 224 | self.assertEqual(book1.data['dn'], 'girl') 225 | self.assertEqual(book1.data['si'], sid) 226 | self.assertEqual(book1.data['bi'], 1) 227 | 228 | 229 | def runOne(test): 230 | ''' 231 | Unittest Runner 232 | ''' 233 | test = BasicTestCase(test) 234 | suite = unittest.TestSuite([test]) 235 | unittest.TextTestRunner(verbosity=2).run(suite) 236 | 237 | def runSome(): 238 | """ Unittest runner """ 239 | tests = [] 240 | names = ['testPackParseJson', 241 | 'testPackParseMsgpack', 242 | 'testSectionedJson', 243 | 'testSectionedMsgpack', ] 244 | tests.extend(map(BasicTestCase, names)) 245 | 246 | suite = unittest.TestSuite(tests) 247 | unittest.TextTestRunner(verbosity=2).run(suite) 248 | 249 | def runAll(): 250 | """ Unittest runner """ 251 | suite = unittest.TestSuite() 252 | suite.addTest(unittest.TestLoader().loadTestsFromTestCase(BasicTestCase)) 253 | 254 | unittest.TextTestRunner(verbosity=2).run(suite) 255 | 256 | if __name__ == '__main__' and __package__ is None: 257 | 258 | #console.reinit(verbosity=console.Wordage.concise) 259 | 260 | #runAll() #run all unittests 261 | 262 | runSome()#only run some 263 | 264 | #runOne('testPackParseJson') 265 | -------------------------------------------------------------------------------- /raet/lane/yarding.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | ''' 3 | yarding.py raet protocol estate classes 4 | ''' 5 | # pylint: skip-file 6 | # pylint: disable=W0611 7 | # Import python libs 8 | import socket 9 | import os 10 | import errno 11 | import sys 12 | 13 | if sys.version_info > (3,): 14 | long = int 15 | 16 | # Import ioflo libs 17 | from ioflo.aid.odicting import odict 18 | 19 | # Import raet libs 20 | from ..abiding import * # import globals 21 | from .. import raeting 22 | from .. import nacling 23 | from .. import lotting 24 | 25 | from ioflo.base.consoling import getConsole 26 | console = getConsole() 27 | 28 | YARD_UXD_DIR = os.path.join('/var', 'cache', 'raet') 29 | ALT_YARD_UXD_DIR = os.path.join('~', '.raet', 'uxd') 30 | 31 | 32 | class Yard(lotting.Lot): 33 | ''' 34 | RAET protocol Yard ie Lane Lot 35 | ''' 36 | 37 | def __init__(self, 38 | stack, 39 | uid=None, 40 | prefix='lane', 41 | name='', 42 | ha='', 43 | sid=None, 44 | dirpath='', 45 | lanename='', 46 | bid=0, 47 | **kwa): 48 | ''' 49 | Setup instance 50 | 51 | stack is required parameter 52 | ''' 53 | uid = uid if uid is not None else stack.nextUid() 54 | 55 | if lanename and " " in lanename: 56 | emsg = "Invalid lanename '{0}'".format(lanename) 57 | raise raeting.YardError(emsg) 58 | 59 | if name and " " in name: 60 | emsg = "Invalid yard name '{0}'".format(self.name) 61 | raise raeting.YardError(emsg) 62 | 63 | if ha: #verify that names are compatible with ha format 64 | lname, yname = Yard.namesFromHa(ha) 65 | if name and name != yname: 66 | emsg = "Incompatible Yard name '{0}' and ha '{1}'".format(name, ha) 67 | raise raeting.YardError(emsg) 68 | 69 | if lanename and lanename != lname: 70 | emsg = "Incompatible Lane name '{0}' and ha '{1}'".format(lanename, ha) 71 | raise raeting.YardError(emsg) 72 | 73 | lanename = lname 74 | name = yname 75 | 76 | name = name or "{0}_{1}".format(prefix, nacling.uuid(18)) 77 | 78 | sid = sid if sid is not None else self.nextSid() #if not given unique sid 79 | 80 | super(Yard, self).__init__(stack=stack, 81 | name=name, 82 | uid=uid, 83 | ha=ha, 84 | sid=sid, 85 | **kwa) 86 | 87 | self.lanename = lanename or 'lane' 88 | self.bid = bid #current book id 89 | 90 | if not ha: 91 | if not dirpath: 92 | dirpath = YARD_UXD_DIR 93 | ha, dirpath = self.computeHa(dirpath, self.lanename, self.name) 94 | 95 | self.dirpath = dirpath 96 | self.ha = ha 97 | 98 | @staticmethod 99 | def computeHa(dirpath, lanename, yardname): 100 | ''' 101 | Compute and return a tuple of the host address and normalize dirpath for yard given the 102 | dirpath, lanename, and yardname 103 | ''' 104 | if not sys.platform == 'win32': 105 | dirpath = os.path.abspath(os.path.expanduser(dirpath)) 106 | if not os.path.exists(dirpath): 107 | try: 108 | os.makedirs(dirpath) 109 | except OSError as ex: 110 | dirpath = os.path.abspath(os.path.expanduser(ALT_YARD_UXD_DIR)) 111 | if not os.path.exists(dirpath): 112 | try: 113 | os.makedirs(dirpath) 114 | except OSError as ex: 115 | err = raeting.get_exception_error(ex) 116 | if err == errno.EEXIST: 117 | pass # race condition 118 | else: 119 | raise 120 | else: 121 | if not os.access(dirpath, os.R_OK | os.W_OK): 122 | dirpath = os.path.abspath(os.path.expanduser(ALT_YARD_UXD_DIR)) 123 | if not os.path.exists(dirpath): 124 | try: 125 | os.makedirs(dirpath) 126 | except OSError as ex: 127 | err = raeting.get_exception_error(ex) 128 | if err == errno.EEXIST: 129 | pass # race condition 130 | else: 131 | raise 132 | 133 | ha = os.path.join(dirpath, "{0}.{1}.uxd".format(lanename, yardname)) 134 | return (ha, dirpath) 135 | 136 | @staticmethod 137 | def namesFromHa(ha): 138 | ''' 139 | Extract and return the lane and yard names from yard host address ha 140 | where return is tuple (lanename, yardname) 141 | ''' 142 | head, tail = os.path.split(ha) 143 | if not tail: 144 | emsg = "Invalid format for ha '{0}'. No file".format(ha) 145 | raise raeting.YardError(emsg) 146 | 147 | root, ext = os.path.splitext(tail) 148 | 149 | if ext != ".uxd": 150 | emsg = "Invalid format for ha '{0}'. Ext not 'uxd'".format(ha) 151 | raise raeting.YardError(emsg) 152 | 153 | lanename, sep, yardname = root.rpartition('.') 154 | if not sep: 155 | emsg = "Invalid format for ha '{0}'. No lane.name".format(ha) 156 | raise raeting.YardError(emsg) 157 | 158 | return (lanename, yardname) 159 | 160 | def nextSid(self): 161 | ''' 162 | Generates next unique sid number. 163 | ''' 164 | self.sid = nacling.uuid(size=18) 165 | return self.sid 166 | 167 | def nextBid(self): 168 | ''' 169 | Generates next book id number. 170 | ''' 171 | self.bid += 1 172 | if self.bid > long(0xffffffff): 173 | self.bid = 1 # rollover to 1 174 | return self.bid 175 | 176 | class RemoteYard(Yard): 177 | ''' 178 | RAET protocol endpoint remote yard ie Remote Lane Lot 179 | 180 | stack is required parameter 181 | ''' 182 | def __init__(self, stack, prefix='yard', uid=None, rsid=0, **kwa): 183 | ''' 184 | Setup instance 185 | ''' 186 | if uid is None: 187 | uid = stack.nextUid() 188 | while uid in stack.remotes or uid == stack.local.uid: 189 | uid = stack.nextUid() 190 | 191 | super(RemoteYard, self).__init__(stack=stack, prefix=prefix, uid=uid, **kwa) 192 | self.rsid = rsid # last sid received from remote 193 | self.books = odict() 194 | 195 | def addBook(self, index, book): 196 | ''' 197 | Safely add book at index,(si, bi) If not already there 198 | ''' 199 | if index in self.books: 200 | emsg = "Cannot add book at index '{0}', alreadys exists".format(index) 201 | raise raeting.YardError(emsg) 202 | self.books[index] = book 203 | console.verbose( "Added book to {0} at '{1}'\n".format(self.name, index)) 204 | 205 | def removeBook(self, index, book=None): 206 | ''' 207 | Safely remove book at index, (si, bi) If book identity same 208 | If book is None then remove without comparing identity 209 | ''' 210 | if index in self.books: 211 | if book: 212 | if book is self.books[index]: 213 | del self.books[index] 214 | else: 215 | del self.books[index] 216 | 217 | def removeStaleBooks(self): 218 | ''' 219 | Remove stale books associated with remote when index si different than remote.rsid 220 | where index is tuple (ln, rn, si, bi) (si, bi) 221 | ''' 222 | for index, book in self.books.items(): 223 | sid = index[2] 224 | if sid != self.rsid: 225 | self.removeBook(index, book) 226 | emsg = "Stale book at '{0}' in page from remote {1}\n".format(index, self.name) 227 | console.terse(emsg) 228 | self.stack.incStat('stale_book') 229 | -------------------------------------------------------------------------------- /raet/lotting.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | ''' 3 | lotting.py provides base class for stack endpoint interface objects 4 | defines interface protocol that stack objects depend on 5 | 6 | Lot subclasses or objects that follow Lot protocol must have following 7 | attributes or properties that are both gettable and settable. 8 | 9 | .stack 10 | .name 11 | .uid 12 | .ha 13 | 14 | ''' 15 | # pylint: skip-file 16 | # pylint: disable=W0611 17 | 18 | # Import ioflo libs 19 | from ioflo.aid.odicting import odict 20 | 21 | from ioflo.base.consoling import getConsole 22 | console = getConsole() 23 | 24 | # Import raet libs 25 | from .abiding import * # import globals 26 | from . import raeting, nacling 27 | 28 | class Lot(object): 29 | ''' 30 | RAET protocol stack endpoint 31 | way is group of lots 32 | ''' 33 | Uid = 0 34 | 35 | def __init__(self, stack, uid=None, name='', prefix='lot', ha=None, sid=0): 36 | ''' 37 | Setup Lot instance 38 | 39 | stack is a required parameter 40 | ''' 41 | self.stack = stack 42 | self.name = name or "{0}_{1}".format(prefix, nacling.uuid(size=16)) 43 | self.uid = uid if uid is not None else self.stack.nextUid() 44 | self.ha = ha 45 | self.sid = sid # current session ID 46 | 47 | def nextSid(self): 48 | ''' 49 | Generates next session id number. 50 | Follover at wrap modulor (N-1) = 2^32 -1 = 0xffffffff 51 | ''' 52 | self.sid += 1 53 | if self.sid > raeting.SID_ROLLOVER: #0xffffffff 54 | self.sid = 1 # rollover to 1 as 0 is special 55 | return self.sid 56 | 57 | def validSid(self, sid): 58 | ''' 59 | Compare new sid to old .sid and return True 60 | If old is zero Then new is always valid 61 | If new is >= old modulo N where N is 2^32 = 0x100000000 62 | And >= means the difference is less than N//2 = 0x80000000 63 | (((new - old) % 0x100000000) < (0x100000000 // 2)) 64 | ''' 65 | return self.validateSid(new=sid, old=self.sid) 66 | 67 | @staticmethod 68 | def validateSid(new, old): 69 | ''' 70 | Compare new sid to old sid and return True 71 | If old is zero Then new is always valid 72 | If new is >= old modulo N where N is 2^32 = 0x100000000 73 | And >= means the difference is less than N//2 = 0x80000000 74 | 0 = 0 % anything 75 | ''' 76 | # If old sid == 0 then new always valid. If new sid == 0 then always valid 77 | if not old or not new: 78 | return True 79 | return (((new - old) % raeting.SID_WRAP_MODULO) < 80 | (raeting.SID_WRAP_DELTA)) 81 | -------------------------------------------------------------------------------- /raet/road/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | ''' 3 | road.raet package 4 | modules associated with UDP socket communications 5 | ''' 6 | 7 | __all__ = ['estating', 'keeping', 'packeting', 'stacking', 'transacting'] 8 | 9 | import importlib 10 | for m in __all__: 11 | importlib.import_module(".{0}".format(m), package='raet.road') 12 | -------------------------------------------------------------------------------- /raet/road/test/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | ''' 3 | raet.road unit test package 4 | ''' 5 | import sys 6 | if sys.version_info < (2, 7): 7 | import unittest2 as unittest 8 | else: 9 | import unittest 10 | import os 11 | 12 | from raet import test 13 | from ioflo.base.consoling import getConsole 14 | console = getConsole() 15 | console.reinit(verbosity=console.Wordage.concise) 16 | 17 | top = os.path.dirname(os.path.abspath(sys.modules.get(__name__).__file__)) 18 | 19 | if __name__ == "__main__": 20 | test.run(top, failfast=True) 21 | -------------------------------------------------------------------------------- /raet/road/test/test_estating.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | ''' 3 | Basic test of estating 4 | 5 | ''' 6 | # pylint: skip-file 7 | # pylint: disable=C0103 8 | import sys 9 | if sys.version_info < (2, 7): 10 | import unittest2 as unittest 11 | else: 12 | import unittest 13 | 14 | import os 15 | import sys 16 | import time 17 | import tempfile 18 | import shutil 19 | 20 | from ioflo.aid.odicting import odict 21 | from ioflo.aid.timing import Timer, StoreTimer 22 | from ioflo.base.storing import Store 23 | 24 | from ioflo.base.consoling import getConsole 25 | console = getConsole() 26 | 27 | if sys.platform == 'win32': 28 | TEMPDIR = 'c:/temp' 29 | if not os.path.exists(TEMPDIR): 30 | os.mkdir(TEMPDIR) 31 | else: 32 | TEMPDIR = '/tmp' 33 | 34 | # Import raet libs 35 | from raet.abiding import * # import globals 36 | from raet import raeting, nacling 37 | from raet.road import estating, stacking 38 | 39 | def setUpModule(): 40 | console.reinit(verbosity=console.Wordage.concise) 41 | 42 | def tearDownModule(): 43 | pass 44 | 45 | 46 | class BasicTestCase(unittest.TestCase): 47 | ''' 48 | Basic pack and parse 49 | ''' 50 | 51 | def setUp(self): 52 | self.store = Store(stamp=0.0) 53 | self.timer = StoreTimer(store=self.store, duration=1.0) 54 | 55 | def tearDown(self): 56 | pass 57 | 58 | def testNormalizeHost(self): 59 | ''' 60 | Test normalizeHost method 61 | ''' 62 | console.terse("{0}\n".format(self.testNormalizeHost.__doc__)) 63 | stack = stacking.RoadStack() 64 | estate = estating.Estate(stack, ha=("", 7540), iha=("", 7540)) 65 | self.assertEqual(estate.ha, ('127.0.0.1', 7540)) 66 | self.assertEqual(estate.iha, ('127.0.0.1', 7540)) 67 | 68 | estate = estating.Estate(stack, ha=("::", 7540), iha=("::", 7540)) 69 | self.assertEqual(estate.ha, ('::1', 7540)) 70 | self.assertEqual(estate.iha, ('::1', 7540)) 71 | 72 | host = estate.normalizeHost("216.58.193.78") 73 | self.assertEqual(host, "216.58.193.78") 74 | host = estate.normalizeHost("2607:f8b0:400a:809::200e") 75 | self.assertEqual(host, '2607:f8b0:400a:809::200e') 76 | 77 | stack.server.close() 78 | 79 | 80 | def runOneBasic(test): 81 | ''' 82 | Unittest Runner 83 | ''' 84 | test = BasicTestCase(test) 85 | suite = unittest.TestSuite([test]) 86 | unittest.TextTestRunner(verbosity=2).run(suite) 87 | 88 | def runSome(): 89 | """ Unittest runner """ 90 | tests = [] 91 | names = [ 92 | 'testNormalizeHost', 93 | ] 94 | tests.extend(map(BasicTestCase, names)) 95 | 96 | suite = unittest.TestSuite(tests) 97 | unittest.TextTestRunner(verbosity=2).run(suite) 98 | 99 | def runAll(): 100 | """ Unittest runner """ 101 | suite = unittest.TestSuite() 102 | suite.addTest(unittest.TestLoader().loadTestsFromTestCase(BasicTestCase)) 103 | unittest.TextTestRunner(verbosity=2).run(suite) 104 | 105 | if __name__ == '__main__' and __package__ is None: 106 | 107 | #console.reinit(verbosity=console.Wordage.concise) 108 | 109 | #runAll() #run all unittests 110 | 111 | runSome()#only run some 112 | 113 | #runOneBasic('testSign') 114 | 115 | -------------------------------------------------------------------------------- /raet/test/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | ''' 3 | raet unit test package 4 | 5 | To run all the unittests: 6 | 7 | from raet import test 8 | test.run() 9 | 10 | ''' 11 | 12 | import sys 13 | if sys.version_info < (2, 7): 14 | import unittest2 as unittest 15 | else: 16 | import unittest 17 | import os 18 | 19 | 20 | from ioflo.base.consoling import getConsole 21 | console = getConsole() 22 | console.reinit(verbosity=console.Wordage.concise) 23 | 24 | import raet 25 | 26 | def run(start=None, failfast=False): 27 | ''' 28 | Run unittests starting at directory given by start 29 | Default start is the location of the raet package 30 | ''' 31 | top = os.path.dirname(os.path.dirname(os.path.dirname(os.path.abspath( 32 | sys.modules.get(__name__).__file__)))) 33 | 34 | if not start: 35 | start = 'raet' # top 36 | 37 | console.terse("\nRunning all RAET tests in '{0}', starting at '{1}'\n".format(top, start)) 38 | loader = unittest.TestLoader() 39 | suite = loader.discover(start, 'test_*.py', top) 40 | unittest.TextTestRunner(verbosity=2, failfast=failfast).run(suite) 41 | 42 | if __name__ == "__main__": 43 | run(failfast=True) 44 | -------------------------------------------------------------------------------- /raet/test/test_template.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | ''' Unit Tests 3 | 4 | ''' 5 | # pylint: skip-file 6 | # pylint: disable=C0103 7 | import sys 8 | if sys.version_info < (2, 7): 9 | import unittest2 as unittest 10 | else: 11 | import unittest 12 | 13 | import os 14 | 15 | from ioflo.aid.odicting import odict 16 | from ioflo.aid.timing import Timer, StoreTimer 17 | from ioflo.base.storing import Store 18 | from ioflo.base.consoling import getConsole 19 | console = getConsole() 20 | 21 | # Import raet libs 22 | from raet.abiding import * # import globals 23 | from raet import raeting, nacling 24 | from raet.road import packeting, estating, keeping, stacking, transacting 25 | 26 | def setUpModule(): 27 | console.reinit(verbosity=console.Wordage.concise) 28 | 29 | def tearDownModule(): 30 | pass 31 | 32 | class BasicTestCase(unittest.TestCase): 33 | """""" 34 | 35 | def setUp(self): 36 | self.store = Store(stamp=0.0) 37 | self.timer = StoreTimer(store=self.store, duration=1.0) 38 | 39 | def tearDown(self): 40 | pass 41 | 42 | def testBasic(self): 43 | ''' 44 | Basic unit tests 45 | ''' 46 | console.terse("{0}\n".format(self.testBasic.__doc__)) 47 | 48 | def runOne(test): 49 | ''' 50 | Unittest Runner 51 | ''' 52 | test = BasicTestCase(test) 53 | suite = unittest.TestSuite([test]) 54 | unittest.TextTestRunner(verbosity=2).run(suite) 55 | 56 | def runSome(): 57 | """ Unittest runner """ 58 | tests = [] 59 | names = ['testBasic'] 60 | tests.extend(map(BasicTestCase, names)) 61 | 62 | suite = unittest.TestSuite(tests) 63 | unittest.TextTestRunner(verbosity=2).run(suite) 64 | 65 | def runAll(): 66 | """ Unittest runner """ 67 | suite = unittest.TestSuite() 68 | suite.addTest(unittest.TestLoader().loadTestsFromTestCase(BasicTestCase)) 69 | 70 | unittest.TextTestRunner(verbosity=2).run(suite) 71 | 72 | if __name__ == '__main__' and __package__ is None: 73 | 74 | #console.reinit(verbosity=console.Wordage.concise) 75 | 76 | runAll() #run all unittests 77 | 78 | #runSome()#only run some 79 | 80 | #runOne('testBasic') 81 | -------------------------------------------------------------------------------- /scripts/raetflo: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | ''' 5 | raet floscript runner CLI 6 | 7 | Runs floscript plan from command line shell 8 | 9 | example: 10 | raetflo -h 11 | raetflo -V 12 | raetflo -v concise -n raet -r -f ../raet/flo/plan/raet.flo -b raet.flo.behaving 13 | raetflo -v verbose -n raet -r -p 0.0625 ../raet/flo/plan/raet.flo -b raet.flo 14 | 15 | ''' 16 | 17 | # Import python libs 18 | import sys 19 | 20 | # Import ioflo libs 21 | import ioflo.app.run 22 | 23 | 24 | def main(): 25 | ''' 26 | Main entry point for ioflo CLI 27 | ''' 28 | args = ioflo.app.run.parseArgs() 29 | 30 | ioflo.app.run.run( name=args.name, 31 | period = float(args.period), 32 | real = args.realtime, 33 | filepath = args.filename, 34 | behaviors=args.behaviors, 35 | username=args.username, 36 | password=args.password, 37 | verbose = args.verbose, 38 | consolepath=args.console, 39 | statistics=args.statistics) 40 | 41 | if __name__ == '__main__': 42 | main() 43 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | """ 2 | setup.py 3 | 4 | Basic setup file to enable pip install 5 | See: 6 | http://pythonhosted.org//setuptools/setuptools.html 7 | https://pypi.python.org/pypi/setuptools 8 | 9 | python setup.py register sdist upload 10 | 11 | More secure to use twine to upload $ pip3 install twine 12 | $ python setup.py sdist 13 | $ twine upload dist/raet-0.6.6.tar.gz 14 | 15 | """ 16 | import os 17 | import sys 18 | from setuptools import setup, find_packages 19 | 20 | # Change to RAET's source's directory prior to running any command 21 | try: 22 | SETUP_DIRNAME = os.path.dirname(__file__) 23 | except NameError: 24 | # We're most likely being frozen and __file__ triggered this NameError 25 | # Let's work around that 26 | SETUP_DIRNAME = os.path.dirname(sys.argv[0]) 27 | 28 | if SETUP_DIRNAME != '': 29 | os.chdir(SETUP_DIRNAME) 30 | 31 | SETUP_DIRNAME = os.path.abspath(SETUP_DIRNAME) 32 | 33 | RAET_METADATA = os.path.join(SETUP_DIRNAME, 'raet', '__metadata__.py') 34 | 35 | # Load the metadata using exec() in order not to trigger raet.__init__ import 36 | exec(compile(open(RAET_METADATA).read(), RAET_METADATA, 'exec')) 37 | 38 | REQUIREMENTS = ['ioflo>=1.2.4', 39 | 'libnacl>=1.4.3', 40 | 'six>=1.6.1', ] 41 | 42 | if sys.version_info < (2, 7): #tuple comparison element by element 43 | # Under Python 2.6, also install 44 | REQUIREMENTS.extend([ 45 | 'importlib>=1.0.3', 46 | 'argparse>=1.2.1', 47 | 'simplejson', 48 | ]) 49 | 50 | if sys.version_info < (3, 4): #tuple comparison element by element 51 | REQUIREMENTS.extend([ 52 | 'enum34>=1.0.4', 53 | ]) 54 | 55 | setup( 56 | name='raet', 57 | version=__version__, 58 | description='Reliable Asynchronous Event Transport protocol', 59 | long_description='Asynchronous transaction based protocol' 60 | ' using Ioflo. http://ioflo.com', 61 | url='https://github.com/RaetProtocol/raet.git', 62 | download_url='https://github.com/RaetProtocol/raet/archive/master.zip', 63 | author=__author__, 64 | author_email='info@ioflo.com', 65 | license=__license__, 66 | keywords=('UDP UXD Communications CurveCP Elliptic Curve Crypto' 67 | 'Reliable Asynchronous Event Transport Protocol'), 68 | include_package_data=True, 69 | packages=find_packages(exclude=['test', 'test.*', 70 | 'docs', 'docs*', 71 | 'log', 'log*']), 72 | package_data={ 73 | '': ['*.txt', '*.md', '*.rst', '*.json', '*.conf', '*.html', 74 | '*.css', '*.ico', '*.png', 'LICENSE', 'LEGAL'], 75 | 'raet': ['flo/plan/*.flo', 'flo/plan/*/*.flo', 76 | 'flo/plan/*.txt', 'flo/plan/*/*.txt',],}, 77 | install_requires=REQUIREMENTS, 78 | setup_requires=["setuptools_git >= 1.1", ], 79 | extras_require={}, 80 | scripts=['scripts/raetflo'],) 81 | 82 | -------------------------------------------------------------------------------- /systest/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | ''' 3 | systest package 4 | ''' 5 | 6 | __all__ = ['lib'] 7 | 8 | import importlib 9 | for m in __all__: 10 | importlib.import_module(".{0}".format(m), package='systest') 11 | -------------------------------------------------------------------------------- /systest/lib/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | ''' 3 | systest.lib package 4 | common libraries for system tests 5 | ''' 6 | 7 | __all__ = ['data', 'netem', 'mp_helper'] 8 | 9 | import importlib 10 | for m in __all__: 11 | importlib.import_module(".{0}".format(m), package='systest.lib') 12 | -------------------------------------------------------------------------------- /systest/lib/data.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | ''' 3 | Data providers for system tests 4 | 5 | ''' 6 | 7 | from ioflo.aid.odicting import odict 8 | from BitVector import BitVector 9 | import data 10 | 11 | 12 | def getStuff(name='master', size=1024, number=0): 13 | ''' 14 | Generate padding stuff for message data unique for the given sender name and the message number and size. 15 | Always returns equal result for equal arguments. Can be used as for data generation as for result check. 16 | 17 | :param name: sender's name 18 | :param size: data size 19 | :param number: message number 20 | :return: string of the given length containing the data 21 | ''' 22 | alpha = '{0}{1}{2}{3}'.format(name, number, 23 | ''.join([chr(n) for n in xrange(ord('A'), ord('Z') + 1)]), 24 | ''.join([chr(n) for n in xrange(ord('a'), ord('z') + 1)])) 25 | num = size / len(alpha) 26 | ret = ''.join([alpha for _ in xrange(num)]) 27 | num = size - len(ret) 28 | ret = ''.join([ret, alpha[:num]]) 29 | assert len(ret) == size, 'Coding fault: generated data size not equal to requested' 30 | return ret 31 | 32 | 33 | def createData(name='master', size=1024, number=0, house='manor', queue='stuff'): 34 | ''' 35 | Create message dictionary with padding of the given size (so the actual message will be bigger) 36 | 37 | :param name: sender name 38 | :param size: padding size 39 | :param number: message number in sequence (just for unicity) 40 | :param house: house name 41 | :param queue: queue name 42 | :return: odict containing the generated message 43 | ''' 44 | stuff = getStuff(name, size, number) 45 | ret = odict(house=house, queue=queue, sender=name, number=number, stuff=stuff) 46 | return ret 47 | 48 | 49 | def generateMessages(name, size, count, house='manor', queue='stuff'): 50 | ''' 51 | Messages generator. 52 | 53 | :param name: sender name 54 | :param size: message padding size 55 | :param count: messages count 56 | :param house: house name 57 | :param queue: queue name 58 | :return: generator object for count of messages 59 | ''' 60 | for i in xrange(count): 61 | yield createData(name, size, i, house, queue) 62 | 63 | 64 | class MessageVerifier(): 65 | ''' 66 | Provide a way to collect information about received messages and check messages contents. 67 | 68 | Current limitations: 69 | - all messages are of the same padding size 70 | - all remotes should send the same message count 71 | - house and queue are the same for all (probably should be removed at all) 72 | 73 | Usage: 74 | - for each message use verifyMessage method to verify it and register the fact it's received 75 | - at the end call checkAllDone and print results 76 | ''' 77 | def __init__(self, size, msgCount, remoteCount, house, queue): 78 | ''' 79 | Setup instance 80 | 81 | :param size: message padding size 82 | :param msgCount: expected per remote message count 83 | :param remoteCount: expected remote count 84 | :param house: house name 85 | :param queue: queue name 86 | ''' 87 | self.size = size 88 | self.count = msgCount 89 | self.remoteCount = remoteCount 90 | self.house = house 91 | self.queue = queue 92 | self.received = {} 93 | 94 | def verifyMessage(self, msg): 95 | ''' 96 | Verify the given message content and mark it as received. The message have to be one of created by the 97 | :func:`generateMessage` generator. 98 | 99 | :param msg: message to verify 100 | ''' 101 | sender = msg[0]['sender'] 102 | number = msg[0]['number'] 103 | expectedMsg = data.createData(sender, self.size, number, self.house, self.queue) 104 | equal = expectedMsg == msg[0] 105 | 106 | if sender not in self.received: 107 | self.received[sender] = (BitVector(size=self.count), # received 108 | BitVector(size=self.count), # duplicated 109 | BitVector(size=self.count)) # wrong content 110 | 111 | if self.received[sender][0][number]: # duplicate 112 | self.received[sender][1][number] = 1 113 | else: # first time received 114 | self.received[sender][0][number] = 1 115 | if not equal: 116 | self.received[sender][2][number] = 1 117 | 118 | def checkAllDone(self): 119 | ''' 120 | Check the status of all messages verified previously. For each remote writes how much messages duplicated, 121 | lost and broken. 122 | 123 | :return: a list of strings containing error messages. Empty list means no error 124 | ''' 125 | errors = [] 126 | if self.remoteCount != len(self.received): 127 | errors.append('remote count not match {0} vs {1}'.format(self.remoteCount, len(self.received))) 128 | for name, results in self.received.iteritems(): 129 | rcv = results[0].count_bits() 130 | dup = results[1].count_bits() 131 | bad = results[2].count_bits() 132 | if rcv != self.count: 133 | errors.append('{0}: lost {1} messages'.format(name, self.count - rcv)) 134 | if dup: 135 | errors.append('{0}: got duplications for {1} messages'.format(name, dup)) 136 | if bad: 137 | errors.append('{0}: {1} received messages are broken'.format(name, bad)) 138 | return errors 139 | 140 | -------------------------------------------------------------------------------- /systest/lib/mp_helper.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | ''' 3 | Helpers for multiprocessing module 4 | 5 | ''' 6 | 7 | from multiprocessing import Value, Lock 8 | 9 | 10 | class Counter(): 11 | ''' 12 | Multiprocessing integer Value() wrapper that can safely be increased and read. 13 | ''' 14 | 15 | def __init__(self, init=0): 16 | self.value = Value('i', 0) 17 | self.lock = Lock() 18 | 19 | def inc(self): 20 | ''' 21 | Increases the value by 1 22 | ''' 23 | with self.lock: 24 | self.value.value += 1 25 | 26 | def get(self): 27 | ''' 28 | Value getter 29 | 30 | :return: the counter value 31 | ''' 32 | with self.lock: 33 | return self.value.value 34 | -------------------------------------------------------------------------------- /systest/lib/netem.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | ''' 3 | Linux tc netem adapter 4 | 5 | ''' 6 | 7 | from subprocess import call, check_output 8 | 9 | SU_CMD = ['sudo'] 10 | NETEM_DEL_LO_ROOT_CMD = ['tc', 'qdisc', 'del', 'dev', 'lo', 'root'] 11 | NETEM_ADD_LO_ROOT_CMD = ['tc', 'qdisc', 'add', 'dev', 'lo', 'root', 'netem'] 12 | NETEM_SHOW_LO = ['tc', 'qdisc', 'show', 'dev', 'lo'] 13 | 14 | 15 | def delay(time=100, jitter=10, correlation=25): 16 | ''' 17 | Add loopback interface netem rule to delay packets 18 | 19 | :param time: delay value in ms 20 | :param jitter: deviation from the specified duration in ms 21 | :param correlation: 22 | :return: True if no error 23 | ''' 24 | time = '{0}ms'.format(time) 25 | jitter = '{0}ms'.format(jitter) 26 | correlation = '{0}%'.format(correlation) 27 | cmd = SU_CMD + NETEM_ADD_LO_ROOT_CMD + ['delay', time, jitter, correlation] 28 | print("calling cmd: {0}".format(cmd)) 29 | return call(cmd) == 0 30 | 31 | 32 | def loss(percent=5, correlation=25): 33 | ''' 34 | Add loopback interface netem rule to loss packets 35 | 36 | :param percent: loss percentage 37 | :param correlation: 38 | :return: True if no error 39 | ''' 40 | percent = '{0}%'.format(percent) 41 | correlation = '{0}%'.format(correlation) 42 | cmd = SU_CMD + NETEM_ADD_LO_ROOT_CMD + ['loss', percent, correlation] 43 | return call(cmd) == 0 44 | 45 | 46 | def duplicate(percent=5, correlation=25): 47 | ''' 48 | Add loopback interface netem rule to loss packets 49 | 50 | :param percent: loss percentage 51 | :param correlation: 52 | :return: True if no error 53 | ''' 54 | percent = '{0}%'.format(percent) 55 | correlation = '{0}%'.format(correlation) 56 | cmd = SU_CMD + NETEM_ADD_LO_ROOT_CMD + ['duplicate', percent, correlation] 57 | return call(cmd) == 0 58 | 59 | 60 | def reorder(time=100, percent=10, correlation=25): 61 | ''' 62 | Add loopback interface netem rule to delay packets 63 | 64 | :param time: delay value, ms 65 | :param percent: deviation from the specified duration, ms 66 | :param correlation: how much packets 67 | :return: True if no error 68 | ''' 69 | time = '{0}ms'.format(time) 70 | percent = '{0}%'.format(percent) 71 | correlation = '{0}%'.format(correlation) 72 | cmd = SU_CMD + NETEM_ADD_LO_ROOT_CMD + ['delay', time, 'reorder', percent, correlation] 73 | return call(cmd) == 0 74 | 75 | 76 | def corrupt(percent=5, correlation=25): 77 | ''' 78 | Add loopback interface netem rule to delay packets 79 | 80 | :param duration: corruption percentage 81 | :param correlation: how much packets 82 | :return: True if no error 83 | ''' 84 | percent = '{0}%'.format(percent) 85 | correlation = '{0}%'.format(correlation) 86 | cmd = SU_CMD + NETEM_ADD_LO_ROOT_CMD + ['corrupt', percent, correlation] 87 | return call(cmd) == 0 88 | 89 | 90 | def clear(): 91 | ''' 92 | Clear all netem rules on loopback interface 93 | 94 | :return: True if no error 95 | ''' 96 | cmd = SU_CMD + NETEM_DEL_LO_ROOT_CMD 97 | return call(cmd) == 0 98 | 99 | 100 | def check(): 101 | ''' 102 | Returns the count of netem rules applied to the loopback 103 | 104 | :return: The count of netem rules 105 | ''' 106 | cmd = SU_CMD + NETEM_SHOW_LO 107 | out = check_output(cmd) 108 | return len(out.splitlines()) -------------------------------------------------------------------------------- /systest/load/test_road_highload.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | ''' 3 | Load test for Raet Road Stack 4 | 5 | ''' 6 | from __future__ import print_function 7 | # pylint: skip-file 8 | import sys 9 | if sys.version_info < (2, 7): 10 | import unittest2 as unittest 11 | else: 12 | import unittest 13 | 14 | import os 15 | 16 | from ioflo.base.consoling import getConsole 17 | console = getConsole() 18 | 19 | import testing 20 | 21 | if sys.platform == 'win32': 22 | TEMPDIR = 'c:/temp' 23 | if not os.path.exists(TEMPDIR): 24 | os.mkdir(TEMPDIR) 25 | else: 26 | TEMPDIR = '/tmp' 27 | 28 | 29 | def setUpModule(): 30 | console.reinit(verbosity=console.Wordage.terse) 31 | # console.reinit(verbosity=console.Wordage.concise) 32 | 33 | 34 | def tearDownModule(): 35 | pass 36 | 37 | 38 | class LoadTestCase(testing.BasicLoadTestCase): 39 | """""" 40 | 41 | def __init__(self, *args, **kwargs): 42 | super(LoadTestCase, self).__init__(*args, **kwargs) 43 | 44 | def setUp(self): 45 | super(LoadTestCase, self).setUp() 46 | 47 | def tearDown(self): 48 | super(LoadTestCase, self).tearDown() 49 | 50 | def testOneToOneToMaster(self): 51 | ''' 52 | One slave sends messages to one master 53 | ''' 54 | console.terse("{0}\n".format(self.testOneToOneToMaster.__doc__)) 55 | self.messagingMultiPeers(masterCount=1, 56 | minionCount=1, 57 | msgSize=testing.MSG_SIZE_MED, 58 | msgCount=testing.MSG_COUNT_MED, 59 | duration=100.0, 60 | direction=testing.DIR_TO_MASTER) 61 | 62 | def testManyToOneToMaster(self): 63 | ''' 64 | Many slaves send messages to one master 65 | ''' 66 | console.terse("{0}\n".format(self.testManyToOneToMaster.__doc__)) 67 | self.messagingMultiPeers(masterCount=1, 68 | minionCount=testing.MULTI_MINION_COUNT, 69 | msgSize=testing.MSG_SIZE_MED, 70 | msgCount=testing.MSG_COUNT_MED, 71 | duration=100.0, 72 | direction=testing.DIR_TO_MASTER) 73 | 74 | def testOneToManyToMaster(self): 75 | ''' 76 | One slave sends messages to many masters 77 | ''' 78 | console.terse("{0}\n".format(self.testOneToManyToMaster.__doc__)) 79 | self.messagingMultiPeers(masterCount=testing.MULTI_MASTER_COUNT, 80 | minionCount=1, 81 | msgSize=testing.MSG_SIZE_MED, 82 | msgCount=testing.MSG_COUNT_MED, 83 | duration=100.0, 84 | direction=testing.DIR_TO_MASTER) 85 | 86 | def testManyToManyToMaster(self): 87 | ''' 88 | Many slaves send messages to many masters 89 | ''' 90 | console.terse("{0}\n".format(self.testManyToManyToMaster.__doc__)) 91 | self.messagingMultiPeers(masterCount=testing.MULTI_MASTER_COUNT, 92 | minionCount=testing.MULTI_MINION_COUNT, 93 | msgSize=testing.MSG_SIZE_MED, 94 | msgCount=testing.MSG_COUNT_MED, 95 | duration=100.0, 96 | direction=testing.DIR_TO_MASTER) 97 | 98 | def testOneToOneFromMaster(self): 99 | ''' 100 | One master sends messages to one slave 101 | ''' 102 | console.terse("{0}\n".format(self.testOneToOneFromMaster.__doc__)) 103 | self.messagingMultiPeers(masterCount=1, 104 | minionCount=1, 105 | msgSize=testing.MSG_SIZE_MED, 106 | msgCount=testing.MSG_COUNT_MED, 107 | duration=100.0, 108 | direction=testing.DIR_FROM_MASTER) 109 | 110 | def testManyToOneFromMaster(self): 111 | ''' 112 | One master sends messages to many slaves 113 | ''' 114 | console.terse("{0}\n".format(self.testManyToOneFromMaster.__doc__)) 115 | self.messagingMultiPeers(masterCount=1, 116 | minionCount=testing.MULTI_MINION_COUNT, 117 | msgSize=testing.MSG_SIZE_MED, 118 | msgCount=testing.MSG_COUNT_MED, 119 | duration=100.0, 120 | direction=testing.DIR_FROM_MASTER) 121 | 122 | def testOneToManyFromMaster(self): 123 | ''' 124 | Many masters send messages to one slave 125 | ''' 126 | console.terse("{0}\n".format(self.testOneToManyFromMaster.__doc__)) 127 | self.messagingMultiPeers(masterCount=testing.MULTI_MASTER_COUNT, 128 | minionCount=1, 129 | msgSize=testing.MSG_SIZE_MED, 130 | msgCount=testing.MSG_COUNT_MED, 131 | duration=100.0, 132 | direction=testing.DIR_FROM_MASTER) 133 | 134 | def testManyToManyFromMaster(self): 135 | ''' 136 | Many masters send messages to many slaves 137 | ''' 138 | console.terse("{0}\n".format(self.testManyToManyFromMaster.__doc__)) 139 | self.messagingMultiPeers(masterCount=testing.MULTI_MASTER_COUNT, 140 | minionCount=testing.MULTI_MINION_COUNT, 141 | msgSize=testing.MSG_SIZE_MED, 142 | msgCount=testing.MSG_COUNT_MED, 143 | duration=100.0, 144 | direction=testing.DIR_FROM_MASTER) 145 | 146 | def testOneToOneBidirectional(self): 147 | ''' 148 | Bidirectional messaging between one master and one slave 149 | ''' 150 | console.terse("{0}\n".format(self.testOneToOneBidirectional.__doc__)) 151 | self.messagingMultiPeers(masterCount=1, 152 | minionCount=1, 153 | msgSize=testing.MSG_SIZE_MED, 154 | msgCount=testing.MSG_COUNT_MED, 155 | duration=100.0, 156 | direction=testing.DIR_BIDIRECTIONAL) 157 | 158 | def testManyToOneBidirectional(self): 159 | ''' 160 | Bidirectional messaging between one master and many slaves 161 | ''' 162 | console.terse("{0}\n".format(self.testManyToOneBidirectional.__doc__)) 163 | self.messagingMultiPeers(masterCount=1, 164 | minionCount=testing.MULTI_MINION_COUNT, 165 | msgSize=testing.MSG_SIZE_MED, 166 | msgCount=testing.MSG_COUNT_MED, 167 | duration=100.0, 168 | direction=testing.DIR_BIDIRECTIONAL) 169 | 170 | def testOneToManyBidirectional(self): 171 | ''' 172 | Bidirectional messaging between many masters and one slave 173 | ''' 174 | console.terse("{0}\n".format(self.testOneToManyBidirectional.__doc__)) 175 | self.messagingMultiPeers(masterCount=testing.MULTI_MASTER_COUNT, 176 | minionCount=1, 177 | msgSize=testing.MSG_SIZE_MED, 178 | msgCount=testing.MSG_COUNT_MED, 179 | duration=100.0, 180 | direction=testing.DIR_BIDIRECTIONAL) 181 | 182 | def testManyToManyBidirectional(self): 183 | ''' 184 | Bidirectional messaging between many masters and many slaves 185 | ''' 186 | console.terse("{0}\n".format(self.testManyToManyBidirectional.__doc__)) 187 | self.messagingMultiPeers(masterCount=testing.MULTI_MASTER_COUNT, 188 | minionCount=testing.MULTI_MINION_COUNT, 189 | msgSize=testing.MSG_SIZE_MED, 190 | msgCount=testing.MSG_COUNT_MED, 191 | duration=1000.0, 192 | direction=testing.DIR_BIDIRECTIONAL) 193 | 194 | def testOneToOneToMasterBig(self): 195 | ''' 196 | One slave sends one big message to one master 197 | ''' 198 | console.terse("{0}\n".format(self.testOneToOneToMasterBig.__doc__)) 199 | self.messagingMultiPeers(masterCount=1, 200 | minionCount=1, 201 | msgSize=testing.MSG_SIZE_BIG, 202 | msgCount=1, 203 | duration=1000.0, 204 | direction=testing.DIR_TO_MASTER) 205 | 206 | def testManyToManyBidirectionalBig(self): 207 | ''' 208 | Bidirectional messaging between many masters and many slaves with big messages 209 | ''' 210 | console.terse("{0}\n".format(self.testManyToManyBidirectionalBig.__doc__)) 211 | self.messagingMultiPeers(masterCount=testing.MULTI_MASTER_COUNT, 212 | minionCount=testing.MULTI_MINION_COUNT, 213 | msgSize=testing.MSG_SIZE_BIG, 214 | msgCount=testing.MSG_COUNT_MED, 215 | duration=1000.0, 216 | direction=testing.DIR_BIDIRECTIONAL) 217 | 218 | 219 | def runOne(test): 220 | ''' 221 | Unittest Runner 222 | ''' 223 | test = LoadTestCase(test) 224 | suite = unittest.TestSuite([test]) 225 | unittest.TextTestRunner(verbosity=2).run(suite) 226 | 227 | 228 | def runSome(): 229 | """ Unittest runner """ 230 | tests = [] 231 | names = [ 232 | 'testOneToOneToMaster', 233 | 'testManyToOneToMaster', 234 | 'testOneToManyToMaster', 235 | 'testManyToManyToMaster', 236 | 'testOneToOneFromMaster', 237 | 'testManyToOneFromMaster', 238 | 'testOneToManyFromMaster', 239 | 'testManyToManyFromMaster', 240 | 'testOneToOneBidirectional', 241 | 'testManyToOneBidirectional', 242 | 'testOneToManyBidirectional', 243 | 'testManyToManyBidirectional', 244 | 'testOneToOneToMasterBig', 245 | 'testManyToManyBidirectionalBig', 246 | ] 247 | tests.extend(map(LoadTestCase, names)) 248 | 249 | suite = unittest.TestSuite(tests) 250 | unittest.TextTestRunner(verbosity=2).run(suite) 251 | 252 | 253 | def runAll(): 254 | """ Unittest runner """ 255 | suite = unittest.TestSuite() 256 | suite.addTest(unittest.TestLoader().loadTestsFromTestCase(LoadTestCase)) 257 | 258 | unittest.TextTestRunner(verbosity=2).run(suite) 259 | 260 | 261 | if __name__ == '__main__' and __package__ is None: 262 | 263 | # console.reinit(verbosity=console.Wordage.concise) 264 | 265 | runAll() # run all unittests 266 | 267 | # runSome() #only run some 268 | -------------------------------------------------------------------------------- /systest/load/test_road_network.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | ''' 3 | Load test for Raet Road Stack with network issues 4 | 5 | ''' 6 | from __future__ import print_function 7 | # pylint: skip-file 8 | import sys 9 | if sys.version_info < (2, 7): 10 | import unittest2 as unittest 11 | else: 12 | import unittest 13 | 14 | import os 15 | 16 | from ioflo.base.consoling import getConsole 17 | console = getConsole() 18 | 19 | from systest.lib import netem 20 | import testing 21 | 22 | if sys.platform == 'win32': 23 | TEMPDIR = 'c:/temp' 24 | if not os.path.exists(TEMPDIR): 25 | os.mkdir(TEMPDIR) 26 | else: 27 | TEMPDIR = '/tmp' 28 | 29 | 30 | def setUpModule(): 31 | console.reinit(verbosity=console.Wordage.terse) 32 | # console.reinit(verbosity=console.Wordage.concise) 33 | 34 | 35 | def tearDownModule(): 36 | pass 37 | 38 | 39 | class NetworkLoadTestCase(testing.BasicLoadTestCase): 40 | """""" 41 | 42 | def __init__(self, *args, **kwargs): 43 | super(NetworkLoadTestCase, self).__init__(*args, **kwargs) 44 | 45 | def setUp(self): 46 | super(NetworkLoadTestCase, self).setUp() 47 | netem.clear() # clear network emulation rules 48 | 49 | def tearDown(self): 50 | super(NetworkLoadTestCase, self).tearDown() 51 | # The only engine have to tear down stacks after all workers have done 52 | if self.engine: 53 | console.terse("Clearing netem rules\n") 54 | netem.clear() # clear network emulation rules 55 | if netem.check() != 0: 56 | console.terse("Error removing netem rules! Check it manually!") 57 | 58 | def testNetemWorks(self): 59 | ''' 60 | Check if system configured to run sudo tc without password 61 | If this test fail add the following in visudo: 62 | username ALL=NOPASSWD: /usr/sbin/tc 63 | This allow user 'username' to run 'sudo tc' without password prompt that is needed for netem module 64 | ''' 65 | console.terse("{0}\n".format(self.testNetemWorks.__doc__)) 66 | self.assertTrue(netem.delay()) 67 | self.assertEqual(netem.check(), 1) 68 | 69 | def testDelayOneToOneToMaster(self): 70 | ''' 71 | One slave sends messages to one master with network delays 72 | ''' 73 | console.terse("{0}\n".format(self.testDelayOneToOneToMaster.__doc__)) 74 | self.assertTrue(netem.delay(time=200, jitter=100, correlation=30)) 75 | self.assertEqual(netem.check(), 1) 76 | self.messagingMultiPeers(masterCount=1, 77 | minionCount=1, 78 | msgSize=testing.MSG_SIZE_MED, 79 | msgCount=testing.MSG_COUNT_MED, 80 | duration=100.0, 81 | direction=testing.DIR_TO_MASTER) 82 | 83 | def testLossOneToOneToMaster(self): 84 | ''' 85 | One slave sends messages to one master with packet loss 86 | ''' 87 | console.terse("{0}\n".format(self.testLossOneToOneToMaster.__doc__)) 88 | self.assertTrue(netem.loss(percent=30, correlation=25)) 89 | self.assertEqual(netem.check(), 1) 90 | self.messagingMultiPeers(masterCount=1, 91 | minionCount=1, 92 | msgSize=testing.MSG_SIZE_MED, 93 | msgCount=testing.MSG_COUNT_MED, 94 | duration=100.0, 95 | direction=testing.DIR_TO_MASTER) 96 | 97 | def testDuplicateOneToOneToMaster(self): 98 | ''' 99 | One slave sends messages to one master with packet duplication 100 | ''' 101 | console.terse("{0}\n".format(self.testDuplicateOneToOneToMaster.__doc__)) 102 | self.assertTrue(netem.duplicate(percent=50, correlation=25)) 103 | self.assertEqual(netem.check(), 1) 104 | self.messagingMultiPeers(masterCount=1, 105 | minionCount=1, 106 | msgSize=testing.MSG_SIZE_MED, 107 | msgCount=testing.MSG_COUNT_MED, 108 | duration=100.0, 109 | direction=testing.DIR_TO_MASTER) 110 | 111 | def testReorderOneToOneToMaster(self): 112 | ''' 113 | One slave sends messages to one master with packet reordering 114 | ''' 115 | console.terse("{0}\n".format(self.testReorderOneToOneToMaster.__doc__)) 116 | self.assertTrue(netem.reorder(time=200, percent=30, correlation=25)) 117 | self.assertEqual(netem.check(), 1) 118 | self.messagingMultiPeers(masterCount=1, 119 | minionCount=1, 120 | msgSize=testing.MSG_SIZE_MED, 121 | msgCount=testing.MSG_COUNT_MED, 122 | duration=100.0, 123 | direction=testing.DIR_TO_MASTER) 124 | 125 | def testCorruptOneToOneToMaster(self): 126 | ''' 127 | One slave sends messages to one master with packet corruption 128 | ''' 129 | console.terse("{0}\n".format(self.testCorruptOneToOneToMaster.__doc__)) 130 | self.assertTrue(netem.corrupt(percent=20, correlation=25)) 131 | self.assertEqual(netem.check(), 1) 132 | self.messagingMultiPeers(masterCount=1, 133 | minionCount=1, 134 | msgSize=testing.MSG_SIZE_MED, 135 | msgCount=testing.MSG_COUNT_MED, 136 | duration=100.0, 137 | direction=testing.DIR_TO_MASTER) 138 | 139 | def testDelayManyToManyBidirectional(self): 140 | ''' 141 | Bidirectional messaging between many masters and many slaves with network delay 142 | ''' 143 | console.terse("{0}\n".format(self.testDelayManyToManyBidirectional.__doc__)) 144 | self.assertTrue(netem.delay(time=200, jitter=100, correlation=30)) 145 | self.assertEqual(netem.check(), 1) 146 | self.messagingMultiPeers(masterCount=testing.MULTI_MASTER_COUNT, 147 | minionCount=testing.MULTI_MINION_COUNT, 148 | msgSize=testing.MSG_SIZE_MED, 149 | msgCount=testing.MSG_COUNT_MED, 150 | duration=100.0, 151 | direction=testing.DIR_BIDIRECTIONAL) 152 | 153 | def testLossManyToManyBidirectional(self): 154 | ''' 155 | Bidirectional messaging between many masters and many slaves with packet loss 156 | ''' 157 | console.terse("{0}\n".format(self.testLossManyToManyBidirectional.__doc__)) 158 | self.assertTrue(netem.loss(percent=30, correlation=25)) 159 | self.assertEqual(netem.check(), 1) 160 | self.messagingMultiPeers(masterCount=testing.MULTI_MASTER_COUNT, 161 | minionCount=testing.MULTI_MINION_COUNT, 162 | msgSize=testing.MSG_SIZE_MED, 163 | msgCount=testing.MSG_COUNT_MED, 164 | duration=100.0, 165 | direction=testing.DIR_BIDIRECTIONAL) 166 | 167 | def testDuplicateManyToManyBidirectional(self): 168 | ''' 169 | Bidirectional messaging between many masters and many slaves with packet duplication 170 | ''' 171 | console.terse("{0}\n".format(self.testDuplicateManyToManyBidirectional.__doc__)) 172 | self.assertTrue(netem.duplicate(percent=50, correlation=25)) 173 | self.assertEqual(netem.check(), 1) 174 | self.messagingMultiPeers(masterCount=testing.MULTI_MASTER_COUNT, 175 | minionCount=testing.MULTI_MINION_COUNT, 176 | msgSize=testing.MSG_SIZE_MED, 177 | msgCount=testing.MSG_COUNT_MED, 178 | duration=100.0, 179 | direction=testing.DIR_BIDIRECTIONAL) 180 | 181 | def testReorderManyToManyBidirectional(self): 182 | ''' 183 | Bidirectional messaging between many masters and many slaves with packet reordering 184 | ''' 185 | console.terse("{0}\n".format(self.testReorderManyToManyBidirectional.__doc__)) 186 | self.assertTrue(netem.reorder(time=200, percent=30, correlation=25)) 187 | self.assertEqual(netem.check(), 1) 188 | self.messagingMultiPeers(masterCount=testing.MULTI_MASTER_COUNT, 189 | minionCount=testing.MULTI_MINION_COUNT, 190 | msgSize=testing.MSG_SIZE_MED, 191 | msgCount=testing.MSG_COUNT_MED, 192 | duration=100.0, 193 | direction=testing.DIR_BIDIRECTIONAL) 194 | 195 | def testCorruptManyToManyBidirectional(self): 196 | ''' 197 | Bidirectional messaging between many masters and many slaves with packet corruption 198 | ''' 199 | console.terse("{0}\n".format(self.testCorruptManyToManyBidirectional.__doc__)) 200 | self.assertTrue(netem.corrupt(percent=20, correlation=25)) 201 | self.assertEqual(netem.check(), 1) 202 | self.messagingMultiPeers(masterCount=testing.MULTI_MASTER_COUNT, 203 | minionCount=testing.MULTI_MINION_COUNT, 204 | msgSize=testing.MSG_SIZE_MED, 205 | msgCount=testing.MSG_COUNT_MED, 206 | duration=100.0, 207 | direction=testing.DIR_BIDIRECTIONAL) 208 | 209 | 210 | def runOne(test): 211 | ''' 212 | Unittest Runner 213 | ''' 214 | test = NetworkLoadTestCase(test) 215 | suite = unittest.TestSuite([test]) 216 | unittest.TextTestRunner(verbosity=2).run(suite) 217 | 218 | 219 | def runSome(): 220 | """ Unittest runner """ 221 | tests = [] 222 | names = [ 223 | 'testNetemWorks', 224 | 'testDelayOneToOneToMaster', 225 | 'testLossOneToOneToMaster', 226 | 'testDuplicateOneToOneToMaster', 227 | 'testReorderOneToOneToMaster', 228 | 'testCorruptOneToOneToMaster', 229 | 'testDelayManyToManyBidirectional', 230 | 'testLossManyToManyBidirectional', 231 | 'testDuplicateManyToManyBidirectional', 232 | 'testReorderManyToManyBidirectional', 233 | 'testCorruptManyToManyBidirectional', 234 | ] 235 | tests.extend(map(NetworkLoadTestCase, names)) 236 | 237 | suite = unittest.TestSuite(tests) 238 | unittest.TextTestRunner(verbosity=2).run(suite) 239 | 240 | 241 | def runAll(): 242 | """ Unittest runner """ 243 | suite = unittest.TestSuite() 244 | suite.addTest(unittest.TestLoader().loadTestsFromTestCase(NetworkLoadTestCase)) 245 | 246 | unittest.TextTestRunner(verbosity=2).run(suite) 247 | 248 | 249 | if __name__ == '__main__' and __package__ is None: 250 | 251 | # console.reinit(verbosity=console.Wordage.concise) 252 | 253 | runAll() # run all unittests 254 | 255 | # runSome() #only run some 256 | --------------------------------------------------------------------------------