diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..d4a2c44 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,21 @@ +# http://editorconfig.org + +root = true + +[*] +indent_style = space +indent_size = 4 +trim_trailing_whitespace = true +insert_final_newline = true +charset = utf-8 +end_of_line = lf + +[*.bat] +indent_style = tab +end_of_line = crlf + +[LICENSE] +insert_final_newline = false + +[Makefile] +indent_style = tab diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..84229f4 --- /dev/null +++ b/.gitignore @@ -0,0 +1,102 @@ +# Byte-compiled / optimized / DLL files +__pycache__/ +*.py[cod] +*$py.class + +# C extensions +*.so + +# Distribution / packaging +.Python +env/ +build/ +develop-eggs/ +dist/ +downloads/ +eggs/ +.eggs/ +lib/ +lib64/ +parts/ +sdist/ +var/ +wheels/ +*.egg-info/ +.installed.cfg +*.egg + +# PyInstaller +# Usually these files are written by a python script from a template +# before PyInstaller builds the exe, so as to inject date/other infos into it. +*.manifest +*.spec + +# Installer logs +pip-log.txt +pip-delete-this-directory.txt + +# Unit test / coverage reports +htmlcov/ +.tox/ +.coverage +.coverage.* +.cache +nosetests.xml +coverage.xml +*.cover +.hypothesis/ +.pytest_cache/ + +# Translations +*.mo +*.pot + +# Django stuff: +*.log +local_settings.py + +# Flask stuff: +instance/ +.webassets-cache + +# Scrapy stuff: +.scrapy + +# Sphinx documentation +docs/_build/ + +# PyBuilder +target/ + +# Jupyter Notebook +.ipynb_checkpoints + +# pyenv +.python-version + +# celery beat schedule file +celerybeat-schedule + +# SageMath parsed files +*.sage.py + +# dotenv +.env + +# virtualenv +.venv +venv/ +ENV/ + +# Spyder project settings +.spyderproject +.spyproject + +# Rope project settings +.ropeproject + +# mkdocs documentation +/site + +# mypy +.mypy_cache/ diff --git a/CONTRIBUTING.rst b/CONTRIBUTING.rst new file mode 100644 index 0000000..1c71002 --- /dev/null +++ b/CONTRIBUTING.rst @@ -0,0 +1,116 @@ +.. highlight:: shell + +============ +Contributing +============ + +Contributions are welcome, and they are greatly appreciated! Every little bit +helps, and credit will always be given. + +You can contribute in many ways: + +Types of Contributions +---------------------- + +Report Bugs +~~~~~~~~~~~ + +Report bugs at https://gitlab.noris.de/PI/colt/issues. + +If you are reporting a bug, please include: + +* Your operating system name and version. +* Any details about your local setup that might be helpful in troubleshooting. +* Detailed steps to reproduce the bug. + +Test different ansible kubespray configurations +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + + TODO: document here how to test ansible configurations + +Implement Features +~~~~~~~~~~~~~~~~~~ + +Look through the Gitlab issues for features. Anything tagged with "enhancement" +and "help wanted" is open to whoever wants to implement it. + +Write Documentation +~~~~~~~~~~~~~~~~~~~ + +colt could always use more documentation, whether as part of the +official colt docs, in docstrings, or even on the web in blog posts, +articles, and such. + +Submit Feedback +~~~~~~~~~~~~~~~ + +The best way to send feedback is to talk to us in `Docker Gilde`_. + + +If you are proposing a feature: + +* Explain in detail how it would work. +* Keep the scope as narrow as possible, to make it easier to implement. +* Remember that this is a volunteer-driven project, and that contributions + are welcome :) + +Get Started! +------------ + +Ready to contribute? Here's how to set up `colt` for local development. + +1. Fork the `colt` repo on GitHub. +2. Clone your fork locally:: + + $ git clone git@gitlab.noris.net:PI/colt.git + +3. Install your local copy into a virtualenv. Assuming you have virtualenvwrapper installed, this is how you set up your fork for local development:: + + $ mkvirtualenv colt + $ cd colt/ + $ python setup.py develop + +4. Create a branch for local development:: + + $ git checkout -b name-of-your-bugfix-or-feature + + Now you can make your changes locally. + +5. When you're done making changes, check that your changes pass flake8 and the + tests, including testing other Python versions with tox:: + + $ flake8 colt tests + $ python setup.py test or py.test + $ tox + + To get flake8 and tox, just pip install them into your virtualenv. + +6. Commit your changes and push your branch to GitHub:: + + $ git add . + $ git commit -m "Your detailed description of your changes." + $ git push origin name-of-your-bugfix-or-feature + +7. Submit a pull request through the GitHub website. + +Pull Request Guidelines +----------------------- + +Before you submit a pull request, check that it meets these guidelines: + +1. The pull request should include tests. +2. If the pull request adds functionality, the docs should be updated. Put + your new functionality into a function with a docstring, and add the + feature to the list in README.rst. +3. The pull request should work for Python 3.4, 3.5 and 3.6. Check + and make sure that the tests pass for all supported Python versions. + +Tips +---- + +To run a subset of tests:: + +$ py.test tests.test_colt + + +.. _Docker Gilde: https://hipchat.noris.de/chat/room/544 diff --git a/MANIFEST.in b/MANIFEST.in new file mode 100644 index 0000000..292d6dd --- /dev/null +++ b/MANIFEST.in @@ -0,0 +1,10 @@ +include CONTRIBUTING.rst +include HISTORY.rst +include LICENSE +include README.rst + +recursive-include tests * +recursive-exclude * __pycache__ +recursive-exclude * *.py[co] + +recursive-include docs *.rst conf.py Makefile make.bat *.jpg *.png *.gif diff --git a/Makefile b/Makefile new file mode 100644 index 0000000..c79642d --- /dev/null +++ b/Makefile @@ -0,0 +1,88 @@ +.PHONY: clean clean-test clean-pyc clean-build docs help +.DEFAULT_GOAL := help + +define BROWSER_PYSCRIPT +import os, webbrowser, sys + +try: + from urllib import pathname2url +except: + from urllib.request import pathname2url + +webbrowser.open("file://" + pathname2url(os.path.abspath(sys.argv[1]))) +endef +export BROWSER_PYSCRIPT + +define PRINT_HELP_PYSCRIPT +import re, sys + +for line in sys.stdin: + match = re.match(r'^([a-zA-Z_-]+):.*?## (.*)$$', line) + if match: + target, help = match.groups() + print("%-20s %s" % (target, help)) +endef +export PRINT_HELP_PYSCRIPT + +BROWSER := python -c "$$BROWSER_PYSCRIPT" + +help: + @python -c "$$PRINT_HELP_PYSCRIPT" < $(MAKEFILE_LIST) + +clean: clean-build clean-pyc clean-test ## remove all build, test, coverage and Python artifacts + +clean-build: ## remove build artifacts + rm -fr build/ + rm -fr dist/ + rm -fr .eggs/ + find . -name '*.egg-info' -exec rm -fr {} + + find . -name '*.egg' -exec rm -f {} + + +clean-pyc: ## remove Python file artifacts + find . -name '*.pyc' -exec rm -f {} + + find . -name '*.pyo' -exec rm -f {} + + find . -name '*~' -exec rm -f {} + + find . -name '__pycache__' -exec rm -fr {} + + +clean-test: ## remove test and coverage artifacts + rm -fr .tox/ + rm -f .coverage + rm -fr htmlcov/ + rm -fr .pytest_cache + +lint: ## check style with flake8 + flake8 colt tests + +test: ## run tests quickly with the default Python + py.test + +test-all: ## run tests on every Python version with tox + tox + +coverage: ## check code coverage quickly with the default Python + coverage run --source colt -m pytest + coverage report -m + coverage html + $(BROWSER) htmlcov/index.html + +docs: ## generate Sphinx HTML documentation, including API docs + rm -f docs/colt.rst + rm -f docs/modules.rst + sphinx-apidoc -o docs/ colt + $(MAKE) -C docs clean + $(MAKE) -C docs html + $(BROWSER) docs/_build/html/index.html + +servedocs: docs ## compile the docs watching for changes + watchmedo shell-command -p '*.rst' -c '$(MAKE) -C docs html' -R -D . + +release: dist ## package and upload a release + twine upload dist/* + +dist: clean ## builds source and wheel package + python setup.py sdist + python setup.py bdist_wheel + ls -l dist + +install: clean ## install the package to the active Python's site-packages + python setup.py install diff --git a/Pipfile b/Pipfile new file mode 100644 index 0000000..40dcfc2 --- /dev/null +++ b/Pipfile @@ -0,0 +1,21 @@ +[[source]] + +url = "https://pypi.python.org/simple" +verify_ssl = true +name = "pypi" + + +[requires] + +python_version = "3.5" + + +[packages] + +python-novaclient = "*" +python-neutronclient = "*" +python-cinderclient = "*" + + +[dev-packages] + diff --git a/Pipfile.lock b/Pipfile.lock new file mode 100644 index 0000000..3ec81a9 --- /dev/null +++ b/Pipfile.lock @@ -0,0 +1,442 @@ +{ + "_meta": { + "hash": { + "sha256": "530e8c38c1b9641953e8f3087be29526ac375bfacf313d1033c3efb5b8d960d1" + }, + "host-environment-markers": { + "implementation_name": "cpython", + "implementation_version": "3.5.4", + "os_name": "posix", + "platform_machine": "x86_64", + "platform_python_implementation": "CPython", + "platform_release": "4.9.92-gentoow-1", + "platform_system": "Linux", + "platform_version": "#1 SMP Sun Apr 1 08:57:47 CEST 2018", + "python_full_version": "3.5.4", + "python_version": "3.5", + "sys_platform": "linux" + }, + "pipfile-spec": 6, + "requires": { + "python_version": "3.5" + }, + "sources": [ + { + "name": "pypi", + "url": "https://pypi.python.org/simple", + "verify_ssl": true + } + ] + }, + "default": { + "appdirs": { + "hashes": [ + "sha256:d8b24664561d0d34ddfaec54636d502d7cea6e29c3eaf68f3df6180863e2166e", + "sha256:9e5896d1372858f8dd3344faf4e5014d21849c756c8d5701f78f8a103b372d92" + ], + "version": "==1.4.3" + }, + "babel": { + "hashes": [ + "sha256:ad209a68d7162c4cff4b29cdebe3dec4cef75492df501b0049a9433c96ce6f80", + "sha256:8ce4cb6fdd4393edd323227cba3a077bceb2a6ce5201c902c65e730046f41f14" + ], + "version": "==2.5.3" + }, + "certifi": { + "hashes": [ + "sha256:14131608ad2fd56836d33a71ee60fa1c82bc9d2c8d98b7bdbc631fe1b3cd1296", + "sha256:edbc3f203427eef571f79a7692bb160a2b0f7ccaa31953e99bd17e307cf63f7d" + ], + "version": "==2018.1.18" + }, + "chardet": { + "hashes": [ + "sha256:fc323ffcaeaed0e0a02bf4d117757b98aed530d9ed4531e3e15460124c106691", + "sha256:84ab92ed1c4d4f16916e05906b6b75a6c0fb5db821cc65e70cbd64a3e2a5eaae" + ], + "version": "==3.0.4" + }, + "cliff": { + "hashes": [ + "sha256:4ffe9da189705d9bc1c91ae58005cf7a5f664cc456724a547604ef398c965d83", + "sha256:38a318fb2927edb61cae365d4bf3a8241f222e2b30cc9e448ae5b92665802a85" + ], + "version": "==2.11.0" + }, + "cmd2": { + "hashes": [ + "sha256:1d5dde413872de87b8504749ffde114878a7a38bbfa87784b2b7709f25dfd668", + "sha256:d04393cd76ca475ef6708dd0c2ac35ac7daf66500f26907718f3f60ddef32f4d" + ], + "version": "==0.8.4" + }, + "debtcollector": { + "hashes": [ + "sha256:bd7f1f538a3a6810c845631dfcdae0ccbb34d897cb527aa1e9ee0c2c01f28229", + "sha256:4e90683553a6bb68d10a29b42c5df90d0e83d5085ff1ac2970c91314acdf8719" + ], + "version": "==1.19.0" + }, + "decorator": { + "hashes": [ + "sha256:94d1d8905f5010d74bbbd86c30471255661a14187c45f8d7f3e5aa8540fdb2e5", + "sha256:7d46dd9f3ea1cf5f06ee0e4e1277ae618cf48dfb10ada7c8427cd46c42702a0e" + ], + "version": "==4.2.1" + }, + "deprecation": { + "hashes": [ + "sha256:0ea3d6f95a5b08fe0e14ba728d4baafd79bfd5e2aaa40b779230cf4af62d1128", + "sha256:e8d0dc5a17d7d551730e5f23ff3a53fc9e438364b9efb47d41c3e9b05522eabe" + ], + "version": "==2.0.2" + }, + "dogpile.cache": { + "hashes": [ + "sha256:631197e78b4471bb0e93d0a86264c45736bc9ae43b4205d581dcc34fbe9b5f31" + ], + "version": "==0.6.5" + }, + "idna": { + "hashes": [ + "sha256:8c7309c718f94b3a625cb648ace320157ad16ff131ae0af362c9f21b80ef6ec4", + "sha256:2c6a5de3089009e3da7c5dde64a141dbc8551d5b7f6cf4ed7c2568d0cc520a8f" + ], + "version": "==2.6" + }, + "iso8601": { + "hashes": [ + "sha256:210e0134677cc0d02f6028087fee1df1e1d76d372ee1db0bf30bf66c5c1c89a3", + "sha256:bbbae5fb4a7abfe71d4688fd64bff70b91bbd74ef6a99d964bab18f7fdf286dd", + "sha256:49c4b20e1f38aa5cf109ddcd39647ac419f928512c869dc01d5c7098eddede82" + ], + "version": "==0.1.12" + }, + "jmespath": { + "hashes": [ + "sha256:f11b4461f425740a1d908e9a3f7365c3d2e569f6ca68a2ff8bc5bcd9676edd63", + "sha256:6a81d4c9aa62caf061cb517b4d9ad1dd300374cd4706997aff9cd6aedd61fc64" + ], + "version": "==0.9.3" + }, + "jsonpatch": { + "hashes": [ + "sha256:8bf92fa26bc42c346c03bd4517722a8e4f429225dbe775ac774b2c70d95dbd33", + "sha256:49f29cab70e9068db3b1dc6b656cbe2ee4edf7dfe9bf5a0055f17a4b6804a4b9" + ], + "version": "==1.23" + }, + "jsonpointer": { + "hashes": [ + "sha256:ff379fa021d1b81ab539f5ec467c7745beb1a5671463f9dcc2b2d458bd361c1e", + "sha256:c192ba86648e05fdae4f08a17ec25180a9aef5008d973407b581798a83975362" + ], + "version": "==2.0" + }, + "keystoneauth1": { + "hashes": [ + "sha256:5a242ded38cf3f6fb0290ecb24e0db9290507667e520dfa41a129ad769d327ec", + "sha256:9f1565eb261677e6d726c1323ce8ed8da3e1b0f70e9cee14f094ebd03fbeb328" + ], + "version": "==3.4.0" + }, + "monotonic": { + "hashes": [ + "sha256:0bcd2b14e3b7ee7cfde796e408176ceffa01d89646f2e532964ef2aae0c9fa3e", + "sha256:a02611d5b518cd4051bf22d21bd0ae55b3a03f2d2993a19b6c90d9d168691f84" + ], + "version": "==1.4" + }, + "msgpack": { + "hashes": [ + "sha256:cfd6535feb0f1cf1c7cdb25773e965cc9f92928244a8c3ef6f8f8a8e1f7ae5c4", + "sha256:f8a57cbda46a94ed0db55b73e6ab0c15e78b4ede8690fa491a0e55128d552bb0", + "sha256:8767eb0032732c3a0da92cbec5ac186ef89a3258c6edca09161472ca0206c45f", + "sha256:2ff43e3247a1e11d544017bb26f580a68306cec7a6257d8818893c1fda665f42", + "sha256:fcea97a352416afcbccd7af9625159d80704a25c519c251c734527329bb20d0e", + "sha256:1369f9edba9500c7a6489b70fdfac773e925342f4531f1e3d4c20ac3173b1ae0", + "sha256:ab189a6365be1860a5ecf8159c248f12d33f79ea799ae9695fa6a29896dcf1d4", + "sha256:e274cd4480d8c76ec467a85a9c6635bbf2258f0649040560382ab58cabb44bcf", + "sha256:0b3b1773d2693c70598585a34ca2715873ba899565f0a7c9a1545baef7e7fbdc", + "sha256:22d9c929d1d539f37da3d1b0e16270fa9d46107beab8c0d4d2bddffffe895cee", + "sha256:0bae5d1538c5c6a75642f75a1781f3ac2275d744a92af1a453c150da3446138b", + "sha256:f86642d60dca13e93260187d56c2bef2487aa4d574a669e8ceefcf9f4c26fd00", + "sha256:8acc8910218555044e23826980b950e96685dc48124a290c86f6f41a296ea172", + "sha256:31a98047355d34d047fcdb55b09cb19f633cf214c705a765bd745456c142130c", + "sha256:0ee8c8c85aa651be3aa0cd005b5931769eaa658c948ce79428766f1bd46ae2c3" + ], + "version": "==0.5.6" + }, + "munch": { + "hashes": [ + "sha256:fc64a4aeb47e34ff1125f69af3cf3f59e51554b96dbaa2b720c6fb6c9e47a551" + ], + "version": "==2.3.1" + }, + "netaddr": { + "hashes": [ + "sha256:56b3558bd71f3f6999e4c52e349f38660e54a7a8a9943335f73dfc96883e08ca", + "sha256:38aeec7cdd035081d3a4c306394b19d677623bf76fa0913f6695127c7753aefd" + ], + "version": "==0.7.19" + }, + "netifaces": { + "hashes": [ + "sha256:137a77c2e0a68a3e409a532fe73340c3df6a59ffe8eb565ec8b1f0a131402d09", + "sha256:ef223d45b73cc96c25a6295f471106b3195d2367b7f153e43490673d89e9240e", + "sha256:4ddf0f329d83516bba096b7eb1ad2ee354a98e2483f89ad3a590e653ece963c8", + "sha256:61fd2706de21aac11475c921ba0fd98af19d5280702a11c5c8e2e910765dc378", + "sha256:48275e627ce9220acfed2e1ca1e4cf01f58940412f2aebac7995750b50232701", + "sha256:f8b352247ae4b6731192d33fd35b27f247e3e4618a2d5cf65de41d46bbb53223", + "sha256:a0c7c19e1fb62ac6018582f72d15ac056e75c3d2ab222fb25369e7766ed67453", + "sha256:8c3a2c7d573511507f0f29c9d1a28ce1b2a958b8d0d7a1b1966c6fd0fa5d2953", + "sha256:5a0114933657eebe4985fdf7b0099a27ec75501901000770addca6ad7bd23008", + "sha256:3b19bf224b3e46c62f5f5e65a9fbd2e9731cda09289c76aca110a3dbdf0c3332", + "sha256:2245677ee3aa1244bbd0fbf3d6e0158d38b612eba406e7be9639e7efe0371bfa", + "sha256:7925add91982cb689963cc28fb8718c006f7713b527d262e32b29b4491cec295", + "sha256:0c4da523f36d36f1ef92ee183f2512f3ceb9a9d2a45f7d19cda5a42c6689ebe0", + "sha256:337f0fae970ab7a9acf5690516f7c7795f41934350cc1e8ad33c5c0331904ac0", + "sha256:563a18f942a9c9f64eed27fe2a1b3dfb5866a440cdaf4d833213798699cc1789", + "sha256:88d8fa4fcccaca07519141e95b42f52fb650bed2e8f5b29c44e22968b92b7097", + "sha256:60f25e5b6d2a682a394c87a6d2bf4d38c8dd8999ee32b955af88ceccaef7fe93", + "sha256:c455ca29737bf9b298408fd78a48f8fc6ddaa1f50a6eb92d814a8874412c631b", + "sha256:369eb616a6c844987bd4df486bb5f591aa0d5552378c6831f56ed81cfc228cab" + ], + "version": "==0.10.6" + }, + "openstacksdk": { + "hashes": [ + "sha256:9819718df593ba825e9e6ac3a65f9bd600ccf37ef39bd8bb37277dcfc3adb201", + "sha256:720590c09b4773adbf72f5d3385fb173fbb68205a23da06543172e9b8de5c86e" + ], + "version": "==0.12.0" + }, + "os-client-config": { + "hashes": [ + "sha256:f602f18ba58e4fe14ff607bebee00d20d34c517bca1289fd0c63f9e777f1ce43", + "sha256:e98bdde50e30396d47d237cfb23e209e8c0a6f834ada190a2dcfe5305bd42af0" + ], + "version": "==1.29.0" + }, + "os-service-types": { + "hashes": [ + "sha256:4dd42c728b7f33e80a44996ace3c044b2544b58c226d7552f5ccc19eb01668b6", + "sha256:b08fb4ec1249d313afea2728fa4db916b1907806364126fe46de482671203111" + ], + "version": "==1.2.0" + }, + "osc-lib": { + "hashes": [ + "sha256:d27adb2079cce3864d9093dac1201bbb9263ce2c2c977ccce398a375ef8fae76", + "sha256:6b02b8fe036b8e5f722b9de6f14923ae7cb4d90aa4474b70df5aa1fdb113b352" + ], + "version": "==1.10.0" + }, + "oslo.config": { + "hashes": [ + "sha256:da22e8726c454c2d3e3e958f834e55a051957a2a4c5c3b3ecec11381451eb328", + "sha256:b65bef82f1f3c0a9b41c30e7f19ceeb3777ed2b834fee8d0714955e88ead70f9" + ], + "version": "==6.0.2" + }, + "oslo.i18n": { + "hashes": [ + "sha256:aa412f35c1160429aedc6a6a5ef5db4aa3aa272602bb7b1432c127150e33203d", + "sha256:c3cf63c01fa3ff1b5ae7d6445d805c6bf5390ac010725cf126b18eb9086f4c4e" + ], + "version": "==3.20.0" + }, + "oslo.serialization": { + "hashes": [ + "sha256:3dbcf9655b1549e145abc40f3016b4b147425b082e3fbaf0624682294c6f1a7a", + "sha256:9563fa6ff64bc0a94f8ad8d2b36c5dda452dfe3ea8bb8a5291ba0355687445c4" + ], + "version": "==2.25.0" + }, + "oslo.utils": { + "hashes": [ + "sha256:ca07f9e5d37955e9379ebecae54c729ea3bf96b54944e9847be8895bf6c115de", + "sha256:5ec18a8e252fa68a715d6b5faac96b433d8575ef8bcb86efeddce3dd7018757f" + ], + "version": "==3.36.0" + }, + "packaging": { + "hashes": [ + "sha256:e9215d2d2535d3ae866c3d6efc77d5b24a0192cce0ff20e42896cc0664f889c0", + "sha256:f019b770dd64e585a99714f1fd5e01c7a8f11b45635aa953fd41c689a657375b" + ], + "version": "==17.1" + }, + "pbr": { + "hashes": [ + "sha256:4e8a0ed6a8705a26768f4c3da26026013b157821fe5f95881599556ea9d91c19", + "sha256:dae4aaa78eafcad10ce2581fc34d694faa616727837fd8e55c1a00951ad6744f" + ], + "version": "==4.0.2" + }, + "prettytable": { + "hashes": [ + "sha256:853c116513625c738dc3ce1aee148b5b5757a86727e67eff6502c7ca59d43c36", + "sha256:2d5460dc9db74a32bcc8f9f67de68b2c4f4d2f01fa3bd518764c69156d9cacd9", + "sha256:a53da3b43d7a5c229b5e3ca2892ef982c46b7923b51e98f0db49956531211c4f" + ], + "version": "==0.7.2" + }, + "pyparsing": { + "hashes": [ + "sha256:fee43f17a9c4087e7ed1605bd6df994c6173c1e977d7ade7b651292fab2bd010", + "sha256:0832bcf47acd283788593e7a0f542407bd9550a55a8a8435214a1960e04bcb04", + "sha256:9e8143a3e15c13713506886badd96ca4b579a87fbdf49e550dbfc057d6cb218e", + "sha256:281683241b25fe9b80ec9d66017485f6deff1af5cde372469134b56ca8447a07", + "sha256:b8b3117ed9bdf45e14dcc89345ce638ec7e0e29b2b579fa1ecf32ce45ebac8a5", + "sha256:8f1e18d3fd36c6795bb7e02a39fd05c611ffc2596c1e0d995d34d67630426c18", + "sha256:e4d45427c6e20a59bf4f88c639dcc03ce30d193112047f94012102f235853a58" + ], + "version": "==2.2.0" + }, + "pyperclip": { + "hashes": [ + "sha256:ce829433a9af640e08ee89b20f7c62132714bcc5d77df114044d0fccb8c3b3b8" + ], + "version": "==1.6.0" + }, + "python-cinderclient": { + "hashes": [ + "sha256:99ef15002b3d2b43b5658d50369b7e1fea99c07d82118ae2173dff8182a70b33", + "sha256:aa846be4f11199d23fd43a98ef42a7646d31822b13191ed23c0aaad5e73b3fc8" + ], + "version": "==3.5.0" + }, + "python-keystoneclient": { + "hashes": [ + "sha256:7c9767e8567be6b14826cbb7d581721bab699c07c5afb38d83dc7aaf996316e7", + "sha256:f82c43c1cde7453ee274090c2e816c27c8a4c1de88583a8a5a509719917396fa" + ], + "version": "==3.15.0" + }, + "python-neutronclient": { + "hashes": [ + "sha256:63612bbe7cdd4dfdf0c8a4b99409eef64539fb0a42fb1fa12ca7635263204f5f", + "sha256:7f86527475a751ec3a101bb98f6341ca40504de59f46e57369c5e0785fe7479f" + ], + "version": "==6.8.0" + }, + "python-novaclient": { + "hashes": [ + "sha256:1449df7765bdf068890369f7d393b8f5b8f7666779f581cb8dcfbb5c6e7c0ad3", + "sha256:40fa11f3ddb8e60454aa3f6af0a9471cb60db0a1fd36193505c0961b416e3214" + ], + "version": "==10.1.0" + }, + "pytz": { + "hashes": [ + "sha256:65ae0c8101309c45772196b21b74c46b2e5d11b6275c45d251b150d5da334555", + "sha256:c06425302f2cf668f1bba7a0a03f3c1d34d4ebeef2c72003da308b3947c7f749" + ], + "version": "==2018.4" + }, + "pyyaml": { + "hashes": [ + "sha256:3262c96a1ca437e7e4763e2843746588a965426550f3797a79fca9c6199c431f", + "sha256:16b20e970597e051997d90dc2cddc713a2876c47e3d92d59ee198700c5427736", + "sha256:e863072cdf4c72eebf179342c94e6989c67185842d9997960b3e69290b2fa269", + "sha256:bc6bced57f826ca7cb5125a10b23fd0f2fff3b7c4701d64c439a300ce665fff8", + "sha256:c01b880ec30b5a6e6aa67b09a2fe3fb30473008c85cd6a67359a1b15ed6d83a4", + "sha256:827dc04b8fa7d07c44de11fabbc888e627fa8293b695e0f99cb544fdfa1bf0d1", + "sha256:592766c6303207a20efc445587778322d7f73b161bd994f227adaa341ba212ab", + "sha256:5f84523c076ad14ff5e6c037fe1c89a7f73a3e04cf0377cb4d017014976433f3", + "sha256:0c507b7f74b3d2dd4d1322ec8a94794927305ab4cebbe89cc47fe5e81541e6e8", + "sha256:b4c423ab23291d3945ac61346feeb9a0dc4184999ede5e7c43e1ffb975130ae6", + "sha256:ca233c64c6e40eaa6c66ef97058cdc80e8d0157a443655baa1b2966e812807ca", + "sha256:4474f8ea030b5127225b8894d626bb66c01cda098d47a2b0d3429b6700af9fd8", + "sha256:326420cbb492172dec84b0f65c80942de6cedb5233c413dd824483989c000608", + "sha256:5ac82e411044fb129bae5cfbeb3ba626acb2af31a8d17d175004b70862a741a7" + ], + "version": "==3.12" + }, + "requests": { + "hashes": [ + "sha256:6a1b267aa90cac58ac3a765d067950e7dbbf75b1da07e895d1f594193a40a38b", + "sha256:9c443e7324ba5b85070c4a818ade28bfabedf16ea10206da1132edaa6dda237e" + ], + "version": "==2.18.4" + }, + "requestsexceptions": { + "hashes": [ + "sha256:3083d872b6e07dc5c323563ef37671d992214ad9a32b0ca4a3d7f5500bf38ce3", + "sha256:b095cbc77618f066d459a02b137b020c37da9f46d9b057704019c9f77dba3065" + ], + "version": "==1.4.0" + }, + "rfc3986": { + "hashes": [ + "sha256:632b8fcd2ac37f24334316227f909be4f9d0738cbf409404cff6fa5f69a24093", + "sha256:8458571c4c57e1cf23593ad860bb601b6a604df6217f829c2bc70dc4b5af941b" + ], + "version": "==1.1.0" + }, + "simplejson": { + "hashes": [ + "sha256:194fa08e4047f16e7087f2a406abd15151a482a097e42d8babb1b8181b2232b1", + "sha256:43dc3082f3a8fd5bb0c80df5a8ab96d81eafeca701615aaa0b01910b1869e678", + "sha256:44a7e0e117032666d37bcfa42161c7eb27c6ed9100d260e5b25751a6d8d7a2e8", + "sha256:ef822f66d932a7ced43844a4684d7bd24c4cc7ebe8030ee7277cf7c033e58a13", + "sha256:b4967af248c1fde0b184d81b2aa9646d96a400342d26f837e772a1dcb11cdc10", + "sha256:cf669980df3a6db918e69920df3eaf52901aa4c007287070a8b6e0da811cd2a2", + "sha256:5539547ba11f4affcdc4890cc85bfdd3f2d7186042d91e9340add98699cc3d50", + "sha256:b2e64d1695bcd0d916e8633ab12179bde8d96e8cbd18d9d0c3020409cfaf8091", + "sha256:c1347a0d6e90d4a0fd67514c8691346c5cd1ee6039415eba97690f4b5d594915", + "sha256:6cf42bc495f7e3fd25e92912a22f47e439f3a809814103a1b727d373f758915a", + "sha256:6560b68e98aba17afa4e898aab21d06d549738267dbe4d0981a24b4c1db66368", + "sha256:4c4ecf20e054716cc1e5a81cadc44d3f4027108d8dd0861d8b1e3bd7a32d4f0a", + "sha256:335d2a6afdd3a31f4ef210b46e6824848491c969f4b3a655d1864f655d57c5d3", + "sha256:1c9c13077560b8c0404c38d8e385d9e171aa8aec2a9b3139ded315a4c5ffc4d8", + "sha256:26f70a009c70866a07c43e25d6d9a1fb027ecef110a6c93cc8aec04ddf2ad05f", + "sha256:c64c9972a847b5de9a47f5e3a06b280ee3301ac83089cc9d7ea922f7cea5954c", + "sha256:ec7b08ffefae94b2c0a85df4ec17e3ada8f9f2bfae18e8b6812ece366917d0c5", + "sha256:ec0d482b9d28c123a2c6ccfa5341d47734b1dee2d61a655a99f26ef9c0080ce7", + "sha256:06b69946903ffd593d45624bdc354c1b857c2b1690ed2112df88d0e4e0294b06", + "sha256:c62045146474c41c5b9e4c758873b3b2872b3e0fefd2b87de3f08292c370fce6", + "sha256:e95f107de632ae6effa6915f194f2c282db592b9aa449070a5f9c065c478ec47" + ], + "version": "==3.13.2" + }, + "six": { + "hashes": [ + "sha256:832dc0e10feb1aa2c68dcc57dbb658f1c7e65b9b61af69048abc87a2db00a0eb", + "sha256:70e8a77beed4562e7f14fe23a786b54f6296e34344c23bc42f07b15018ff98e9" + ], + "version": "==1.11.0" + }, + "stevedore": { + "hashes": [ + "sha256:e3d96b2c4e882ec0c1ff95eaebf7b575a779fd0ccb4c741b9832bed410d58b3d", + "sha256:f1c7518e7b160336040fee272174f1f7b29a46febb3632502a8f2055f973d60b" + ], + "version": "==1.28.0" + }, + "urllib3": { + "hashes": [ + "sha256:06330f386d6e4b195fbfc736b297f58c5a892e4440e54d294d7004e3a9bbea1b", + "sha256:cc44da8e1145637334317feebd728bd869a35285b93cbb4cca2577da7e62db4f" + ], + "version": "==1.22" + }, + "wcwidth": { + "hashes": [ + "sha256:f4ebe71925af7b40a864553f761ed559b43544f8f71746c2d756c7fe788ade7c", + "sha256:3df37372226d6e63e1b1e1eda15c594bca98a22d33a23832a90998faa96bc65e" + ], + "markers": "sys_platform != 'win32'", + "version": "==0.1.7" + }, + "wrapt": { + "hashes": [ + "sha256:d4d560d479f2c21e1b5443bbd15fe7ec4b37fe7e53d335d3b9b0a7b1226fe3c6" + ], + "version": "==1.10.11" + } + }, + "develop": {} +} diff --git a/README.rst b/README.rst new file mode 100644 index 0000000..22bbbf8 --- /dev/null +++ b/README.rst @@ -0,0 +1,90 @@ +==== +colt +==== + +launch kubernetes clusters on OpenStack using ansible-kubespray + + + +Features +-------- + +* Get you kubernetes cluster on noris.cloud in about 5 minutes. + +Usage +----- + +Pre-requisits +~~~~~~~~~~~~~~ + +1. An OS_RC_FILE, you should download it from the openstack WebUI. +2. A pre-created network, and security group. +3. Basic understanding of OpenStack. +4. Ansible installed on your system. + + +Get started +~~~~~~~~~~~ + +1. Clone your colt locally:: + + $ git clone git@gitlab.noris.net:PI/colt.git + +2. Install colt to your system:: + + $ python3 setup.py install + +3. edit your own configuration file:: + + $ editor docs/k8s-machines-config.yml + +You need to have some things pre-created, but the file is self explaining. + +4. clone kubespray:: + + $ git clone -b 'v2.4.0' --single-branch --depth 1 git@github.com:kubernetes-incubator/kubespray.git + +5. You should now edit the file `kubespray/inventory/group_vars/all.yml` and set the and set options as you like, for example:: + + bootstrap_os: ubuntu + +6. Edit the file `kubespray/inventory/group_vars/k8s-cluster.yml` and set the +following options:: + + kube_network_plugin: calico + cluster_name: your-cluster-name.loacl + dashboard_enabled: true + +7. Note for people with ansible pre-knowledge, YOU DON'T need to create your own inventory file, it will be automatically created for you. + +8. Run colt with your cluster configuration, this will create your inventory:: + + $ colt k8s-machines-config.yml -i mycluster.ini + +This last step takes about one minute to complete. + +9. Run ansible kubespray on your newly created machines:: + + + $ ansible-playbook -i hosts.ini kubespray/cluster.yml \ + --ssh-extra-args="-o StrictHostKeyChecking=no" -u ubuntu \ + -e ansible_python_interpreter="/usr/bin/python3" -b + + +Known Issues +------------ + +Creating OS machines with floating IPS is still not implemented. You need +to run colt and ansible on a machine which can access your kubernetes cluster +via ssh or your should run ansible via a bastion host. + + +Credits +------- + +This package was created with Cookiecutter_ and the `audreyr/cookiecutter-pypackage`_ project template. + +.. _Cookiecutter: https://github.com/audreyr/cookiecutter +.. _`audreyr/cookiecutter-pypackage`: https://github.com/audreyr/cookiecutter-pypackage + +.. highlight:: shell diff --git a/colt/__init__.py b/colt/__init__.py new file mode 100644 index 0000000..abac5c5 --- /dev/null +++ b/colt/__init__.py @@ -0,0 +1,7 @@ +# -*- coding: utf-8 -*- + +"""Top-level package for colt.""" + +__author__ = """Oz Tiram""" +__email__ = 'oz.tiram@noris.de' +__version__ = '0.1.0' diff --git a/colt/colt.py b/colt/colt.py new file mode 100644 index 0000000..27c5fc0 --- /dev/null +++ b/colt/colt.py @@ -0,0 +1,277 @@ +# https://support.ultimum.io/support/solutions/articles/1000125460-python-novaclient-neutronclient-glanceclient-swiftclient-heatclient +# http://docs.openstack.org/developer/python-novaclient/ref/v2/servers.html +import argparse +import asyncio +import os +import uuid +import sys + +import yaml +from configparser import ConfigParser + +from novaclient import client as nvclient +from novaclient.exceptions import NotFound as NovaNotFound +from cinderclient import client as cclient +from neutronclient.v2_0 import client as ntclient + +from keystoneauth1 import identity +from keystoneauth1 import session + +from .hue import red, info, que, lightcyan as cyan + + +def chunks(l, n): + """Yield successive n-sized chunks from l.""" + for i in range(0, len(l), n): + yield l[i:i + n] + + +def distribute_hosts(hosts_zones): + """ + Given [(['host1', 'host2', 'host3'], 'A'), (['host4', 'host5'], 'B')] + return: + [(host1, zone), + (host2, zone), + (host3, zone), + (host4, zone), + (host5, zone)] + """ + for item in hosts_zones: + hosts, zone = item[0], item[1] + for host in hosts: + yield (host, zone) + + +def get_host_zones(hosts, zones): + # brain fuck warning + # this divides the lists of hosts into zones + # >>> hosts + # >>> ['host1', 'host2', 'host3', 'host4', 'host5'] + # >>> zones + # >>> ['A', 'B'] + # >>> list(zip([hosts[i:i + n] for i in range(0, len(hosts), n)], zones)) # noqa + # >>> [(['host1', 'host2', 'host3'], 'A'), (['host4', 'host5'], 'B')] # noqa + if len(zones) == len(hosts): + return list(zip(hosts, zones)) + else: + end = len(zones) + 1 if len(zones) % 2 else len(zones) + host_zones = list(zip([hosts[i:i + end] for i in + range(0, len(hosts), end)], + zones)) + return distribute_hosts(host_zones) + + +# ugly global variables don't do this to much +# only tolerated here because we don't define any classes for the sake of +# readablitiy. this will be refactored in v0.2 + +nova, cinder, neutron = None, None, None + + +async def create_instance_with_volume(name, zone, flavor, image, nics, + keypair, secgroups, role, hosts): + + global nova, neutron, cinder + + try: + print(que("Checking if %s does not exist already exist" % name)) + server = nova.servers.find(name=name) + ip = server.interface_list()[0].fixed_ips[0]['ip_address'] + print(info("This machine already exists ... skipping")) + hosts[name] = (ip, role) + return + except NovaNotFound: + print(info("Okay, launching %s" % name)) + + bdm_v2 = { + "boot_index": 0, + "source_type": "volume", + "volume_size": "25", + "destination_type": "volume", + "delete_on_termination": True} + + v = cinder.volumes.create(12, name=uuid.uuid4(), imageRef=image.id) + + while v.status != 'available': + await asyncio.sleep(1) + v = cinder.volumes.get(v.id) + + v.update(bootable=True) + # wait for mark as bootable + await asyncio.sleep(2) + + # k8s does not like swap + swapoff = """ +#cloud-config +manage_etc_hosts: true +runcmd: + - swapoff -a + """ + bdm_v2["uuid"] = v.id + print("Creating instance %s... " % name) + instance = nova.servers.create(name=name, + image=None, + key_name=keypair.name, + flavor=flavor, + nics=nics, security_groups=secgroups, + block_device_mapping_v2=[bdm_v2], + userdata=swapoff, + ) + + inst_status = instance.status + print("waiting for 10 seconds for the machine to be launched ... ") + await asyncio.sleep(10) + + while inst_status == 'BUILD': + print("Instance: " + instance.name + " is in " + inst_status + + " state, sleeping for 5 seconds more...") + await asyncio.sleep(5) + instance = nova.servers.get(instance.id) + inst_status = instance.status + + print("Instance: " + instance.name + " is in " + inst_status + "state") + + ip = instance.interface_list()[0].fixed_ips[0]['ip_address'] + print("Instance booted! Name: " + instance.name + " Status: " + + instance.status + ", IP: " + ip) + + hosts[name] = (ip, role) + + +def read_os_auth_variables(): + """ + Automagically read all OS_* variables and + yield key: value pairs which can be used for + OS connection + """ + d = {} + for k, v in os.environ.items(): + if k.startswith("OS_"): + d[k[3:].lower()] = v + + [d.pop(i) for i in ('interface', 'region_name', 'identity_api_version')] + + return d + + +def get_clients(): + try: + auth = identity.Password(**read_os_auth_variables()) + sess = session.Session(auth=auth) + nova = nvclient.Client('2.1', session=sess) + neutron = ntclient.Client(session=sess) + cinder = cclient.Client('3.0', session=sess) + except KeyError: + print(red("Did you source your OS rc file?")) + sys.exit(1) + + return nova, neutron, cinder + + +def create_machines(nova, neutron, cinder, config): + + print(info(cyan("gathering information from openstack ..."))) + keypair = nova.keypairs.get(config['keypair']) + image = nova.glance.find_image(config['image']) + master_flavor = nova.flavors.find(name=config['master_flavor']) + node_flavor = nova.flavors.find(name=config['node_flavor']) + secgroup = neutron.find_resource('security_group', + config['security_group']) + secgroups = [secgroup['id']] + + net = neutron.find_resource("network", config["private_net"]) + nics = [{'net-id': net['id']}] + print(info(cyan("got my info, now launching machines ..."))) + + hosts = {} + build_args_master = [master_flavor, image, nics, keypair, secgroups, + "master", hosts] + build_args_node = [node_flavor, image, nics, keypair, secgroups, "node", + hosts] + cluster = config['cluster-name'] + masters = ["master-%s-%s" % (i, cluster) for i in + range(1, config['n-masters'] + 1)] + nodes = ["node-%s-%s" % (i, cluster) for i in + range(1, config['n-nodes'] + 1)] + + masters_zones = list(get_host_zones(masters, config['availibity-zones'])) + nodes_zones = list(get_host_zones(nodes, config['availibity-zones'])) + loop = asyncio.get_event_loop() + + tasks = [loop.create_task(create_instance_with_volume( + name, zone, *build_args_master)) for (name, zone) in + masters_zones] + + tasks.extend([loop.create_task(create_instance_with_volume( + name, zone, *build_args_node)) for (name, zone) in + nodes_zones]) + + loop.run_until_complete(asyncio.wait(tasks)) + + loop.close() + + return create_inventory(hosts, config) + + +def create_inventory(hosts, config): + """ + :hosts: + :config: config dictionary + """ + + cfg = ConfigParser(allow_no_value=True, delimiters=('\t', ' ')) + + [cfg.add_section(item) for item in ["all", "kube-master", "kube-node", + "etcd", "k8s-cluster:children"]] + masters = [] + nodes = [] + + for host, (ip, role) in hosts.items(): + cfg.set("all", host, "ansible_ssh_host=%s ip=%s" % (ip, ip)) + if role == "master": + cfg.set("kube-master", host) + masters.append(host) + if role == "node": + cfg.set("kube-node", host) + nodes.append(host) + + # add etcd + for master in masters: + cfg.set("etcd", master) + + if config["n-etcd"] > len(masters): + for node in nodes[:-len(masters)]: + cfg.set("etcd", node) + + # add all cluster groups + cfg.set("k8s-cluster:children", "kube-node") + cfg.set("k8s-cluster:children", "kube-master") + + return cfg + + +def main(): + global nova, neutron, cinder + parser = argparse.ArgumentParser() + parser.add_argument("config", help="YAML configuration") + parser.add_argument("-i", "--inventory", help="Path to Ansible inventory") + + args = parser.parse_args() + + if not args.config: + parser.print_help() + sys.exit(2) + + with open(args.config, 'r') as stream: + config = yaml.load(stream) + + nova, neutron, cinder = get_clients() + cfg = create_machines(nova, neutron, cinder, config) + + if args.inventory: + with open(args.inventory, 'w') as f: + cfg.write(f) + else: + print(info("Here is your inventory ...")) + print(red("You can save this inventory to a file with the option -i")) + cfg.write(sys.stdout) diff --git a/colt/hue.py b/colt/hue.py new file mode 100644 index 0000000..8a09e74 --- /dev/null +++ b/colt/hue.py @@ -0,0 +1,49 @@ + +# magic! taken from https://github.com/UltimateHackers/hue/blob/master/hue.py + +COMMANDS = { + # Lables + 'info': (33, '[!] '), + 'que': (34, '[?] '), + 'bad': (31, '[-] '), + 'good': (32, '[+] '), + 'run': (97, '[~] '), + + # Colors + 'green': 32, + 'lightgreen': 92, + 'grey': 37, + 'black': 30, + 'red': 31, + 'lightred': 91, + 'cyan': 36, + 'lightcyan': 96, + 'blue': 34, + 'lightblue': 94, + 'purple': 35, + 'yellow': 93, + 'white': 97, + 'lightpurple': 95, + 'orange': 33, + + # Styles + 'bg': ';7', + 'bold': ';1', + 'italic': '3', + 'under': '4', + 'strike': '09', +} + + +def _gen(string, prefix, key): + colored = prefix if prefix else string + not_colored = string if prefix else '' + return '\033[{}m{}\033[0m{}'.format(key, colored, not_colored) + + +for key, val in COMMANDS.items(): + value = val[0] if isinstance(val, tuple) else val + prefix = val[1] if isinstance(val, tuple) else '' + locals()[key] = lambda s, prefix=prefix, key=value: _gen(s, prefix, key) + +__all__ = list(COMMANDS.keys()) diff --git a/docs/Makefile b/docs/Makefile new file mode 100644 index 0000000..48189b0 --- /dev/null +++ b/docs/Makefile @@ -0,0 +1,20 @@ +# Minimal makefile for Sphinx documentation +# + +# You can set these variables from the command line. +SPHINXOPTS = +SPHINXBUILD = python -msphinx +SPHINXPROJ = colt +SOURCEDIR = . +BUILDDIR = _build + +# Put it first so that "make" without argument is like "make help". +help: + @$(SPHINXBUILD) -M help "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) + +.PHONY: help Makefile + +# Catch-all target: route all unknown targets to Sphinx using the new +# "make mode" option. $(O) is meant as a shortcut for $(SPHINXOPTS). +%: Makefile + @$(SPHINXBUILD) -M $@ "$(SOURCEDIR)" "$(BUILDDIR)" $(SPHINXOPTS) $(O) diff --git a/docs/conf.py b/docs/conf.py new file mode 100755 index 0000000..895642a --- /dev/null +++ b/docs/conf.py @@ -0,0 +1,163 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- +# +# colt documentation build configuration file, created by +# sphinx-quickstart on Fri Jun 9 13:47:02 2017. +# +# This file is execfile()d with the current directory set to its +# containing dir. +# +# Note that not all possible configuration values are present in this +# autogenerated file. +# +# All configuration values have a default; values that are commented out +# serve to show the default. + +# If extensions (or modules to document with autodoc) are in another +# directory, add these directories to sys.path here. If the directory is +# relative to the documentation root, use os.path.abspath to make it +# absolute, like shown here. +# +import os +import sys +sys.path.insert(0, os.path.abspath('..')) + +import colt + +# -- General configuration --------------------------------------------- + +# If your documentation needs a minimal Sphinx version, state it here. +# +# needs_sphinx = '1.0' + +# Add any Sphinx extension module names here, as strings. They can be +# extensions coming with Sphinx (named 'sphinx.ext.*') or your custom ones. +extensions = ['sphinx.ext.autodoc', 'sphinx.ext.viewcode'] + +# Add any paths that contain templates here, relative to this directory. +templates_path = ['_templates'] + +# The suffix(es) of source filenames. +# You can specify multiple suffix as a list of string: +# +# source_suffix = ['.rst', '.md'] +source_suffix = '.rst' + +# The master toctree document. +master_doc = 'index' + +# General information about the project. +project = u'colt' +copyright = u"2018, Oz Tiram" +author = u"Oz Tiram" + +# The version info for the project you're documenting, acts as replacement +# for |version| and |release|, also used in various other places throughout +# the built documents. +# +# The short X.Y version. +version = colt.__version__ +# The full version, including alpha/beta/rc tags. +release = colt.__version__ + +# The language for content autogenerated by Sphinx. Refer to documentation +# for a list of supported languages. +# +# This is also used if you do content translation via gettext catalogs. +# Usually you set "language" from the command line for these cases. +language = None + +# List of patterns, relative to source directory, that match files and +# directories to ignore when looking for source files. +# This patterns also effect to html_static_path and html_extra_path +exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store'] + +# The name of the Pygments (syntax highlighting) style to use. +pygments_style = 'sphinx' + +# If true, `todo` and `todoList` produce output, else they produce nothing. +todo_include_todos = False + + +# -- Options for HTML output ------------------------------------------- + +# The theme to use for HTML and HTML Help pages. See the documentation for +# a list of builtin themes. +# +html_theme = 'alabaster' + +# Theme options are theme-specific and customize the look and feel of a +# theme further. For a list of options available for each theme, see the +# documentation. +# +# html_theme_options = {} + +# Add any paths that contain custom static files (such as style sheets) here, +# relative to this directory. They are copied after the builtin static files, +# so a file named "default.css" will overwrite the builtin "default.css". +html_static_path = ['_static'] + + +# -- Options for HTMLHelp output --------------------------------------- + +# Output file base name for HTML help builder. +htmlhelp_basename = 'coltdoc' + + +# -- Options for LaTeX output ------------------------------------------ + +latex_elements = { + # The paper size ('letterpaper' or 'a4paper'). + # + # 'papersize': 'letterpaper', + + # The font size ('10pt', '11pt' or '12pt'). + # + # 'pointsize': '10pt', + + # Additional stuff for the LaTeX preamble. + # + # 'preamble': '', + + # Latex figure (float) alignment + # + # 'figure_align': 'htbp', +} + +# Grouping the document tree into LaTeX files. List of tuples +# (source start file, target name, title, author, documentclass +# [howto, manual, or own class]). +latex_documents = [ + (master_doc, 'colt.tex', + u'colt Documentation', + u'Oz Tiram', 'manual'), +] + + +# -- Options for manual page output ------------------------------------ + +# One entry per manual page. List of tuples +# (source start file, name, description, authors, manual section). +man_pages = [ + (master_doc, 'colt', + u'colt Documentation', + [author], 1) +] + + +# -- Options for Texinfo output ---------------------------------------- + +# Grouping the document tree into Texinfo files. List of tuples +# (source start file, target name, title, author, +# dir menu entry, description, category) +texinfo_documents = [ + (master_doc, 'colt', + u'colt Documentation', + author, + 'colt', + 'One line description of project.', + 'Miscellaneous'), +] + + + diff --git a/docs/contributing.rst b/docs/contributing.rst new file mode 100644 index 0000000..e582053 --- /dev/null +++ b/docs/contributing.rst @@ -0,0 +1 @@ +.. include:: ../CONTRIBUTING.rst diff --git a/docs/history.rst b/docs/history.rst new file mode 100644 index 0000000..2506499 --- /dev/null +++ b/docs/history.rst @@ -0,0 +1 @@ +.. include:: ../HISTORY.rst diff --git a/docs/index.rst b/docs/index.rst new file mode 100644 index 0000000..76a328f --- /dev/null +++ b/docs/index.rst @@ -0,0 +1,19 @@ +Welcome to colt's documentation! +====================================== + +.. toctree:: + :maxdepth: 2 + :caption: Contents: + + readme + installation + usage + modules + contributing + history + +Indices and tables +================== +* :ref:`genindex` +* :ref:`modindex` +* :ref:`search` diff --git a/docs/installation.rst b/docs/installation.rst new file mode 100644 index 0000000..b8cac6c --- /dev/null +++ b/docs/installation.rst @@ -0,0 +1,51 @@ +.. highlight:: shell + +============ +Installation +============ + + +Stable release +-------------- + +To install colt, run this command in your terminal: + +.. code-block:: console + + $ pip install colt + +This is the preferred method to install colt, as it will always install the most recent stable release. + +If you don't have `pip`_ installed, this `Python installation guide`_ can guide +you through the process. + +.. _pip: https://pip.pypa.io +.. _Python installation guide: http://docs.python-guide.org/en/latest/starting/installation/ + + +From sources +------------ + +The sources for colt can be downloaded from the `Github repo`_. + +You can either clone the public repository: + +.. code-block:: console + + $ git clone git://github.com/oz123/colt + +Or download the `tarball`_: + +.. code-block:: console + + $ curl -OL https://github.com/oz123/colt/tarball/master + +Once you have a copy of the source, you can install it with: + +.. code-block:: console + + $ python setup.py install + + +.. _Github repo: https://github.com/oz123/colt +.. _tarball: https://github.com/oz123/colt/tarball/master diff --git a/docs/k8s-machines-config.yml b/docs/k8s-machines-config.yml new file mode 100644 index 0000000..c75ea62 --- /dev/null +++ b/docs/k8s-machines-config.yml @@ -0,0 +1,17 @@ +# Use this file to configure the type of machines you want to create +# on OpenStack +--- +master_flavor: 'ECS.GP1.2-8' +node_flavor: 'ECS.C1.4-8' +private_net: 'k8s-nude' +cluster-name: 'nude' +availibity-zones: + - de-nbg6-1b + - de-nbg6-1a +n-masters: 2 +n-nodes: 3 +n-etcd: 3 +keypair: 'otiram' +security_group: 'k8s-nude-k8s-a0tp4t' +user_data: 'cloud-init-parts/generic' +image: "Ubuntu Xenial Server Cloudimg" diff --git a/docs/make.bat b/docs/make.bat new file mode 100644 index 0000000..2026969 --- /dev/null +++ b/docs/make.bat @@ -0,0 +1,36 @@ +@ECHO OFF + +pushd %~dp0 + +REM Command file for Sphinx documentation + +if "%SPHINXBUILD%" == "" ( + set SPHINXBUILD=python -msphinx +) +set SOURCEDIR=. +set BUILDDIR=_build +set SPHINXPROJ=colt + +if "%1" == "" goto help + +%SPHINXBUILD% >NUL 2>NUL +if errorlevel 9009 ( + echo. + echo.The Sphinx module was not found. Make sure you have Sphinx installed, + echo.then set the SPHINXBUILD environment variable to point to the full + echo.path of the 'sphinx-build' executable. Alternatively you may add the + echo.Sphinx directory to PATH. + echo. + echo.If you don't have Sphinx installed, grab it from + echo.http://sphinx-doc.org/ + exit /b 1 +) + +%SPHINXBUILD% -M %1 %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% +goto end + +:help +%SPHINXBUILD% -M help %SOURCEDIR% %BUILDDIR% %SPHINXOPTS% + +:end +popd diff --git a/docs/readme.rst b/docs/readme.rst new file mode 100644 index 0000000..72a3355 --- /dev/null +++ b/docs/readme.rst @@ -0,0 +1 @@ +.. include:: ../README.rst diff --git a/docs/usage.rst b/docs/usage.rst new file mode 100644 index 0000000..252b121 --- /dev/null +++ b/docs/usage.rst @@ -0,0 +1,7 @@ +===== +Usage +===== + +To use colt in a project:: + + import colt diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..63d408e --- /dev/null +++ b/requirements.txt @@ -0,0 +1,49 @@ +pbr==4.0.2 +msgpack==0.5.6 +oslo.i18n==3.20.0 +wcwidth==0.1.7; +oslo.config==6.0.2 +munch==2.3.1 +monotonic==1.4 +decorator==4.2.1 +prettytable==0.7.2 +jsonpointer==2.0 +cmd2==0.8.4 +dogpile.cache==0.6.5 +netifaces==0.10.6 +os-client-config==1.29.0 +pyyaml==3.12 +packaging==17.1 +iso8601==0.1.12 +debtcollector==1.19.0 +python-keystoneclient==3.15.0 +os-service-types==1.2.0 +python-neutronclient==6.8.0 +oslo.utils==3.36.0 +oslo.serialization==2.25.0 +requests==2.18.4 +stevedore==1.28.0 +deprecation==2.0.2 +jmespath==0.9.3 +pytz==2018.4 +simplejson==3.13.2 +six==1.11.0 +certifi==2018.1.18 +jsonpatch==1.23 +urllib3==1.22 +pyparsing==2.2.0 +appdirs==1.4.3 +netaddr==0.7.19 +babel==2.5.3 +openstacksdk==0.12.0 +keystoneauth1==3.4.0 +rfc3986==1.1.0 +idna==2.6 +python-novaclient==10.1.0 +osc-lib==1.10.0 +python-cinderclient==3.5.0 +wrapt==1.10.11 +cliff==2.11.0 +chardet==3.0.4 +requestsexceptions==1.4.0 +pyperclip==1.6.0 diff --git a/requirements_dev.txt b/requirements_dev.txt new file mode 100644 index 0000000..0c3ac27 --- /dev/null +++ b/requirements_dev.txt @@ -0,0 +1,13 @@ +pip==9.0.1 +bumpversion==0.5.3 +wheel==0.30.0 +watchdog==0.8.3 +flake8==3.5.0 +tox==2.9.1 +coverage==4.5.1 +Sphinx==1.7.1 +twine==1.10.0 + +pytest==3.4.2 +pytest-runner==2.11.1 +-r requirements.txt diff --git a/setup.cfg b/setup.cfg new file mode 100644 index 0000000..d49ad92 --- /dev/null +++ b/setup.cfg @@ -0,0 +1,52 @@ +[bumpversion] +current_version = 0.1.0 +commit = True +tag = True + +[bumpversion:file:setup.py] +search = version='{current_version}' +replace = version='{new_version}' + +[bumpversion:file:colt/__init__.py] +search = __version__ = '{current_version}' +replace = __version__ = '{new_version}' + +[bdist_wheel] +universal = 1 + +[flake8] +exclude = docs +ignore = F403,F405 + +[aliases] +# Define setup.py command aliases here +test = pytest + +[tool:pytest] +collect_ignore = ['setup.py'] + +[metadata] +name = colt +author = Oz N Tiram +author-email = oz.tiram@noris.de +summary = launch kubernetes clusters on OpenStack using ansible-kubespray +description-file = README.rst +home-page = https://github.com/oz123/wolkenbrot +classifier = + Development Status :: 3 - Alpha + Programming Language :: Python + Programming Language :: Python :: 3', + Programming Language :: Python :: 3.5, + Programming Language :: Python :: 3.6, + Intended Audience :: System Administrators + Intended Audience :: Developers + Operating System :: OS Independent + Topic :: Software Development + +[files] +packages = + colt + +[entry_points] +console_scripts = + colt = colt.colt:main diff --git a/setup.py b/setup.py new file mode 100644 index 0000000..2b3267f --- /dev/null +++ b/setup.py @@ -0,0 +1,51 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +"""The setup script.""" + +from setuptools import setup + +with open('README.rst') as readme_file: + readme = readme_file.read() + +with open('requirements.txt') as r: + requirements = r.readlines() + requirements = [r.split(' ', 1) for r in requirements][0] +requirements = [] + +setup_requirements = ['pytest-runner', ] + +test_requirements = ['pytest', ] + +setup( + setup_requires=['pbr'], + pbr=True, +) + + +#setup( +# author="Oz Tiram", +# author_email='oz.tiram@noris.de', +# classifiers=[ +# 'Development Status :: 2 - Pre-Alpha', +# 'Intended Audience :: Developers', +# 'Natural Language :: English', +# 'Programming Language :: Python :: 3', +# 'Programming Language :: Python :: 3.5', +# 'Programming Language :: Python :: 3.6', +# ], +# description=( +# "launch kubernetes clusters on OpenStack using ansible-kubespray"), +# install_requires=requirements, +# long_description=readme, +# include_package_data=True, +# keywords='colt', +# name='colt', +# packages=find_packages(include=['colt']), +# setup_requires=setup_requirements, +# test_suite='tests', +# tests_require=test_requirements, +# url='https://github.com/oz123/colt', +# version='0.1.0', +# zip_safe=False, +#) diff --git a/tests/test_colt.py b/tests/test_colt.py new file mode 100644 index 0000000..3bd8072 --- /dev/null +++ b/tests/test_colt.py @@ -0,0 +1,25 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +"""Tests for `colt` package.""" + +import pytest + + +from colt import colt + + +@pytest.fixture +def response(): + """Sample pytest fixture. + + See more at: http://doc.pytest.org/en/latest/fixture.html + """ + # import requests + # return requests.get('https://github.com/audreyr/cookiecutter-pypackage') + + +def test_content(response): + """Sample pytest test function with the pytest fixture as an argument.""" + # from bs4 import BeautifulSoup + # assert 'GitHub' in BeautifulSoup(response.content).title.string diff --git a/tox.ini b/tox.ini new file mode 100644 index 0000000..825badb --- /dev/null +++ b/tox.ini @@ -0,0 +1,20 @@ +[tox] +envlist = py27, py34, py35, p36, pypy, docs +skipsdist = true + +[testenv:docs] +basepython=python +changedir=docs +deps=sphinx +commands= + sphinx-build -b html -d {envtmpdir}/doctrees . {envtmpdir}/html + +[testenv] +setenv = + PYTHONPATH = {toxinidir} +deps = + -r{toxinidir}/requirements_dev.txt +commands = + pip install -U pip + py.test +