From 20d2643f745217670b56a85cb436aea2caf49973 Mon Sep 17 00:00:00 2001 From: Ian Wienand Date: Thu, 24 Nov 2022 11:16:00 +1100 Subject: [PATCH] launch: Automatically do RAX rdns updates when launching nodes On the old bridge node we had some unmanaged venv's with a very old, now unmaintained RAX DNS API interaction tool. Adding the RDNS entries is fairly straight forward, and this small tool is mostly a copy of some of the bits for our dns api backup tool. It really just comes down to getting a token and making a post request with the name/ip addresses. When the cloud the node is launched as is identified as RAX, this will automatically add the PTR records for the ip4 & 6 addresses. It also has an entrypoint to be called manually. This is added and hacked in, along with a config file for the appropriate account (I have added these details on bridge). I've left the update of openstack.org DNS entries as a manual procedure. Although they could be set automatically with small updates to the tool (just a different POST) -- details like CNAMES, etc. and the relatively few servers we start in the RAX mangaed DNS domains means I think it's easier to just do manually via the web ui. The output comment is updated. Change-Id: I8a42afdd00be2595ca73819610757ce5d4435d0a --- launch/pyproject.toml | 1 + launch/src/opendev_launch/dns.py | 55 ++----- launch/src/opendev_launch/rax_rdns.py | 136 ++++++++++++++++++ .../roles/install-launch-node/tasks/main.yaml | 8 ++ .../templates/rax-rdns-auth.conf.j2 | 4 + .../zuul/templates/group_vars/bastion.yaml.j2 | 4 + 6 files changed, 167 insertions(+), 41 deletions(-) create mode 100644 launch/src/opendev_launch/rax_rdns.py create mode 100644 playbooks/roles/install-launch-node/templates/rax-rdns-auth.conf.j2 diff --git a/launch/pyproject.toml b/launch/pyproject.toml index f1a56a379f..4041013365 100644 --- a/launch/pyproject.toml +++ b/launch/pyproject.toml @@ -27,6 +27,7 @@ dependencies = [ [project.scripts] launch-node = "opendev_launch:launch_node.main" show-dns = "opendev_launch:dns.main" +rax-rdns = "opendev_launch:rax_rdns.main" [tool.setuptools.package-data] opendev_launch = ["*.sh"] diff --git a/launch/src/opendev_launch/dns.py b/launch/src/opendev_launch/dns.py index c3c7504c13..fd56019a69 100755 --- a/launch/src/opendev_launch/dns.py +++ b/launch/src/opendev_launch/dns.py @@ -19,8 +19,10 @@ # limitations under the License. import argparse +from . import rax_rdns from .sshfp import sshfp_print_records + def get_href(server): if not hasattr(server, 'links'): return None @@ -33,18 +35,15 @@ def print_dns(cloud, server): ip4 = server.public_v4 ip6 = server.public_v6 - if 'rax' in cloud.config.name: - print_reverse_dns(cloud, server, ip4, ip6) - if server.name.endswith('opendev.org'): print_dns_opendev(server.name.rsplit('.', 2)[0], ip4, ip6) else: - print_dns_legacy(server, ip4, ip6) + print("Login to manage.rackspace.com and setup DNS manually.") + print_inventory_yaml(server, ip4, ip6) def print_dns_opendev(name, ip4, ip6): - print("\n") print("Put the following into zone-opendev.org:zones/opendev.org/zone.db") print("{name} IN A {ip4}".format(name=name, ip4=ip4)) @@ -52,7 +51,8 @@ def print_dns_opendev(name, ip4, ip6): print("{name} IN AAAA {ip6}".format(name=name, ip6=ip6)) sshfp_print_records(name, ip4) -def print_reverse_dns(cloud, server, ip4, ip6): + +def set_rax_reverse_dns(cloud, server, ip4, ip6): # Get the server object from the sdk layer so that we can pull the # href data out of the links dict. try: @@ -63,43 +63,12 @@ def print_reverse_dns(cloud, server, ip4, ip6): raise href = get_href(raw_server) - print("\n") - print("Run the following commands to set up DNS:") - print("\n") - print(". ~root/ci-launch/openstackci-rs-nova.sh") - print(". ~root/rackdns-venv/bin/activate") - print("\n") - print( - "rackdns rdns-create --name %s \\\n" - " --data %s \\\n" - " --server-href %s \\\n" - " --ttl 3600" % ( - server.name, ip6, href)) - print("\n") - print( - "rackdns rdns-create --name %s \\\n" - " --data %s \\\n" - " --server-href %s \\\n" - " --ttl 3600" % ( - server.name, ip4, href)) - print("\n") + # Reads default config file /etc/rax-rdns-auth.conf and calls to + # API to set reverse dns for RAX servers. + auth = rax_rdns.get_auth() + rax_rdns.rax_rdns(server.name, href, ip4, ip6, 3600, auth) -def print_dns_legacy(server, ip4, ip6): - print(". ~root/ci-launch/openstack-rs-nova.sh") - print("\n") - print( - "rackdns record-create --name %s \\\n" - " --type AAAA --data %s \\\n" - " --ttl 3600 openstack.org" % ( - server.name, ip6)) - print("\n") - print( - "rackdns record-create --name %s \\\n" - " --type A --data %s \\\n" - " --ttl 3600 openstack.org" % ( - server.name, ip4)) - def print_inventory_yaml(server, ip4, ip6): print("\n") print("Put the following into system-config:inventory/base/hosts.yaml") @@ -130,4 +99,8 @@ def main(): print("Please update your version of shade/openstacksdk." " openstacksdk >= 0.12 is required") raise + + if 'rax' in cloud.config.name: + set_rax_reverse_dns(cloud, server, ip4, ip6) + print_dns(cloud, server) diff --git a/launch/src/opendev_launch/rax_rdns.py b/launch/src/opendev_launch/rax_rdns.py new file mode 100644 index 0000000000..565a133eb7 --- /dev/null +++ b/launch/src/opendev_launch/rax_rdns.py @@ -0,0 +1,136 @@ +#!/usr/bin/env python3 + +# Copyright 2022 Red Hat, Inc. +# +# Licensed under the Apache License, Version 2.0 (the "License"); you may +# not use this file except in compliance with the License. You may obtain +# a copy of the License at +# +# http://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT +# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the +# License for the specific language governing permissions and limitations +# under the License. + +# Set RDNS values for a server +# +# Set auth in an .ini file specified with --config: +# +# [DEFAULT] +# RACKSPACE_USERNAME = +# RACKSPACE_PROJECT_ID = +# RACKSPACE_API_KEY = +# + +import argparse +import configparser +import collections +import logging +import os +import requests +import sys + +# Verbose call debugging: +# import http.client as http_client +# http_client.HTTPConnection.debuglevel = 1 + +RACKSPACE_IDENTITY_ENDPOINT='https://identity.api.rackspacecloud.com/v2.0/tokens' +RACKSPACE_DNS_ENDPOINT="https://dns.api.rackspacecloud.com/v1.0" + +def _get_auth_token(session, username, api_key): + # Get auth token + data = {'auth': + { + 'RAX-KSKEY:apiKeyCredentials': + { + 'username': username, + 'apiKey': api_key + } + } + } + token_response = session.post(url=RACKSPACE_IDENTITY_ENDPOINT, json=data) + token = token_response.json()['access']['token']['id'] + + return token + + +def get_auth(config_file='/etc/rax-rdns-auth.conf'): + '''Return a tuple for passing to rax_rnds update function''' + try: + logging.info("Reading config file %s" % config_file) + config = configparser.ConfigParser() + config.read(config_file) + return (config['DEFAULT']['RACKSPACE_PROJECT_ID'], + config['DEFAULT']['RACKSPACE_USERNAME'], + config['DEFAULT']['RACKSPACE_API_KEY']) + except Exception as e: + logging.error("Can not read config: %s" % e) + sys.exit(1) + + +def rax_rdns(name, server_href, ip4, ip6, ttl, auth): + (rax_project_id, rax_username, rax_api_key) = auth + + session = requests.Session() + token = _get_auth_token(session, rax_username, rax_api_key) + + rdns_url = '%s/%s/rdns' % (RACKSPACE_DNS_ENDPOINT, + rax_project_id) + + rdns_json = { + 'recordsList': { + 'records': [ + { + 'name': name, + 'type': 'PTR', + 'data': ip4, + 'ttl': ttl + }, { + 'name': name, + 'type': 'PTR', + 'data': ip6, + 'ttl': ttl + } + ] + }, + 'link': { + 'content': '', + 'href': server_href, + 'rel': 'cloudServersOpenStack' + } + } + + headers = { + 'Accept': 'application/json', + 'X-Auth-Token': token, + 'X-Project-Id': rax_project_id, + 'Content-Type': 'application/json' + } + + r = session.post(url=rdns_url, headers=headers, json=rdns_json) + logging.info("RDNS Done: %s %s" % (r.status_code, r.reason)) + + +def main(): + parser = argparse.ArgumentParser(description='Update RDNS') + parser.add_argument('--debug', dest='debug', action='store_true') + parser.add_argument('--config', dest='config', + default='/etc/rax-rdns-auth.conf') + parser.add_argument('--ttl', dest='ttl', type=int, default=3600) + parser.add_argument('name') + parser.add_argument('server_href') + parser.add_argument('ip4') + parser.add_argument('ip6') + args = parser.parse_args() + + logging.basicConfig(level=logging.INFO) + if args.debug: + logging.getLogger().setLevel(logging.DEBUG) + requests_log = logging.getLogger("requests.packages.urllib3") + requests_log.setLevel(logging.DEBUG) + requests_log.propogate = True + + auth = get_auth(args.config) + rax_rdns(args.name, args.server_href, args.ip4, args.ip6, args.ttl, auth) diff --git a/playbooks/roles/install-launch-node/tasks/main.yaml b/playbooks/roles/install-launch-node/tasks/main.yaml index 9927006f66..fb26ecffab 100644 --- a/playbooks/roles/install-launch-node/tasks/main.yaml +++ b/playbooks/roles/install-launch-node/tasks/main.yaml @@ -4,6 +4,14 @@ vars: create_venv_path: '/usr/launcher-venv' +- name: Add RAX rdns credentials + template: + src: rax-rdns-auth.conf.j2 + dest: /etc/rax-rdns-auth.conf + owner: root + group: root + mode: '0600' + - name: Install node launcher pip: name: 'file:///home/zuul/src/opendev.org/opendev/system-config/launch' diff --git a/playbooks/roles/install-launch-node/templates/rax-rdns-auth.conf.j2 b/playbooks/roles/install-launch-node/templates/rax-rdns-auth.conf.j2 new file mode 100644 index 0000000000..2b74988646 --- /dev/null +++ b/playbooks/roles/install-launch-node/templates/rax-rdns-auth.conf.j2 @@ -0,0 +1,4 @@ +[DEFAULT] +RACKSPACE_USERNAME={{ rackspace_rdns_username }} +RACKSPACE_PROJECT_ID={{ rackspace_rdns_project_id }} +RACKSPACE_API_KEY={{ rackspace_rdns_api_key }} diff --git a/playbooks/zuul/templates/group_vars/bastion.yaml.j2 b/playbooks/zuul/templates/group_vars/bastion.yaml.j2 index dfcfcec145..20eaa0aeed 100644 --- a/playbooks/zuul/templates/group_vars/bastion.yaml.j2 +++ b/playbooks/zuul/templates/group_vars/bastion.yaml.j2 @@ -7,3 +7,7 @@ extra_users: [] rackspace_dns_username: user rackspace_dns_project_id: 1234 rackspace_dns_api_key: apikey + +rackspace_rdns_username: user +rackspace_rdns_project_id: 1234 +rackspace_rdns_api_key: apikey