Skip to content

Commit

Permalink
add support for JMX authentication
Browse files Browse the repository at this point in the history
Several changes based on PR review

This commit includes the following changes:

* Do not store jmx password in job.json
* Prompt for jmx password rather than taking --jmx-password option
* Promt for password when continuing job that uses JMX auth

prompt for jmx password with cstarpar

remove unused imports, resolve merge conflict

fix typo

Set jmx_password attr when --jmx-username is not passed and fix call to run_nodetool
  • Loading branch information
John Sanda authored and adejanovski committed Mar 29, 2019
1 parent 7b3200e commit b4016e3
Show file tree
Hide file tree
Showing 6 changed files with 57 additions and 18 deletions.
8 changes: 7 additions & 1 deletion cstar/args.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,12 +83,14 @@ def add_cstar_arguments(parser, commands, execute_command, execute_continue, exe
_add_common_arguments(continue_parser)
_add_cstar_arguments_without_command(continue_parser)
_add_ssh_arguments(continue_parser)
_add_jmx_auth_arguments(continue_parser)

cleanup_parser = subparsers.add_parser('cleanup-jobs', help='Cleanup old finished jobs and exit (*)')
cleanup_parser.set_defaults(func=execute_cleanup)
_add_common_arguments(cleanup_parser)
_add_cstar_arguments_without_command(cleanup_parser)
_add_ssh_arguments(cleanup_parser)
_add_jmx_auth_arguments(cleanup_parser)

for (name, command) in commands.items():
command_parser = subparsers.add_parser(name, help=command.description)
Expand All @@ -98,6 +100,7 @@ def add_cstar_arguments(parser, commands, execute_command, execute_continue, exe
_add_strategy_arguments(command_parser)
_add_common_arguments(command_parser)
_add_ssh_arguments(command_parser)
_add_jmx_auth_arguments(command_parser)
command_parser.set_defaults(func=lambda args: execute_command(args), command=command)


Expand All @@ -107,10 +110,13 @@ def add_cstarpar_arguments(parser):
_add_common_arguments(parser)
_add_strategy_arguments(parser)
_add_ssh_arguments(parser)
_add_jmx_auth_arguments(parser)
parser.add_argument('command', help='Command to run once for each Cassandra host')

def _add_ssh_arguments(parser):
parser.add_argument('--ssh-username', help='Username for ssh connection', default=None)
parser.add_argument('--ssh-password', help='Password for ssh connection', default=None)
parser.add_argument('--ssh-identity-file', help='Identity file for ssh connection', default=None)


def _add_jmx_auth_arguments(parser):
parser.add_argument('--jmx-username', help='JMX username', default=None)
33 changes: 23 additions & 10 deletions cstar/cstarcli.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,21 +15,22 @@
"""Argument parsing and related plumbing for the cstar command"""

import argparse
import getpass
import sys
import uuid

import cstar.args
import cstar.cleanup
import cstar.command
import cstar.strategy
import cstar.job
import cstar.remote
import cstar.jobreader
from cstar.output import msg, error, emph
import cstar.jobrunner
import cstar.output
from cstar.exceptions import BadFileFormatVersion, FileTooOld,NoHostsSpecified, BadArgument
import cstar.signalhandler
import cstar.jobrunner
import cstar.cleanup
import cstar.strategy
from cstar.exceptions import BadArgument
from cstar.exceptions import BadFileFormatVersion, FileTooOld
from cstar.output import msg, error, emph


def fallback(*args):
Expand All @@ -56,6 +57,10 @@ def execute_continue(args):
except (FileTooOld, BadFileFormatVersion) as e:
error(e)
msg("Resuming job", job.job_id)

if job.jmx_username:
job.jmx_password = getpass.getpass(prompt="JMX Password ")

msg("Running ", job.command)

cstar.signalhandler.print_message_and_save_on_sigint(job, job.job_id)
Expand Down Expand Up @@ -115,10 +120,12 @@ def execute_command(args):
dc_filter=args.dc_filter,
sleep_on_new_runner=args.ssh_pause_time,
sleep_after_done=args.node_done_pause_time,
ssh_username = args.ssh_username,
ssh_password = args.ssh_password,
ssh_identity_file = args.ssh_identity_file,
ssh_lib=args.ssh_lib)
ssh_username=args.ssh_username,
ssh_password=args.ssh_password,
ssh_identity_file=args.ssh_identity_file,
ssh_lib=args.ssh_lib,
jmx_username=args.jmx_username,
jmx_password=args.jmx_password)
job.run()

def validate_uuid4(uuid_string):
Expand All @@ -141,6 +148,12 @@ def main():
return

namespace = parser.parse_args(sys.argv[1:])

if namespace.jmx_username:
namespace.jmx_password = getpass.getpass(prompt="JMX Password ")
else:
namespace.jmx_password = None

cstar.output.configure(namespace.verbose)
namespace.func(namespace)

Expand Down
10 changes: 9 additions & 1 deletion cstar/cstarparcli.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@
"""Argument parsing and related plumbing for the cstarpar command"""

import argparse
import getpass
import sys
import uuid

