2017-05-26 04:48:44 +08:00
|
|
|
#!/usr/bin/python -B
|
|
|
|
#
|
|
|
|
# make_public.py
|
|
|
|
#
|
|
|
|
# This source file is part of the FoundationDB open source project
|
|
|
|
#
|
|
|
|
# Copyright 2013-2018 Apple Inc. and the FoundationDB project authors
|
2018-02-22 02:25:11 +08:00
|
|
|
#
|
2017-05-26 04:48:44 +08:00
|
|
|
# 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
|
2018-02-22 02:25:11 +08:00
|
|
|
#
|
2017-05-26 04:48:44 +08:00
|
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
2018-02-22 02:25:11 +08:00
|
|
|
#
|
2017-05-26 04:48:44 +08:00
|
|
|
# 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 random
|
|
|
|
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)
|
2018-03-16 07:30:29 +08:00
|
|
|
s.connect(('www.foundationdb.org', 80))
|
2017-05-26 04:48:44 +08:00
|
|
|
return s.getsockname()[0]
|
|
|
|
except Exception as e:
|
|
|
|
print 'ERROR: Could not determine an address'
|
|
|
|
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 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 "")
|