mirror of https://github.com/nucypher/nucypher.git
Smoothing over auto-ip detection
parent
64742d2bc6
commit
af812be748
|
@ -84,6 +84,7 @@ class EthereumContractRegistry:
|
|||
raise cls.RegistryError(f"Failed to fetch registry from {github_endpoint} with status code {response.status_code} ")
|
||||
|
||||
filepath = filepath or cls._default_registry_filepath
|
||||
# TODO : Use envvar for config root and registry path
|
||||
try:
|
||||
with open(filepath, 'wb') as registry_file: # TODO: Skip re-write if already up to date
|
||||
registry_file.write(response.content)
|
||||
|
|
|
@ -27,6 +27,7 @@ from typing import List
|
|||
|
||||
from nucypher.characters.lawful import Ursula
|
||||
from nucypher.cli.config import NucypherClickConfig
|
||||
from nucypher.cli.types import IPV4_ADDRESS
|
||||
from nucypher.config.constants import DEFAULT_CONFIG_ROOT, USER_LOG_DIR
|
||||
from nucypher.network.middleware import RestMiddleware
|
||||
from nucypher.network.teachers import TEACHER_NODES
|
||||
|
@ -55,6 +56,10 @@ LOG = Logger('cli.actions')
|
|||
console_emitter = NucypherClickConfig.emit
|
||||
|
||||
|
||||
class UnknownIPAddress(RuntimeError):
|
||||
pass
|
||||
|
||||
|
||||
def load_seednodes(min_stake: int,
|
||||
federated_only: bool,
|
||||
network_domain: str,
|
||||
|
@ -105,31 +110,48 @@ def destroy_configuration_root(config_root=None, force=False, logs: bool = False
|
|||
return config_root
|
||||
|
||||
|
||||
def get_external_ip():
|
||||
def get_external_ip_from_centralized_source():
|
||||
ip_request = requests.get('https://ifconfig.me/')
|
||||
if ip_request.status_code == 200:
|
||||
return ip_request.text
|
||||
return None
|
||||
raise UnknownIPAddress(f"There was an error determining the IP address automatically. (status code {ip_request.status_code})")
|
||||
|
||||
|
||||
def determine_external_ip_address(force: bool = False) -> str:
|
||||
try:
|
||||
rest_host = get_external_ip_from_centralized_source()
|
||||
except UnknownIPAddress:
|
||||
if force:
|
||||
raise
|
||||
else:
|
||||
# Interactive
|
||||
if not force:
|
||||
if not click.confirm(f"Is this the public-facing IPv4 address ({rest_host}) you want to use for Ursula?"):
|
||||
rest_host = click.prompt("Please enter Ursula's public-facing IPv4 address here:", type=IPV4_ADDRESS)
|
||||
else:
|
||||
console_emitter(message=f"WARNING: --force is set, using auto-detected IP '{rest_host}'", color='yellow')
|
||||
|
||||
return rest_host
|
||||
|
||||
|
||||
def destroy_configuration(character_config, force: bool = False) -> None:
|
||||
|
||||
if not force:
|
||||
click.confirm(CHARACTER_DESTRUCTION.format(name=character_config._NAME,
|
||||
root=character_config.config_root), abort=True)
|
||||
if not force:
|
||||
click.confirm(CHARACTER_DESTRUCTION.format(name=character_config._NAME,
|
||||
root=character_config.config_root), abort=True)
|
||||
|
||||
try:
|
||||
character_config.destroy()
|
||||
try:
|
||||
character_config.destroy()
|
||||
|
||||
except FileNotFoundError:
|
||||
message = 'Failed: No nucypher files found at {}'.format(character_config.config_root)
|
||||
console_emitter(message=message, color='red')
|
||||
character_config.log.debug(message)
|
||||
raise click.Abort()
|
||||
else:
|
||||
message = "Deleted configuration files at {}".format(character_config.config_root)
|
||||
console_emitter(message=message, color='green')
|
||||
character_config.log.debug(message)
|
||||
except FileNotFoundError:
|
||||
message = 'Failed: No nucypher files found at {}'.format(character_config.config_root)
|
||||
console_emitter(message=message, color='red')
|
||||
character_config.log.debug(message)
|
||||
raise click.Abort()
|
||||
else:
|
||||
message = "Deleted configuration files at {}".format(character_config.config_root)
|
||||
console_emitter(message=message, color='green')
|
||||
character_config.log.debug(message)
|
||||
|
||||
|
||||
def forget(configuration):
|
||||
|
|
|
@ -27,6 +27,7 @@ from nucypher.blockchain.eth.clients import NuCypherGethDevnetProcess
|
|||
from nucypher.blockchain.eth.token import NU
|
||||
from nucypher.characters.banners import URSULA_BANNER
|
||||
from nucypher.cli import actions, painting
|
||||
from nucypher.cli.actions import UnknownIPAddress
|
||||
from nucypher.cli.config import nucypher_click_config
|
||||
from nucypher.cli.processes import UrsulaCommandProtocol
|
||||
from nucypher.cli.types import (
|
||||
|
@ -35,8 +36,8 @@ from nucypher.cli.types import (
|
|||
EXISTING_READABLE_FILE,
|
||||
STAKE_DURATION,
|
||||
STAKE_EXTENSION,
|
||||
STAKE_VALUE
|
||||
)
|
||||
STAKE_VALUE,
|
||||
IPV4_ADDRESS)
|
||||
from nucypher.config.characters import UrsulaConfiguration
|
||||
from nucypher.utilities.sandbox.constants import (
|
||||
TEMPORARY_DOMAIN,
|
||||
|
@ -170,25 +171,7 @@ def ursula(click_config,
|
|||
# Attempts to automatically get the external IP from ifconfig.me
|
||||
# If the request fails, it falls back to the standard process.
|
||||
if not rest_host:
|
||||
rest_host = actions.get_external_ip()
|
||||
if rest_host is None and force:
|
||||
raise RuntimeError(f"There was an error determining the IP address automatically.")
|
||||
else:
|
||||
is_valid_address = False
|
||||
if rest_host is not None and not force:
|
||||
is_valid_address = click.confirm(f"Is this the public-facing IPv4 address ({rest_host}) you want to use for Ursula?")
|
||||
if not is_valid_address:
|
||||
rest_host = click.prompt("Please enter Ursula's public-facing IPv4 address here:")
|
||||
|
||||
|
||||
# Validate the IPv4 address
|
||||
try:
|
||||
socket.inet_aton(rest_host)
|
||||
if force:
|
||||
click_config.emit(message=f"WARNING: --force is set, using IP {rest_host}", color='yellow')
|
||||
except OSError:
|
||||
raise ValueError("The IP address {rest_host} is not a valid IPv4 address.")
|
||||
|
||||
rest_host = actions.determine_external_ip_address(force=force)
|
||||
|
||||
new_password = click_config.get_password(confirm=True)
|
||||
|
||||
|
|
|
@ -640,13 +640,15 @@ class NodeConfiguration(ABC):
|
|||
*args, **kwargs)
|
||||
|
||||
def write_keyring(self, password: str, **generation_kwargs) -> NucypherKeyring:
|
||||
|
||||
#
|
||||
# Decentralized
|
||||
#
|
||||
|
||||
# Note: It is assumed the blockchain is not yet available.
|
||||
if not self.federated_only and not self.checksum_public_address:
|
||||
|
||||
#
|
||||
# Integrated Provider Process
|
||||
#
|
||||
|
||||
# "Casual Geth"
|
||||
if self.provider_process:
|
||||
|
||||
if not os.path.exists(self.provider_process.data_dir):
|
||||
|
|
|
@ -23,6 +23,7 @@ from twisted.internet import threads
|
|||
|
||||
from nucypher.characters.base import Learner
|
||||
from nucypher.cli import actions
|
||||
from nucypher.cli.actions import UnknownIPAddress
|
||||
from nucypher.cli.main import nucypher_cli
|
||||
from nucypher.config.node import NodeConfiguration
|
||||
from nucypher.utilities.sandbox.constants import (
|
||||
|
@ -119,63 +120,53 @@ def test_ursula_cannot_init_with_dev_flag(click_runner):
|
|||
def test_ursula_rest_host_determination(click_runner):
|
||||
|
||||
# Patch the get_external_ip call
|
||||
original_call = actions.get_external_ip
|
||||
actions.get_external_ip = lambda: '192.0.2.0'
|
||||
original_call = actions.get_external_ip_from_centralized_source
|
||||
try:
|
||||
actions.get_external_ip_from_centralized_source = lambda: '192.0.2.0'
|
||||
|
||||
args = ('ursula', 'init',
|
||||
'--federated-only',
|
||||
'--network', TEMPORARY_DOMAIN
|
||||
)
|
||||
args = ('ursula', 'init',
|
||||
'--federated-only',
|
||||
'--network', TEMPORARY_DOMAIN
|
||||
)
|
||||
|
||||
user_input = f'Y\n{INSECURE_DEVELOPMENT_PASSWORD}\n{INSECURE_DEVELOPMENT_PASSWORD}'
|
||||
user_input = f'Y\n{INSECURE_DEVELOPMENT_PASSWORD}\n{INSECURE_DEVELOPMENT_PASSWORD}'
|
||||
|
||||
result = click_runner.invoke(nucypher_cli, args, catch_exceptions=False,
|
||||
input=user_input)
|
||||
|
||||
assert result.exit_code == 0
|
||||
assert '(192.0.2.0)' in result.output
|
||||
|
||||
args = ('ursula', 'init',
|
||||
'--federated-only',
|
||||
'--network', TEMPORARY_DOMAIN,
|
||||
'--force'
|
||||
)
|
||||
|
||||
user_input = f'{INSECURE_DEVELOPMENT_PASSWORD}\n{INSECURE_DEVELOPMENT_PASSWORD}\n'
|
||||
|
||||
result = click_runner.invoke(nucypher_cli, args, catch_exceptions=False,
|
||||
input=user_input)
|
||||
|
||||
assert result.exit_code == 0
|
||||
assert 'IP 192.0.2.0' in result.output
|
||||
|
||||
# Patch get_external_ip call to error output
|
||||
actions.get_external_ip = lambda: None
|
||||
|
||||
args = ('ursula', 'init',
|
||||
'--federated-only',
|
||||
'--network', TEMPORARY_DOMAIN,
|
||||
'--force'
|
||||
)
|
||||
|
||||
user_input = f'{INSECURE_DEVELOPMENT_PASSWORD}\n{INSECURE_DEVELOPMENT_PASSWORD}\n'
|
||||
with pytest.raises(RuntimeError):
|
||||
result = click_runner.invoke(nucypher_cli, args, catch_exceptions=True,
|
||||
result = click_runner.invoke(nucypher_cli, args, catch_exceptions=False,
|
||||
input=user_input)
|
||||
|
||||
# Patch get_external_ip call to return bad IP
|
||||
actions.get_external_ip = lambda: '382.328.382.328'
|
||||
assert result.exit_code == 0
|
||||
assert '(192.0.2.0)' in result.output
|
||||
|
||||
args = ('ursula', 'init',
|
||||
'--federated-only',
|
||||
'--network', TEMPORARY_DOMAIN,
|
||||
'--force'
|
||||
)
|
||||
args = ('ursula', 'init',
|
||||
'--federated-only',
|
||||
'--network', TEMPORARY_DOMAIN,
|
||||
'--force'
|
||||
)
|
||||
|
||||
user_input = f'{INSECURE_DEVELOPMENT_PASSWORD}\n{INSECURE_DEVELOPMENT_PASSWORD}\n'
|
||||
with pytest.raises(OSError):
|
||||
result = click_runner.invoke(nucypher_cli, args, catch_exceptions=True,
|
||||
user_input = f'{INSECURE_DEVELOPMENT_PASSWORD}\n{INSECURE_DEVELOPMENT_PASSWORD}\n'
|
||||
|
||||
result = click_runner.invoke(nucypher_cli, args, catch_exceptions=False,
|
||||
input=user_input)
|
||||
|
||||
# Unpatch call
|
||||
actions.get_external_ip = original_call
|
||||
assert result.exit_code == 0
|
||||
assert '192.0.2.0' in result.output
|
||||
|
||||
# Patch get_external_ip call to error output
|
||||
def amazing_ip_oracle():
|
||||
raise UnknownIPAddress
|
||||
actions.get_external_ip_from_centralized_source = amazing_ip_oracle()
|
||||
|
||||
args = ('ursula', 'init',
|
||||
'--federated-only',
|
||||
'--network', TEMPORARY_DOMAIN,
|
||||
'--force'
|
||||
)
|
||||
|
||||
user_input = f'{INSECURE_DEVELOPMENT_PASSWORD}\n{INSECURE_DEVELOPMENT_PASSWORD}\n'
|
||||
|
||||
with pytest.raises(UnknownIPAddress):
|
||||
_result = click_runner.invoke(nucypher_cli, args, catch_exceptions=True, input=user_input)
|
||||
|
||||
finally:
|
||||
# Unpatch call
|
||||
actions.get_external_ip_from_centralized_source = original_call
|
||||
|
|
Loading…
Reference in New Issue