Files
apple-foundationdb/packaging/make_public.py
2024-08-05 14:00:32 -07:00

155 lines
4.3 KiB
Python
Executable File

#!/usr/bin/env python3
#
# make_public.py
#
# This source file is part of the FoundationDB open source project
#
# Copyright 2013-2024 Apple Inc. and the FoundationDB project authors
#
# 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.
#
import argparse
import platform
import socket
import sys
import re
import errno
import subprocess
import os
def invalidClusterFile(clusterFile):
print("ERROR: '%s' is not a valid cluster file" % clusterFile)
sys.exit(1)
def getOrValidateAddress(address):
if address is None:
try:
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.connect(("www.foundationdb.org", 80))
return s.getsockname()[0]
except Exception as e:
print("ERROR: Could not determine an address: %s" % e)
exit(1)
else:
try:
s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
s.bind((address, 8000))
s.close()
return address
except socket.error as e:
if e.errno == errno.EADDRINUSE:
return address
else:
print("ERROR: Address %s could not be bound" % address)
exit(1)
def makePublic(clusterFile, newAddress, makeTLS):
newAddress = getOrValidateAddress(newAddress)
f = open(clusterFile, "r")
clusterStr = None
for line in f:
line = line.strip()
if len(line) > 0:
if line[0] == '#':
continue
if clusterStr is not None:
invalidClusterFile(clusterFile)
return
clusterStr = line
if clusterStr is None:
invalidClusterFile(clusterFile)
if not re.match(
"^[a-zA-Z0-9_]*:[a-zA-Z0-9]*@([0-9\\.]*:[0-9]*(:tls)?,)*[0-9\\.]*:[0-9]*(:tls)?$",
clusterStr,
):
invalidClusterFile(clusterFile)
if not re.match(
"^.*@(127\\.0\\.0\\.1:[0-9]*(:tls)?,)*127\\.0\\.0\\.1:[0-9]*(:tls)?$",
clusterStr,
):
print(
"ERROR: Cannot modify cluster file whose coordinators are not at address 127.0.0.1"
)
sys.exit(1)
f.close()
f = open(clusterFile, "w")
clusterStr = clusterStr.replace("127.0.0.1", newAddress)
if makeTLS:
clusterStr = re.sub("([0-9]),", "\\1:tls,", clusterStr)
if not clusterStr.endswith(":tls"):
clusterStr += ":tls"
f.write(clusterStr + "\n")
f.close()
return newAddress, clusterStr.count(":tls") != 0
def restartServer():
subprocess.call(["service", "foundationdb", "restart"])
if __name__ == "__main__":
if platform.system() != "Linux":
print("ERROR: this script can only be run on Linux")
sys.exit(1)
parser = argparse.ArgumentParser(
description="Converts a cluster with a local address to one with a public address"
)
parser.add_argument(
"-C",
dest="clusterFile",
type=str,
help="The cluster file to be converted. If unspecified, the cluster file at /etc/foundationdb/fdb.cluster is used.",
default="/etc/foundationdb/fdb.cluster",
)
parser.add_argument(
"-a",
dest="address",
type=str,
help="The new IP address to use. By default, an interface with access to the internet is chosen.",
)
parser.add_argument(
"-t",
dest="tls",
action="store_true",
default=False,
help="Convert addresses without TLS enabled to accepting TLS connections.",
)
args = parser.parse_args()
if os.geteuid() != 0:
print("ERROR: this script must be run as root")
sys.exit(1)
address, hasTLS = makePublic(args.clusterFile, args.address, args.tls)
restartServer()
print(
"%s is now using address %s%s"
% (args.clusterFile, address, " (TLS enabled)" if hasTLS else "")
)