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} ")
|
raise cls.RegistryError(f"Failed to fetch registry from {github_endpoint} with status code {response.status_code} ")
|
||||||
|
|
||||||
filepath = filepath or cls._default_registry_filepath
|
filepath = filepath or cls._default_registry_filepath
|
||||||
|
# TODO : Use envvar for config root and registry path
|
||||||
try:
|
try:
|
||||||
with open(filepath, 'wb') as registry_file: # TODO: Skip re-write if already up to date
|
with open(filepath, 'wb') as registry_file: # TODO: Skip re-write if already up to date
|
||||||
registry_file.write(response.content)
|
registry_file.write(response.content)
|
||||||
|
|
|
@ -27,6 +27,7 @@ from typing import List
|
||||||
|
|
||||||
from nucypher.characters.lawful import Ursula
|
from nucypher.characters.lawful import Ursula
|
||||||
from nucypher.cli.config import NucypherClickConfig
|
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.config.constants import DEFAULT_CONFIG_ROOT, USER_LOG_DIR
|
||||||
from nucypher.network.middleware import RestMiddleware
|
from nucypher.network.middleware import RestMiddleware
|
||||||
from nucypher.network.teachers import TEACHER_NODES
|
from nucypher.network.teachers import TEACHER_NODES
|
||||||
|
@ -55,6 +56,10 @@ LOG = Logger('cli.actions')
|
||||||
console_emitter = NucypherClickConfig.emit
|
console_emitter = NucypherClickConfig.emit
|
||||||
|
|
||||||
|
|
||||||
|
class UnknownIPAddress(RuntimeError):
|
||||||
|
pass
|
||||||
|
|
||||||
|
|
||||||
def load_seednodes(min_stake: int,
|
def load_seednodes(min_stake: int,
|
||||||
federated_only: bool,
|
federated_only: bool,
|
||||||
network_domain: str,
|
network_domain: str,
|
||||||
|
@ -105,31 +110,48 @@ def destroy_configuration_root(config_root=None, force=False, logs: bool = False
|
||||||
return config_root
|
return config_root
|
||||||
|
|
||||||
|
|
||||||
def get_external_ip():
|
def get_external_ip_from_centralized_source():
|
||||||
ip_request = requests.get('https://ifconfig.me/')
|
ip_request = requests.get('https://ifconfig.me/')
|
||||||
if ip_request.status_code == 200:
|
if ip_request.status_code == 200:
|
||||||
return ip_request.text
|
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:
|
def destroy_configuration(character_config, force: bool = False) -> None:
|
||||||
|
|
||||||
if not force:
|
if not force:
|
||||||
click.confirm(CHARACTER_DESTRUCTION.format(name=character_config._NAME,
|
click.confirm(CHARACTER_DESTRUCTION.format(name=character_config._NAME,
|
||||||
root=character_config.config_root), abort=True)
|
root=character_config.config_root), abort=True)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
character_config.destroy()
|
character_config.destroy()
|
||||||
|
|
||||||
except FileNotFoundError:
|
except FileNotFoundError:
|
||||||
message = 'Failed: No nucypher files found at {}'.format(character_config.config_root)
|
message = 'Failed: No nucypher files found at {}'.format(character_config.config_root)
|
||||||
console_emitter(message=message, color='red')
|
console_emitter(message=message, color='red')
|
||||||
character_config.log.debug(message)
|
character_config.log.debug(message)
|
||||||
raise click.Abort()
|
raise click.Abort()
|
||||||
else:
|
else:
|
||||||
message = "Deleted configuration files at {}".format(character_config.config_root)
|
message = "Deleted configuration files at {}".format(character_config.config_root)
|
||||||
console_emitter(message=message, color='green')
|
console_emitter(message=message, color='green')
|
||||||
character_config.log.debug(message)
|
character_config.log.debug(message)
|
||||||
|
|
||||||
|
|
||||||
def forget(configuration):
|
def forget(configuration):
|
||||||
|
|
|
@ -27,6 +27,7 @@ from nucypher.blockchain.eth.clients import NuCypherGethDevnetProcess
|
||||||
from nucypher.blockchain.eth.token import NU
|
from nucypher.blockchain.eth.token import NU
|
||||||
from nucypher.characters.banners import URSULA_BANNER
|
from nucypher.characters.banners import URSULA_BANNER
|
||||||
from nucypher.cli import actions, painting
|
from nucypher.cli import actions, painting
|
||||||
|
from nucypher.cli.actions import UnknownIPAddress
|
||||||
from nucypher.cli.config import nucypher_click_config
|
from nucypher.cli.config import nucypher_click_config
|
||||||
from nucypher.cli.processes import UrsulaCommandProtocol
|
from nucypher.cli.processes import UrsulaCommandProtocol
|
||||||
from nucypher.cli.types import (
|
from nucypher.cli.types import (
|
||||||
|
@ -35,8 +36,8 @@ from nucypher.cli.types import (
|
||||||
EXISTING_READABLE_FILE,
|
EXISTING_READABLE_FILE,
|
||||||
STAKE_DURATION,
|
STAKE_DURATION,
|
||||||
STAKE_EXTENSION,
|
STAKE_EXTENSION,
|
||||||
STAKE_VALUE
|
STAKE_VALUE,
|
||||||
)
|
IPV4_ADDRESS)
|
||||||
from nucypher.config.characters import UrsulaConfiguration
|
from nucypher.config.characters import UrsulaConfiguration
|
||||||
from nucypher.utilities.sandbox.constants import (
|
from nucypher.utilities.sandbox.constants import (
|
||||||
TEMPORARY_DOMAIN,
|
TEMPORARY_DOMAIN,
|
||||||
|
@ -170,25 +171,7 @@ def ursula(click_config,
|
||||||
# Attempts to automatically get the external IP from ifconfig.me
|
# Attempts to automatically get the external IP from ifconfig.me
|
||||||
# If the request fails, it falls back to the standard process.
|
# If the request fails, it falls back to the standard process.
|
||||||
if not rest_host:
|
if not rest_host:
|
||||||
rest_host = actions.get_external_ip()
|
rest_host = actions.determine_external_ip_address(force=force)
|
||||||
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.")
|
|
||||||
|
|
||||||
|
|
||||||
new_password = click_config.get_password(confirm=True)
|
new_password = click_config.get_password(confirm=True)
|
||||||
|
|
||||||
|
|
|
@ -640,13 +640,15 @@ class NodeConfiguration(ABC):
|
||||||
*args, **kwargs)
|
*args, **kwargs)
|
||||||
|
|
||||||
def write_keyring(self, password: str, **generation_kwargs) -> NucypherKeyring:
|
def write_keyring(self, password: str, **generation_kwargs) -> NucypherKeyring:
|
||||||
|
|
||||||
|
#
|
||||||
|
# Decentralized
|
||||||
|
#
|
||||||
|
|
||||||
# Note: It is assumed the blockchain is not yet available.
|
# Note: It is assumed the blockchain is not yet available.
|
||||||
if not self.federated_only and not self.checksum_public_address:
|
if not self.federated_only and not self.checksum_public_address:
|
||||||
|
|
||||||
#
|
# "Casual Geth"
|
||||||
# Integrated Provider Process
|
|
||||||
#
|
|
||||||
|
|
||||||
if self.provider_process:
|
if self.provider_process:
|
||||||
|
|
||||||
if not os.path.exists(self.provider_process.data_dir):
|
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.characters.base import Learner
|
||||||
from nucypher.cli import actions
|
from nucypher.cli import actions
|
||||||
|
from nucypher.cli.actions import UnknownIPAddress
|
||||||
from nucypher.cli.main import nucypher_cli
|
from nucypher.cli.main import nucypher_cli
|
||||||
from nucypher.config.node import NodeConfiguration
|
from nucypher.config.node import NodeConfiguration
|
||||||
from nucypher.utilities.sandbox.constants import (
|
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):
|
def test_ursula_rest_host_determination(click_runner):
|
||||||
|
|
||||||
# Patch the get_external_ip call
|
# Patch the get_external_ip call
|
||||||
original_call = actions.get_external_ip
|
original_call = actions.get_external_ip_from_centralized_source
|
||||||
actions.get_external_ip = lambda: '192.0.2.0'
|
try:
|
||||||
|
actions.get_external_ip_from_centralized_source = lambda: '192.0.2.0'
|
||||||
|
|
||||||
args = ('ursula', 'init',
|
args = ('ursula', 'init',
|
||||||
'--federated-only',
|
'--federated-only',
|
||||||
'--network', TEMPORARY_DOMAIN
|
'--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,
|
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,
|
|
||||||
input=user_input)
|
input=user_input)
|
||||||
|
|
||||||
# Patch get_external_ip call to return bad IP
|
assert result.exit_code == 0
|
||||||
actions.get_external_ip = lambda: '382.328.382.328'
|
assert '(192.0.2.0)' in result.output
|
||||||
|
|
||||||
args = ('ursula', 'init',
|
args = ('ursula', 'init',
|
||||||
'--federated-only',
|
'--federated-only',
|
||||||
'--network', TEMPORARY_DOMAIN,
|
'--network', TEMPORARY_DOMAIN,
|
||||||
'--force'
|
'--force'
|
||||||
)
|
)
|
||||||
|
|
||||||
user_input = f'{INSECURE_DEVELOPMENT_PASSWORD}\n{INSECURE_DEVELOPMENT_PASSWORD}\n'
|
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,
|
result = click_runner.invoke(nucypher_cli, args, catch_exceptions=False,
|
||||||
input=user_input)
|
input=user_input)
|
||||||
|
|
||||||
# Unpatch call
|
assert result.exit_code == 0
|
||||||
actions.get_external_ip = original_call
|
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