Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Some Updates to worker management #2494

Merged
merged 8 commits into from Jan 12, 2021
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
2 changes: 2 additions & 0 deletions MANIFEST.in
Expand Up @@ -12,4 +12,6 @@ recursive-include nucypher/blockchain/eth/aragon_artifacts *.json
recursive-include nucypher/blockchain/eth/contract_registry *.json *.md
prune nucypher/blockchain/eth/contract_registry/historical
recursive-include nucypher/network/templates *.html *.mako
recursive-include nucypher/utilities/templates *.html *.mako
recursive-include deploy/ansible/worker *.yml
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Alright! Getting this thing published.

recursive-include nucypher/acumen/ *json
10 changes: 5 additions & 5 deletions deploy/ansible/worker/include/run_ursula.yml
Expand Up @@ -76,7 +76,7 @@
max-file: "5"
image: "{{ nucypher_image | default('nucypher/nucypher:latest') }}"
restart_policy: "unless-stopped"
command: "nucypher ursula run {{nucypher_ursula_run_options | default('')}} --lonely {{prometheus | default('')}} {{gas_strategy | default('')}} --network {{network_name}}"
command: "nucypher ursula run {{nucypher_ursula_run_options}} --lonely"
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍 much needed cleanup

volumes:
- /home/nucypher:/root/.local/share/
ports:
Expand All @@ -85,14 +85,14 @@
env: "{{runtime_envvars}}"

- name: "wait a few seconds for the seed node to become available"
when: SEED_NODE_URI is not undefined
when: SEED_NODE_URI is not undefined and SEED_NODE_URI
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is the extra check for ensuring the SEED_NODE_URI value is non-empty?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yeah... it errors if SEED_NODE_URI is undefined but it can still be None.
So the first check is to avoid an error if it's undefined, the 2nd one is the actual logic of detecting if it has a non None value.

pause:
seconds: 15

- name: "Run Staked Ursula (non-seed)"
become: yes
become_user: nucypher
when: SEED_NODE_URI is undefined or inventory_hostname != SEED_NODE_URI
when: inventory_hostname != SEED_NODE_URI
docker_container:
recreate: yes
name: ursula
Expand All @@ -104,7 +104,7 @@
max-file: "5"
image: "{{ nucypher_image | default('nucypher/nucypher:latest') }}"
restart_policy: "unless-stopped"
command: "nucypher ursula run {{nucypher_ursula_run_options | default('')}} --disable-availability-check {{teacher_options}} {{prometheus | default('')}} {{gas_strategy | default('')}} --network {{network_name}}"
command: "nucypher ursula run {{nucypher_ursula_run_options}} {{teacher_options}}"
volumes:
- /home/nucypher:/root/.local/share/
ports:
Expand Down Expand Up @@ -133,5 +133,5 @@
become: yes
wait_for:
path: "/var/lib/docker/containers/{{ursula_container_name['stdout']}}/{{ursula_container_name['stdout']}}-json.log"
search_regex: "Checking worker settings:"
search_regex: "Awaiting worker qualification"
timeout: 30
Expand Up @@ -33,6 +33,8 @@ to keep your Nucypher Ursula nodes working and up to date.
+----------------------+-------------------------------------------------------------------------------+
| ``destroy`` | Shut down and cleanup resources deployed on AWS or Digital Ocean |
+----------------------+-------------------------------------------------------------------------------+
| ``stop`` | Stop the selected nodes. |
+----------------------+-------------------------------------------------------------------------------+
| ``status`` | Prints a formatted status of selected managed hosts. |
+----------------------+-------------------------------------------------------------------------------+
| ``logs`` | Download and display the accumulated stdout logs of selected hosts |
Expand Down Expand Up @@ -73,6 +75,9 @@ Some examples:
# update all your existing hosts to the latest code
$ nucypher cloudworkers update --nucypher-image nucypher/nucypher:latest

# stop the running Ursula on your hosts
$ nucypher cloudworkers stop

# change two of your existing hosts to use alchemy instead of infura as a delegated blockchain
# note: hosts created for local stakers will have the staker's checksum address as their nickname by default
$ nucypher cloudworkers update --remote-provider wss://eth-mainnet.ws.alchemyapi.io/v2/aodfh298fh2398fh2398hf3924f... --include-host 0x9a92354D3811938A1f35644825188cAe3103bA8e --include-host 0x1Da644825188cAe3103bA8e92354D3811938A1f35
Expand Down Expand Up @@ -112,3 +117,6 @@ Some examples:
# backup all your worker's critical data
# note: this is also done after any update or deploy operations
for ns in $(nucypher cloudworkers list-namespaces); do nucypher cloudworkers backup --namespace $ns; done