Expand Down Expand Up @@ -48,6 +49,11 @@ def parse_job_mode():
def main():
namespace = parse_job_mode()

if namespace.jmx_username:
namespace.jmx_password = getpass.getpass(prompt="JMX Password ")
else:
namespace.jmx_password = None

if bool(namespace.seed_host) + bool(namespace.host) + bool(namespace.host_file) != 1:
error("Exactly one of --seed-host, --host and --host-file must be used", print_traceback=False)

Expand Down Expand Up @@ -91,7 +97,9 @@ def main():
ssh_username = namespace.ssh_username,
ssh_password = namespace.ssh_password,
ssh_identity_file = namespace.ssh_identity_file,
ssh_lib=namespace.ssh_lib)
ssh_lib=namespace.ssh_lib,
jmx_username=namespace.jmx_username,
jmx_password=namespace.jmx_password)
job.run()


Expand Down
21 changes: 16 additions & 5 deletions cstar/job.py
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,8 @@ def __init__(self):
self.ssh_username = None
self.ssh_password = None
self.ssh_identity_file = None
self.jmx_username = None
self.jmx_password = None
self.returned_jobs = list()

def __enter__(self):
Expand All @@ -89,8 +91,8 @@ def get_cluster_topology(self, seed_nodes):
tried_hosts.append(host)
conn = self._connection(host)

describe_res = conn.run(("nodetool", "describecluster"))
topology_res = conn.run(("nodetool", "ring"))
describe_res = self.run_nodetool(conn, "describecluster")
topology_res = self.run_nodetool(conn, "ring")

if (describe_res.status == 0) and (topology_res.status == 0):
cluster_name = cstar.nodetoolparser.parse_describe_cluster(describe_res.out)
Expand Down Expand Up @@ -129,7 +131,7 @@ def create_lookup_thread(ip):
print("Preheating done")

def get_keyspaces(self, conn):
cfstats_output = conn.run(("nodetool", "cfstats","|","grep","Keyspace"))
cfstats_output = self.run_nodetool(conn, *("cfstats", "|", "grep", "Keyspace"))
return cstar.nodetoolparser.extract_keyspaces_from_cfstats(cfstats_output.out)

def get_endpoint_mapping(self, topology):
Expand All @@ -149,7 +151,7 @@ def get_endpoint_mapping(self, topology):
for keyspace in keyspaces:
if not keyspace in ['system', 'system_schema']:
debug("Fetching endpoint mapping for keyspace", keyspace)
res = conn.run(("nodetool", "describering", keyspace))
res = self.run_nodetool(conn, *("describering", keyspace))
has_error = False

if res.status != 0 and not keyspace.startswith("system"):
Expand All @@ -168,11 +170,18 @@ def get_endpoint_mapping(self, topology):
raise HostIsDown("Could not find any working host while fetching endpoint mapping. Tried the following hosts:",
", ".join(host.fqdn for host in tried_hosts))

def run_nodetool(self, conn, *cmds):
if self.jmx_username and self.jmx_password:
return conn.run(("nodetool", "-u", self.jmx_username, "-pw", self.jmx_password, *cmds))
else:
return conn.run(("nodetool", *cmds))

def setup(self, hosts, seeds, command, job_id, strategy, cluster_parallel, dc_parallel, job_runner,
max_concurrency, timeout, env, stop_after, key_space, output_directory,
ignore_down_nodes, dc_filter,
sleep_on_new_runner, sleep_after_done,
ssh_username, ssh_password, ssh_identity_file, ssh_lib):
ssh_username, ssh_password, ssh_identity_file, ssh_lib,
jmx_username, jmx_password):

msg("Starting setup")

Expand All @@ -193,6 +202,8 @@ def setup(self, hosts, seeds, command, job_id, strategy, cluster_parallel, dc_pa
self.ssh_password = ssh_password
self.ssh_identity_file = ssh_identity_file
self.ssh_lib = ssh_lib
self.jmx_username = jmx_username
self.jmx_password = jmx_password
if not os.path.exists(self.output_directory):
os.makedirs(self.output_directory)

Expand Down
1 change: 1 addition & 0 deletions cstar/jobreader.py
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,7 @@ def _parse(input, file, output_directory, job, job_id, stop_after, max_days, end
job.ssh_identity_file = data['ssh_identity_file']
job.ssh_password = data['ssh_password']
job.ssh_lib = data['ssh_lib']
job.jmx_username = data['jmx_username']

strategy = cstar.strategy.parse(state['strategy'])
cluster_parallel = state['cluster_parallel']
Expand Down
2 changes: 1 addition & 1 deletion cstar/jobwriter.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ def _progress_to_dict(self):


def _job_to_dict(self):
skip = {"results", "handled_finished_jobs", "do_loop", "job_id", "job_runner"}
skip = {"results", "handled_finished_jobs", "do_loop", "job_id", "job_runner", "jmx_password"}
data = dict((key, _to_dict(val)) for key, val in self.__dict__.items() if key[0] != '_' and key not in skip)
data["version"] = FILE_FORMAT_VERSION
data["job_runner"] = self.job_runner.__name__
Expand Down

0 comments on commit b4016e3

Please sign in to comment.