diff --git a/launch/README.rst b/launch/README.rst index 171f4ebbad..49c0873154 100644 --- a/launch/README.rst +++ b/launch/README.rst @@ -1,7 +1,8 @@ Create Server ============= -The commands in this section should be run as root. +The commands in this section should be run as root on the bastion +host. To launch a node in the OpenStack CI account (production servers):: @@ -9,24 +10,24 @@ To launch a node in the OpenStack CI account (production servers):: export OS_REGION_NAME=DFW export FLAVOR="8 GB Performance" export FQDN=servername01.opendev.org - cd /opt/system-config/launch/ - ./launch-node.py $FQDN --flavor "$FLAVOR" \ + + /usr/launcher-venv/bin/launch-node $FQDN --flavor "$FLAVOR" \ --cloud=$OS_CLOUD --region=$OS_REGION_NAME Manually add the hostname to DNS (the launch script does not do so automatically, but it prints the commands to run). Note that for *.opendev.org hosts you'll only be able to add the reverse dns records via the printed commands. Forward A and AAAA records should -be added to opendev/zone-opendev.org/zones/opendev.org/zone.db. +be added to ``opendev/zone-opendev.org/zones/opendev.org/zone.db``. We need to add the host to our static inventory file so that the ansible runs see the new host. The launch script prints out the appropriate lines to add to -opendev/system-config:inventory/openstack.yaml. +``opendev/system-config:inventory/openstack.yaml``. In order for Ansible to work, you also need to accept the root SSH key for the new server. Once the new DNS entries have propagated, -as root on bridge.openstack.org: +as ``root`` on the bastion server:: ssh root@$FQDN @@ -38,6 +39,6 @@ Add DNS Records The launch-node script will print the commands needed to be run to configure DNS for a newly launched server. To see the commands -for an existing server, run: +for an existing server, run:: - ./dns.py $FQDN + /usr/launcher-venv/bin/show-dns $FQDN diff --git a/launch/pyproject.toml b/launch/pyproject.toml new file mode 100644 index 0000000000..f1a56a379f --- /dev/null +++ b/launch/pyproject.toml @@ -0,0 +1,32 @@ +[build-system] +requires = ["setuptools>=61.0"] +build-backend = "setuptools.build_meta" + +[project] +name = "opendev_launch" +version = "1.0.0" +description = "launch nodes" +requires-python = ">=3.6" +classifiers = [ + "Programming Language :: Python :: 3", + "License :: OSI Approved :: Apache2 License", + "Operating System :: OS Independent", +] +dependencies = [ + "paramiko>=2.9.1", + # This is a very specific list which is known to work + # with RAX storage... + "python-openstackclient==4.0.2", + "python-cinderclient==9.1.0", + "openstacksdk==0.102.0" +] + +[project.urls] +"Homepage" = "https://opendev.org/" + +[project.scripts] +launch-node = "opendev_launch:launch_node.main" +show-dns = "opendev_launch:dns.main" + +[tool.setuptools.package-data] +opendev_launch = ["*.sh"] diff --git a/launch/src/opendev_launch/__init__.py b/launch/src/opendev_launch/__init__.py new file mode 100644 index 0000000000..e69de29bb2 diff --git a/launch/dns.py b/launch/src/opendev_launch/dns.py similarity index 98% rename from launch/dns.py rename to launch/src/opendev_launch/dns.py index 3768ab29d7..c3c7504c13 100755 --- a/launch/dns.py +++ b/launch/src/opendev_launch/dns.py @@ -19,7 +19,7 @@ # limitations under the License. import argparse -from sshfp import sshfp_print_records +from .sshfp import sshfp_print_records def get_href(server): if not hasattr(server, 'links'): @@ -131,6 +131,3 @@ def main(): " openstacksdk >= 0.12 is required") raise print_dns(cloud, server) - -if __name__ == '__main__': - main() diff --git a/launch/launch-node.py b/launch/src/opendev_launch/launch_node.py similarity index 99% rename from launch/launch-node.py rename to launch/src/opendev_launch/launch_node.py index 1f773b84ef..461cb9e9cf 100755 --- a/launch/launch-node.py +++ b/launch/src/opendev_launch/launch_node.py @@ -28,15 +28,15 @@ import tempfile import time import traceback -import dns -import utils +from . import dns +from . import utils import openstack import paramiko -from sshclient import SSHException +from .sshclient import SSHException -SCRIPT_DIR = os.path.dirname(sys.argv[0]) +SCRIPT_DIR = os.path.dirname(os.path.abspath(__file__)) try: # This unactionable warning does not need to be printed over and over. @@ -419,6 +419,3 @@ def main(): print("When requesting an exception you can use the") print("infra-root@openstack.org email address to verify the responsible") print("party.") - -if __name__ == '__main__': - main() diff --git a/launch/make_swap.sh b/launch/src/opendev_launch/make_swap.sh similarity index 100% rename from launch/make_swap.sh rename to launch/src/opendev_launch/make_swap.sh diff --git a/launch/mount_volume.sh b/launch/src/opendev_launch/mount_volume.sh similarity index 100% rename from launch/mount_volume.sh rename to launch/src/opendev_launch/mount_volume.sh diff --git a/launch/sshclient.py b/launch/src/opendev_launch/sshclient.py similarity index 100% rename from launch/sshclient.py rename to launch/src/opendev_launch/sshclient.py diff --git a/launch/sshfp.py b/launch/src/opendev_launch/sshfp.py similarity index 100% rename from launch/sshfp.py rename to launch/src/opendev_launch/sshfp.py diff --git a/launch/utils.py b/launch/src/opendev_launch/utils.py similarity index 97% rename from launch/utils.py rename to launch/src/opendev_launch/utils.py index 4c9bf9dd5f..ae6b540618 100644 --- a/launch/utils.py +++ b/launch/src/opendev_launch/utils.py @@ -23,7 +23,7 @@ import socket import paramiko -from sshclient import SSHClient +from .sshclient import SSHClient def iterate_timeout(max_seconds, purpose): diff --git a/playbooks/roles/install-launch-node/README.rst b/playbooks/roles/install-launch-node/README.rst new file mode 100644 index 0000000000..3c5917a76f --- /dev/null +++ b/playbooks/roles/install-launch-node/README.rst @@ -0,0 +1 @@ +Install the launch node script to a venv diff --git a/playbooks/roles/install-launch-node/tasks/main.yaml b/playbooks/roles/install-launch-node/tasks/main.yaml new file mode 100644 index 0000000000..9927006f66 --- /dev/null +++ b/playbooks/roles/install-launch-node/tasks/main.yaml @@ -0,0 +1,11 @@ +- name: Create launcher venv + include_role: + name: create-venv + vars: + create_venv_path: '/usr/launcher-venv' + +- name: Install node launcher + pip: + name: 'file:///home/zuul/src/opendev.org/opendev/system-config/launch' + virtualenv: '/usr/launcher-venv' + diff --git a/playbooks/service-bridge.yaml b/playbooks/service-bridge.yaml index 1c6a3bc4fd..27354700e5 100644 --- a/playbooks/service-bridge.yaml +++ b/playbooks/service-bridge.yaml @@ -62,3 +62,7 @@ vars: logrotate_file_name: /var/log/ansible/zuul_reboot.log logrotate_frequency: weekly + + - name: Install node launcher + include_role: + name: install-launch-node diff --git a/testinfra/test_bridge.py b/testinfra/test_bridge.py index d85bcb7263..6685953396 100644 --- a/testinfra/test_bridge.py +++ b/testinfra/test_bridge.py @@ -23,14 +23,12 @@ def test_zuul_data(host, zuul_data): assert 'extra' in zuul_data assert 'zuul' in zuul_data['extra'] - def test_clouds_yaml(host): clouds_yaml = host.file('/etc/openstack/clouds.yaml') assert clouds_yaml.exists assert b'password' in clouds_yaml.content - def test_openstacksdk_config(host): f = host.file('/etc/openstack') assert f.exists @@ -47,7 +45,6 @@ def test_openstacksdk_config(host): assert f.group == 'root' assert f.mode == 0o640 - def test_root_authorized_keys(host): authorized_keys = host.file('/root/.ssh/authorized_keys') assert authorized_keys.exists @@ -56,14 +53,12 @@ def test_root_authorized_keys(host): lines = content.split('\n') assert len(lines) >= 2 - def test_ara(host): ara = host.run('/usr/ansible-venv/bin/ara-manage migrate') assert ara.rc == 0 database = host.file('/root/.ara/server/ansible.sqlite') assert database.exists - def test_kube_config(host): if platform.machine() != 'x86_64': pytest.skip() @@ -72,14 +67,12 @@ def test_kube_config(host): assert b'Z2l0ZWFfazhzX2tleQ==' in kubeconfig.content - def test_kubectl(host): if platform.machine() != 'x86_64': pytest.skip() kube = host.run('kubectl help') assert kube.rc == 0 - def test_zuul_authorized_keys(host): authorized_keys = host.file('/home/zuul/.ssh/authorized_keys') assert authorized_keys.exists @@ -92,7 +85,6 @@ def test_zuul_authorized_keys(host): for key in keys: assert 'ssh-rsa' in key - def test_rax_dns_backup(host): config_file = host.file('/etc/rax-dns-auth.conf') assert config_file.exists @@ -103,7 +95,6 @@ def test_rax_dns_backup(host): output_dir = host.file('/var/lib/rax-dns-backup') assert output_dir.exists - def test_ssh_known_hosts(host): f = host.file('/etc/ssh/ssh_known_hosts') @@ -116,3 +107,8 @@ def test_ssh_known_hosts(host): # Nothing special about this host, just testing it has an entry we # expect. assert b'bridge01.opendev.org,104.130.253.34,2001:4800:7818:103:be76:4eff:fe04:48c1 ssh-ed25519 AAAAC3NzaC1lZDI1NTE5AAAAIGG6WTR3dkhn766C69IRcLNN1Oxx7WMrcNsN03r+uZbU' in f.content + +def test_launch_node_venv(host): + launch = host.run('/usr/launcher-venv/bin/launch-node --help') + assert 'usage: launch-node' in launch.stdout + assert launch.rc == 0