# show some info about your hosts
nucypher cloudworkers list-hosts -v
1 change: 1 addition & 0 deletions newsfragments/2494.bugfix.rst
@@ -0,0 +1 @@
cloudworkers bugfixes, cli args refactor and new "cloudworkers stop" feature.
72 changes: 40 additions & 32 deletions nucypher/cli/commands/cloudworkers.py
Expand Up @@ -18,8 +18,6 @@
import click
import os

from nucypher.cli.options import option_gas_strategy, option_max_gas_price

try:
from nucypher.utilities.clouddeploy import CloudDeployers
except ImportError:
Expand Down Expand Up @@ -60,11 +58,11 @@ def cloudworkers():
@click.option('--seed-network', help="Do you want the 1st node to be --lonely and act as a seed node for this network", default=False, is_flag=True)
@click.option('--include-stakeholder', 'stakes', help="limit worker to specified stakeholder addresses", multiple=True)
@click.option('--wipe', help="Clear nucypher configs on existing nodes and start a fresh node with new keys.", default=False, is_flag=True)
@click.option('--prometheus', help="Run Prometheus on workers.", default=False, is_flag=True)
@click.option('--namespace', help="Namespace for these operations. Used to address hosts and data locally and name hosts on cloud platforms.", type=click.STRING, default='local-stakeholders')
@click.option('--env', '-e', 'envvars', help="environment variables (ENVVAR=VALUE)", multiple=True, type=click.STRING, default=[])
@click.option('--cli', '-c', 'cliargs', help="cli arguments for 'nucypher run': eg.'--max-gas-price 50'/'--c max-gas-price=50'", multiple=True, type=click.STRING, default=[])
@group_general_config
def up(general_config, staker_options, config_file, cloudprovider, aws_profile, remote_provider, nucypher_image, seed_network, stakes, wipe, prometheus, namespace, envvars):
def up(general_config, staker_options, config_file, cloudprovider, aws_profile, remote_provider, nucypher_image, seed_network, stakes, wipe, prometheus, namespace, envvars, cliargs):
vepkenez marked this conversation as resolved.
Show resolved Hide resolved
"""Creates workers for all stakes owned by the user for the given network."""

emitter = setup_emitter(general_config)
Expand All @@ -84,7 +82,7 @@ def up(general_config, staker_options, config_file, cloudprovider, aws_profile,
config_file = config_file or StakeHolderConfiguration.default_filepath()

deployer = CloudDeployers.get_deployer(cloudprovider)(emitter, STAKEHOLDER, config_file, remote_provider,
nucypher_image, seed_network, aws_profile, prometheus, namespace=namespace, network=STAKEHOLDER.network, envvars=envvars)
nucypher_image, seed_network, aws_profile, prometheus, namespace=namespace, network=STAKEHOLDER.network, envvars=envvars, cliargs=cliargs)
if staker_addresses:
config = deployer.create_nodes(staker_addresses)

