├── clearstack ├── tests │ ├── __init__.py │ ├── test_shell.py │ ├── test_sequence.py │ ├── utils.py │ ├── test_argument.py │ ├── test_modules_util.py │ └── test_answer_file.py ├── common │ ├── __init__.py │ ├── singleton.py │ ├── swupd.py │ └── util.py ├── locale │ └── clearstack.pot ├── modules │ ├── __init__.py │ ├── clearlinux.py │ ├── horizon.py │ ├── conf.py │ ├── mongodb.py │ ├── ceilometer.py │ ├── glance.py │ ├── nova.py │ ├── heat.py │ ├── keystone.py │ ├── rabbitmq.py │ ├── mariadb.py │ ├── openstack.py │ ├── swift.py │ └── neutron.py ├── plugins │ ├── __init__.py │ ├── horizon_500.py │ ├── mongodb_170.py │ ├── ceilometer_800.py │ ├── glance_300.py │ ├── amqp_100.py │ ├── mariadb_150.py │ ├── nova_400.py │ ├── keystone_200.py │ ├── heat_650.py │ ├── provision_700.py │ ├── swift_600.py │ ├── neutron_450.py │ └── pre_000.py ├── templates │ ├── __init__.py │ ├── horizon.py │ ├── pre_compute.sh │ ├── rabbitmq.py │ ├── mongodb.py │ ├── ceilometer.py │ ├── pre_controller.sh │ ├── compute_cleanup.sh │ ├── glance.py │ ├── provision.py │ ├── neutron_compute.py │ ├── mariadb.py │ ├── controller_cleanup.sh │ ├── keystone.py │ ├── heat.py │ ├── swift.py │ ├── nova.py │ ├── neutron.py │ └── nova_compute.py ├── __init__.py ├── group.py ├── argument.py ├── sequence.py ├── validators.py ├── controller.py ├── answer_file.py ├── run_setup.py ├── shell.py ├── utils.py └── ssh.py ├── babel.cfg ├── test-requirements-py3.txt ├── requirements-py3.txt ├── AUTHORS ├── .gitignore ├── PKG-INFO ├── README.rst ├── tox.ini ├── setup.py ├── setup.cfg ├── HACKING.rst └── LICENSE /clearstack/tests/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /babel.cfg: -------------------------------------------------------------------------------- 1 | [python: **.py] 2 | -------------------------------------------------------------------------------- /clearstack/common/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /clearstack/locale/clearstack.pot: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /clearstack/modules/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /clearstack/plugins/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /clearstack/templates/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /test-requirements-py3.txt: -------------------------------------------------------------------------------- 1 | coverage>=3.6 2 | flake8>=2.2.4 3 | testrepository>=0.0.18 4 | mock 5 | -------------------------------------------------------------------------------- /requirements-py3.txt: -------------------------------------------------------------------------------- 1 | pbr # Apache-2.0 2 | ipaddress # Python-2.0 3 | netifaces # MIT 4 | paramiko # LGPL-2.1 5 | sphinx # BSD-2-Clause 6 | -------------------------------------------------------------------------------- /AUTHORS: -------------------------------------------------------------------------------- 1 | Alberto Murillo 2 | Julio Montes 3 | Obed Munoz 4 | Victor Morales 5 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .coverage 2 | cover/ 3 | .testrepository 4 | subunit.log 5 | .venv 6 | *.pyc 7 | .idea 8 | *.sw? 9 | *.egg? 10 | *~ 11 | .tox 12 | ChangeLog 13 | build 14 | dist 15 | clearstack.egg-info 16 | clearstack/versioninfo 17 | # Development environment files 18 | .project 19 | .pydevproject 20 | .DS_Store 21 | covhtml/ 22 | tags 23 | AUTHORS 24 | -------------------------------------------------------------------------------- /PKG-INFO: -------------------------------------------------------------------------------- 1 | Metadata-Version: 1.1 2 | Name: clearstack 3 | Version: 1.1.7 4 | Summary: Tool for set up an Openstack environment 5 | Home-page: 6 | Author: Alberto Murillo, Julio Montes, Obed Munoz, Victor Morales 7 | Author-email: intel.com 8 | License: Apache-2.0 9 | Description: Tool for set up an Openstack environment 10 | Keywords: Openstack 11 | Platform: Unix 12 | Classifier: Environment :: OpenStack 13 | Classifier: Intended Audience :: Information Technology 14 | Classifier: Intended Audience :: System Administrators 15 | Classifier: License :: OSI Approved :: Apache Software License 16 | Classifier: Operating System :: POSIX :: Linux 17 | Classifier: Programming Language :: Python :: 3 18 | Classifier: Programming Language :: Python :: 3.3 19 | -------------------------------------------------------------------------------- /clearstack/__init__.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2015 Intel Corporation 3 | # 4 | # Author: Julio Montes 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file 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 | # 18 | 19 | import pbr.version 20 | 21 | 22 | __version__ = pbr.version.VersionInfo('clearstack').version_string() 23 | -------------------------------------------------------------------------------- /clearstack/templates/horizon.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2015 Intel Corporation 3 | # 4 | # Author: Alberto Murillo 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file 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 | # 18 | 19 | from modules.horizon import Horizon 20 | 21 | 22 | horizon = Horizon.get() 23 | horizon.install() 24 | horizon.start_server() 25 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | [DEPRECATED NOTICE] 2 | -------------------- 3 | This projet is no longer supported. Use this repository instead: 4 | https://github.com/clearlinux/clear-config-management 5 | 6 | ==== 7 | 8 | A tool to deploy components of Openstack on multiple servers with Clear Linux* Project for Intel Architecture installed 9 | 10 | ==== 11 | 12 | Contents: 13 | 14 | 1) Description of this project 15 | 2) Compiling, prerequisites 16 | 3) Bugs and feedback? 17 | 18 | ==== 19 | 20 | 21 | ==== 22 | 23 | 2. Installing 24 | 25 | $ pip3 install -r requirements-py3.txt 26 | $ python3 setup.py install 27 | 28 | ==== 29 | 30 | 3. Bugs, feedback, contact 31 | 32 | clearstack is hosted on github. You can find releases, an issue 33 | tracker and git sources on github.com/clearlinux/clearstack. For 34 | mailing lists, subscribe to dev@lists.clearlinux.org (via 35 | lists.clearlinux.org). 36 | 37 | This project has many contributors. Not all may be mentioned in the 38 | AUTHORS file. 39 | -------------------------------------------------------------------------------- /clearstack/templates/pre_compute.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Copyright (c) 2015 Intel Corporation 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | # 17 | 18 | if [ -f /bin/swupd ];then 19 | if [ ! -f /usr/share/clear/bundles/openstack-configure ];then 20 | swupd bundle-add openstack-configure 21 | fi 22 | elif [ -f /bin/clr_bundle_add];then 23 | if [ ! -f /usr/share/clear/bundles/openstack-configure ];then 24 | clr_bundle_add openstack-configure 25 | fi 26 | fi 27 | -------------------------------------------------------------------------------- /clearstack/group.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2015 Intel Corporation 3 | # 4 | # Author: Julio Montes 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file 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 | # 18 | 19 | 20 | class Group(object): 21 | def __init__(self, group_name, arguments): 22 | self.group_name = group_name 23 | self.arguments = arguments 24 | 25 | def get_group_name(self): 26 | return self.group_name 27 | 28 | def get_all_arguments(self): 29 | return self.arguments 30 | -------------------------------------------------------------------------------- /clearstack/modules/clearlinux.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2015 Intel Corporation 3 | # 4 | # Author: Alberto Murillo 5 | # Author: Julio Montes 6 | # Author: Victor Morales 7 | # 8 | # Licensed under the Apache License, Version 2.0 (the "License"); 9 | # you may not use this file except in compliance with the License. 10 | # You may obtain a copy of the License at 11 | # 12 | # http://www.apache.org/licenses/LICENSE-2.0 13 | # 14 | # Unless required by applicable law or agreed to in writing, software 15 | # distributed under the License is distributed on an "AS IS" BASIS, 16 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | # See the License for the specific language governing permissions and 18 | # limitations under the License. 19 | # 20 | 21 | from common import util 22 | 23 | 24 | def support_hw_acceleration(): 25 | stdout, stderr = util.run_command("egrep -c '(vmx|svm)' /proc/cpuinfo") 26 | return bool(int(stdout.decode('utf-8'))) 27 | -------------------------------------------------------------------------------- /tox.ini: -------------------------------------------------------------------------------- 1 | [tox] 2 | minversion = 1.6 3 | skipsdist = True 4 | envlist = py34,pep8 5 | 6 | [testenv] 7 | usedevelop = True 8 | install_command = pip install -U {opts} {packages} 9 | setenv = VIRTUAL_ENV={envdir} 10 | OS_STDOUT_NOCAPTURE=False 11 | OS_STDERR_NOCAPTURE=False 12 | 13 | deps = -r{toxinidir}/requirements-py3.txt 14 | -r{toxinidir}/test-requirements-py3.txt 15 | commands = python setup.py testr --testr-args='{posargs}' 16 | 17 | [testenv:pep8] 18 | commands = 19 | flake8 20 | 21 | [testenv:venv] 22 | commands = {posargs} 23 | 24 | [testenv:cover] 25 | commands = python setup.py testr --coverage --testr-args='{posargs}' 26 | 27 | [tox:jenkins] 28 | downloadcache = ~/cache/pip 29 | 30 | [testenv:debug] 31 | commands = oslo_debug_helper -t keystoneclient/tests {posargs} 32 | 33 | [flake8] 34 | # H405: multi line docstring summary not separated with an empty line 35 | ignore = H405 36 | show-source = True 37 | exclude = .venv,.tox,dist,doc,*egg,build 38 | 39 | [testenv:docs] 40 | commands= 41 | python setup.py build_sphinx 42 | -------------------------------------------------------------------------------- /clearstack/templates/rabbitmq.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2015 Intel Corporation 3 | # 4 | # Author: Julio Montes 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file 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 | # 18 | 19 | from modules.rabbitmq import Rabbitmq 20 | from modules.conf import CONF 21 | 22 | rabbitmq_auth_user = CONF["CONFIG_AMQP_AUTH_USER"] 23 | rabbitmq_auth_pw = CONF["CONFIG_AMQP_AUTH_PASSWORD"] 24 | 25 | rabbit = Rabbitmq.get() 26 | rabbit.install() 27 | rabbit.start_server() 28 | rabbit.add_user(rabbitmq_auth_user, rabbitmq_auth_pw) 29 | rabbit.set_permissions(rabbitmq_auth_user, '".*" ".*" ".*"') 30 | -------------------------------------------------------------------------------- /clearstack/templates/mongodb.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2015 Intel Corporation 3 | # 4 | # Author: Alberto Murillo 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file 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 | # 18 | 19 | from common import util 20 | from modules.conf import CONF 21 | from modules.mongodb import MongoDB 22 | 23 | mongo = MongoDB.get() 24 | 25 | if util.str2bool(CONF['CONFIG_MONGODB_INSTALL']): 26 | mongo.install() 27 | mongo.configure() 28 | mongo.start_server() 29 | 30 | mongo.setup_database('ceilometer', 'ceilometer', 31 | CONF['CONFIG_CEILOMETER_DB_PW']) 32 | -------------------------------------------------------------------------------- /clearstack/tests/test_shell.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2015 Intel Corporation 3 | # 4 | # Author: Julio Montes 5 | # Author: Victor Morales 6 | # 7 | # Licensed under the Apache License, Version 2.0 (the "License"); 8 | # you may not use this file except in compliance with the License. 9 | # You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, software 14 | # distributed under the License is distributed on an "AS IS" BASIS, 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | # See the License for the specific language governing permissions and 17 | # limitations under the License. 18 | # 19 | 20 | import testtools 21 | from testtools import matchers 22 | 23 | from clearstack.tests import utils 24 | 25 | 26 | class ShellTest(testtools.TestCase): 27 | 28 | def setUp(self): 29 | super(ShellTest, self).setUp() 30 | 31 | def test_help(self): 32 | required = 'usage:' 33 | help_text = utils.shell('--help') 34 | self.assertThat(help_text, 35 | matchers.MatchesRegex(required)) 36 | -------------------------------------------------------------------------------- /clearstack/common/singleton.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2015 Intel Corporation 3 | # 4 | # Author: Julio Montes 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file 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 | # 18 | 19 | 20 | class Singleton: 21 | def __init__(self, decorated): 22 | self._decorated = decorated 23 | 24 | def get(self): 25 | try: 26 | return self._instance 27 | except AttributeError: 28 | self._instance = self._decorated() 29 | return self._instance 30 | 31 | def __call__(self): 32 | raise TypeError('Singletons must be accessed through `Get()`.') 33 | 34 | def __instancecheck__(self, inst): 35 | return isinstance(inst, self._decorated) 36 | -------------------------------------------------------------------------------- /clearstack/templates/ceilometer.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2015 Intel Corporation 3 | # 4 | # Author: Alberto Murillo 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file 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 | # 18 | 19 | from modules.ceilometer import Ceilometer 20 | from common import util 21 | 22 | 23 | ceilometer = Ceilometer.get() 24 | config_file = "/etc/ceilometer/ceilometer.conf" 25 | 26 | ceilometer.install() 27 | ceilometer.create_user() 28 | ceilometer.create_service() 29 | ceilometer.create_endpoint() 30 | 31 | ceilometer.config_debug(config_file) 32 | ceilometer.config_database(config_file) 33 | ceilometer.config_rabbitmq(config_file) 34 | ceilometer.config_auth(config_file) 35 | ceilometer.config_service_credentials(config_file) 36 | 37 | util.run_command("systemctl restart update-triggers.target") 38 | ceilometer.start_server() 39 | -------------------------------------------------------------------------------- /clearstack/tests/test_sequence.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2015 Intel Corporation 3 | # 4 | # Author: Julio Montes 5 | # Author: Victor Morales 6 | # 7 | # Licensed under the Apache License, Version 2.0 (the "License"); 8 | # you may not use this file except in compliance with the License. 9 | # You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, software 14 | # distributed under the License is distributed on an "AS IS" BASIS, 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | # See the License for the specific language governing permissions and 17 | # limitations under the License. 18 | # 19 | 20 | import mock 21 | 22 | import testtools 23 | 24 | from clearstack.sequence import Sequence 25 | 26 | 27 | class SequenceTest(testtools.TestCase): 28 | def setUp(self): 29 | super(SequenceTest, self).setUp() 30 | 31 | def test_run(self): 32 | mock_function = mock.Mock(return_value=False) 33 | mock_function.__name__ = 'Bar' 34 | 35 | seq = Sequence('test', mock_function) 36 | self.assertRaises(Exception, seq.run) 37 | 38 | seq = Sequence('test', mock_function, ["subsequence"]) 39 | self.assertRaises(Exception, seq.run) 40 | -------------------------------------------------------------------------------- /clearstack/templates/pre_controller.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | # 3 | # Copyright (c) 2015 Intel Corporation 4 | # 5 | # Licensed under the Apache License, Version 2.0 (the "License"); 6 | # you may not use this file except in compliance with the License. 7 | # You may obtain a copy of the License at 8 | # 9 | # http://www.apache.org/licenses/LICENSE-2.0 10 | # 11 | # Unless required by applicable law or agreed to in writing, software 12 | # distributed under the License is distributed on an "AS IS" BASIS, 13 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 14 | # See the License for the specific language governing permissions and 15 | # limitations under the License. 16 | # 17 | 18 | if [ -f /bin/swupd ];then 19 | if [ ! -f /usr/share/clear/bundles/openstack-configure ];then 20 | swupd bundle-add openstack-configure 21 | fi 22 | 23 | if [ ! -f /usr/share/clear/bundles/openstack-python-clients -a ! -f /usr/share/clear/bundles/openstack-all-in-one ];then 24 | swupd bundle-add openstack-python-clients 25 | fi 26 | elif [ -f /bin/clr_bundle_add];then 27 | if [ ! -f /usr/share/clear/bundles/openstack-configure ];then 28 | clr_bundle_add openstack-configure 29 | fi 30 | 31 | if [ ! -f /usr/share/clear/bundles/openstack-python-clients -a ! -f /usr/share/clear/bundles/openstack-all-in-one ];then 32 | clr_bundle_add openstack-python-clients 33 | fi 34 | fi 35 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # 3 | # Copyright (c) 2015 Intel Corporation 4 | # 5 | # Author: Julio Montes 6 | # 7 | # Licensed under the Apache License, Version 2.0 (the "License"); 8 | # you may not use this file except in compliance with the License. 9 | # You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, software 14 | # distributed under the License is distributed on an "AS IS" BASIS, 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | # See the License for the specific language governing permissions and 17 | # limitations under the License. 18 | # 19 | 20 | # THIS FILE IS MANAGED BY THE GLOBAL REQUIREMENTS REPO - DO NOT EDIT 21 | import setuptools 22 | 23 | # In python < 2.7.4, a lazy loading of package `pbr` will break 24 | # setuptools if some other modules registered functions in `atexit`. 25 | # solution from: http://bugs.python.org/issue15881#msg170215 26 | try: 27 | import multiprocessing # noqa 28 | except ImportError: 29 | pass 30 | 31 | setuptools.setup( 32 | setup_requires=['pbr'], 33 | pbr=True, 34 | packages=['clearstack'], 35 | package_dir={'clearstack': 'clearstack'}, 36 | scripts=['clearstack/templates/pre_compute.sh', 37 | 'clearstack/templates/pre_controller.sh'] 38 | ) 39 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [metadata] 2 | name = clearstack 3 | summary = Tool for set up an OpenStack environment 4 | description-file = 5 | README.rst 6 | author = Alberto Murillo, Julio Montes, Obed Munoz, Victor Morales 7 | author-email = intel.com 8 | home-page = 9 | classifier = 10 | Environment :: OpenStack 11 | Intended Audience :: Information Technology 12 | Intended Audience :: System Administrators 13 | License :: OSI Approved :: Apache Software License 14 | Operating System :: POSIX :: Linux 15 | Programming Language :: Python :: 3 16 | Programming Language :: Python :: 3.3 17 | 18 | [files] 19 | packages = 20 | clearstack 21 | 22 | [global] 23 | setup-hooks = 24 | pbr.hooks.setup_hook 25 | 26 | [entry_points] 27 | console_scripts = 28 | clearstack = clearstack.shell:main 29 | 30 | [build_sphinx] 31 | source-dir = doc/source 32 | build-dir = doc/build 33 | all_files = 1 34 | 35 | [pbr] 36 | warnerrors = True 37 | 38 | [upload_sphinx] 39 | upload-dir = doc/build/html 40 | 41 | [compile_catalog] 42 | directory = clearstack/locale 43 | domain = clearstack 44 | 45 | [update_catalog] 46 | domain = clearstack 47 | output_dir = clearstack/locale 48 | input_file = clearstack/locale/clearstack.pot 49 | 50 | [extract_messages] 51 | keywords = _ gettext ngettext l_ lazy_gettext 52 | mapping_file = babel.cfg 53 | output_file = clearstack/locale/clearstack.pot 54 | 55 | [wheel] 56 | universal = 1 57 | -------------------------------------------------------------------------------- /clearstack/tests/utils.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2015 Intel Corporation 3 | # 4 | # Author: Julio Montes 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file 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 | # 18 | 19 | import os 20 | import sys 21 | import io 22 | 23 | from clearstack import shell as clearstack_shell 24 | 25 | 26 | def shell(argstr): 27 | orig = sys.stdout 28 | clean_env = {} 29 | _old_env, os.environ = os.environ, clean_env.copy() 30 | try: 31 | sys.stdout = io.StringIO() 32 | _shell = clearstack_shell.ClearstackConfiguratorShell() 33 | _shell.main(argstr.split()) 34 | except SystemExit: 35 | exc_type, exc_value, exc_traceback = sys.exc_info() 36 | assert exc_value, 0 37 | finally: 38 | out = sys.stdout.getvalue() 39 | sys.stdout.close() 40 | sys.stdout = orig 41 | os.environ = _old_env 42 | return out 43 | -------------------------------------------------------------------------------- /clearstack/tests/test_argument.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2015 Intel Corporation 3 | # 4 | # Author: Julio Montes 5 | # Author: Victor Morales 6 | # 7 | # Licensed under the Apache License, Version 2.0 (the "License"); 8 | # you may not use this file except in compliance with the License. 9 | # You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, software 14 | # distributed under the License is distributed on an "AS IS" BASIS, 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | # See the License for the specific language governing permissions and 17 | # limitations under the License. 18 | # 19 | 20 | import testtools 21 | 22 | 23 | class ArgumentTest(testtools.TestCase): 24 | def setUp(self): 25 | super(ArgumentTest, self).setUp() 26 | 27 | # def test_argument_validate(self): 28 | # argument = Argument('cmd_option', 'description', 'conf_name', 29 | # 'default_value') 30 | # self.assertTrue(argument.validate('test')) 31 | 32 | # def validator(value): 33 | # return 'ERROR' 34 | 35 | # argument = Argument('cmd_option', 'description', 'conf_name', 36 | # 'default_value', [validator]) 37 | # self.assertFalse(argument.validate('test')) 38 | -------------------------------------------------------------------------------- /clearstack/argument.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2015 Intel Corporation 3 | # 4 | # Author: Julio Montes 5 | # Author: Victor Morales 6 | # 7 | # Licensed under the Apache License, Version 2.0 (the "License"); 8 | # you may not use this file except in compliance with the License. 9 | # You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, software 14 | # distributed under the License is distributed on an "AS IS" BASIS, 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | # See the License for the specific language governing permissions and 17 | # limitations under the License. 18 | # 19 | 20 | 21 | class Argument(object): 22 | def __init__(self, cmd_option, description, 23 | conf_name, default_value, validators=[], 24 | options=None): 25 | self.cmd_option = cmd_option 26 | self.description = description 27 | self.conf_name = conf_name 28 | self.default_value = default_value 29 | self.validators = validators 30 | self.option_list = options 31 | 32 | def validate(self, option): 33 | for validator in self.validators: 34 | try: 35 | validator(option) 36 | except ValueError as e: 37 | raise ValueError("{0}: {1}".format(self.conf_name, str(e))) 38 | -------------------------------------------------------------------------------- /clearstack/modules/horizon.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2015 Intel Corporation 3 | # 4 | # Author: Alberto Murillo 5 | # Author: Julio Montes 6 | # Author: Obed Munoz 7 | # Author: Victor Morales 8 | # 9 | # Licensed under the Apache License, Version 2.0 (the "License"); 10 | # you may not use this file except in compliance with the License. 11 | # You may obtain a copy of the License at 12 | # 13 | # http://www.apache.org/licenses/LICENSE-2.0 14 | # 15 | # Unless required by applicable law or agreed to in writing, software 16 | # distributed under the License is distributed on an "AS IS" BASIS, 17 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | # See the License for the specific language governing permissions and 19 | # limitations under the License. 20 | # 21 | 22 | from modules.openstack import OpenStackService 23 | from modules.conf import CONF 24 | from common.singleton import Singleton 25 | 26 | 27 | @Singleton 28 | class Horizon(OpenStackService): 29 | _name = "horizon" 30 | _bundle = "openstack-dashboard" 31 | if CONF['CONFIG_HTTP_SERVICE'] == 'nginx': 32 | _services = ["nginx", "uwsgi@horizon.socket"] 33 | elif CONF['CONFIG_HTTP_SERVICE'] == 'apache2': 34 | _services = ["httpd"] 35 | # These are needed by OpenStackService but not used by horizon 36 | _type = "" 37 | _public_url = "" 38 | _description = "" 39 | _password = True 40 | -------------------------------------------------------------------------------- /clearstack/templates/compute_cleanup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # reset neutron services 4 | neutron_services="neutron-server neutron-linuxbridge-agent \ 5 | neutron-dhcp-agent neutron-metadata-agent neutron-l3-agent" 6 | systemctl stop $neutron_services 7 | systemctl disable $neutron_services 8 | 9 | # Reset compute services 10 | systemctl disable libvirtd.socket libvirtd.service nova-compute.service \ 11 | nova-network.service nova-metadata.{socket,service} 12 | systemctl stop libvirtd.socket libvirtd.service nova-compute.service \ 13 | nova-network.service nova-metadata.{socket,service} 14 | 15 | # Delete nova config file 16 | rm -rf /etc/nova 17 | 18 | # Update /etc/nova permissions 19 | systemctl restart update-triggers.target 20 | 21 | # Clean Bridges 22 | ip link set br100 down 23 | brctl delbr br100 24 | 25 | # Restart network service 26 | systemctl restart systemd-networkd 27 | 28 | # Clean Nova data 29 | rm -rf /var/lib/nova/CA/* 30 | rm -rf /var/lib/nova/instances/* 31 | rm -rf /var/lib/nova/keys/* 32 | rm -rf /var/lib/nova/networks/* 33 | 34 | # Clean Libvirt data 35 | rm -rf /var/lib/libvirt/qemu/*.monitor 36 | rm -rf /etc/libvirt/nwfilter/* 37 | rm -rf /etc/libvirt/qemu/* 38 | 39 | # Kill reamining qemu VMs 40 | ps aux | grep qemu | grep -v grep | awk '{print $2}' | xargs kill -9 41 | 42 | # Kill all about dnsmasq 43 | ps aux | grep dnsmasq | grep -v grep | awk '{print $2}' | xargs kill -9 44 | 45 | # Clean Logs 46 | rm -rf /var/log/nova/* 47 | rm -rf /var/log/libvirt/qemu/* 48 | rm -rf /var/log/swupd/* 49 | -------------------------------------------------------------------------------- /clearstack/modules/conf.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2015 Intel Corporation 3 | # 4 | # Author: Alberto Murillo 5 | # Author: Julio Montes 6 | # 7 | # Licensed under the Apache License, Version 2.0 (the "License"); 8 | # you may not use this file except in compliance with the License. 9 | # You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, software 14 | # distributed under the License is distributed on an "AS IS" BASIS, 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | # See the License for the specific language governing permissions and 17 | # limitations under the License. 18 | # 19 | 20 | import os 21 | import configparser 22 | 23 | 24 | _conf_file = "{0}/../defaults.conf".format(os.path.dirname(__file__)) 25 | _config = configparser.RawConfigParser() 26 | _config.optionxform = str 27 | _config.read(_conf_file) 28 | 29 | CONF = dict(_config['general']) 30 | 31 | ENV = {"OS_PROJECT_DOMAIN_ID": "default", 32 | "OS_USER_DOMAIN_ID": "default", 33 | "OS_PROJECT_NAME": "admin", 34 | "OS_USERNAME": "admin", 35 | "OS_PASSWORD": "{0}".format(CONF['CONFIG_KEYSTONE_ADMIN_PW']), 36 | "OS_TENANT_NAME": "admin", 37 | "OS_AUTH_URL": "http://{0}:35357/v3" 38 | .format(CONF['CONFIG_CONTROLLER_HOST']), 39 | "OS_IDENTITY_API_VERSION": "3", 40 | "OS_IMAGE_API_VERSION": "2"} 41 | -------------------------------------------------------------------------------- /clearstack/plugins/horizon_500.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2015 Intel Corporation 3 | # 4 | # Author: Alberto Murillo 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file 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 | # 18 | 19 | from clearstack import utils 20 | from clearstack.controller import Controller 21 | from clearstack.common import util 22 | 23 | 24 | def init_config(): 25 | conf = {} 26 | 27 | for group in conf: 28 | Controller.get().add_group(group, conf[group]) 29 | 30 | 31 | def init_sequences(): 32 | controller = Controller.get() 33 | conf = controller.CONF 34 | if util.str2bool(conf['CONFIG_HORIZON_INSTALL']): 35 | controller.add_sequence("Setting up horizon", setup_horizon) 36 | 37 | 38 | def setup_horizon(): 39 | template = "horizon" 40 | conf = Controller.get().CONF 41 | recipe = utils.get_template(template) 42 | return utils.run_recipe("{0}.py".format(template), recipe, 43 | [conf["CONFIG_CONTROLLER_HOST"]]) 44 | -------------------------------------------------------------------------------- /clearstack/sequence.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2015 Intel Corporation 3 | # 4 | # Author: Julio Montes 5 | # Author: Victor Morales 6 | # 7 | # Licensed under the Apache License, Version 2.0 (the "License"); 8 | # you may not use this file except in compliance with the License. 9 | # You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, software 14 | # distributed under the License is distributed on an "AS IS" BASIS, 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | # See the License for the specific language governing permissions and 17 | # limitations under the License. 18 | # 19 | 20 | from clearstack.common.util import LOG 21 | 22 | 23 | class Sequence: 24 | def __init__(self, desc, function, args=None): 25 | self.description = desc 26 | self.function = function 27 | self.function_args = args 28 | 29 | def run(self): 30 | LOG.info(self.description) 31 | if self.function_args: 32 | if not self.function(*self.function_args): 33 | raise Exception("error running {0}({1})" 34 | .format(self.function.__name__, 35 | self.function_args)) 36 | else: 37 | if not self.function(): 38 | raise Exception("error running {0}" 39 | .format(self.function.__name__)) 40 | -------------------------------------------------------------------------------- /clearstack/templates/glance.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2015 Intel Corporation 3 | # 4 | # Author: Alberto Murillo 5 | # Author: Julio Montes 6 | # 7 | # Licensed under the Apache License, Version 2.0 (the "License"); 8 | # you may not use this file except in compliance with the License. 9 | # You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, software 14 | # distributed under the License is distributed on an "AS IS" BASIS, 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | # See the License for the specific language governing permissions and 17 | # limitations under the License. 18 | # 19 | 20 | from common import util 21 | from modules.conf import CONF 22 | from modules.glance import Glance 23 | 24 | 25 | glance = Glance.get() 26 | config_files = ["/etc/glance/glance-api.conf"] 27 | config_files.append("/etc/glance/glance-registry.conf") 28 | 29 | glance.install() 30 | glance.create_user() 31 | glance.create_service() 32 | glance.create_endpoint() 33 | 34 | for config_file in config_files: 35 | glance.config_debug(config_file) 36 | glance.config_database(config_file) 37 | glance.config_auth(config_file) 38 | if util.str2bool(CONF['CONFIG_CEILOMETER_INSTALL']): 39 | glance.ceilometer_enable(config_file) 40 | 41 | util.run_command("systemctl restart update-triggers.target") 42 | glance.sync_database() 43 | glance.start_server() 44 | -------------------------------------------------------------------------------- /clearstack/templates/provision.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2015 Intel Corporation 3 | # 4 | # Author: Alberto Murillo 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file 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 | # 18 | 19 | from modules.glance import Glance 20 | from modules.neutron import Neutron 21 | from modules.nova import Nova 22 | from modules.conf import CONF 23 | from common import util 24 | 25 | glance = Glance.get() 26 | nova = Nova.get() 27 | neutron = Neutron.get() 28 | 29 | if util.str2bool(CONF['CONFIG_PROVISION_DEMO']): 30 | name = CONF['CONFIG_PROVISION_IMAGE_NAME'] 31 | format = CONF['CONFIG_PROVISION_IMAGE_FORMAT'] 32 | url = CONF['CONFIG_PROVISION_IMAGE_URL'] 33 | glance.create_image(name, format, url, public=True) 34 | floating_range = CONF['CONFIG_PROVISION_DEMO_FLOATRANGE'] 35 | neutron.create_network('private', '10.0.0.0/24', public=False) 36 | neutron.create_network('public', floating_range, public=True) 37 | neutron.create_router('router', gw='public', interfaces=['private']) 38 | -------------------------------------------------------------------------------- /clearstack/templates/neutron_compute.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2015 Intel Corporation 3 | # 4 | # Author: Alberto Murillo 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file 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 | # 18 | 19 | from modules.conf import CONF 20 | from modules.neutron import Neutron 21 | from common import util 22 | 23 | 24 | neutron = Neutron.get() 25 | config_file = "/etc/neutron/neutron.conf" 26 | services = ['nova-compute', 'neutron-linuxbridge-agent'] 27 | ip_list = CONF['CONFIG_COMPUTE_HOSTS'].split(',') 28 | local_ip = util.find_my_ip_from_config(ip_list) 29 | local_nic = util.get_nic(local_ip) 30 | 31 | neutron.install() 32 | neutron.config_debug(config_file) 33 | neutron.config_rabbitmq(config_file) 34 | neutron.config_auth(config_file) 35 | neutron.config_linux_bridge_agent(local_ip, local_nic) 36 | neutron.config_neutron_on_nova('/etc/nova/nova.conf') 37 | 38 | if util.str2bool(CONF['CONFIG_CEILOMETER_INSTALL']): 39 | neutron.ceilometer_enable(config_file) 40 | 41 | util.run_command("systemctl restart update-triggers.target") 42 | 43 | neutron.start_server(services) 44 | -------------------------------------------------------------------------------- /clearstack/templates/mariadb.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2015 Intel Corporation 3 | # 4 | # Author: Alberto Murillo 5 | # Author: Julio Montes 6 | # 7 | # Licensed under the Apache License, Version 2.0 (the "License"); 8 | # you may not use this file except in compliance with the License. 9 | # You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, software 14 | # distributed under the License is distributed on an "AS IS" BASIS, 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | # See the License for the specific language governing permissions and 17 | # limitations under the License. 18 | # 19 | 20 | from common.util import LOG 21 | from common import util 22 | from modules.conf import CONF 23 | from modules.mariadb import MariaDB 24 | 25 | conf = CONF 26 | mariadb = MariaDB.get() 27 | mariadb_user = CONF["CONFIG_MARIADB_USER"] 28 | mariadb_pw = CONF["CONFIG_MARIADB_PW"] 29 | 30 | if util.str2bool(conf['CONFIG_MARIADB_INSTALL']): 31 | mariadb.install() 32 | mariadb.configure() 33 | mariadb.start_server() 34 | mariadb.secure_installation(mariadb_user, mariadb_pw) 35 | 36 | databases = ['keystone', 'glance', 'nova', 'neutron', 'heat'] 37 | 38 | for database in databases: 39 | if database == 'keystone' or util.str2bool(conf['CONFIG_%s_INSTALL' 40 | % database.upper()]): 41 | LOG.info("Setting up mariadb for %s" % database) 42 | password = CONF['CONFIG_%s_DB_PW' % database.upper()] 43 | mariadb.setup_database(database, database, password) 44 | -------------------------------------------------------------------------------- /clearstack/validators.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2015 Intel Corporation 3 | # 4 | # Author: Alberto Murillo 5 | # Author: Julio Montes 6 | # 7 | # Licensed under the Apache License, Version 2.0 (the "License"); 8 | # you may not use this file except in compliance with the License. 9 | # You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, software 14 | # distributed under the License is distributed on an "AS IS" BASIS, 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | # See the License for the specific language governing permissions and 17 | # limitations under the License. 18 | # 19 | 20 | import ipaddress 21 | import os 22 | import socket 23 | 24 | 25 | def y_or_n(value): 26 | if not value.lower() in ("n", "y"): 27 | raise ValueError("please set 'y' or 'n'") 28 | 29 | 30 | def ip_or_hostname(value): 31 | for v in value.split(","): 32 | try: 33 | ipaddress.ip_address(v) 34 | except ValueError: 35 | socket.gethostbyname(v) 36 | 37 | 38 | def cidr(value): 39 | ip = ipaddress.ip_network(value) 40 | if not ip: 41 | raise ValueError("Invalid cidr") 42 | 43 | 44 | def file(value): 45 | value = os.path.expanduser(value) 46 | if not os.path.exists(value): 47 | raise ValueError("file {0} not found".format(value)) 48 | 49 | 50 | def not_empty(value): 51 | if not value.strip(): 52 | raise ValueError("empty value") 53 | 54 | 55 | def digit(value): 56 | if not value.isdigit(): 57 | raise ValueError("{0} is not a digit".format(value)) 58 | -------------------------------------------------------------------------------- /clearstack/common/swupd.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2015 Intel Corporation 3 | # 4 | # Author: Alberto Murillo 5 | # Author: Victor Morales 6 | # 7 | # Licensed under the Apache License, Version 2.0 (the "License"); 8 | # you may not use this file except in compliance with the License. 9 | # You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, software 14 | # distributed under the License is distributed on an "AS IS" BASIS, 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | # See the License for the specific language governing permissions and 17 | # limitations under the License. 18 | # 19 | 20 | import os 21 | 22 | from common import util 23 | from common.util import LOG 24 | 25 | 26 | class Client(): 27 | def install(bundle): 28 | if not os.path.isfile("/usr/share/clear/bundles/" + str(bundle)) and \ 29 | not os.path.isfile("/usr/share/clear/bundles/" 30 | "openstack-all-in-one"): 31 | LOG.info("Installing {0} bundle".format(bundle)) 32 | cmd = "clr_bundle_add -V {0}".format(bundle) 33 | if(os.path.isfile("/bin/swupd")): 34 | cmd = "swupd bundle-add -V {0}".format(bundle) 35 | 36 | try: 37 | stdout, stderr = util.run_command(cmd) 38 | if stderr: 39 | LOG.error("swupd bundle-add: {0}\n{1}" 40 | .format(stdout, stderr)) 41 | except Exception: 42 | LOG.error("clearstack: cannot install" 43 | " {0} bundle".format(bundle)) 44 | -------------------------------------------------------------------------------- /clearstack/templates/controller_cleanup.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # reset neutron services 4 | neutron_services="neutron-server neutron-linuxbridge-agent \ 5 | neutron-dhcp-agent neutron-metadata-agent neutron-l3-agent" 6 | systemctl stop $neutron_services 7 | systemctl disable $neutron_services 8 | 9 | # reset nova services 10 | systemctl stop memcached uwsgi@nova-{api,metadata}.{service,socket} nova-cert \ 11 | nova-consoleauth nova-scheduler \ 12 | nova-conductor nova-novncproxy 13 | systemctl disable memcached uwsgi@nova-{api,metadata}.{service,socket} nova-cert \ 14 | nova-consoleauth nova-scheduler \ 15 | nova-conductor nova-novncproxy 16 | rm -rf /etc/nova 17 | 18 | # reset glance services 19 | systemctl stop glance-api glance-registry 20 | systemctl disable glance-api glance-registry 21 | rm -rf /etc/glance 22 | rm -rf /var/lib/glance/images/* 23 | 24 | # reset keystone services 25 | systemctl stop httpd nginx uwsgi@keystone{admin,public}.{socket,service} 26 | systemctl disable httpd nginx 27 | rm -rf /etc/keystone 28 | rm /etc/httpd/conf.d/wsgi-keystone.conf 29 | 30 | # reset horizon 31 | systemctl stop httpd nginx uwsgi@horizon.{socket,service} 32 | 33 | # reset owners and permissions 34 | systemctl restart update-triggers.target 35 | 36 | # reset rabbitmq 37 | systemctl stop rabbitmq-server 38 | systemctl disable rabbitmq-server 39 | rm -rf /etc/rabbitmq/rabbitmq.config 40 | rm -rf /var/lib/rabbitmq/* 41 | rm -rf /etc/hosts 42 | 43 | # reset mariadb 44 | systemctl stop mariadb 45 | systemctl disable mariadb 46 | rm -rf /etc/mariadb 47 | rm -rf /var/lib/mysql 48 | 49 | # Clean Logs 50 | rm -rf /var/log/nova/* 51 | rm -rf /var/log/keystone/* 52 | rm -rf /var/log/glance/* 53 | rm -rf /var/log/rabbitmq/* 54 | rm -rf /var/log/httpd/* 55 | rm -rf /var/log/swupd/* 56 | -------------------------------------------------------------------------------- /clearstack/templates/keystone.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2015 Intel Corporation 3 | # 4 | # Author: Alberto Murillo 5 | # Author: Julio Montes 6 | # 7 | # Licensed under the Apache License, Version 2.0 (the "License"); 8 | # you may not use this file except in compliance with the License. 9 | # You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, software 14 | # distributed under the License is distributed on an "AS IS" BASIS, 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | # See the License for the specific language governing permissions and 17 | # limitations under the License. 18 | # 19 | 20 | from modules.conf import CONF 21 | from modules.keystone import Keystone 22 | from common import util 23 | 24 | keystone = Keystone.get() 25 | config_file = "/etc/keystone/keystone.conf" 26 | 27 | keystone.install() 28 | keystone.config_debug(config_file) 29 | keystone.config_database(config_file) 30 | keystone.config_admin_token(config_file) 31 | 32 | util.run_command("systemctl restart update-triggers.target") 33 | keystone.sync_database() 34 | keystone.start_server() 35 | 36 | keystone.create_service() 37 | keystone.create_endpoint() 38 | keystone.create_project("admin", "Admin Project") 39 | keystone.create_role("admin") 40 | keystone.create_user(user="admin", project="admin", role="admin") 41 | keystone.create_project("service", "Service Project") 42 | keystone.create_project("demo", "Demo Project") 43 | keystone.create_role("user") 44 | keystone.create_user(user="demo", project="demo", role="user", 45 | password=CONF['CONFIG_KEYSTONE_DEMO_PW']) 46 | util.delete_option(config_file, "DEFAULT", "admin_token") 47 | keystone.start_server() 48 | -------------------------------------------------------------------------------- /clearstack/plugins/mongodb_170.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2015 Intel Corporation 3 | # 4 | # Author: Alberto Murillo 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file 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 | # 18 | 19 | from clearstack.controller import Controller 20 | from clearstack.argument import Argument 21 | from clearstack import utils 22 | from clearstack import validators 23 | from clearstack.common import util 24 | 25 | 26 | def init_config(): 27 | conf = { 28 | "MONGODB": [ 29 | Argument("mongodb-host", 30 | "The IP address or hostname of the MongoDB server", 31 | "CONFIG_MONGODB_HOST", 32 | util.get_ip(), 33 | validators=[validators.ip_or_hostname]) 34 | ] 35 | } 36 | 37 | for group in conf: 38 | Controller.get().add_group(group, conf[group]) 39 | 40 | 41 | def init_sequences(): 42 | controller = Controller.get() 43 | conf = controller.CONF 44 | if util.str2bool(conf['CONFIG_CEILOMETER_INSTALL']): 45 | controller.add_sequence("Setting up MongoDB", setup_mongodb) 46 | 47 | 48 | def setup_mongodb(): 49 | conf = Controller.get().CONF 50 | recipe = utils.get_template('mongodb') 51 | return utils.run_recipe("mongodb.py", recipe, 52 | [conf["CONFIG_MONGODB_HOST"]]) 53 | -------------------------------------------------------------------------------- /clearstack/tests/test_modules_util.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2015 Intel Corporation 3 | # 4 | # Author: Julio Montes 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file 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 | # 18 | 19 | import testtools 20 | 21 | from clearstack.common import util 22 | 23 | 24 | class ModulesUtilTest(testtools.TestCase): 25 | def setUp(self): 26 | super(ModulesUtilTest, self).setUp() 27 | 28 | # # Test if run_command is hidden debug logs 29 | # def test_0000_run_command(self): 30 | # util.setup_debugging(True, False) 31 | # util.run_command("echo", debug=False) 32 | # logging.StreamHandler().close() 33 | # self.assertEqual("echo" in open(self.log_file).read(), False) 34 | 35 | # # Test if run_command is showing debug logs 36 | # def test_0001_run_command(self): 37 | # util.setup_debugging(True, False) 38 | # util.run_command("echo") 39 | # logging.StreamHandler().close() 40 | # self.assertEqual("echo" in open(self.log_file).read(), True) 41 | 42 | # Test command not found 43 | def test_0002_run_command(self): 44 | self.assertRaises(Exception, util.run_command, "inexistente") 45 | 46 | # Test simple command 47 | def test_0003_run_command(self): 48 | try: 49 | util.run_command("echo") 50 | except Exception: 51 | self.fail() 52 | -------------------------------------------------------------------------------- /clearstack/templates/heat.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2015 Intel Corporation 3 | # 4 | # Author: Alberto Murillo 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file 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 | # 18 | 19 | from common import util 20 | from modules.heat import Heat 21 | 22 | 23 | heat = Heat.get() 24 | config_file = "/etc/heat/heat.conf" 25 | 26 | heat.install() 27 | heat.create_user() 28 | heat.create_service(name='heat', description='OpenStack Orchestration', 29 | type='orchestration') 30 | heat.create_service(name='heat-cfn', description='OpenStack Orchestration', 31 | type='cloudformation') 32 | heat.create_endpoint() 33 | publicurl = "http://%s:8000/v1" % heat._controller 34 | heat.create_endpoint(publicurl=publicurl, internalurl=publicurl, 35 | adminurl=publicurl, type='cloudformation') 36 | heat.create_domain(heat.domain_name, 'Stack projects and users') 37 | heat.create_user(user=heat.domain_admin, password=heat.domain_admin_pw, 38 | domain=heat.domain_name) 39 | heat.create_role('heat_stack_owner') 40 | heat.create_role('heat_stack_user') 41 | 42 | heat.config_database(config_file) 43 | heat.config_rabbitmq(config_file) 44 | heat.config_auth(config_file) 45 | heat.config_domain(config_file) 46 | 47 | util.run_command("systemctl restart update-triggers.target") 48 | heat.sync_database() 49 | heat.start_server() 50 | -------------------------------------------------------------------------------- /clearstack/tests/test_answer_file.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2015 Intel Corporation 3 | # 4 | # Author: Julio Montes 5 | # Author: Victor Morales 6 | # 7 | # Licensed under the Apache License, Version 2.0 (the "License"); 8 | # you may not use this file except in compliance with the License. 9 | # You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, software 14 | # distributed under the License is distributed on an "AS IS" BASIS, 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | # See the License for the specific language governing permissions and 17 | # limitations under the License. 18 | # 19 | 20 | import mock 21 | import testtools 22 | 23 | from clearstack.answer_file import AnswerFile 24 | from clearstack.argument import Argument 25 | from clearstack.controller import Controller 26 | 27 | conf = {'COMPONENT': [Argument('argument', 28 | 'description', 29 | 'CONFIG_ARGUMET', 30 | 'secure')]} 31 | 32 | for group in conf: 33 | Controller.get().add_group(group, conf[group]) 34 | 35 | 36 | class AnswerFileTest(testtools.TestCase): 37 | def setUp(self): 38 | super(AnswerFileTest, self).setUp() 39 | 40 | def test_generate_file(self): 41 | m = mock.mock_open() 42 | filename = '/tmp/clearstack.answerfile' 43 | with mock.patch('clearstack.answer_file.open', m, create=True): 44 | AnswerFile.get().generate(filename, {}) 45 | m.assert_called_once_with(filename, 'w') 46 | 47 | @mock.patch('os.path.isfile') 48 | def test_read_non_existing_file(self, mock_isfile): 49 | mock_isfile.side_effect = [False] 50 | filename = '/tmp/clearstack.answerfile' 51 | self.assertRaises(IOError, AnswerFile.get().read, filename, {}) 52 | -------------------------------------------------------------------------------- /clearstack/templates/swift.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2015 Intel Corporation 3 | # 4 | # Author: Alberto Murillo 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file 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 | # 18 | 19 | from common import util 20 | from modules.conf import CONF 21 | from modules.swift import Swift 22 | 23 | 24 | swift = Swift.get() 25 | config_file = "/etc/swift/proxy-server.conf" 26 | 27 | swift.install() 28 | swift.create_user() 29 | swift.create_service() 30 | swift.create_endpoint() 31 | 32 | swift.config_auth(config_file) 33 | swift.config_memcache(config_file) 34 | swift.config_hash('/etc/swift/swift.conf') 35 | 36 | # Storage configuration 37 | swift.parse_devices() 38 | swift.prepare_devices() 39 | swift.create_rings() 40 | swift.config_rsync() 41 | swift.config_storage_services() 42 | 43 | if util.str2bool(CONF['CONFIG_CEILOMETER_INSTALL']): 44 | swift.ceilometer_enable(config_file) 45 | 46 | util.run_command("systemctl restart update-triggers.target") 47 | 48 | # Start controller services 49 | swift.start_server() 50 | 51 | # Start storage node services 52 | services = ['rsyncd', 'swift-account', 'swift-account-auditor', 53 | 'swift-account-reaper', 'swift-account-replicator', 54 | 'swift-container', 'swift-container-auditor', 55 | 'swift-container-replicator', 'swift-container-updater', 56 | 'swift-object', 'swift-object-auditor', 57 | 'swift-object-replicator', 'swift-object-updater'] 58 | swift.start_server(services) 59 | -------------------------------------------------------------------------------- /HACKING.rst: -------------------------------------------------------------------------------- 1 | Clearstack Style Commandments 2 | ============================== 3 | 4 | - Step 1: Read the OpenStack Style Commandments 5 | http://docs.openstack.org/developer/hacking/ 6 | - Step 2: Read on 7 | 8 | Docstrings 9 | ---------- 10 | 11 | Docstrings should ONLY use triple-double-quotes (``"""``) 12 | 13 | Single-line docstrings should NEVER have extraneous whitespace 14 | between enclosing triple-double-quotes. 15 | 16 | Deviation! Sentence fragments do not have punctuation. Specifically in the 17 | command classes the one line docstring is also the help string for that 18 | command and those do not have periods. 19 | 20 | """A one line docstring looks like this""" 21 | 22 | Calling Methods 23 | --------------- 24 | 25 | Deviation! When breaking up method calls due to the 79 char line length limit, 26 | use the alternate 4 space indent. With the first argument on the succeeding 27 | line all arguments will then be vertically aligned. Use the same convention 28 | used with other data structure literals and terminate the method call with 29 | the last argument line ending with a comma and the closing paren on its own 30 | line indented to the starting line level. 31 | 32 | unnecessarily_long_function_name( 33 | 'string one', 34 | 'string two', 35 | kwarg1=constants.ACTIVE, 36 | kwarg2=['a', 'b', 'c'], 37 | ) 38 | 39 | Python 3.x Compatibility 40 | ------------------------ 41 | 42 | Clearstack is only Python 3.4 compatible. Common guidelines: 43 | 44 | * print statements are functions: print statements should be converted 45 | to an appropriate log or other output mechanism. 46 | * Use six where applicable: x.iteritems is converted to six.iteritems(x) 47 | for example 48 | 49 | Running Tests 50 | ------------- 51 | The testing system is based on a combination of tox and testr. If you just 52 | want to run the whole suite, run `tox` and all will be fine. However, if 53 | you'd like to dig in a bit more, you might want to learn some things about 54 | testr itself. A basic walkthrough for OpenStack can be found at 55 | http://wiki.openstack.org/testr 56 | -------------------------------------------------------------------------------- /clearstack/modules/mongodb.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2015 Intel Corporation 3 | # 4 | # Author: Alberto Murillo 5 | # Author: Victor Morales 6 | # 7 | # Licensed under the Apache License, Version 2.0 (the "License"); 8 | # you may not use this file except in compliance with the License. 9 | # You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, software 14 | # distributed under the License is distributed on an "AS IS" BASIS, 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | # See the License for the specific language governing permissions and 17 | # limitations under the License. 18 | # 19 | 20 | from common import util 21 | from common.singleton import Singleton 22 | from common.swupd import Client as swupd_client 23 | from common.util import LOG 24 | 25 | 26 | @Singleton 27 | class MongoDB: 28 | def install(self): 29 | swupd_client.install("database-mongodb") 30 | 31 | def start_server(self): 32 | LOG.debug("starting services") 33 | util.run_command("systemctl enable mongodb") 34 | util.run_command("systemctl restart mongodb") 35 | count = 0 36 | while count < 10: 37 | try: 38 | util.run_command("mongo --host 127.0.0.1") 39 | return 40 | except: 41 | util.run_command("sleep 1") 42 | count += 1 43 | raise Exception("Failed to start mongodb service") 44 | 45 | def configure(self): 46 | config_file = "/etc/mongodb/mongod.conf" 47 | config = {'bind_ip': '0.0.0.0'} 48 | util.write_properties(config_file, config) 49 | 50 | def setup_database(self, database, user, password): 51 | cmd = ("mongo --host 127.0.0.1 --eval '" 52 | "db = db.getSiblingDB(\"%s\");" 53 | "db.createUser({user: \"%s\",pwd: \"%s\"," 54 | "roles: [ \"readWrite\", \"dbAdmin\" ]})'" 55 | % (database, user, password)) 56 | util.run_command(cmd) 57 | -------------------------------------------------------------------------------- /clearstack/templates/nova.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2015 Intel Corporation 3 | # 4 | # Author: Alberto Murillo 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file 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 | # 18 | 19 | from modules.nova import Nova 20 | from modules.conf import CONF 21 | from common import util 22 | 23 | 24 | nova = Nova.get() 25 | config_file = "/etc/nova/nova.conf" 26 | ip_list = CONF['CONFIG_CONTROLLER_HOST'].split(',') 27 | my_ip = util.find_my_ip_from_config(ip_list) 28 | 29 | # Install nova controller 30 | nova.install() 31 | nova.create_user() 32 | nova.create_service() 33 | nova.create_endpoint() 34 | 35 | # Configure nova controller 36 | nova.config_debug(config_file) 37 | nova.config_database(config_file) 38 | nova.config_rabbitmq(config_file) 39 | nova.config_auth(config_file) 40 | 41 | # Setup vncproxy 42 | config = \ 43 | "[DEFAULT]\n" + \ 44 | "my_ip=%s\n" % my_ip + \ 45 | "[vnc]\n" + \ 46 | "vncserver_listen=0.0.0.0\n" + \ 47 | "vncserver_proxyclient_address=%s\n" % my_ip 48 | util.write_config(config_file, config) 49 | 50 | # Setup glance host 51 | config = \ 52 | "[glance]\n" + \ 53 | "host=%s\n" % CONF['CONFIG_CONTROLLER_HOST'] 54 | util.write_config(config_file, config) 55 | 56 | if CONF['CONFIG_HTTP_SERVICE'] == 'nginx': 57 | util.link_file('/usr/share/nginx/conf.d/nova-api.template', 58 | '/etc/nginx/nova-api.conf') 59 | else: 60 | util.link_file('/usr/share/defaults/httpd/conf.d/nova-api.template', 61 | '/etc/httpd/conf.d/nova-api.conf') 62 | 63 | util.run_command("systemctl restart update-triggers.target") 64 | nova.sync_database() 65 | nova.start_server() 66 | -------------------------------------------------------------------------------- /clearstack/plugins/ceilometer_800.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2015 Intel Corporation 3 | # 4 | # Author: Alberto Murillo 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file 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 | # 18 | 19 | from clearstack import utils 20 | from clearstack import validators 21 | from clearstack.controller import Controller 22 | from clearstack.argument import Argument 23 | from clearstack.common import util 24 | 25 | 26 | def init_config(): 27 | conf = { 28 | "CEILOMETER": [ 29 | Argument("ceilometer-db-pw", 30 | "Password for ceilometer to access DB", 31 | "CONFIG_CEILOMETER_DB_PW", 32 | utils.generate_random_pw(), 33 | validators=[validators.not_empty]), 34 | Argument("ceilometer-ks-pw", 35 | "Password to use for Ceilometer to" 36 | " authenticate with Keystone", 37 | "CONFIG_CEILOMETER_KS_PW", 38 | utils.generate_random_pw(), 39 | validators=[validators.not_empty]) 40 | ] 41 | } 42 | 43 | for group in conf: 44 | Controller.get().add_group(group, conf[group]) 45 | 46 | 47 | def init_sequences(): 48 | controller = Controller.get() 49 | conf = controller.CONF 50 | if util.str2bool(conf['CONFIG_CEILOMETER_INSTALL']): 51 | controller.add_sequence("Setting up ceilometer", setup_ceilometer) 52 | 53 | 54 | def setup_ceilometer(): 55 | conf = Controller.get().CONF 56 | recipe = utils.get_template("ceilometer") 57 | return utils.run_recipe("ceilometer.py", recipe, 58 | [conf["CONFIG_CONTROLLER_HOST"]]) 59 | -------------------------------------------------------------------------------- /clearstack/plugins/glance_300.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2015 Intel Corporation 3 | # 4 | # Author: Alberto Murillo 5 | # Author: Julio Montes 6 | # 7 | # Licensed under the Apache License, Version 2.0 (the "License"); 8 | # you may not use this file except in compliance with the License. 9 | # You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, software 14 | # distributed under the License is distributed on an "AS IS" BASIS, 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | # See the License for the specific language governing permissions and 17 | # limitations under the License. 18 | # 19 | 20 | from clearstack import utils 21 | from clearstack import validators 22 | from clearstack.controller import Controller 23 | from clearstack.argument import Argument 24 | from clearstack.common import util 25 | 26 | 27 | def init_config(): 28 | conf = { 29 | "GLANCE": [ 30 | Argument("glance-db-pw", 31 | "Password for glance to access DB", 32 | "CONFIG_GLANCE_DB_PW", 33 | utils.generate_random_pw(), 34 | validators=[validators.not_empty]), 35 | Argument("glance-ks-pw", 36 | "Password to use for Glance to" 37 | " authenticate with Keystone", 38 | "CONFIG_GLANCE_KS_PW", 39 | utils.generate_random_pw(), 40 | validators=[validators.not_empty]) 41 | ] 42 | } 43 | 44 | for group in conf: 45 | Controller.get().add_group(group, conf[group]) 46 | 47 | 48 | def init_sequences(): 49 | controller = Controller.get() 50 | conf = controller.CONF 51 | if util.str2bool(conf['CONFIG_GLANCE_INSTALL']): 52 | controller.add_sequence("Setting up glance", setup_glance) 53 | 54 | 55 | def setup_glance(): 56 | conf = Controller.get().CONF 57 | recipe = utils.get_template("glance") 58 | return utils.run_recipe("glance.py", recipe, 59 | [conf["CONFIG_CONTROLLER_HOST"]]) 60 | -------------------------------------------------------------------------------- /clearstack/plugins/amqp_100.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2015 Intel Corporation 3 | # 4 | # Author: Julio Montes 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file 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 | # 18 | 19 | from clearstack import utils 20 | from clearstack import validators 21 | from clearstack.argument import Argument 22 | from clearstack.controller import Controller 23 | from clearstack.common import util 24 | 25 | 26 | def init_config(): 27 | conf = { 28 | "AMQP": [ 29 | Argument("amqp-auth-user", 30 | "User for amqp authentication", 31 | "CONFIG_AMQP_AUTH_USER", 32 | "amqp_user", 33 | validators=[validators.not_empty]), 34 | Argument("amqp-auth-pw", 35 | "Password for amqp user authentication", 36 | "CONFIG_AMQP_AUTH_PASSWORD", 37 | utils.generate_random_pw(), 38 | validators=[validators.not_empty]), 39 | Argument("amqp-host", 40 | "The IP address or hostname of the server on which" 41 | " to install the AMQP service", 42 | "CONFIG_AMQP_HOST", 43 | util.get_ip(), 44 | validators=[validators.ip_or_hostname]) 45 | ] 46 | } 47 | 48 | for group in conf: 49 | Controller.get().add_group(group, conf[group]) 50 | 51 | 52 | def init_sequences(): 53 | Controller.get().add_sequence("Setting up rabbit", setup_rabbit) 54 | 55 | 56 | def setup_rabbit(): 57 | conf = Controller.get().CONF 58 | recipe = utils.get_template("rabbitmq") 59 | return utils.run_recipe("rabbitmq.py", recipe, [conf["CONFIG_AMQP_HOST"]]) 60 | -------------------------------------------------------------------------------- /clearstack/templates/neutron.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2015 Intel Corporation 3 | # 4 | # Author: Alberto Murillo 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file 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 | # 18 | 19 | from modules.conf import CONF 20 | from modules.neutron import Neutron 21 | from common import util 22 | 23 | 24 | neutron = Neutron.get() 25 | config_file = "/etc/neutron/neutron.conf" 26 | ip_list = CONF['CONFIG_CONTROLLER_HOST'].split(',') 27 | local_ip = util.find_my_ip_from_config(ip_list) 28 | local_nic = util.get_nic(local_ip) 29 | 30 | # Install neutron controller 31 | neutron.install() 32 | neutron.create_user() 33 | neutron.create_service() 34 | neutron.create_endpoint() 35 | 36 | # Configure neutron controller 37 | neutron.config_debug(config_file) 38 | neutron.config_database(config_file) 39 | neutron.config_rabbitmq(config_file) 40 | neutron.config_auth(config_file) 41 | 42 | neutron.config_nova(config_file) 43 | neutron.config_ml2_plugin() 44 | neutron.config_linux_bridge_agent(local_ip, local_nic) 45 | neutron.config_l3_agent("/etc/neutron/l3_agent.ini") 46 | neutron.config_dhcp_agent("/etc/neutron/dhcp_agent.ini") 47 | neutron.config_metadata_agent("/etc/neutron/metadata_agent.ini") 48 | neutron.config_neutron_on_nova("/etc/nova/nova.conf") 49 | 50 | if util.str2bool(CONF['CONFIG_CEILOMETER_INSTALL']): 51 | neutron.ceilometer_enable(config_file) 52 | 53 | if util.str2bool(CONF['CONFIG_LBAAS_INSTALL']): 54 | neutron.install('openstack-lbaas') 55 | neutron.config_lbaas() 56 | 57 | if util.str2bool(CONF['CONFIG_VPNAAS_INSTALL']): 58 | neutron.install('openstack-vpnaas') 59 | neutron.config_vpnaas() 60 | 61 | util.run_command("systemctl restart update-triggers.target") 62 | neutron.sync_database() 63 | neutron.start_server() 64 | -------------------------------------------------------------------------------- /clearstack/plugins/mariadb_150.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2015 Intel Corporation 3 | # 4 | # Author: Alberto Murillo 5 | # Author: Julio Montes 6 | # 7 | # Licensed under the Apache License, Version 2.0 (the "License"); 8 | # you may not use this file except in compliance with the License. 9 | # You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, software 14 | # distributed under the License is distributed on an "AS IS" BASIS, 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | # See the License for the specific language governing permissions and 17 | # limitations under the License. 18 | # 19 | 20 | from clearstack.controller import Controller 21 | from clearstack.argument import Argument 22 | from clearstack import utils 23 | from clearstack import validators 24 | from clearstack.common import util 25 | 26 | 27 | def init_config(): 28 | conf = { 29 | "MARIADB": [ 30 | Argument("mariadb-host", 31 | "The IP address or hostname of the MariaDB server", 32 | "CONFIG_MARIADB_HOST", 33 | util.get_ip(), 34 | validators=[validators.ip_or_hostname]), 35 | Argument("mariadb-user", 36 | "User for mariadb authentication", 37 | "CONFIG_MARIADB_USER", 38 | "root", 39 | validators=[validators.not_empty]), 40 | Argument("mariadb-pw", 41 | "Password for mariadb user", 42 | "CONFIG_MARIADB_PW", 43 | utils.generate_random_pw(), 44 | validators=[validators.not_empty]) 45 | ] 46 | } 47 | 48 | for group in conf: 49 | Controller.get().add_group(group, conf[group]) 50 | 51 | 52 | def init_sequences(): 53 | controller = Controller.get() 54 | controller.add_sequence("Setting up mariadb", 55 | setup_mariadb, args=['mariadb']) 56 | 57 | 58 | def setup_mariadb(template): 59 | conf = Controller.get().CONF 60 | recipe = utils.get_template(template) 61 | return utils.run_recipe("{0}.py".format(template), recipe, 62 | [conf["CONFIG_MARIADB_HOST"]]) 63 | -------------------------------------------------------------------------------- /clearstack/modules/ceilometer.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2015 Intel Corporation 3 | # 4 | # Author: Alberto Murillo 5 | # Author: Victor Morales 6 | # 7 | # Licensed under the Apache License, Version 2.0 (the "License"); 8 | # you may not use this file except in compliance with the License. 9 | # You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, software 14 | # distributed under the License is distributed on an "AS IS" BASIS, 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | # See the License for the specific language governing permissions and 17 | # limitations under the License. 18 | # 19 | 20 | from modules.keystone import Keystone 21 | from modules.openstack import OpenStackService 22 | from modules.conf import CONF 23 | from common import util 24 | from common.singleton import Singleton 25 | 26 | 27 | @Singleton 28 | class Ceilometer(OpenStackService): 29 | _name = "ceilometer" 30 | _bundle = "openstack-telemetry" 31 | _services = ["ceilometer-agent-central", "ceilometer-agent-notification", 32 | "ceilometer-api", "ceilometer-collector", 33 | "ceilometer-alarm-evaluator", "ceilometer-alarm-notifier"] 34 | _type = "metering" 35 | _description = "OpenStack Telemetry Service" 36 | _public_url = "http://{0}:8777".format(CONF['CONFIG_CONTROLLER_HOST']) 37 | 38 | def config_database(self, configfile): 39 | dbpass = CONF['CONFIG_%s_DB_PW' % self._name.upper()] 40 | dbhost = CONF['CONFIG_MONGODB_HOST'] 41 | config = ("[database]\n" 42 | "connection=mongodb://{0}:{1}@{2}:27017/{0}" 43 | .format(self._name, dbpass, dbhost)) 44 | util.write_config(configfile, config) 45 | 46 | def config_service_credentials(self, configfile): 47 | keystone = Keystone.get() 48 | config = \ 49 | "[service_credentials]\n" + \ 50 | "os_auth_url = %s\n" % keystone._admin_url + \ 51 | "os_username = %s\n" % self._name + \ 52 | "os_tenant_name = service\n" + \ 53 | "os_password = %s\n" % self._password + \ 54 | "os_endpoint_type = internalURL\n" + \ 55 | "os_region_name = %s\n" % self._region 56 | util.write_config(configfile, config) 57 | -------------------------------------------------------------------------------- /clearstack/templates/nova_compute.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2015 Intel Corporation 3 | # 4 | # Author: Alberto Murillo 5 | # Author: Julio Montes 6 | # Author: Obed Munoz 7 | # Author: Victor Morales 8 | # 9 | # Licensed under the Apache License, Version 2.0 (the "License"); 10 | # you may not use this file except in compliance with the License. 11 | # You may obtain a copy of the License at 12 | # 13 | # http://www.apache.org/licenses/LICENSE-2.0 14 | # 15 | # Unless required by applicable law or agreed to in writing, software 16 | # distributed under the License is distributed on an "AS IS" BASIS, 17 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | # See the License for the specific language governing permissions and 19 | # limitations under the License. 20 | # 21 | 22 | from modules import clearlinux 23 | from modules.nova import Nova 24 | from modules.conf import CONF 25 | from common import util 26 | 27 | 28 | nova = Nova.get() 29 | config_file = "/etc/nova/nova.conf" 30 | services = ['libvirtd.socket', 'nova-compute'] 31 | ip_list = CONF['CONFIG_COMPUTE_HOSTS'].split(',') 32 | my_ip = util.find_my_ip_from_config(ip_list) 33 | 34 | if CONF['CONFIG_HTTP_SERVICE'] == 'nginx': 35 | services.extend(['nginx', 'uwsgi@nova-metadata.socket']) 36 | elif CONF['CONFIG_HTTP_SERVICE'] == 'apache2': 37 | services.append('httpd') 38 | else: 39 | services.append('nova-api-metadata') 40 | 41 | nova.install_compute() 42 | nova.config_debug(config_file) 43 | nova.config_rabbitmq(config_file) 44 | nova.config_auth(config_file) 45 | 46 | # Setup vncproxy server 47 | config = ("[DEFAULT]\n" 48 | "my_ip={0}\n" 49 | "[vnc]\n" 50 | "vnc_enabled=True\n" 51 | "vncserver_listen=0.0.0.0\n" 52 | "vncserver_proxyclient_address={0}\n" 53 | "novncproxy_base_url=http://{1}:6080/vnc_auto.html\n" 54 | .format(my_ip, CONF['CONFIG_CONTROLLER_HOST'])) 55 | 56 | # Setup glance host 57 | config += ("[glance]\n" 58 | "host=%s\n") % CONF['CONFIG_CONTROLLER_HOST'] 59 | 60 | # Disable HW acceleration on unsupported HW 61 | if not clearlinux.support_hw_acceleration(): 62 | config += ("[libvirt]\n" 63 | "virt_type=qemu\n") 64 | 65 | util.write_config(config_file, config) 66 | 67 | if util.str2bool(CONF['CONFIG_CEILOMETER_INSTALL']): 68 | nova.ceilometer_enable(config_file) 69 | 70 | util.run_command("systemctl restart update-triggers.target") 71 | nova.start_server(services) 72 | -------------------------------------------------------------------------------- /clearstack/controller.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2015 Intel Corporation 3 | # 4 | # Author: Julio Montes 5 | # Author: Victor Morales 6 | # 7 | # Licensed under the Apache License, Version 2.0 (the "License"); 8 | # you may not use this file except in compliance with the License. 9 | # You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, software 14 | # distributed under the License is distributed on an "AS IS" BASIS, 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | # See the License for the specific language governing permissions and 17 | # limitations under the License. 18 | # 19 | 20 | from clearstack.group import Group 21 | from clearstack.sequence import Sequence 22 | from clearstack.common.singleton import Singleton 23 | 24 | DEBUG = False 25 | 26 | 27 | @Singleton 28 | class Controller: 29 | CONF = {} 30 | _plugins = [] 31 | _groups = [] 32 | _sequences = [] 33 | 34 | def add_sequence(self, desc, function, args=None): 35 | self._sequences.append(Sequence(desc, function, args)) 36 | 37 | def run_all_sequences(self): 38 | for seq in self._sequences: 39 | try: 40 | seq.run() 41 | except Exception as e: 42 | raise e 43 | 44 | def add_plugin(self, plugin): 45 | self._plugins.append(plugin) 46 | 47 | def get_all_plugins(self): 48 | return self._plugins 49 | 50 | def add_group(self, name, args): 51 | self._groups.append(Group(name, args)) 52 | 53 | def get_all_groups(self): 54 | return self._groups 55 | 56 | def get_all_arguments(self): 57 | """Get a list of the configuration argument loaded""" 58 | arguments = [] 59 | for group in self._groups: 60 | arguments.extend([argument.conf_name 61 | for argument in group.get_all_arguments()]) 62 | return arguments 63 | 64 | def validate_groups(self, conf_values): 65 | """ Load validation functions, in order to check 66 | the values in the answer file """ 67 | arguments = {} 68 | for group in self._groups: 69 | for arg in group.get_all_arguments(): 70 | try: 71 | arg.validate(conf_values[arg.conf_name]) 72 | except Exception as e: 73 | raise Exception("{0}: {1}".format(arg.conf_name, str(e))) 74 | return arguments 75 | -------------------------------------------------------------------------------- /clearstack/plugins/nova_400.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2015 Intel Corporation 3 | # 4 | # Author: Alberto Murillo 5 | # Author: Julio Montes 6 | # 7 | # Licensed under the Apache License, Version 2.0 (the "License"); 8 | # you may not use this file except in compliance with the License. 9 | # You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, software 14 | # distributed under the License is distributed on an "AS IS" BASIS, 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | # See the License for the specific language governing permissions and 17 | # limitations under the License. 18 | # 19 | 20 | from clearstack import utils 21 | from clearstack import validators 22 | from clearstack.controller import Controller 23 | from clearstack.argument import Argument 24 | from clearstack.common import util 25 | 26 | 27 | def init_config(): 28 | conf = { 29 | "NOVA": [ 30 | Argument("nova-db-pw", 31 | "Password for nova to access DB", 32 | "CONFIG_NOVA_DB_PW", 33 | utils.generate_random_pw(), 34 | validators=[validators.not_empty]), 35 | Argument("nova-ks-pw", 36 | "Password to use for the Nova to" 37 | " authenticate with Keystone", 38 | "CONFIG_NOVA_KS_PW", 39 | utils.generate_random_pw(), 40 | validators=[validators.not_empty]) 41 | ] 42 | } 43 | 44 | for group in conf: 45 | Controller.get().add_group(group, conf[group]) 46 | 47 | 48 | def init_sequences(): 49 | controller = Controller.get() 50 | conf = controller.CONF 51 | if util.str2bool(conf['CONFIG_NOVA_INSTALL']): 52 | controller.add_sequence("Setting up nova controller", 53 | setup_controller) 54 | controller.add_sequence("Setting up nova computes", 55 | setup_computes) 56 | 57 | 58 | def setup_controller(): 59 | conf = Controller.get().CONF 60 | recipe = utils.get_template('nova') 61 | return utils.run_recipe("nova.py", recipe, 62 | [conf["CONFIG_CONTROLLER_HOST"]]) 63 | 64 | 65 | def setup_computes(): 66 | conf = Controller.get().CONF 67 | recipe = utils.get_template('nova_compute') 68 | return utils.run_recipe("nova_compute.py", recipe, 69 | conf["CONFIG_COMPUTE_HOSTS"].split(',')) 70 | -------------------------------------------------------------------------------- /clearstack/answer_file.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2015 Intel Corporation 3 | # 4 | # Author: Julio Montes 5 | # Author: Victor Morales 6 | # 7 | # Licensed under the Apache License, Version 2.0 (the "License"); 8 | # you may not use this file except in compliance with the License. 9 | # You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, software 14 | # distributed under the License is distributed on an "AS IS" BASIS, 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | # See the License for the specific language governing permissions and 17 | # limitations under the License. 18 | # 19 | 20 | import os 21 | 22 | import configparser 23 | 24 | from clearstack.controller import Controller 25 | from clearstack.common.util import LOG 26 | from clearstack.common.singleton import Singleton 27 | 28 | 29 | @Singleton 30 | class AnswerFile: 31 | def generate(self, file, variables_cmd): 32 | with open(file, "w") as f: 33 | f.write("[general]\n\n") 34 | for group in Controller.get().get_all_groups(): 35 | for argument in group.get_all_arguments(): 36 | f.write("# {0}\n".format(argument.description)) 37 | value = variables_cmd.get(argument.conf_name, 38 | argument.default_value) 39 | f.write("{0}={1}\n\n".format(argument.conf_name, value)) 40 | 41 | def read(self, file, variables_cmd): 42 | conf = Controller.get().CONF 43 | config = configparser.RawConfigParser() 44 | config.optionxform = str 45 | if not os.path.isfile(file): 46 | raise IOError("file {0} not found".format(file)) 47 | 48 | """ Validate option in answer file""" 49 | config.read(file) 50 | if not config.has_section('general'): 51 | raise KeyError("answer file {0} doesn't have general" 52 | " section".format(file)) 53 | conf_file = dict(config['general']) 54 | conf_file.update(variables_cmd) # override variables 55 | conf.update(conf_file) 56 | 57 | try: 58 | Controller.get().validate_groups(conf_file) 59 | except Exception as e: 60 | raise e 61 | 62 | all_args = Controller.get().get_all_arguments() 63 | for non_supported in (set(conf_file) - set(all_args)): 64 | LOG.warn("clearstack: variable {0} is not" 65 | " supported yet".format(non_supported)) 66 | -------------------------------------------------------------------------------- /clearstack/modules/glance.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2015 Intel Corporation 3 | # 4 | # Author: Alberto Murillo 5 | # Author: Julio Montes 6 | # Author: Victor Morales 7 | # 8 | # Licensed under the Apache License, Version 2.0 (the "License"); 9 | # you may not use this file except in compliance with the License. 10 | # You may obtain a copy of the License at 11 | # 12 | # http://www.apache.org/licenses/LICENSE-2.0 13 | # 14 | # Unless required by applicable law or agreed to in writing, software 15 | # distributed under the License is distributed on an "AS IS" BASIS, 16 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | # See the License for the specific language governing permissions and 18 | # limitations under the License. 19 | # 20 | 21 | import os 22 | 23 | from modules.openstack import OpenStackService 24 | from modules.conf import CONF 25 | from common import util 26 | from common.util import LOG 27 | from common.singleton import Singleton 28 | 29 | 30 | @Singleton 31 | class Glance(OpenStackService): 32 | _name = "glance" 33 | _bundle = "openstack-image" 34 | _services = ["glance-api", "glance-registry"] 35 | _type = "image" 36 | _description = "OpenStack Image" 37 | _public_url = "http://{0}:9292".format(CONF['CONFIG_CONTROLLER_HOST']) 38 | 39 | def sync_database(self): 40 | LOG.debug("populating glance database") 41 | util.run_command("su -s /bin/sh -c" 42 | " \"glance-manage db_sync\" glance") 43 | 44 | def create_image(self, name, format, url, public=False): 45 | try: 46 | LOG.debug("checking if image '{0}' exists".format(name)) 47 | util.run_command("openstack image show %s" % name, 48 | environ=self._env) 49 | except: 50 | LOG.debug("creating image '{0}'".format(name)) 51 | command = ("openstack image create --disk-format %s %s" 52 | % (format, name)) 53 | if os.path.isfile(url): 54 | command += " --file %s" % url 55 | else: 56 | command += " --location %s" % url 57 | if public: 58 | command += " --public" 59 | util.run_command(command, environ=self._env) 60 | 61 | def ceilometer_enable(self, configfile): 62 | LOG.debug("setting up rabbitmq configuration" 63 | " in '{0}'".format(configfile)) 64 | self.config_rabbitmq(configfile) 65 | config = ("[DEFAULT]\n" 66 | "notification_driver = messagingv2\n") 67 | util.write_config(configfile, config) 68 | -------------------------------------------------------------------------------- /clearstack/plugins/keystone_200.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2015 Intel Corporation 3 | # 4 | # Author: Alberto Murillo 5 | # Author: Julio Montes 6 | # 7 | # Licensed under the Apache License, Version 2.0 (the "License"); 8 | # you may not use this file except in compliance with the License. 9 | # You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, software 14 | # distributed under the License is distributed on an "AS IS" BASIS, 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | # See the License for the specific language governing permissions and 17 | # limitations under the License. 18 | # 19 | 20 | import uuid 21 | 22 | from clearstack.controller import Controller 23 | from clearstack.argument import Argument 24 | from clearstack import utils 25 | from clearstack import validators 26 | 27 | 28 | def init_config(): 29 | conf = { 30 | "KEYSTONE": [ 31 | Argument("keystone-db-pw", 32 | "Password for keystone to access DB", 33 | "CONFIG_KEYSTONE_DB_PW", 34 | utils.generate_random_pw(), 35 | validators=[validators.not_empty]), 36 | Argument("keystone-admin-token", 37 | "The token to use for the Keystone service api", 38 | "CONFIG_KEYSTONE_ADMIN_TOKEN", 39 | uuid.uuid4().hex, 40 | validators=[validators.not_empty]), 41 | Argument("keystone-admin-pw", 42 | "The password to use for the Keystone admin user", 43 | "CONFIG_KEYSTONE_ADMIN_PW", 44 | utils.generate_random_pw(), 45 | validators=[validators.not_empty]), 46 | Argument("keystone-demo-pw", 47 | "The password to use for the Keystone demo user", 48 | "CONFIG_KEYSTONE_DEMO_PW", 49 | utils.generate_random_pw(), 50 | validators=[validators.not_empty]), 51 | Argument("keystone-region", 52 | "Region name", 53 | "CONFIG_KEYSTONE_REGION", 54 | "RegionOne", 55 | validators=[validators.not_empty]) 56 | ] 57 | } 58 | 59 | for group in conf: 60 | Controller.get().add_group(group, conf[group]) 61 | 62 | 63 | def init_sequences(): 64 | Controller.get().add_sequence("Setting up keystone", setup_keystone) 65 | 66 | 67 | def setup_keystone(): 68 | conf = Controller.get().CONF 69 | recipe = utils.get_template('keystone') 70 | return utils.run_recipe("keystone.py", recipe, 71 | [conf["CONFIG_CONTROLLER_HOST"]]) 72 | -------------------------------------------------------------------------------- /clearstack/modules/nova.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2015 Intel Corporation 3 | # 4 | # Author: Alberto Murillo 5 | # Author: Julio Montes 6 | # Author: Obed Munoz 7 | # Author: Victor Morales 8 | # 9 | # Licensed under the Apache License, Version 2.0 (the "License"); 10 | # you may not use this file except in compliance with the License. 11 | # You may obtain a copy of the License at 12 | # 13 | # http://www.apache.org/licenses/LICENSE-2.0 14 | # 15 | # Unless required by applicable law or agreed to in writing, software 16 | # distributed under the License is distributed on an "AS IS" BASIS, 17 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | # See the License for the specific language governing permissions and 19 | # limitations under the License. 20 | # 21 | 22 | from modules.openstack import OpenStackService 23 | from modules.ceilometer import Ceilometer 24 | from modules.conf import CONF 25 | from common import util 26 | from common.util import LOG 27 | from common.singleton import Singleton 28 | 29 | 30 | @Singleton 31 | class Nova(OpenStackService): 32 | _name = "nova" 33 | _bundle = "openstack-compute-controller" 34 | _services = ["nova-cert", "nova-consoleauth", "nova-scheduler", 35 | "nova-conductor", "nova-novncproxy"] 36 | if CONF['CONFIG_HTTP_SERVICE'] == 'nginx': 37 | _services.extend(["nginx", "uwsgi@nova-api.socket", 38 | "uwsgi@nova-metadata.socket"]) 39 | elif CONF['CONFIG_HTTP_SERVICE'] == 'apache2': 40 | _services.append("httpd") 41 | else: 42 | _services.append("nova-api") 43 | _type = "compute" 44 | _description = "OpenStack Compute" 45 | _password = CONF['CONFIG_NOVA_KS_PW'] 46 | _public_url = ("http://{0}:8774/v2/%\(tenant_id\)s" 47 | .format(CONF['CONFIG_CONTROLLER_HOST'])) 48 | 49 | def install_compute(self): 50 | self.install("openstack-compute") 51 | 52 | def sync_database(self): 53 | LOG.debug("populating nova database") 54 | util.run_command("su -s /bin/sh -c \"nova-manage db sync\" nova") 55 | 56 | def ceilometer_enable(self, configfile): 57 | ceilometer = Ceilometer.get() 58 | ceilometer_cfg = "/etc/ceilometer/ceilometer.conf" 59 | 60 | ceilometer.install() 61 | ceilometer.config_rabbitmq(ceilometer_cfg) 62 | ceilometer.config_auth(ceilometer_cfg) 63 | ceilometer.config_service_credentials(ceilometer_cfg) 64 | 65 | config = ("[DEFAULT]\n" 66 | "instance_usage_audit = True\n" 67 | "instance_usage_audit_period = hour\n" 68 | "notify_on_state_change = vm_and_task_state\n" 69 | "notification_driver = messagingv2\n") 70 | util.write_config(configfile, config) 71 | self.start_server(['ceilometer-agent-compute.service']) 72 | -------------------------------------------------------------------------------- /clearstack/plugins/heat_650.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2015 Intel Corporation 3 | # 4 | # Author: Alberto Murillo 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file 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 | # 18 | 19 | from clearstack import utils 20 | from clearstack import validators 21 | from clearstack.controller import Controller 22 | from clearstack.argument import Argument 23 | from clearstack.common import util 24 | 25 | 26 | def init_config(): 27 | conf = { 28 | "HEAT": [ 29 | Argument("heat-db-pw", 30 | "Password for heat to access DB", 31 | "CONFIG_HEAT_DB_PW", 32 | utils.generate_random_pw(), 33 | validators=[validators.not_empty]), 34 | Argument("heat-ks-pw", 35 | "Password to use for Heat to" 36 | " authenticate with Keystone", 37 | "CONFIG_HEAT_KS_PW", 38 | utils.generate_random_pw(), 39 | validators=[validators.not_empty]), 40 | Argument("heat-domain", 41 | "Name of the Identity domain for Orchestration.", 42 | "CONFIG_HEAT_DOMAIN", 43 | "heat", 44 | validators=[validators.not_empty]), 45 | Argument("heat-domain-admin", 46 | "Name of the Identity domain administrative user for " 47 | "Orchestration.", 48 | "CONFIG_HEAT_DOMAIN_ADMIN", 49 | "heat_domain_admin", 50 | validators=[validators.not_empty]), 51 | Argument("heat-domain-password", 52 | "Password for the Identity domain administrative user " 53 | "for Orchestration", 54 | "CONFIG_HEAT_DOMAIN_PASSWORD", 55 | utils.generate_random_pw(), 56 | validators=[validators.not_empty]) 57 | ] 58 | } 59 | 60 | for group in conf: 61 | Controller.get().add_group(group, conf[group]) 62 | 63 | 64 | def init_sequences(): 65 | controller = Controller.get() 66 | conf = controller.CONF 67 | if util.str2bool(conf['CONFIG_HEAT_INSTALL']): 68 | controller.add_sequence("Setting up heat", setup_heat) 69 | 70 | 71 | def setup_heat(): 72 | conf = Controller.get().CONF 73 | recipe = utils.get_template("heat") 74 | return utils.run_recipe("heat.py", recipe, 75 | [conf["CONFIG_CONTROLLER_HOST"]]) 76 | -------------------------------------------------------------------------------- /clearstack/modules/heat.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2015 Intel Corporation 3 | # 4 | # Author: Alberto Murillo 5 | # Author: Victor Morales 6 | # 7 | # Licensed under the Apache License, Version 2.0 (the "License"); 8 | # you may not use this file except in compliance with the License. 9 | # You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, software 14 | # distributed under the License is distributed on an "AS IS" BASIS, 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | # See the License for the specific language governing permissions and 17 | # limitations under the License. 18 | # 19 | 20 | import configparser 21 | 22 | from modules.openstack import OpenStackService 23 | from modules.conf import CONF 24 | from common import util 25 | from common.util import LOG 26 | from common.singleton import Singleton 27 | 28 | 29 | @Singleton 30 | class Heat(OpenStackService): 31 | _name = "heat" 32 | _bundle = "openstack-orchestration" 33 | _services = ["heat-api", "heat-api-cfn", "heat-engine"] 34 | _type = "orchestration" 35 | _description = "OpenStack Orchestration" 36 | _public_url = ("http://{0}:8004/v1/%\(tenant_id\)s" 37 | .format(CONF['CONFIG_CONTROLLER_HOST'])) 38 | 39 | domain_admin = CONF['CONFIG_HEAT_DOMAIN_ADMIN'] 40 | domain_admin_pw = CONF['CONFIG_HEAT_DOMAIN_PASSWORD'] 41 | domain_name = CONF['CONFIG_HEAT_DOMAIN'] 42 | 43 | def sync_database(self): 44 | LOG.debug("populating heat database") 45 | util.run_command("su -s /bin/sh -c" 46 | " \"heat-manage db_sync\" heat") 47 | 48 | def config_auth(self, configfile): 49 | OpenStackService.config_auth(self, configfile) 50 | config = configparser.RawConfigParser(allow_no_value=True) 51 | config.read(configfile) 52 | auth_uri = config['keystone_authtoken']['auth_uri'] 53 | config['trustee'] = config['keystone_authtoken'] 54 | if not config.has_section('clients_keystone'): 55 | config.add_section('clients_keystone') 56 | config['clients_keystone']['auth_uri'] = auth_uri 57 | if not config.has_section('ec2authtoken'): 58 | config.add_section('ec2authtoken') 59 | config['ec2authtoken']['auth_uri'] = auth_uri 60 | with open(configfile, 'w') as f: 61 | config.write(f) 62 | 63 | def config_domain(self, configfile): 64 | config = ("[DEFAULT]\n" 65 | "heat_metadata_server_url = http://{0}:8000\n" 66 | "heat_waitcondition_server_url = " 67 | "http://{0}:8000/v1/waitcondition\n" 68 | "stack_domain_admin = {1}\n" 69 | "stack_domain_admin_password = {2}\n" 70 | "stack_user_domain_name = {3}\n" 71 | .format(self._controller, self.domain_admin, 72 | self.domain_admin_pw, self.domain_name)) 73 | util.write_config(configfile, config) 74 | -------------------------------------------------------------------------------- /clearstack/modules/keystone.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2015 Intel Corporation 3 | # 4 | # Author: Alberto Murillo 5 | # Author: Julio Montes 6 | # Author: Obed Munoz 7 | # Author: Victor Morales 8 | # 9 | # Licensed under the Apache License, Version 2.0 (the "License"); 10 | # you may not use this file except in compliance with the License. 11 | # You may obtain a copy of the License at 12 | # 13 | # http://www.apache.org/licenses/LICENSE-2.0 14 | # 15 | # Unless required by applicable law or agreed to in writing, software 16 | # distributed under the License is distributed on an "AS IS" BASIS, 17 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | # See the License for the specific language governing permissions and 19 | # limitations under the License. 20 | # 21 | 22 | from modules.openstack import OpenStackService 23 | from modules.conf import CONF 24 | from common import util 25 | from common.util import LOG 26 | from common.singleton import Singleton 27 | 28 | 29 | @Singleton 30 | class Keystone(OpenStackService): 31 | _name = "keystone" 32 | _bundle = "openstack-identity" 33 | if CONF['CONFIG_HTTP_SERVICE'] == 'nginx': 34 | _services = ["memcached", "nginx", "uwsgi@keystone-admin.socket", 35 | "uwsgi@keystone-public.socket"] 36 | elif CONF['CONFIG_HTTP_SERVICE'] == 'apache2': 37 | _services = ["memcached", "httpd"] 38 | else: 39 | _services = ["keystone"] 40 | _type = "identity" 41 | _description = "OpenStack Identity" 42 | _user = "admin" 43 | _password = CONF['CONFIG_KEYSTONE_ADMIN_PW'] 44 | _public_url = "http://%s:5000/v3" % CONF['CONFIG_CONTROLLER_HOST'] 45 | _internal_url = _public_url 46 | _admin_url = "http://%s:35357/v3" % CONF['CONFIG_CONTROLLER_HOST'] 47 | _env = {"OS_TOKEN": CONF['CONFIG_KEYSTONE_ADMIN_TOKEN'], 48 | "OS_URL": "http://{0}:35357/v3" 49 | .format(CONF['CONFIG_CONTROLLER_HOST']), 50 | "OS_IDENTITY_API_VERSION": "3"} 51 | 52 | def sync_database(self): 53 | LOG.debug("populating keystone database") 54 | util.run_command("su -s /bin/sh -c" 55 | " \"keystone-manage db_sync\" keystone") 56 | 57 | def create_project(self, project, description): 58 | try: 59 | """ test if project already exists """ 60 | LOG.debug("checking if project '{0}' exists".format(project)) 61 | util.run_command("openstack project show %s" % project, 62 | environ=self._env) 63 | except: 64 | LOG.debug("setting up project '{0}'".format(project)) 65 | util.run_command("openstack project create --domain default" 66 | " --description \"%s\" %s" 67 | % (description, project), environ=self._env) 68 | 69 | def config_admin_token(self, configfile): 70 | config = \ 71 | "[DEFAULT]\n" + \ 72 | "admin_token=%s\n" % CONF['CONFIG_KEYSTONE_ADMIN_TOKEN'] 73 | util.write_config(configfile, config) 74 | -------------------------------------------------------------------------------- /clearstack/plugins/provision_700.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2015 Intel Corporation 3 | # 4 | # Author: Alberto Murillo 5 | # Author: Victor Morales 6 | # 7 | # Licensed under the Apache License, Version 2.0 (the "License"); 8 | # you may not use this file except in compliance with the License. 9 | # You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, software 14 | # distributed under the License is distributed on an "AS IS" BASIS, 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | # See the License for the specific language governing permissions and 17 | # limitations under the License. 18 | # 19 | 20 | from clearstack import utils 21 | from clearstack import validators 22 | from clearstack.controller import Controller 23 | from clearstack.argument import Argument 24 | from clearstack.common import util 25 | 26 | 27 | def init_config(): 28 | conf = { 29 | "PROVISION_INIT": [ 30 | Argument("provision-demo", 31 | "Specify 'y' to provision for demo usage and testing." 32 | " ['y', 'n']", 33 | "CONFIG_PROVISION_DEMO", 34 | "n", 35 | options=['y', 'n'], 36 | validators=[validators.y_or_n]) 37 | ], 38 | "PROVISION_DEMO": [ 39 | Argument("provision-demo-floatrange", 40 | "CIDR network address for the floating IP subnet.", 41 | "CONFIG_PROVISION_DEMO_FLOATRANGE", 42 | "172.24.4.224/28", 43 | validators=[validators.cidr]), 44 | Argument("privision-image-format", 45 | 'Format for the demo image (default "qcow2").', 46 | "CONFIG_PROVISION_IMAGE_FORMAT", 47 | "qcow2", 48 | validators=[validators.not_empty]), 49 | Argument("provision-image-name", 50 | 'The name to be assigned to the demo image in Glance ' 51 | '(default "cirros")', 52 | "CONFIG_PROVISION_IMAGE_NAME", 53 | "cirros", 54 | validators=[validators.not_empty]), 55 | Argument("provision-image-url", 56 | 'A URL or local file location for an image to download' 57 | 'and provision in Glance (defaults to a URL for a ' 58 | 'recent "cirros" image).', 59 | "CONFIG_PROVISION_IMAGE_URL", 60 | 'http://download.cirros-cloud.net/0.3.4/cirros-0.3.4-' 61 | 'x86_64-disk.img', 62 | validators=[validators.not_empty]) 63 | ] 64 | } 65 | 66 | for group in conf: 67 | Controller.get().add_group(group, conf[group]) 68 | 69 | 70 | def init_sequences(): 71 | controller = Controller.get() 72 | conf = controller.CONF 73 | if util.str2bool(conf['CONFIG_PROVISION_DEMO']): 74 | controller.add_sequence("Running provisioning", 75 | setup_controller) 76 | 77 | 78 | def setup_controller(): 79 | conf = Controller.get().CONF 80 | templates = ['provision'] 81 | recipe = "" 82 | for template in templates: 83 | recipe += utils.get_template(template) 84 | 85 | return utils.run_recipe("provision.py", recipe, 86 | [conf["CONFIG_CONTROLLER_HOST"]]) 87 | -------------------------------------------------------------------------------- /clearstack/run_setup.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2015 Intel Corporation 3 | # 4 | # Author: Alberto Murillo 5 | # Author: Julio Montes 6 | # Author: Victor Morales 7 | # 8 | # Licensed under the Apache License, Version 2.0 (the "License"); 9 | # you may not use this file except in compliance with the License. 10 | # You may obtain a copy of the License at 11 | # 12 | # http://www.apache.org/licenses/LICENSE-2.0 13 | # 14 | # Unless required by applicable law or agreed to in writing, software 15 | # distributed under the License is distributed on an "AS IS" BASIS, 16 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | # See the License for the specific language governing permissions and 18 | # limitations under the License. 19 | # 20 | 21 | import re 22 | import os 23 | 24 | from importlib import import_module 25 | 26 | from clearstack import utils 27 | from clearstack.controller import Controller 28 | from clearstack.common.util import LOG 29 | 30 | 31 | def load_plugins(): 32 | """ return if plugins already are loaded """ 33 | if Controller.get().get_all_plugins(): 34 | return 35 | 36 | path = "plugins" 37 | base_module = "clearstack.{0}".format(path) 38 | directory = "{0}/{1}".format(os.path.dirname( 39 | os.path.realpath(__file__)), path) 40 | rx_val = r'^[a-zA-Z]+_[0-9]{3}\.py$' 41 | files = [fd for fd in os.listdir(directory) if re.match(rx_val, fd)] 42 | for fd in sorted(files, key=_get_weight): 43 | plugin = import_module("{0}.{1}".format(base_module, fd.split(".")[0])) 44 | Controller.get().add_plugin(plugin) 45 | try: 46 | getattr(plugin, "init_config")() 47 | except AttributeError: 48 | LOG.debug("missing attribute: init_config in %s", 49 | plugin.__file__) 50 | 51 | 52 | def add_arguments(parser): 53 | load_plugins() 54 | for group in Controller.get().get_all_groups(): 55 | for argument in group.get_all_arguments(): 56 | parser.add_argument("--{0}".format(argument.cmd_option), 57 | action="store", 58 | dest=argument.conf_name, 59 | help=argument.description, 60 | choices=argument.option_list) 61 | 62 | 63 | def load_sequences(): 64 | load_plugins() 65 | for plugin in Controller.get().get_all_plugins(): 66 | try: 67 | getattr(plugin, "init_sequences")() 68 | except AttributeError: 69 | LOG.debug("missing attribute: init_sequences in %s", 70 | plugin.__file__) 71 | 72 | 73 | def run_all_sequences(): 74 | load_sequences() 75 | 76 | try: 77 | utils.copy_resources() 78 | except Exception as e: 79 | raise e 80 | 81 | try: 82 | Controller.get().run_all_sequences() 83 | except Exception as e: 84 | raise e 85 | finally: 86 | utils.get_logs() 87 | 88 | 89 | def generate_admin_openrc(): 90 | conf = Controller.get().CONF 91 | home = os.getenv('HOME') 92 | with open("{0}/admin-openrc.sh".format(home), "w") as f: 93 | f.write('export OS_PROJECT_DOMAIN_ID=default\n') 94 | f.write('export OS_USER_DOMAIN_ID=default\n') 95 | f.write('export OS_PROJECT_NAME=admin\n') 96 | f.write('export OS_USERNAME="admin"\n') 97 | f.write('export OS_TENANT_NAME="admin"\n') 98 | f.write('export OS_AUTH_URL=http://{0}:35357/v3\n' 99 | .format(conf['CONFIG_CONTROLLER_HOST'])) 100 | f.write('export OS_REGION_NAME="{0}"\n' 101 | .format(conf['CONFIG_KEYSTONE_REGION'])) 102 | f.write('export OS_PASSWORD={0}\n' 103 | .format(conf['CONFIG_KEYSTONE_ADMIN_PW'])) 104 | f.write('export OS_IDENTITY_API_VERSION=3\n') 105 | 106 | 107 | def _get_weight(item): 108 | tmp = item.split('_')[-1] 109 | tmp = tmp.split('.')[0] 110 | return tmp 111 | -------------------------------------------------------------------------------- /clearstack/plugins/swift_600.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2015 Intel Corporation 3 | # 4 | # Author: Alberto Murillo 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file 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 | # 18 | 19 | import os 20 | import stat 21 | 22 | from clearstack import utils 23 | from clearstack import validators 24 | from clearstack.controller import Controller 25 | from clearstack.argument import Argument 26 | from clearstack.common import util 27 | 28 | 29 | def init_config(): 30 | conf = { 31 | "SWIFT": [ 32 | Argument("swift-ks-pw", 33 | "Password to use for the Object Storage service to " 34 | " authenticate with with the Identity service", 35 | "CONFIG_SWIFT_KS_PW", 36 | utils.generate_random_pw(), 37 | validators=[validators.not_empty]), 38 | Argument("swift-storages", 39 | "Comma-separated list of devices to use as storage device" 40 | " for Object Storage. e.g. /path/to/dev1,/path/to/dev2." 41 | " Clearstack DOES NOT creare the file system, you must " 42 | "format it with xfs. Leave blank to use a loop device", 43 | "CONFIG_SWIFT_STORAGES", 44 | '', 45 | validators=[validate_storage]), 46 | Argument("swift-storage-zones", 47 | "Number of Object Storage storage zones; this number " 48 | "MUST be no larger than the number of configured " 49 | "storage devices.", 50 | "CONFIG_SWIFT_STORAGE_ZONES", 51 | '1', 52 | validators=[validators.digit]), 53 | Argument("swift-storage-replicas", 54 | "Number of Object Storage storage replicas; this number " 55 | "MUST be no larger than the number of configured " 56 | "storage zones.", 57 | "CONFIG_SWIFT_STORAGE_REPLICAS", 58 | '1', 59 | validators=[validators.digit]), 60 | Argument("swift-hash", 61 | "Custom seed number to use for swift_hash_path_suffix in" 62 | " /etc/swift/swift.conf. If you do not provide a value, " 63 | "a seed number is automatically generated.", 64 | "CONFIG_SWIFT_HASH", 65 | utils.generate_random_pw(), 66 | validators=[validators.not_empty]), 67 | Argument("swift-storage-size", 68 | "Size of the Object Storage loopback file storage " 69 | "device in GB", 70 | "CONFIG_SWIFT_STORAGE_SIZE", 71 | "2", 72 | validators=[validators.digit]), 73 | ] 74 | } 75 | 76 | for group in conf: 77 | Controller.get().add_group(group, conf[group]) 78 | 79 | 80 | def init_sequences(): 81 | controller = Controller.get() 82 | conf = controller.CONF 83 | if util.str2bool(conf['CONFIG_SWIFT_INSTALL']): 84 | controller.add_sequence("Setting up swift", setup_swift) 85 | 86 | 87 | def setup_swift(): 88 | conf = Controller.get().CONF 89 | recipe = utils.get_template("swift") 90 | return utils.run_recipe("swift.py", recipe, 91 | [conf["CONFIG_CONTROLLER_HOST"]]) 92 | 93 | 94 | def validate_storage(value): 95 | if not value: 96 | return 97 | devices = value.split(',') 98 | for device in devices: 99 | mode = os.stat(device).st_mode 100 | if not stat.S_ISBLK(mode): 101 | raise ValueError("%s is not a block device" % device) 102 | -------------------------------------------------------------------------------- /clearstack/modules/rabbitmq.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2015 Intel Corporation 3 | # 4 | # Author: Alberto Murillo 5 | # Author: Julio Montes 6 | # Author: Victor Morales 7 | # 8 | # Licensed under the Apache License, Version 2.0 (the "License"); 9 | # you may not use this file except in compliance with the License. 10 | # You may obtain a copy of the License at 11 | # 12 | # http://www.apache.org/licenses/LICENSE-2.0 13 | # 14 | # Unless required by applicable law or agreed to in writing, software 15 | # distributed under the License is distributed on an "AS IS" BASIS, 16 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | # See the License for the specific language governing permissions and 18 | # limitations under the License. 19 | # 20 | import sys 21 | 22 | from common import util 23 | from common.singleton import Singleton 24 | from common.swupd import Client as swupd_client 25 | from common.util import LOG 26 | 27 | 28 | @Singleton 29 | class Rabbitmq: 30 | def __init__(self): 31 | hostname, stderr = util.run_command("hostname") 32 | util.write_in_file_ine("/etc/hosts", "127.0.0.1 {0}" 33 | .format(str(hostname.decode("utf-8")[:-1]))) 34 | 35 | def user_exists(self, user): 36 | stdout = None 37 | stderr = None 38 | try: 39 | LOG.debug("Checking if rabbitmq user '{0}' exists".format(user)) 40 | stdout, stderr = util.run_command("rabbitmqctl list_users" 41 | " | grep {0}".format(user)) 42 | except: 43 | pass 44 | 45 | if not stdout: 46 | LOG.debug("rabbitmq user '{0}' does not exists".format(user)) 47 | return False 48 | 49 | LOG.debug("rabbitmq user '{0}' does exists".format(user)) 50 | return True 51 | 52 | def install(self): 53 | swupd_client.install("message-broker-rabbitmq") 54 | 55 | def enable_server(self): 56 | enabled = util.service_enabled("rabbitmq-server.service") 57 | if not enabled: 58 | util.run_command("systemctl enable rabbitmq-server") 59 | 60 | def start_server(self): 61 | LOG.debug("enabling rabbitmq-server service") 62 | self.enable_server() 63 | status = util.service_status("rabbitmq-server.service") 64 | LOG.debug("rabbitmq-server status: " + status) 65 | if status == "active": 66 | LOG.debug("rabbitmq-server service is already running") 67 | return 68 | elif status == "inactive" or status == "unknown": 69 | LOG.debug("starting rabbitmq-server service") 70 | util.run_command("systemctl restart rabbitmq-server") 71 | elif status == "failed": 72 | # try to re-run the service, catch the error if fails again 73 | try: 74 | LOG.debug("rabbitmq-server failed to start previously. " 75 | "Trying to start service...") 76 | util.run_command("systemctl restart rabbitmq-server") 77 | except: 78 | LOG.debug("rabbitmq-server.service failed to start." 79 | "Try 'rm -rf /var/lib/rabbitmq/*' and re-run" 80 | "clearstack") 81 | sys.exit(1) 82 | else: 83 | LOG.debug("Error: rabbitmq-server service status" 84 | " '{0}' unknown... Exiting clearstack".format(status)) 85 | sys.exit(1) 86 | 87 | def add_user(self, auth_user, auth_pw): 88 | """ todo: what we do with guest """ 89 | LOG.debug("adding rabbitmq user '{0}'".format(auth_user)) 90 | if not self.user_exists(auth_user): 91 | util.run_command("rabbitmqctl add_user {0} {1}" 92 | .format(auth_user, auth_pw), debug=False) 93 | 94 | def delete_user(self, user): 95 | LOG.debug("deleting rabbitmq user '{0}'".format(user)) 96 | util.run_command("rabbitmqctl delete_user {1}" 97 | .format(user)) 98 | 99 | def set_permissions(self, auth_user, permissions): 100 | LOG.debug("setting rabbitmq permissions for " 101 | "user '{0}'".format(auth_user)) 102 | util.run_command("rabbitmqctl set_permissions {0} {1}" 103 | .format(auth_user, permissions)) 104 | -------------------------------------------------------------------------------- /clearstack/modules/mariadb.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2015 Intel Corporation 3 | # 4 | # Author: Alberto Murillo 5 | # Author: Julio Montes 6 | # Author: Obed Munoz 7 | # Author: Victor Morales 8 | # 9 | # Licensed under the Apache License, Version 2.0 (the "License"); 10 | # you may not use this file except in compliance with the License. 11 | # You may obtain a copy of the License at 12 | # 13 | # http://www.apache.org/licenses/LICENSE-2.0 14 | # 15 | # Unless required by applicable law or agreed to in writing, software 16 | # distributed under the License is distributed on an "AS IS" BASIS, 17 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 18 | # See the License for the specific language governing permissions and 19 | # limitations under the License. 20 | # 21 | 22 | import sys 23 | 24 | from common import util 25 | from common.singleton import Singleton 26 | from common.swupd import Client as swupd_client 27 | from common.util import LOG 28 | from modules.conf import CONF 29 | 30 | 31 | @Singleton 32 | class MariaDB: 33 | def install(self): 34 | swupd_client.install("database-mariadb") 35 | 36 | def start_server(self): 37 | LOG.debug("starting mariadb service") 38 | util.run_command("systemctl enable mariadb") 39 | util.run_command("systemctl restart mariadb") 40 | 41 | def configure(self): 42 | config_file = "/etc/mariadb/openstack.cnf" 43 | config = """ 44 | [mysqld] 45 | default-storage-engine = innodb 46 | innodb_file_per_table 47 | collation-server = utf8_general_ci 48 | init-connect = 'SET NAMES utf8' 49 | character-set-server = utf8 50 | bind-address = 0.0.0.0 51 | """ 52 | LOG.debug("configuring mariadb options in '{0}'".format(config_file)) 53 | util.write_config(config_file, config) 54 | 55 | def secure_installation(self, user, password): 56 | LOG.debug("calling mariadb secure installation") 57 | try: 58 | """ test if mysql has a password """ 59 | util.run_command("mysql -u{0} -e \"\"".format(user), debug=False) 60 | """ Secure the database service """ 61 | util.run_command('mysqladmin -u root password "{0}"' 62 | .format(password, debug=False)) 63 | util.run_command('mysql -u root -p"{0}" -e "UPDATE mysql.user ' 64 | 'SET Password=PASSWORD(\'{0}\') ' 65 | 'WHERE User=\'root\'"' 66 | .format(password, debug=False)) 67 | util.run_command('mysql -u root -p"{0}" -e "DELETE FROM ' 68 | 'mysql.user WHERE User=\'root\' AND Host ' 69 | ' NOT IN (\'localhost\', \'127.0.0.1\', ' 70 | '\'::1\')"' 71 | .format(password, debug=False)) 72 | util.run_command('mysql -u root -p"{0}" -e "DELETE FROM ' 73 | 'mysql.user WHERE User=\'\'"' 74 | .format(password, debug=False)) 75 | util.run_command('mysql -u root -p"{0}" -e "DELETE FROM mysql.db ' 76 | 'WHERE Db=\'test\' OR Db=\'test\_%\'"' 77 | .format(password, debug=False)) 78 | util.run_command('mysql -u root -p"{0}" -e ' 79 | '"FLUSH PRIVILEGES"' 80 | .format(password, debug=False)) 81 | except: 82 | pass 83 | 84 | try: 85 | """ verify the password """ 86 | util.run_command("mysql -u{0} -p{1} -e \"\"" 87 | .format(user, password), debug=False) 88 | except: 89 | LOG.error("clearstack: cannot connect to mysql database," 90 | " the password is incorrect") 91 | return sys.exit(1) 92 | 93 | def setup_database(self, database, user, password): 94 | LOG.debug("setting up '{0}' database".format(database)) 95 | mariadb_user = CONF["CONFIG_MARIADB_USER"] 96 | mariadb_pw = CONF["CONFIG_MARIADB_PW"] 97 | util.run_command("mysql -u{0} -p{1} -e" 98 | " \"CREATE DATABASE if not exists {2};\"" 99 | .format(mariadb_user, mariadb_pw, database), 100 | debug=False) 101 | util.run_command("mysql -u{0} -p{1} -e" 102 | " \"GRANT ALL PRIVILEGES ON {2}.* TO" 103 | " '{3}'@'localhost' IDENTIFIED BY '{4}';\"" 104 | .format(mariadb_user, mariadb_pw, database, user, 105 | password), debug=False) 106 | util.run_command("mysql -u{0} -p{1} -e" 107 | " \"GRANT ALL PRIVILEGES ON {2}.* TO '{3}'@'%'" 108 | " IDENTIFIED BY '{4}';\"" 109 | .format(mariadb_user, mariadb_pw, database, user, 110 | password), debug=False) 111 | -------------------------------------------------------------------------------- /clearstack/shell.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2015 Intel Corporation 3 | # 4 | # Author: Julio Montes 5 | # Author: Victor Morales 6 | # 7 | # Licensed under the Apache License, Version 2.0 (the "License"); 8 | # you may not use this file except in compliance with the License. 9 | # You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, software 14 | # distributed under the License is distributed on an "AS IS" BASIS, 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | # See the License for the specific language governing permissions and 17 | # limitations under the License. 18 | # 19 | 20 | """Command-line interface to configure Clearstack.""" 21 | 22 | from __future__ import print_function 23 | 24 | import argparse 25 | import sys 26 | 27 | import clearstack 28 | from clearstack.answer_file import AnswerFile 29 | from clearstack import run_setup 30 | from clearstack import utils 31 | from clearstack.common.util import LOG 32 | 33 | 34 | class ClearstackConfiguratorShell(object): 35 | 36 | def get_base_parser(self): 37 | parser = argparse.ArgumentParser( 38 | prog='clearstack', 39 | description=__doc__.strip(), 40 | epilog='See "clearstack help COMMAND" ' 41 | 'for help on a specific command.', 42 | add_help=False, 43 | formatter_class=argparse.HelpFormatter, 44 | ) 45 | 46 | # Global arguments 47 | parser.add_argument('-h', 48 | '--help', 49 | action='store_true', 50 | help=argparse.SUPPRESS) 51 | 52 | parser.add_argument('--version', 53 | action='version', 54 | version=clearstack.__version__, 55 | help="Shows the client version and exits.") 56 | 57 | parser.add_argument('-d', 58 | '--debug', 59 | action='store_true', 60 | help="Enable debug mode in clearstack") 61 | 62 | parser.add_argument('--gen-answer-file', 63 | action='store', 64 | dest='gen_answer_file', 65 | help='Generate an answer file') 66 | 67 | parser.add_argument('--answer-file', 68 | action='store', 69 | dest='answer_file', 70 | help='Read answer file') 71 | 72 | parser.add_argument('--gen-keys', 73 | action='store', 74 | dest='gen_keys', 75 | help='Generate ssh keys') 76 | 77 | return parser 78 | 79 | def main(self, argv): 80 | self.parser = self.get_base_parser() 81 | run_setup.add_arguments(self.parser) 82 | (options, args) = self.parser.parse_known_args(argv) 83 | utils.setup_debugging(options.debug) 84 | 85 | LOG.debug('Starting clearstack') 86 | 87 | if not argv or options.help: 88 | self.do_help(options) 89 | return 0 90 | 91 | if options.gen_keys: 92 | LOG.debug('generating ssh keys') 93 | utils.generate_ssh_keys(options.gen_keys) 94 | 95 | # todo: fix 96 | # if options.allinone: 97 | # LOG.debug('testing root access') 98 | # if os.geteuid() != 0: 99 | # LOG.error("clearstack: error: you need to have root access") 100 | # sys.exit(1) 101 | 102 | """ Save user's variables, used to read/write answerfile """ 103 | variables_cmd = {k: v for (k, v) in options.__dict__.items() 104 | if v is not None and k.startswith("CONFIG_")} 105 | 106 | ansfile = AnswerFile.get() 107 | if options.gen_answer_file: 108 | LOG.debug('generating answer file') 109 | ansfile.generate(options.gen_answer_file, variables_cmd) 110 | 111 | if options.answer_file: 112 | try: 113 | LOG.debug('Reading answer file') 114 | ansfile.read(options.answer_file, variables_cmd) 115 | LOG.debug('Running all sequences') 116 | run_setup.run_all_sequences() 117 | except Exception as e: 118 | LOG.error("clearstack: {0}".format(str(e))) 119 | sys.exit(1) 120 | LOG.debug('Generating admin-openrc') 121 | run_setup.generate_admin_openrc() 122 | 123 | @utils.arg('command', metavar='', nargs='?', 124 | help='Display help for .') 125 | def do_help(self, args): 126 | self.parser.print_help() 127 | 128 | 129 | def main(): 130 | try: 131 | ClearstackConfiguratorShell().main(sys.argv[1:]) 132 | except KeyboardInterrupt: 133 | print("... terminating clearstack", file=sys.stderr) 134 | sys.exit(130) 135 | except Exception as e: 136 | print(str(e), file=sys.stderr) 137 | sys.exit(1) 138 | 139 | if __name__ == "__main__": 140 | sys.exit(main()) 141 | -------------------------------------------------------------------------------- /clearstack/utils.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2015 Intel Corporation 3 | # 4 | # Author: Alberto Murillo 5 | # Author: Julio Montes 6 | # Author: Victor Morales 7 | # 8 | # Licensed under the Apache License, Version 2.0 (the "License"); 9 | # you may not use this file except in compliance with the License. 10 | # You may obtain a copy of the License at 11 | # 12 | # http://www.apache.org/licenses/LICENSE-2.0 13 | # 14 | # Unless required by applicable law or agreed to in writing, software 15 | # distributed under the License is distributed on an "AS IS" BASIS, 16 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | # See the License for the specific language governing permissions and 18 | # limitations under the License. 19 | # 20 | 21 | import calendar 22 | import configparser 23 | import datetime 24 | import os 25 | import binascii 26 | import time 27 | import shutil 28 | 29 | from clearstack import controller 30 | from clearstack.ssh import SshHandler 31 | from clearstack.controller import Controller 32 | from clearstack.common import util 33 | 34 | 35 | __now = datetime.datetime.now() 36 | __recipes_directory = "/tmp/clearstack-{0}-{1}-{2}-{3}/".format( 37 | __now.year, __now.month, __now.day, calendar.timegm(time.gmtime())) 38 | 39 | 40 | def arg(*args, **kwargs): 41 | def _decorator(func): 42 | func.__dict__.setdefault('arguments', []).insert(0, (args, kwargs)) 43 | return func 44 | return _decorator 45 | 46 | 47 | def run_recipe(recipe_file, recipe_src, hosts): 48 | recipes_dir = __recipes_directory 49 | if not os.path.isdir(recipes_dir): 50 | os.makedirs(recipes_dir) 51 | 52 | if controller.DEBUG and recipe_file.endswith('.py'): 53 | recipe_src = "from common import util\n" + \ 54 | "util.setup_debugging(True)\n\n" + \ 55 | recipe_src 56 | 57 | recipe_file = os.path.join(recipes_dir, recipe_file) 58 | with open(recipe_file, "w") as f: 59 | f.write(recipe_src) 60 | 61 | _run_recipe_in_hosts(recipe_file, recipes_dir, hosts) 62 | return True 63 | 64 | 65 | def _run_recipe_local(recipe_file): 66 | if recipe_file.endswith('.py'): 67 | util.run_command("python3 {0}".format(recipe_file)) 68 | else: 69 | util.run_command("bash -f {0}".format(recipe_file)) 70 | 71 | 72 | def _run_recipe_in_hosts(recipe_file, recipes_dir, _hosts): 73 | hosts = set(_hosts) 74 | ssh = SshHandler.get() 75 | 76 | if util.has_localhost(hosts): 77 | _run_recipe_local(recipe_file) 78 | util.remove_localhost(hosts) 79 | 80 | for host in hosts: 81 | try: 82 | ssh.transfer_file(recipe_file, recipes_dir, host) 83 | ssh.run_recipe(recipe_file, host) 84 | except Exception as e: 85 | raise e 86 | 87 | 88 | def get_all_hosts(): 89 | conf = Controller.get().CONF 90 | hosts = set() 91 | hosts.update(set(conf["CONFIG_COMPUTE_HOSTS"].split(","))) 92 | hosts.add(conf["CONFIG_CONTROLLER_HOST"]) 93 | hosts.add(conf["CONFIG_AMQP_HOST"]) 94 | hosts.add(conf["CONFIG_MARIADB_HOST"]) 95 | hosts.add(conf["CONFIG_MONGODB_HOST"]) 96 | return hosts 97 | 98 | 99 | def generate_conf_file(conf_file): 100 | """ create defaults.conf file """ 101 | conf = Controller.get().CONF 102 | config_file = configparser.RawConfigParser() 103 | config_file.optionxform = str 104 | dir_name = os.path.dirname(conf_file) 105 | 106 | if not os.path.isdir(dir_name): 107 | os.makedirs(dir_name) 108 | 109 | config_file.add_section("general") 110 | for key, value in conf.items(): 111 | config_file.set("general", key, '{0}'.format(value)) 112 | 113 | with open(conf_file, 'w') as f: 114 | config_file.write(f) 115 | 116 | 117 | def copy_resources(): 118 | _copy_resources_to_hosts(get_all_hosts()) 119 | 120 | 121 | def _copy_resources_local(): 122 | resources_dir = os.path.dirname(os.path.realpath(__file__)) 123 | modules_src = "{0}/modules".format(resources_dir) 124 | common_src = "{0}/common".format(resources_dir) 125 | modules_dst = "{0}/modules".format(__recipes_directory) 126 | common_dst = "{0}/common".format(__recipes_directory) 127 | shutil.copytree(modules_src, modules_dst) 128 | shutil.copytree(common_src, common_dst) 129 | 130 | 131 | def _copy_resources_to_hosts(_hosts): 132 | ssh = SshHandler.get() 133 | try: 134 | ssh.test_hosts(_hosts) 135 | except Exception as e: 136 | raise e 137 | 138 | resources_dir = os.path.dirname(os.path.realpath(__file__)) 139 | modules_dir = "{0}/modules".format(resources_dir) 140 | common_dir = "{0}/common".format(resources_dir) 141 | conf_file = "{0}/defaults.conf".format(__recipes_directory) 142 | 143 | if util.has_localhost(_hosts): 144 | _copy_resources_local() 145 | util.remove_localhost(_hosts) 146 | 147 | generate_conf_file(conf_file) 148 | 149 | """ Copy modules and conf to hosts """ 150 | for host in _hosts: 151 | try: 152 | ssh.transfer_file(modules_dir, __recipes_directory, host) 153 | ssh.transfer_file(common_dir, __recipes_directory, host) 154 | ssh.transfer_file(conf_file, __recipes_directory, host) 155 | except Exception as e: 156 | raise e 157 | 158 | 159 | def get_logs(): 160 | SshHandler.get().get_logs(get_all_hosts()) 161 | 162 | 163 | def get_template(template): 164 | directory = "{0}/{1}".format(os.path.dirname( 165 | os.path.realpath(__file__)), "templates") 166 | if not template.endswith(".sh"): 167 | template = template + ".py" 168 | template = os.path.join(directory, template) 169 | source = "\n{0} {1} {0}\n".format("#" * 5, template) 170 | with open(template, 'r') as f: 171 | source += f.read() 172 | source += "\n{0}\n".format("#" * 60) 173 | return source 174 | 175 | raise Exception("cannot load {0} template".format(template)) 176 | 177 | 178 | def generate_random_pw(): 179 | return binascii.b2a_hex(os.urandom(10)).decode("utf-8") 180 | 181 | 182 | def generate_ssh_keys(output): 183 | util.run_command("ssh-keygen -b 4096 -f {0} -a 500 -N ''" 184 | .format(output)) 185 | 186 | 187 | def setup_debugging(debug): 188 | controller.DEBUG = debug 189 | util.setup_debugging(debug, is_remote_host=False) 190 | -------------------------------------------------------------------------------- /clearstack/ssh.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2015 Intel Corporation 3 | # 4 | # Author: Julio Montes 5 | # Author: Obed Munoz 6 | # Author: Victor Morales 7 | # 8 | # Licensed under the Apache License, Version 2.0 (the "License"); 9 | # you may not use this file except in compliance with the License. 10 | # You may obtain a copy of the License at 11 | # 12 | # http://www.apache.org/licenses/LICENSE-2.0 13 | # 14 | # Unless required by applicable law or agreed to in writing, software 15 | # distributed under the License is distributed on an "AS IS" BASIS, 16 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | # See the License for the specific language governing permissions and 18 | # limitations under the License. 19 | # 20 | 21 | import os 22 | 23 | import paramiko 24 | 25 | from clearstack.controller import Controller 26 | from clearstack.common import util 27 | from clearstack.common.util import LOG 28 | from clearstack.common.singleton import Singleton 29 | 30 | 31 | @Singleton 32 | class SshHandler(object): 33 | def __init__(self): 34 | conf = Controller.get().CONF 35 | path = os.path.expanduser( 36 | conf['CONFIG_PRIVATE_SSH_KEY']) 37 | path = os.path.realpath(path) 38 | self.ssh_private_key = path 39 | self.ssh_user = "root" 40 | 41 | def connect(self, user, key_file, host): 42 | ''' Creates a connection to the host using SSH key ''' 43 | private_key = paramiko.RSAKey.from_private_key_file(key_file) 44 | connection = paramiko.SSHClient() 45 | connection.set_missing_host_key_policy(paramiko.AutoAddPolicy()) 46 | connection.connect(hostname=host, username=user, pkey=private_key, 47 | timeout=1000) 48 | return connection 49 | 50 | def run_command(self, connection, command): 51 | try: 52 | stdin, stdout, stderr = connection.exec_command(command) 53 | while not stdout.channel.exit_status_ready(): 54 | pass 55 | except Exception as e: 56 | raise e 57 | 58 | ''' if stderr is not empty then something fail ''' 59 | error = stderr.read() 60 | if error: 61 | raise Exception(error.decode('utf-8')) 62 | 63 | return stdin, stdout, stderr 64 | 65 | def transfer_file(self, file, dest_path, ip): 66 | try: 67 | connection = self.connect(self.ssh_user, self.ssh_private_key, ip) 68 | sftp = connection.open_sftp() 69 | except paramiko.ssh_exception.SSHException: 70 | raise Exception("cannot send {0} to {1}, please check" 71 | " your ssh connection".format(file, ip)) 72 | 73 | if os.path.isdir(file): 74 | parent_dir = "/".join(file.split('/')[:-1]) 75 | try: 76 | sftp.mkdir(dest_path) 77 | except IOError: 78 | pass 79 | for dirpath, dirnames, filenames in os.walk(file): 80 | remote_path = dest_path + dirpath.split(parent_dir)[1] 81 | try: 82 | sftp.mkdir(remote_path) 83 | except: 84 | LOG.info("clearstack: Directory {0} is already created" 85 | "in remote host".format(remote_path)) 86 | for filename in filenames: 87 | local_path = os.path.join(dirpath, filename) 88 | remote_filepath = os.path.join(remote_path, filename) 89 | sftp.put(local_path, remote_filepath) 90 | else: 91 | filename = file.split('/')[-1] 92 | sftp.put(file, "{0}/{1}".format(dest_path, filename)) 93 | 94 | connection.close() 95 | 96 | def test_python_in_host(self, host, connection): 97 | try: 98 | stdin, stdout, stderr = self.run_command(connection, 99 | 'python3 --version') 100 | except: 101 | raise Exception("cannot run python3 in {0}," 102 | " please install python3".format(host)) 103 | 104 | def test_hosts(self, _hosts): 105 | hosts = set(_hosts) 106 | connection = None 107 | conf = Controller.get().CONF 108 | 109 | util.remove_localhost(hosts) 110 | 111 | if not conf['CONFIG_PRIVATE_SSH_KEY'] and hosts: 112 | raise Exception("CONFIG_PRIVATE_SSH_KEY: missing private key") 113 | 114 | for host in hosts: 115 | try: 116 | connection = self.connect(self.ssh_user, self.ssh_private_key, 117 | host) 118 | self.test_python_in_host(host, connection) 119 | except Exception as e: 120 | raise Exception("host {0}: {1}".format(host, str(e))) 121 | finally: 122 | if connection: 123 | connection.close() 124 | 125 | def run_recipe(self, recipe_file, host): 126 | connection = None 127 | interpreter = "python3" 128 | if recipe_file.endswith('.sh'): 129 | interpreter = "bash -f" 130 | 131 | try: 132 | connection = self.connect(self.ssh_user, self.ssh_private_key, 133 | host) 134 | cmd = "source /root/.bashrc 2> /dev/null;" \ 135 | "source /usr/share/defaults/etc/profile 2> /dev/null;" \ 136 | "{0} {1}".format(interpreter, recipe_file) 137 | stdin, stdout, stderr = self.run_command(connection, cmd) 138 | except Exception as e: 139 | LOG.error("clearstack: an error has occurred in {0}," 140 | " please check logs for more information" 141 | .format(host)) 142 | raise e 143 | finally: 144 | if connection: 145 | connection.close() 146 | 147 | def get_logs(self, _hosts): 148 | hosts = set(_hosts) 149 | basename = os.path.splitext(util.LOG_FILE)[0] 150 | connection = None 151 | 152 | util.remove_localhost(hosts) 153 | 154 | for host in hosts: 155 | new_name = "{0}-{1}.log".format(basename, host) 156 | try: 157 | connection = self.connect(self.ssh_user, self.ssh_private_key, 158 | host) 159 | sftp = connection.open_sftp() 160 | sftp.get(util.HOST_LOG_FILE, new_name) 161 | except: 162 | LOG.warning("clearstack: cannot get log file from {0}".format( 163 | host)) 164 | finally: 165 | if connection: 166 | connection.close() 167 | -------------------------------------------------------------------------------- /clearstack/plugins/neutron_450.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2015 Intel Corporation 3 | # 4 | # Author: Alberto Murillo 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file 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 | # 18 | 19 | from clearstack import utils 20 | from clearstack import validators 21 | from clearstack.controller import Controller 22 | from clearstack.argument import Argument 23 | from clearstack.common import util 24 | 25 | 26 | def init_config(): 27 | conf = { 28 | "NEUTRON": [ 29 | Argument("neutron-ks-pw", 30 | "Password to use for OpenStack Networking (neutron) to" 31 | " authenticate with the Identity service.", 32 | "CONFIG_NEUTRON_KS_PW", 33 | utils.generate_random_pw(), 34 | validators=[validators.not_empty]), 35 | Argument("neutron-db-pw", 36 | "The password to use for OpenStack Networking to access " 37 | "the database.", 38 | "CONFIG_NEUTRON_DB_PW", 39 | utils.generate_random_pw(), 40 | validators=[validators.not_empty]), 41 | # Argument('neutron-l3-ext-bridge', 42 | # 'The name of the Open vSwitch bridge (or empty for ' 43 | # 'linuxbridge) for the OpenStack Networking L3 agent to ' 44 | # 'use for external traffic', 45 | # 'CONFIG_NEUTRON_L3_EXT_BRIDGE', 46 | # 'br-ex', 47 | # validators=[validators.not_empty]), 48 | Argument('neutron-metadata-pw', 49 | 'Password for the OpenStack Networking metadata agent', 50 | 'CONFIG_NEUTRON_METADATA_PW', 51 | utils.generate_random_pw(), 52 | validators=[validators.not_empty]), 53 | Argument('neutron-lbaas-install', 54 | "Specify 'y' to install OpenStack Networking's " 55 | "Load-Balancing-as-a-Service (LBaaS)", 56 | "CONFIG_LBAAS_INSTALL", 57 | 'n', 58 | options=['y', 'n'], 59 | validators=[validators.y_or_n]), 60 | Argument('neutron-vpnass-install', 61 | "Specify 'y' to install OpenStack Networking's " 62 | "VPN-as-a-Service (VPNaaS)", 63 | "CONFIG_VPNAAS_INSTALL", 64 | 'n', 65 | options=['y', 'n'], 66 | validators=[validators.y_or_n]) 67 | ], 68 | # "NEUTRON_OVS_AGENT": [ 69 | # Argument("neutron-ovs-bridge-mappings", 70 | # "Comma-separated list of bridge mappings for the " 71 | # "OpenStack Networking Open vSwitch plugin. Each tuple " 72 | # "in the list must be in he format " 73 | # " :", 74 | # "CONFIG_NEUTRON_OVS_BRIDGE_MAPPINGS", 75 | # "external:br-ex"), 76 | # Argument("neutron-ovs-bridge-interfaces", 77 | # "Comma-separated list of colon-separated Open vSwitch" 78 | # " : pairs.", 79 | # "CONFIG_NEUTRON_OVS_BRIDGE_IFACES", 80 | # "br-ex:%s" % util.get_net_interface()) 81 | # ], 82 | "NEUTRON_ML2_PLUGIN": [ 83 | Argument("neutron-ml2-type-drivers", 84 | "Comma-separated list of network-type driver entry " 85 | "points to be loaded from the neutron.ml2.type_drivers " 86 | "namespace", 87 | "CONFIG_NEUTRON_ML2_TYPE_DRIVERS", 88 | "flat,vlan,vxlan", 89 | options=['local', 'flat', 'vlan', 'gre', 'vxlan'], 90 | validators=[validators.not_empty]), 91 | Argument("neutron-ml2-tenant-network-types", 92 | "Comma-separated, ordered list of network types to " 93 | "allocate as tenant networks", 94 | "CONFIG_NEUTRON_ML2_TENANT_NETWORK_TYPES", 95 | "vxlan", 96 | options=['local', 'vlan', 'gre', 'vxlan'], 97 | validators=[validators.not_empty]), 98 | Argument("neutron-ml2-mechanism-drivers", 99 | "Comma-separated, ordered list of network types to " 100 | "allocate as tenant networks", 101 | "CONFIG_NEUTRON_ML2_MECHANISM_DRIVERS", 102 | "linuxbridge,l2population", 103 | options=['openvswitch', 'linuxbridge'], 104 | validators=[validators.not_empty]), 105 | Argument("neutron-ml2-flat-networks", 106 | "Comma-separated list of physical_network names with " 107 | "wich flat networks can be created.", 108 | "CONFIG_NEUTRON_ML2_FLAT_NETWORKS", 109 | "public", 110 | validators=[validators.not_empty]), 111 | Argument("neutron-ml2-tunnel-id-ranges", 112 | "Comma-separated list of : tuples " 113 | "enumerating ranges of GRE tunnel IDs that are available " 114 | "for tenant-network allocation.", 115 | "CONFIG_NEUTRON_ML2_TUNNEL_ID_RANGES", 116 | "1:1000", 117 | validators=[validators.not_empty]), 118 | Argument("neutron-l2-agent", 119 | "Name of the L2 agent to be used with OpenStack " 120 | "Networking", 121 | "CONFIG_NEUTRON_L2_AGENT", 122 | "linuxbridge", 123 | options=['openvswitch', 'linuxbridge'], 124 | validators=[validators.not_empty]) 125 | ] 126 | } 127 | 128 | for group in conf: 129 | Controller.get().add_group(group, conf[group]) 130 | 131 | 132 | def init_sequences(): 133 | controller = Controller.get() 134 | conf = controller.CONF 135 | if util.str2bool(conf['CONFIG_NEUTRON_INSTALL']): 136 | controller.add_sequence("Setting up neutron controller", 137 | setup_controller) 138 | controller.add_sequence("Setting up neutron on computes nodes", 139 | setup_compute_nodes) 140 | 141 | 142 | def setup_controller(): 143 | conf = Controller.get().CONF 144 | recipe = utils.get_template('neutron') 145 | return utils.run_recipe("neutron.py", recipe, 146 | [conf["CONFIG_CONTROLLER_HOST"]]) 147 | 148 | 149 | def setup_compute_nodes(): 150 | conf = Controller.get().CONF 151 | recipe = utils.get_template('neutron_compute') 152 | return utils.run_recipe("neutron_compute.py", recipe, 153 | conf["CONFIG_COMPUTE_HOSTS"].split(',')) 154 | -------------------------------------------------------------------------------- /clearstack/common/util.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2015 Intel Corporation 3 | # 4 | # Author: Alberto Murillo 5 | # Author: Julio Montes 6 | # 7 | # Licensed under the Apache License, Version 2.0 (the "License"); 8 | # you may not use this file except in compliance with the License. 9 | # You may obtain a copy of the License at 10 | # 11 | # http://www.apache.org/licenses/LICENSE-2.0 12 | # 13 | # Unless required by applicable law or agreed to in writing, software 14 | # distributed under the License is distributed on an "AS IS" BASIS, 15 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 16 | # See the License for the specific language governing permissions and 17 | # limitations under the License. 18 | # 19 | 20 | import os 21 | import socket 22 | import subprocess 23 | import configparser 24 | import netifaces 25 | import ipaddress 26 | import logging 27 | from errno import EACCES, EPERM, ENOENT 28 | 29 | HOST_LOG_DIR = '/var/log/clearstack' 30 | HOST_LOG_FILE = "{0}/clearstack.log".format(HOST_LOG_DIR) 31 | LOG_DIR = '/var/log/clearstack' 32 | if os.geteuid() != 0: 33 | LOG_DIR = '/tmp/log/clearstack' 34 | LOG_FILE = "{0}/clearstack.log".format(LOG_DIR) 35 | LOG = logging.getLogger("Clearstack") 36 | 37 | 38 | def _print_error_message(self, e, file_name): 39 | # PermissionError 40 | if e.errno == EPERM or e.errno == EACCES: 41 | print("PermissionError error({0}): {1} for:\n{2}".format(e.errno, 42 | e.strerror, file_name)) 43 | # FileNotFoundError 44 | elif e.errno == ENOENT: 45 | print("FileNotFoundError error({0}): {1} as:\n{2}".format(e.errno, 46 | e.strerror, file_name)) 47 | elif IOError: 48 | print("I/O error({0}): {1} as:\n{2}".format(e.errno, e.strerror, 49 | file_name)) 50 | elif OSError: 51 | print("OS error({0}): {1} as:\n{2}".format(e.errno, e.strerror, 52 | file_name)) 53 | 54 | 55 | def port_open(port): 56 | """Return True if given port is already open in localhost. 57 | Return False otherwise.""" 58 | sck = socket.socket(socket.AF_INET, socket.SOCK_STREAM) 59 | return (sck.connect_ex(('127.0.0.1', port)) == 0) 60 | 61 | 62 | def service_status(service): 63 | """Return status of a given systemd service.""" 64 | stdout, stderr = run_command("systemctl is-active " + str(service)) 65 | return (stdout.strip().decode("utf-8")) 66 | 67 | 68 | def service_enabled(service): 69 | """Return True if systemd service is enabled, False otherwise""" 70 | stdout, stderr = run_command("systemctl is-enabled " + str(service)) 71 | return (stdout.strip() == b"enabled") 72 | 73 | 74 | def setup_debugging(debug, is_remote_host=True): 75 | if not os.path.isdir(LOG_DIR): 76 | os.makedirs(LOG_DIR) 77 | try: 78 | logging.basicConfig(filename=LOG_FILE, 79 | format='%(message)s', 80 | level=logging.INFO) 81 | except (IOError, OSError) as e: 82 | _print_error_message(e, LOG_FILE) 83 | 84 | ''' paramiko detects all output as error (stderr)''' 85 | ''' if it is a remote host redirect output to log file ''' 86 | if not is_remote_host: 87 | sh = logging.StreamHandler() 88 | sh.setLevel(logging.INFO) 89 | LOG.addHandler(sh) 90 | 91 | if debug: 92 | LOG.setLevel(logging.DEBUG) 93 | 94 | 95 | def run_command(command, stdin=None, environ=None, debug=True): 96 | """Returns (stdout, stderr), raises error on non-zero return code""" 97 | if environ is None: 98 | env = None 99 | else: 100 | env = os.environ.copy() 101 | env.update(environ) 102 | 103 | if debug: # to avoid show passwords 104 | LOG.debug("command: %s", command) 105 | 106 | proc = subprocess.Popen(['bash', '-c', command], 107 | stdout=subprocess.PIPE, stderr=subprocess.PIPE, 108 | stdin=subprocess.PIPE, env=env) 109 | stdout, stderr = proc.communicate() 110 | if proc.returncode and stderr: 111 | raise Exception("Error running: {0}\n{1}" 112 | .format(command, stderr.decode("utf-8"))) 113 | 114 | return stdout, stderr 115 | 116 | 117 | def str2bool(value): 118 | return value.lower() in ("yes", "true", "t", "1", "y") 119 | 120 | 121 | def write_config(file, data): 122 | directory = os.path.dirname(file) 123 | if not os.path.isdir(directory): 124 | os.makedirs(directory) 125 | config = configparser.RawConfigParser(allow_no_value=True) 126 | if os.path.isfile(file): 127 | config.read(file) 128 | config.read_string(data) 129 | with open(file, 'w') as f: 130 | config.write(f) 131 | 132 | 133 | def write_properties(file, data): 134 | directory = os.path.dirname(file) 135 | if not os.path.isdir(directory): 136 | os.makedirs(directory) 137 | if os.path.isfile(file): 138 | with open(file, 'r') as f: 139 | for l in f.readlines(): 140 | key, value = [x.strip() for x in l.split('=')] 141 | data[key] = value 142 | output = "" 143 | for key, value in data.items(): 144 | output += "%s = %s\n" % (key, value) 145 | with open(file, 'w') as f: 146 | f.write(output) 147 | 148 | 149 | def get_option(file, section, option): 150 | config = configparser.RawConfigParser(allow_no_value=True) 151 | config.read(file) 152 | return config[section][option] 153 | 154 | 155 | def delete_option(file, section, option=None): 156 | config = configparser.RawConfigParser(allow_no_value=True) 157 | config.read(file) 158 | if option: 159 | config.remove_option(section, option) 160 | else: 161 | config.remove_section(section) 162 | with open(file, 'w') as f: 163 | config.write(f) 164 | 165 | 166 | # write in file if not exist the line 167 | def write_in_file_ine(file, data): 168 | with open(file, 'a+') as f: 169 | f.seek(0) 170 | if not any(data == x.rstrip('\r\n') for x in f): 171 | f.write(data + '\n') 172 | return True 173 | return False 174 | 175 | 176 | def get_dns(): 177 | with open('/etc/resolv.conf', 'r') as f: 178 | return [l.split(' ')[1].strip() for l in f.readlines() 179 | if l.startswith('nameserver')] 180 | 181 | 182 | def get_netmask(): 183 | interface = get_net_interface() 184 | mask = netifaces.ifaddresses(interface)[netifaces.AF_INET][0]['netmask'] 185 | return ipaddress.IPv4Network('0.0.0.0/%s' % mask).prefixlen 186 | 187 | 188 | def get_gateway(): 189 | return netifaces.gateways()['default'][netifaces.AF_INET][0] 190 | 191 | 192 | def get_net_interface(): 193 | return (netifaces.gateways())['default'][netifaces.AF_INET][1] 194 | 195 | 196 | def get_ips(): 197 | ips = [] 198 | for iface in netifaces.interfaces(): 199 | try: 200 | for addr in netifaces.ifaddresses(iface)[netifaces.AF_INET]: 201 | ips.append(addr['addr']) 202 | except: 203 | pass 204 | return ips 205 | 206 | 207 | def get_nic(ip): 208 | for iface in netifaces.interfaces(): 209 | try: 210 | for addr in netifaces.ifaddresses(iface)[netifaces.AF_INET]: 211 | if addr['addr'] == ip: 212 | return iface 213 | except: 214 | pass 215 | return None 216 | 217 | 218 | def get_ip(): 219 | interface = get_net_interface() 220 | return netifaces.ifaddresses(interface)[netifaces.AF_INET][0]['addr'] 221 | 222 | 223 | def find_my_ip_from_config(config_ips): 224 | ip = set(get_ips()) & set(config_ips) 225 | return ip.pop() 226 | 227 | 228 | def is_localhost(host): 229 | return (host == "localhost" or 230 | host == socket.gethostname() or 231 | host in get_ips()) 232 | 233 | 234 | def has_localhost(hosts): 235 | for host in hosts: 236 | if is_localhost(host): 237 | return True 238 | return False 239 | 240 | 241 | def remove_localhost(hosts): 242 | for host in hosts.copy(): 243 | if is_localhost(host): 244 | hosts.remove(host) 245 | 246 | 247 | def ensure_directory(dir): 248 | if not os.path.exists(dir): 249 | os.makedirs(dir) 250 | 251 | 252 | def link_file(source, target): 253 | dir = os.path.dirname(target) 254 | ensure_directory(dir) 255 | if os.path.exists(target): 256 | os.remove(target) 257 | os.symlink(source, target) 258 | -------------------------------------------------------------------------------- /clearstack/plugins/pre_000.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2015 Intel Corporation 3 | # 4 | # Author: Alberto Murillo 5 | # Author: Julio Montes 6 | # Author: Obed Munoz 7 | # 8 | # Licensed under the Apache License, Version 2.0 (the "License"); 9 | # you may not use this file except in compliance with the License. 10 | # You may obtain a copy of the License at 11 | # 12 | # http://www.apache.org/licenses/LICENSE-2.0 13 | # 14 | # Unless required by applicable law or agreed to in writing, software 15 | # distributed under the License is distributed on an "AS IS" BASIS, 16 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | # See the License for the specific language governing permissions and 18 | # limitations under the License. 19 | # 20 | 21 | import os 22 | 23 | from clearstack.argument import Argument 24 | from clearstack.controller import Controller 25 | from clearstack import validators 26 | from clearstack import utils 27 | from clearstack.common import util 28 | 29 | 30 | def validate_ssh_key(ssh_key): 31 | hosts = utils.get_all_hosts() 32 | util.remove_localhost(hosts) 33 | if len(hosts) != 0: 34 | validators.file(ssh_key) 35 | 36 | 37 | def init_config(): 38 | home = os.getenv('HOME') 39 | if home is None: 40 | home = "/root" 41 | conf = { 42 | "GENERAL": [ 43 | Argument("debug-mode", 44 | "Set to 'y' if you want to run" 45 | " OpenStack services in debug mode", 46 | "CONFIG_DEBUG_MODE", 47 | "n", 48 | options=['y', 'n'], 49 | validators=[validators.y_or_n]), 50 | Argument("ssh-private-key", 51 | "Path to the private SSH key file", 52 | "CONFIG_PRIVATE_SSH_KEY", 53 | "", 54 | validators=[validate_ssh_key]), 55 | Argument("controller-host", 56 | "IP address or hostname of the server on which " 57 | " to install OpenStack services specific to" 58 | " controller role such as API servers", 59 | "CONFIG_CONTROLLER_HOST", 60 | util.get_ip(), 61 | validators=[validators.ip_or_hostname]), 62 | Argument("clean-controller-host", 63 | "Set 'y' if you would like Clearstack to " 64 | "clean up controller host", 65 | "CONFIG_CLEAN_CONTROLLER_HOST", 66 | "y", 67 | validators=[validators.y_or_n]), 68 | Argument("compute-hosts", 69 | "List of IP addresses or hostnames of the server on which" 70 | " to install the Nova compute service", 71 | "CONFIG_COMPUTE_HOSTS", 72 | util.get_ip(), 73 | validators=[validators.ip_or_hostname]), 74 | Argument("clean-compute-hosts", 75 | "Set 'y' if you would like Clearstack to " 76 | "clean up compute hosts", 77 | "CONFIG_CLEAN_COMPUTE_HOSTS", 78 | "y", 79 | validators=[validators.y_or_n]), 80 | Argument("mariadb-install", 81 | "Set 'y' if you would like Clearstack to install MariaDB", 82 | "CONFIG_MARIADB_INSTALL", 83 | "y", 84 | options=['y', 'n'], 85 | validators=[validators.y_or_n]), 86 | Argument("mongodb-install", 87 | "Set 'y' if you would like Clearstack to install MongoDB", 88 | "CONFIG_MONGODB_INSTALL", 89 | "y", 90 | options=['y', 'n'], 91 | validators=[validators.y_or_n]), 92 | Argument("http-service", 93 | "Set 'apache2' or 'nginx' as HTTP Service for Horizon, " 94 | "Keystone and Nova API web services", 95 | "CONFIG_HTTP_SERVICE", 96 | "nginx", 97 | options=['nginx', 'apache2'], 98 | validators=[validators.not_empty]), 99 | Argument("glance-install ", 100 | "Set 'y' if you would like Clearstack to install" 101 | " Openstack image (glance)", 102 | "CONFIG_GLANCE_INSTALL", 103 | "y", 104 | options=['y', 'n'], 105 | validators=[validators.y_or_n]), 106 | Argument("nova-install ", 107 | "Set 'y' if you would like Clearstack to install" 108 | " Openstack compute (nova)", 109 | "CONFIG_NOVA_INSTALL", 110 | "y", 111 | options=['y', 'n'], 112 | validators=[validators.y_or_n]), 113 | Argument("horizon-install", 114 | "Set 'y' if you would like Clearstack to install" 115 | " OpenStack dashboard (horizon)", 116 | "CONFIG_HORIZON_INSTALL", 117 | "y", 118 | options=['y', 'n'], 119 | validators=[validators.y_or_n]), 120 | Argument("neutron-install", 121 | "Set 'y' if you would like Clearstack to install" 122 | " OpenStack Networking (neutron)", 123 | "CONFIG_NEUTRON_INSTALL", 124 | "y", 125 | options=['y', 'n'], 126 | validators=[validators.y_or_n]), 127 | Argument("ceilometer-install", 128 | "Set 'y' if you would like Clearstack to install" 129 | " OpenStack Telemetry (ceilometer)", 130 | "CONFIG_CEILOMETER_INSTALL", 131 | "y", 132 | options=['y', 'n'], 133 | validators=[validators.y_or_n]), 134 | Argument("heat-install", 135 | "Set 'y' if you would like Clearstack to install" 136 | " OpenStack Orchestration (heat)", 137 | "CONFIG_HEAT_INSTALL", 138 | "n", 139 | options=['y', 'n'], 140 | validators=[validators.y_or_n]), 141 | Argument("swift-install", 142 | "Set 'y' if you would like Clearstack to install" 143 | " OpenStack Object Storage (swift)", 144 | "CONFIG_SWIFT_INSTALL", 145 | "n", 146 | options=['y', 'n'], 147 | validators=[validators.y_or_n]) 148 | ] 149 | } 150 | 151 | for group in conf: 152 | Controller.get().add_group(group, conf[group]) 153 | 154 | 155 | def init_sequences(): 156 | Controller.get().add_sequence("Setting up controller host", 157 | setup_controller) 158 | Controller.get().add_sequence("Setting up compute hosts", 159 | setup_computes) 160 | 161 | 162 | def setup_controller(): 163 | conf = Controller.get().CONF 164 | if util.str2bool(conf['CONFIG_CLEAN_CONTROLLER_HOST']): 165 | try: 166 | utils.run_recipe("{0}".format("controller_cleanup.sh"), 167 | utils.get_template("controller_cleanup.sh"), 168 | [conf["CONFIG_CONTROLLER_HOST"]]) 169 | except: 170 | pass 171 | 172 | template = "pre_controller.sh" 173 | recipe = utils.get_template(template) 174 | return utils.run_recipe("{0}".format(template), recipe, 175 | [conf["CONFIG_CONTROLLER_HOST"]]) 176 | 177 | 178 | def setup_computes(): 179 | conf = Controller.get().CONF 180 | if util.str2bool(conf['CONFIG_CLEAN_COMPUTE_HOSTS']): 181 | try: 182 | utils.run_recipe("{0}".format("compute_cleanup.sh"), 183 | utils.get_template("compute_cleanup.sh"), 184 | conf["CONFIG_COMPUTE_HOSTS"].split(',')) 185 | except: 186 | pass 187 | 188 | template = "pre_compute.sh" 189 | recipe = utils.get_template(template) 190 | return utils.run_recipe("{0}".format(template), recipe, 191 | conf["CONFIG_COMPUTE_HOSTS"].split(',')) 192 | -------------------------------------------------------------------------------- /clearstack/modules/openstack.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2015 Intel Corporation 3 | # 4 | # Author: Alberto Murillo 5 | # Author: Obed Munoz 6 | # Author: Victor Morales 7 | # 8 | # Licensed under the Apache License, Version 2.0 (the "License"); 9 | # you may not use this file except in compliance with the License. 10 | # You may obtain a copy of the License at 11 | # 12 | # http://www.apache.org/licenses/LICENSE-2.0 13 | # 14 | # Unless required by applicable law or agreed to in writing, software 15 | # distributed under the License is distributed on an "AS IS" BASIS, 16 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | # See the License for the specific language governing permissions and 18 | # limitations under the License. 19 | # 20 | 21 | from common import util 22 | from common.swupd import Client as swupd_client 23 | from common.util import LOG 24 | from modules.conf import CONF 25 | from modules.conf import ENV 26 | 27 | 28 | class OpenStackService: 29 | _env = "" 30 | _internal_url = "" 31 | _admin_url = "" 32 | _region = "" 33 | _user = "" 34 | _controller = CONF["CONFIG_CONTROLLER_HOST"] 35 | _password = "" 36 | 37 | def __init__(self): 38 | if not self._env: 39 | self._env = ENV 40 | if not self._user: 41 | self._user = self._name 42 | if not self._password: 43 | self._password = CONF['CONFIG_%s_KS_PW' % self._name.upper()] 44 | if not self._internal_url: 45 | self._internal_url = self._public_url 46 | if not self._admin_url: 47 | self._admin_url = self._public_url 48 | if not self._region: 49 | self._region = CONF['CONFIG_KEYSTONE_REGION'] 50 | 51 | def install(self, bundle=None): 52 | bundle = bundle or self._bundle 53 | swupd_client.install(bundle) 54 | 55 | def start_server(self, services=None): 56 | services = services or self._services 57 | LOG.debug("Starting services") 58 | util.run_command("systemctl enable %s" % " ".join(services)) 59 | for service in services: 60 | if service.endswith(".socket"): 61 | util.run_command("systemctl stop %s" % 62 | service.replace(".socket", ".service")) 63 | util.run_command("systemctl restart %s" % service) 64 | 65 | def create_service(self, name=None, description=None, type=None): 66 | name = name or self._name 67 | description = description or self._description 68 | type = type or self._type 69 | LOG.debug("setting up %s service" % name) 70 | try: 71 | """ test if service already exists """ 72 | util.run_command("openstack service show %s" % name, 73 | environ=self._env) 74 | except: 75 | util.run_command("openstack service create %s" 76 | " --name %s --description \"%s\"" 77 | % (type, name, description), 78 | environ=self._env) 79 | 80 | def create_endpoint(self, publicurl=None, 81 | internalurl=None, 82 | adminurl=None, 83 | region=None, 84 | type=None): 85 | publicurl = publicurl or self._public_url 86 | internalurl = internalurl or self._internal_url 87 | adminurl = adminurl or self._admin_url 88 | region = region or self._region 89 | type = type or self._type 90 | 91 | LOG.debug("creating endpoint") 92 | """ test if endpoint already exists """ 93 | out, err = util.run_command("openstack endpoint list | grep %s" 94 | % self._name, environ=self._env) 95 | if not out: 96 | cmd = ("openstack endpoint create --region {0} {1}" 97 | .format(region, type)) 98 | util.run_command(cmd + " public {0}".format(publicurl), 99 | environ=self._env) 100 | util.run_command(cmd + " internal {0}".format(internalurl), 101 | environ=self._env) 102 | util.run_command(cmd + " admin {0}".format(adminurl), 103 | environ=self._env) 104 | 105 | def create_role(self, role): 106 | LOG.debug("setting up %s role" % role) 107 | try: 108 | util.run_command("openstack role show %s" % role, 109 | environ=self._env) 110 | except: 111 | util.run_command("openstack role create %s" % role, 112 | environ=self._env) 113 | 114 | def add_role(self, user, role, project="service", domain="default"): 115 | # openstack role add: error: argument --project: not allowed with 116 | # argument --domain 117 | cmd = "openstack role add --user {0} {1}".format(user, role) 118 | if domain != "default": 119 | cmd += " --domain %s" % domain 120 | else: 121 | cmd += " --project %s" % project 122 | util.run_command(cmd, environ=self._env) 123 | 124 | def create_user(self, user=None, password=None, domain="default", 125 | project="service", role="admin"): 126 | user = user or self._user 127 | password = password or self._password 128 | LOG.debug("setting up %s user" % user) 129 | try: 130 | """ test if user already exists """ 131 | util.run_command("openstack user show %s" % user, 132 | environ=self._env) 133 | except: 134 | util.run_command("openstack user create --domain {0}" 135 | " --password={1}" 136 | " --email {2}@example.com {2}" 137 | .format(domain, password, user), 138 | environ=self._env, debug=False) 139 | self.add_role(user, role, project, domain) 140 | 141 | def create_domain(self, domain, description): 142 | LOG.debug("setting up %s domain" % domain) 143 | try: 144 | """ test if domain already exists """ 145 | util.run_command("openstack domain show %s" % domain, 146 | environ=self._env) 147 | except: 148 | util.run_command("openstack domain create --description \"%s\" %s" 149 | % (description, domain), 150 | environ=self._env, debug=False) 151 | 152 | def config_debug(self, configfile): 153 | if util.str2bool(CONF['CONFIG_DEBUG_MODE']): 154 | config = "[DEFAULT]\n" + \ 155 | "debug=True\n" + \ 156 | "verbose=True\n" 157 | util.write_config(configfile, config) 158 | 159 | def config_database(self, configfile): 160 | dbpass = CONF['CONFIG_%s_DB_PW' % self._name.upper()] 161 | dbhost = CONF['CONFIG_MARIADB_HOST'] 162 | config = ("[database]\n" 163 | "connection=mysql://{0}:{1}@{2}/{0}" 164 | .format(self._name, dbpass, dbhost)) 165 | util.write_config(configfile, config) 166 | 167 | def config_rabbitmq(self, configfile): 168 | rabbit_host = CONF['CONFIG_AMQP_HOST'] 169 | rabbit_password = CONF['CONFIG_AMQP_AUTH_PASSWORD'] 170 | rabbit_user = CONF['CONFIG_AMQP_AUTH_USER'] 171 | config = \ 172 | "[DEFAULT]\n" + \ 173 | "rpc_backend=rabbit\n" + \ 174 | "[oslo_messaging_rabbit]\n" + \ 175 | "rabbit_host=%s\n" % rabbit_host + \ 176 | "rabbit_userid=%s\n" % rabbit_user + \ 177 | "rabbit_password=%s\n" % rabbit_password + \ 178 | "send_single_reply=True" 179 | util.write_config(configfile, config) 180 | 181 | def config_auth(self, configfile, section='keystone_authtoken'): 182 | config = ("[{0}]\n" 183 | "auth_uri=http://{1}:5000\n" 184 | "auth_url=http://{1}:35357\n" 185 | "auth_plugin=password\n" 186 | "project_domain_id=default\n" 187 | "user_domain_id=default\n" 188 | "project_name=service\n" 189 | "username={2}\n" 190 | "password={3}" 191 | .format(section, self._controller, self._name, 192 | self._password)) 193 | util.write_config(configfile, config) 194 | -------------------------------------------------------------------------------- /clearstack/modules/swift.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2015 Intel Corporation 3 | # 4 | # Author: Alberto Murillo 5 | # 6 | # Licensed under the Apache License, Version 2.0 (the "License"); 7 | # you may not use this file 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 | # 18 | 19 | import os 20 | import shutil 21 | 22 | from common import util 23 | from commmon.util import LOG 24 | from modules.openstack import OpenStackService 25 | from modules.conf import CONF 26 | from common.singleton import Singleton 27 | 28 | 29 | @Singleton 30 | class Swift(OpenStackService): 31 | _name = "swift" 32 | _bundle = "openstack-object-storage" 33 | _services = ["swift-proxy", "memcached"] 34 | _type = "object-store" 35 | _description = "OpenStack Object Storage" 36 | _public_url = ("http://{0}:8080/v1/AUTH_%\(tenant_id\)s" 37 | .format(CONF['CONFIG_CONTROLLER_HOST'])) 38 | _admin_url = "http://{0}:8080/v1".format(CONF['CONFIG_CONTROLLER_HOST']) 39 | 40 | _devices = [] 41 | 42 | def ceilometer_enable(self, configfile): 43 | pass 44 | 45 | def config_auth(self, configfile): 46 | confdir = os.path.dirname(configfile) 47 | if not os.path.isdir(confdir): 48 | os.makedirs(confdir) 49 | shutil.copy('/usr/share/defaults/swift/proxy-server.conf', confdir) 50 | OpenStackService.config_auth(self, configfile, 51 | section='filter:authtoken') 52 | config = ("[pipeline:main]\n" 53 | "pipeline = catch_errors gatekeeper healthcheck " 54 | "proxy-logging cache container_sync bulk ratelimit " 55 | "authtoken keystoneauth container-quotas account-quotas " 56 | "slo dlo versioned_writes proxy-logging proxy-server\n" 57 | "[filter:authtoken]\n" 58 | "paste.filter_factory = " 59 | "keystonemiddleware.auth_token:filter_factory\n" 60 | "delay_auth_decision = True\n" 61 | "[app:proxy-server]\n" 62 | "use = egg:swift#proxy\n" 63 | "account_autocreate = True\n" 64 | "[filter:keystoneauth]\n" 65 | "use = egg:swift#keystoneauth\n" 66 | "operator_roles = admin,user\n") 67 | util.write_config(configfile, config) 68 | 69 | def config_memcache(self, configfile): 70 | config = ("[filter:cache]\n" 71 | "use = egg:swift#memcache\n" 72 | "memcache_servers = 127.0.0.1:11211") 73 | util.write_config(configfile, config) 74 | 75 | def config_hash(self, configfile): 76 | suffix = CONF['CONFIG_SWIFT_HASH'] 77 | config = ("[swift-hash]\n" 78 | "swift_hash_path_suffix = {0}").format(suffix) 79 | util.write_config(configfile, config) 80 | 81 | def parse_devices(self): 82 | 83 | def create_loopback(name, size): 84 | # Remove the file if exists 85 | if os.path.isfile(name): 86 | os.remove(name) 87 | # Create an empty file 88 | with open(name, 'wb') as f: 89 | f.seek(1024 * 1024 * 1024 * size - 1) 90 | f.write(b"\0") 91 | LOG.debug("formatting '{0}' as XFS".format(name)) 92 | util.run_command("mkfs.xfs %s" % name) 93 | 94 | devs = CONF['CONFIG_SWIFT_STORAGES'] 95 | if devs: 96 | devs = devs.split(',') 97 | devs = [x.strip() for x in devs] 98 | device_number = 0 99 | num_zones = int(CONF["CONFIG_SWIFT_STORAGE_ZONES"]) 100 | for dev in devs: 101 | device_number += 1 102 | zone = (device_number % num_zones) + 1 103 | self._devices.append({'device': dev, 'zone': zone, 104 | 'name': 'device%s' % device_number}) 105 | else: 106 | # Setup loopdevice 107 | filename = '/srv/loopback-device' 108 | filesize = int(CONF['CONFIG_SWIFT_STORAGE_SIZE']) 109 | create_loopback(filename, filesize) 110 | self._devices.append({'device': filename, 'zone': 1, 111 | 'name': 'loopback'}) 112 | 113 | def prepare_devices(self): 114 | # Avoid adding duplicate entries in fstab 115 | mounted_devices = [] 116 | if os.path.isfile('/etc/fstab'): 117 | with open('/etc/fstab', 'r') as f: 118 | for l in f: 119 | mounted_devices.append(l.split()[0].strip()) 120 | 121 | # Add each device to fstab if not already added 122 | fstab = "" 123 | for device in self._devices: 124 | # Format the device with xfs filesystem 125 | util.ensure_directory('/srv/node/%s' % device['name']) 126 | 127 | # Ensure the device is mounted 128 | if device['device'] not in mounted_devices: 129 | fstab += ("{0} /srv/node/{1} xfs noatime,nodiratime,nobarrier," 130 | "logbufs=8 0 2\n").format(device['device'], 131 | device['name']) 132 | with open('/etc/fstab', 'a') as f: 133 | f.write(fstab) 134 | 135 | util.run_command('mount -a') 136 | # Change ownership of /srv to swift 137 | util.run_command("chown -R swift:swift /srv") 138 | 139 | def create_rings(self): 140 | replicas = CONF['CONFIG_SWIFT_STORAGE_REPLICAS'] 141 | ip = util.get_ip() 142 | for ringtype, port in [('object', '6000'), 143 | ('container', '6001'), 144 | ('account', 6002)]: 145 | LOG.debug("creating '{0}' ring with {1} " 146 | "replicas".format(ringtype, replicas)) 147 | cmd = ("swift-ring-builder {0}.builder create 10 {1} 1" 148 | .format(ringtype, replicas)) 149 | util.run_command(cmd) 150 | for device in self._devices: 151 | LOG.debug("adding '{0}' storage node on ring " 152 | "'{1}'".format(device['name'], ringtype)) 153 | cmd = ("swift-ring-builder %s.builder add --region 1 " 154 | "--zone %s --ip %s --port %s --device %s --weight 100" 155 | % (ringtype, device['zone'], ip, port, device['name'])) 156 | util.run_command(cmd) 157 | LOG.debug("rebalancing ring '{0}'".format(ringtype)) 158 | cmd = "swift-ring-builder {0}.builder rebalance".format(ringtype) 159 | util.run_command(cmd) 160 | if os.path.isfile("/etc/swift/%s.ring.gz" % ringtype): 161 | os.remove("/etc/swift/%s.ring.gz" % ringtype) 162 | shutil.move("%s.ring.gz" % ringtype, "/etc/swift") 163 | 164 | def config_storage_services(self): 165 | confdir = '/etc/swift/' 166 | shutil.copy('/usr/share/defaults/swift/account-server.conf', confdir) 167 | shutil.copy('/usr/share/defaults/swift/container-server.conf', confdir) 168 | shutil.copy('/usr/share/defaults/swift/object-server.conf', confdir) 169 | shutil.copy('/usr/share/defaults/swift/container-reconciler.conf', 170 | confdir) 171 | shutil.copy('/usr/share/defaults/swift/object-expirer.conf', confdir) 172 | for type in ['account', 'container', 'object']: 173 | conf = ("[DEFAULT]\n" 174 | "bind_ip = 0.0.0.0\n" 175 | "devices = /srv/node\n" 176 | "[pipeline:main]\n" 177 | "pipeline = healthcheck recon {0}-server\n" 178 | "[filter:recon]\n" 179 | "recon_cache_path = /var/cache/swift\n").format(type) 180 | util.write_config('/etc/swift/%s-server.conf' % type, conf) 181 | 182 | def config_rsync(self): 183 | config = """ 184 | uid = swift 185 | gid = swift 186 | log file = /var/log/rsyncd.log 187 | pid file = /var/run/rsyncd.pid 188 | address = {0} 189 | 190 | [account] 191 | max connections = 2 192 | path = /srv/node/ 193 | read only = false 194 | lock file = /var/lock/account.lock 195 | 196 | [container] 197 | max connections = 2 198 | path = /srv/node/ 199 | read only = false 200 | lock file = /var/lock/container.lock 201 | 202 | [object] 203 | max connections = 2 204 | path = /srv/node/ 205 | read only = false 206 | lock file = /var/lock/object.lock 207 | """.format(util.get_ip()) 208 | with open('/etc/rsyncd.conf', 'w') as f: 209 | f.write(config) 210 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | -------------------------------------------------------------------------------- /clearstack/modules/neutron.py: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (c) 2015 Intel Corporation 3 | # 4 | # Author: Alberto Murillo 5 | # Author: Obed Munoz 6 | # Author: Victor Morales 7 | # 8 | # Licensed under the Apache License, Version 2.0 (the "License"); 9 | # you may not use this file except in compliance with the License. 10 | # You may obtain a copy of the License at 11 | # 12 | # http://www.apache.org/licenses/LICENSE-2.0 13 | # 14 | # Unless required by applicable law or agreed to in writing, software 15 | # distributed under the License is distributed on an "AS IS" BASIS, 16 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 17 | # See the License for the specific language governing permissions and 18 | # limitations under the License. 19 | # 20 | 21 | from ipaddress import IPv4Network 22 | 23 | from modules.keystone import Keystone 24 | from modules.nova import Nova 25 | from modules.openstack import OpenStackService 26 | from modules.conf import CONF 27 | from common import util 28 | from common.util import LOG 29 | from common.singleton import Singleton 30 | 31 | 32 | metadata_password = CONF['CONFIG_NEUTRON_METADATA_PW'] 33 | tenant_network_types = CONF['CONFIG_NEUTRON_ML2_TENANT_NETWORK_TYPES'] 34 | mechanism_drivers = CONF['CONFIG_NEUTRON_ML2_MECHANISM_DRIVERS'] 35 | vni_ranges = CONF['CONFIG_NEUTRON_ML2_TUNNEL_ID_RANGES'] 36 | type_drivers = CONF['CONFIG_NEUTRON_ML2_TYPE_DRIVERS'] 37 | flat_networks = CONF['CONFIG_NEUTRON_ML2_FLAT_NETWORKS'] 38 | 39 | 40 | @Singleton 41 | class Neutron(OpenStackService): 42 | _name = "neutron" 43 | _bundle = "openstack-network" 44 | _services = ["neutron-server", "neutron-linuxbridge-agent", 45 | "neutron-dhcp-agent", "neutron-metadata-agent", 46 | "neutron-l3-agent"] 47 | _type = "network" 48 | _description = "OpenStack Networking" 49 | _public_url = ("http://{0}:9696" 50 | .format(CONF['CONFIG_CONTROLLER_HOST'])) 51 | 52 | def sync_database(self): 53 | LOG.debug("populating neutron database") 54 | util.run_command('su -s /bin/sh -c "neutron-db-manage ' 55 | '--config-file /etc/neutron/neutron.conf ' 56 | '--config-file /etc/neutron/plugins/ml2/ml2_conf.ini ' 57 | 'upgrade head" neutron') 58 | if util.str2bool(CONF['CONFIG_LBAAS_INSTALL']): 59 | util.run_command('su -s /bin/sh -c "neutron-db-manage ' 60 | '--service lbaas upgrade head"') 61 | 62 | def config_ml2_plugin(self): 63 | config = \ 64 | "[DEFAULT]\n" + \ 65 | "core_plugin = ml2\n" \ 66 | "service_plugins = router\n" + \ 67 | "allow_overlapping_ips = True\n" 68 | util.write_config("/etc/neutron/neutron.conf", config) 69 | config = \ 70 | "[ml2]\n" + \ 71 | "type_drivers = %s\n" % type_drivers + \ 72 | "tenant_network_types = %s\n" % tenant_network_types + \ 73 | "mechanism_drivers = %s\n" % mechanism_drivers + \ 74 | "extension_drivers = port_security\n" + \ 75 | "[ml2_type_flat]\n" + \ 76 | "flat_networks = public\n" + \ 77 | "[ml2_type_vxlan]\n" + \ 78 | "vni_ranges = %s\n" % vni_ranges + \ 79 | "[securitygroup]\n" + \ 80 | "enable_ipset = True\n" 81 | util.write_config("/etc/neutron/plugins/ml2/ml2_conf.ini", config) 82 | util.link_file('/etc/neutron/plugins/ml2/ml2_conf.ini', 83 | '/etc/neutron/plugin.ini') 84 | 85 | def config_linux_bridge_agent(self, local_ip, local_nic): 86 | config = \ 87 | "[linux_bridge]\n" + \ 88 | "physical_interface_mappings = public:%s\n" % local_nic + \ 89 | "[vxlan]\n" + \ 90 | "enable_vxlan = True\n" + \ 91 | "local_ip = %s\n" % local_ip + \ 92 | "l2_population = True\n" + \ 93 | "[agent]\n" + \ 94 | "prevent_arp_spoofing = True\n" + \ 95 | "[securitygroup]\n" + \ 96 | "enable_security_group = True\n" + \ 97 | "firewall_driver = neutron.agent.linux.iptables_firewall." + \ 98 | "IptablesFirewallDriver\n" 99 | util.write_config("/etc/neutron/plugins/ml2/linuxbridge_agent.ini", 100 | config) 101 | 102 | def config_l3_agent(self, configfile): 103 | config = ("[DEFAULT]\n" 104 | "interface_driver = " 105 | "neutron.agent.linux.interface.BridgeInterfaceDriver\n" 106 | "external_network_bridge = \n") 107 | util.write_config(configfile, config) 108 | 109 | def config_dhcp_agent(self, configfile): 110 | config = ("[DEFAULT]\n" 111 | "interface_driver = " 112 | "neutron.agent.linux.interface.BridgeInterfaceDriver\n" 113 | "dhcp_driver = neutron.agent.linux.dhcp.Dnsmasq\n" 114 | "enable_isolated_metadata = True\n") 115 | util.write_config(configfile, config) 116 | 117 | def config_metadata_agent(self, configfile): 118 | config = \ 119 | "[DEFAULT]\n" + \ 120 | "auth_uri = http://%s:5000\n" % self._controller + \ 121 | "auth_url = http://%s:35357\n" % self._controller + \ 122 | "auth_region = %s\n" % self._region + \ 123 | "auth_plugin = password\n" + \ 124 | "project_domain_id = default\n" + \ 125 | "user_domain_id = default\n" + \ 126 | "project_name = service\n" + \ 127 | "username = %s\n" % self._name + \ 128 | "password = %s\n" % self._password + \ 129 | "nova_metadata_ip = %s\n" % self._controller + \ 130 | "metadata_proxy_shared_secret = %s\n" % metadata_password 131 | util.write_config(configfile, config) 132 | 133 | def config_nova(self, configfile): 134 | nova = Nova.get() 135 | config = ("[DEFAULT]\n" 136 | "notify_nova_on_port_status_changes = True\n" 137 | "notify_nova_on_port_data_changes = True\n" 138 | "nova_url = http://{0}:8774/v2\n" 139 | "[nova]\n" 140 | "auth_url = http://{0}:35357\n" 141 | "auth_plugin = password\n" 142 | "project_domain_id = default\n" 143 | "user_domain_id = default\n" 144 | "region_name = {1}\n" 145 | "project_name = service\n" 146 | "username = nova\n" 147 | "password = {2}\n" 148 | .format(self._controller, self._region, nova._password)) 149 | util.write_config(configfile, config) 150 | 151 | def config_neutron_on_nova(self, configfile): 152 | keystone = Keystone.get() 153 | config = \ 154 | "[DEFAULT]\n" + \ 155 | "network_api_class = nova.network.neutronv2.api.API\n" + \ 156 | "security_group_api = neutron\n" + \ 157 | "linuxnet_interface_driver = " + \ 158 | "nova.network.linux_net.NeutronLinuxBridgeInterfaceDriver\n" + \ 159 | "firewall_driver = nova.virt.firewall.NoopFirewallDriver\n" + \ 160 | "[neutron]\n" + \ 161 | "url = %s\n" % self._public_url + \ 162 | "auth_url = %s\n" % keystone._admin_url + \ 163 | "auth_plugin = password\n" + \ 164 | "project_domain_id = default\n" + \ 165 | "user_domain_id = default\n" + \ 166 | "region_name = %s\n" % self._region + \ 167 | "project_name = service\n" + \ 168 | "username = neutron\n" + \ 169 | "password = %s\n" % self._password + \ 170 | "service_metadata_proxy = True\n" + \ 171 | "metadata_proxy_shared_secret = %s\n" % metadata_password 172 | util.write_config(configfile, config) 173 | if CONF['CONFIG_HTTP_SERVICE'] == 'nginx': 174 | nova_api_services = ['uwsgi@nova-api.socket', 175 | 'uwsgi@nova-metadata.socket'] 176 | elif CONF['CONFIG_HTTP_SERVICE'] == 'apache2': 177 | nova_api_services = ['httpd'] 178 | else: 179 | nova_api_services = ['nova-api'] 180 | self.start_server(nova_api_services) 181 | 182 | def add_service_plugin(self, plugin): 183 | plugins = util.get_option('/etc/neutron/neutron.conf', 184 | 'DEFAULT', 'service_plugins').split(',') 185 | if plugin not in plugins: 186 | plugins.append(plugin) 187 | config = ('[DEFAULT]\n' 188 | "service_plugins = %s\n" % ','.join(plugins)) 189 | util.write_config("/etc/neutron/neutron.conf", config) 190 | 191 | def config_lbaas(self): 192 | self.add_service_plugin('lbaas') 193 | config = ("[DEFAULT]\n" 194 | "interface_driver = " 195 | "neutron.agent.linux.interface.BridgeInterfaceDriver\n") 196 | util.write_config("/etc/neutron/lbaas_agent.ini", config) 197 | self._services += ['neutron-lbaas-agent'] 198 | 199 | def config_vpnaas(self): 200 | self.add_service_plugin('vpnaas') 201 | driver = ("neutron_vpnaas.services.vpn.device_drivers.libreswan_ipsec" 202 | ".LibreSwanDriver") 203 | config = "[vpnagent]\n" + \ 204 | "vpn_device_driver = %s\n" % driver 205 | util.write_config("/etc/neutron/vpnaas_agent.ini", config) 206 | self._services += ['ipsec', 'neutron-vpn-agent'] 207 | 208 | def create_network(self, name, network, public=None): 209 | cidr = IPv4Network(network) 210 | cidr_e = cidr.exploded 211 | cidr_gw = (cidr.network_address + 1).exploded 212 | cidr_start = (cidr.network_address + 2).exploded 213 | cidr_end = (cidr.broadcast_address - 1).exploded 214 | try: 215 | LOG.debug("checking if network '{0}' exists".format(name)) 216 | util.run_command("neutron net-show %s" % name, 217 | environ=self._env) 218 | except: 219 | LOG.debug("creating network '{0}'".format(name)) 220 | cmd = "neutron net-create %s" % name 221 | if public: 222 | cmd += (" --provider:physical_network public" 223 | " --shared --provider:network_type flat") 224 | util.run_command(cmd, environ=self._env) 225 | cmd = ("neutron subnet-create %s %s --name %s" 226 | " --gateway %s" % (name, cidr_e, name, cidr_gw)) 227 | if public: 228 | cmd += (" --allocation-pool start=%s,end=%s" 229 | % (cidr_start, cidr_end)) 230 | util.run_command(cmd, environ=self._env) 231 | if public: 232 | util.run_command("neutron net-update %s --router:external" 233 | % name, environ=self._env) 234 | 235 | def create_router(self, router, gw, interfaces): 236 | try: 237 | LOG.debug("checking if router '{0}' exists".format(router)) 238 | util.run_command("neutron router-show %s" % router, 239 | environ=self._env) 240 | except: 241 | LOG.debug("creating router '{0}'".format(router)) 242 | util.run_command("neutron router-create %s" % router, 243 | environ=self._env) 244 | util.run_command("neutron router-gateway-set %s %s" 245 | % (router, gw), environ=self._env) 246 | for i in interfaces: 247 | util.run_command("neutron router-interface-add %s %s" 248 | % (router, i), environ=self._env) 249 | 250 | def ceilometer_enable(self, configfile): 251 | LOG.debug("setting up rabbitmq configuration" 252 | " in '{0}'".format(configfile)) 253 | self.config_rabbitmq(configfile) 254 | config = ("[DEFAULT]\n" 255 | "notification_driver = messagingv2\n") 256 | util.write_config(configfile, config) 257 | --------------------------------------------------------------------------------