Expand All @@ -99,13 +97,13 @@ def up(general_config, staker_options, config_file, cloudprovider, aws_profile,
@click.option('--remote-provider', help="The blockchain provider for the remote node, if not provided, nodes will run geth.", default=None)
@click.option('--nucypher-image', help="The docker image containing the nucypher code to run on the remote nodes. (default is nucypher/nucypher:latest)", default=None)
@click.option('--seed-network', help="Do you want the 1st node to be --lonely and act as a seed node for this network", default=False, is_flag=True)
@click.option('--prometheus', help="Run Prometheus on workers.", default=False, is_flag=True)
@click.option('--count', help="Create this many nodes.", type=click.INT, default=1)
@click.option('--namespace', help="Namespace for these operations. Used to address hosts and data locally and name hosts on cloud platforms.", type=click.STRING, default='local-stakeholders')
@click.option('--network', help="The Nucypher network name these hosts will run on.", type=click.STRING, default='mainnet')
@click.option('--env', '-e', 'envvars', help="environment variables (ENVVAR=VALUE)", multiple=True, type=click.STRING, default=[])
@click.option('--cli', '-c', 'cliargs', help="cli arguments for 'nucypher run': eg.'--max-gas-price 50'/'--c max-gas-price=50'", multiple=True, type=click.STRING, default=[])
@group_general_config
def create(general_config, cloudprovider, aws_profile, remote_provider, nucypher_image, seed_network, prometheus, count, namespace, network, envvars):
def create(general_config, cloudprovider, aws_profile, remote_provider, nucypher_image, seed_network, prometheus, count, namespace, network, envvars, cliargs):
vepkenez marked this conversation as resolved.
Show resolved Hide resolved
"""Creates the required number of workers to be staked later under a namespace"""

emitter = setup_emitter(general_config)
Expand All @@ -115,7 +113,7 @@ def create(general_config, cloudprovider, aws_profile, remote_provider, nucypher
return

deployer = CloudDeployers.get_deployer(cloudprovider)(emitter, None, None, remote_provider, nucypher_image, seed_network,
aws_profile, prometheus, namespace=namespace, network=network, envvars=envvars)
aws_profile, prometheus, namespace=namespace, network=network, envvars=envvars, cliargs=cliargs)

names = []
i = 1
Expand Down Expand Up @@ -190,16 +188,14 @@ def add_for_stake(general_config, staker_options, config_file, staker_address, h
@click.option('--nucypher-image', help="The docker image containing the nucypher code to run on the remote nodes.", default=None)
@click.option('--seed-network', help="Do you want the 1st node to be --lonely and act as a seed node for this network", default=False, is_flag=True)
@click.option('--wipe', help="Clear your nucypher config and start a fresh node with new keys", default=False, is_flag=True)
@click.option('--prometheus', help="Run Prometheus on workers.", default=False, is_flag=True)
@click.option('--namespace', help="Namespace for these operations. Used to address hosts and data locally and name hosts on cloud platforms.", type=click.STRING, default='local-stakeholders')
@click.option('--network', help="The Nucypher network name these hosts will run on.", type=click.STRING, default='mainnet')
@option_gas_strategy
@option_max_gas_price
@click.option('--include-host', 'include_hosts', help="specify hosts to update", multiple=True, type=click.STRING)
@click.option('--env', '-e', 'envvars', help="environment variables (ENVVAR=VALUE)", multiple=True, type=click.STRING, default=[])
@click.option('--cli', '-c', 'cliargs', help="cli arguments for 'nucypher run': eg.'--max-gas-price 50'/'--c max-gas-price=50'", multiple=True, type=click.STRING, default=[])
@group_general_config
def deploy(general_config, remote_provider, nucypher_image, seed_network, sentry_dsn, wipe, prometheus,
namespace, network, gas_strategy, max_gas_price, include_hosts, envvars):
def deploy(general_config, remote_provider, nucypher_image, seed_network, wipe,
namespace, network, include_hosts, envvars, cliargs):
"""Deploys NuCypher on managed hosts."""

emitter = setup_emitter(general_config)
Expand All @@ -214,13 +210,10 @@ def deploy(general_config, remote_provider, nucypher_image, seed_network, sentry
remote_provider,
nucypher_image,
seed_network,
sentry_dsn,
prometheus=prometheus,
namespace=namespace,
network=network,
gas_strategy=gas_strategy,
max_gas_price=max_gas_price,
envvars=envvars)
envvars=envvars,
cliargs=cliargs)

hostnames = deployer.config['instances'].keys()
if include_hosts:
Expand All @@ -235,16 +228,14 @@ def deploy(general_config, remote_provider, nucypher_image, seed_network, sentry
@click.option('--nucypher-image', help="The docker image containing the nucypher code to run on the remote nodes.", default=None)
@click.option('--seed-network', help="Do you want the 1st node to be --lonely and act as a seed node for this network", default=False, is_flag=True)
@click.option('--wipe', help="Clear your nucypher config and start a fresh node with new keys", default=False, is_flag=True)
@click.option('--prometheus', help="Run Prometheus on workers.", default=False, is_flag=True)
@click.option('--namespace', help="Namespace for these operations. Used to address hosts and data locally and name hosts on cloud platforms.", type=click.STRING, default='local-stakeholders')
@click.option('--network', help="The Nucypher network name these hosts will run on.", type=click.STRING, default='mainnet')
@click.option('--include-host', 'include_hosts', help="specify hosts to update", multiple=True, type=click.STRING)
@click.option('--env', '-e', 'envvars', help="environment variables (ENVVAR=VALUE)", multiple=True, type=click.STRING, default=[])
@option_gas_strategy
@option_max_gas_price
@click.option('--cli', '-c', 'cliargs', help="cli arguments for 'nucypher run': eg.'--max-gas-price 50'/'--c max-gas-price=50'", multiple=True, type=click.STRING, default=[])
@group_general_config
def update(general_config, remote_provider, nucypher_image, seed_network, sentry_dsn, wipe, prometheus,
namespace, network, gas_strategy, max_gas_price, include_hosts, envvars):
def update(general_config, remote_provider, nucypher_image, seed_network, wipe,
namespace, network, include_hosts, envvars, cliargs):
"""Updates existing installations of Nucypher on existing managed remote hosts."""

emitter = setup_emitter(general_config)
Expand All @@ -260,13 +251,10 @@ def update(general_config, remote_provider, nucypher_image, seed_network, sentry
remote_provider,
nucypher_image,
seed_network,
sentry_dsn,
prometheus=prometheus,
namespace=namespace,
network=network,
gas_strategy=gas_strategy,
max_gas_price=max_gas_price,
envvars=envvars
envvars=envvars,
cliargs=cliargs,
)

emitter.echo(f"updating the following existing hosts:")
Expand Down Expand Up @@ -325,7 +313,7 @@ def logs(general_config, namespace, network, include_hosts):
@cloudworkers.command('backup')
@click.option('--namespace', help="Namespace for these operations. Used to address hosts and data locally and name hosts on cloud platforms.", type=click.STRING, default='local-stakeholders')
@click.option('--network', help="The Nucypher network name these hosts will run on.", type=click.STRING, default='mainnet')
@click.option('--include-host', 'include_hosts', help="Query status on only the named hosts", multiple=True, type=click.STRING)
@click.option('--include-host', 'include_hosts', help="backup only the named hosts", multiple=True, type=click.STRING)
@group_general_config
def backup(general_config, namespace, network, include_hosts):
"""Creates backups of important data from selected remote workers"""
Expand All @@ -343,6 +331,27 @@ def backup(general_config, namespace, network, include_hosts):
deployer.backup_remote_data(hostnames)


@cloudworkers.command('stop')
@click.option('--namespace', help="Namespace for these operations. Used to address hosts and data locally and name hosts on cloud platforms.", type=click.STRING, default='local-stakeholders')
@click.option('--network', help="The Nucypher network name these hosts will run on.", type=click.STRING, default='mainnet')
@click.option('--include-host', 'include_hosts', help="stop only the named hosts", multiple=True, type=click.STRING)
@group_general_config
def stop(general_config, namespace, network, include_hosts):
"""Stops the Ursula on selected remote workers"""

emitter = setup_emitter(general_config)
if not CloudDeployers:
emitter.echo("Ansible is required to use `nucypher cloudworkers *` commands. (Please run 'pip install ansible'.)", color="red")
return

deployer = CloudDeployers.get_deployer('generic')(emitter, None, None, namespace=namespace, network=network)

hostnames = deployer.config['instances'].keys()
if include_hosts:
hostnames = include_hosts
deployer.stop_worker_process(hostnames)


@cloudworkers.command('destroy')
@click.option('--cloudprovider', help="aws or digitalocean")
@click.option('--namespace', help="Namespace for these operations. Used to address hosts and data locally and name hosts on cloud platforms.", type=click.STRING, default='local-stakeholders')
Expand Down Expand Up @@ -395,9 +404,8 @@ def list_namespaces(general_config, network):
@cloudworkers.command('list-hosts')
@click.option('--network', help="The network whose hosts you want to see.", type=click.STRING, default='mainnet')
@click.option('--namespace', help="The network whose hosts you want to see.", type=click.STRING, default='local-stakeholders')
@click.option('--include-data', help="Print the full config data for each node.", is_flag=True, default=False)
@group_general_config
def list_hosts(general_config, network, namespace, include_data):
def list_hosts(general_config, network, namespace):
"""Prints local config info about known hosts"""

emitter = setup_emitter(general_config)
Expand All @@ -408,7 +416,7 @@ def list_hosts(general_config, network, namespace, include_data):
deployer = CloudDeployers.get_deployer('generic')(emitter, None, None, network=network, namespace=namespace)
for name, data in deployer.get_all_hosts():
emitter.echo(name)
if include_data:
if general_config.verbosity >= 2:
for k, v in data.items():
emitter.echo(f"\t{k}: {v}")

Expand Down