def gen_hosts(option, config_file, user, master_proxy): dcos_client = mesos.DCOSClient() mesos_hosts = [] dns_hosts = [] for host in mesos.MesosDNSClient().hosts('master.mesos.'): mesos_hosts.append(host['ip']) summary = dcos_client.get_state_summary() for host in summary['slaves']: mesos_hosts.append(host['hostname']) scom = 'cat /etc/resolv.conf' output = _ssh(True, None, option, config_file, user, master_proxy, scom, print_command=False, short_circuit=True, output=True, tty=False) for line in output.splitlines(): if line.startswith('nameserver'): host = line.strip().split()[1] dns_hosts.append(host) return (mesos_hosts, dns_hosts)
def _list_components(leader, slave, use_json): """ List components for a leader or slave_ip node :param leader: use leader ip flag :type leader: bool :param slave_ip: agent ip address :type slave_ip: str :param use_json: print components in json format :type use_json: bool """ if not (leader or slave): raise DCOSException('--leader or --mesos-id must be provided') if leader and slave: raise DCOSException( 'Unable to use leader and mesos id at the same time') slave_ip = _get_slave_ip(slave) if slave_ip: print_components(slave_ip, use_json) return leaders = mesos.MesosDNSClient().hosts('leader.mesos') if len(leaders) != 1: raise DCOSException('Expecting one leader. Got {}'.format(leaders)) if 'ip' not in leaders[0]: raise DCOSException( 'Invalid leader response, missing field `ip`. ' 'Got {}'.format(leaders[0])) print_components(leaders[0]['ip'], use_json)
def _ssh(leader, slave, option, config_file, user, master_proxy, proxy_ip, private_ip, command): """SSH into a DC/OS node using the IP addresses found in master's state.json :param leader: True if the user has opted to SSH into the leading master :type leader: bool | None :param slave: The slave ID if the user has opted to SSH into a slave :type slave: str | None :param option: SSH option :type option: [str] :param config_file: SSH config file :type config_file: str | None :param user: SSH user :type user: str | None :param master_proxy: If True, SSH-hop from a master :type master_proxy: bool | None :param proxy_ip: If set, SSH-hop from this IP address :type proxy_ip: str | None :param private_ip: The private IP address of the node we want to SSH to. :type private_ip: str | None :param command: Command to run on the node :type command: str | None :rtype: int :returns: process return code """ dcos_client = mesos.DCOSClient() if leader: host = mesos.MesosDNSClient().leader()[0]['ip'] elif private_ip: host = private_ip else: summary = dcos_client.get_state_summary() slave_obj = next( (slave_ for slave_ in summary['slaves'] if slave_['id'] == slave), None) if slave_obj: host = mesos.parse_pid(slave_obj['pid'])[1] else: raise DCOSException('No slave found with ID [{}]'.format(slave)) if command is None: command = '' ssh_options = ssh_util.get_ssh_options(config_file, option, user, proxy_ip, master_proxy) cmd = "ssh {0} {1} -- {2}".format(ssh_options, host, command) emitter.publish(DefaultError("Running `{}`".format(cmd))) if not master_proxy and not proxy_ip: emitter.publish( DefaultError("If you are running this command from a separate " "network than DC/OS, consider using " "`--master-proxy` or `--proxy-ip`")) return subprocess.Subproc().call(cmd, shell=True)
def get_host(host): if not host: dcos_client = mesos.DCOSClient() host = dcos_client.metadata().get('PUBLIC_IPV4') if not host: host = mesos.MesosDNSClient().hosts('leader.mesos.')[0]['ip'] if not host: raise DCOSException("*** No host detected. Please set one manually.") return host
def __init__(self, ssh_client, r_addroute, r_delroute, disablevips, disableoverlay): self.dcos_client = mesos.DCOSClient() self.dns_client = mesos.MesosDNSClient() self.ssh_client = ssh_client self.addroute = marshal_networks(r_addroute) self.delroute = marshal_networks(r_delroute) self.disablevips = disablevips self.disableoverlay = disableoverlay
def _list(json_, extra_field_names): """List DC/OS nodes :param json_: If true, output json. Otherwise, output a human readable table. :type json_: bool :param extra_field_names: List of additional field names to include in table output :type extra_field_names: [str] :returns: process return code :rtype: int """ client = mesos.DCOSClient() masters = mesos.MesosDNSClient().masters() master_state = client.get_master_state() slaves = client.get_state_summary()['slaves'] for master in masters: if master['ip'] == master_state['hostname']: master['type'] = 'master (leader)' region, zone = util.get_fault_domain(master_state) master['region'] = region master['zone'] = zone for key in ('id', 'pid', 'version'): master[key] = master_state.get(key) else: master['type'] = 'master' for slave in slaves: region, zone = util.get_fault_domain(slave) slave['type'] = 'agent' slave['region'] = region slave['zone'] = zone nodes = masters + slaves if json_: emitter.publish(nodes) else: for extra_field_name in extra_field_names: field_name = extra_field_name.split(':')[-1] if len(slaves) > 0: try: tables._dotted_itemgetter(field_name)(slaves[0]) except KeyError: emitter.publish( errors.DefaultError('Field "%s" is invalid.' % field_name)) return table = tables.node_table(nodes, extra_field_names) output = six.text_type(table) if output: emitter.publish(output) else: emitter.publish(errors.DefaultError('No agents found.'))
def setup_universe_server(): # Add test repos to Marathon and Cosmos for name, url in UNIVERSE_TEST_REPOS.items(): add_app('tests/data/' + name + '.json', False) watch_all_deployments() # wait for DNS records for the universe app to be propagated host = urlparse(url).netloc for i in range(30): for record in mesos.MesosDNSClient().hosts(host): if record['host'] == host and record['ip'] != '': break time.sleep(1) assert_command(['dcos', 'package', 'repo', 'add', name, url])
def show_leader(self, json_): """ Returns the Marathon leader in the cluster :param json_: output json if True :type json_: bool :returns: process return code :rtype: int """ hosts = mesos.MesosDNSClient().hosts('marathon.mesos') leader = hosts[0] if json_: emitter.publish(leader) else: table = tables.dns_table(hosts) emitter.publish(table) return 0
def ping(self, once): """ Pings the marathon client X times where X is the number of masters. :param once: run ping once regardless of number of masters :type once: bool :returns: str response :rtype: str """ if once: count = 1 else: count = len(mesos.MesosDNSClient().masters()) consecutive_count = 0 client = self._create_marathon_client() timeout = 10 @retrying.retry(stop_max_delay=timeout*1000) def ping_for_each_master(): nonlocal consecutive_count try: response = client.ping() consecutive_count = consecutive_count + 1 except Exception: consecutive_count = 0 if consecutive_count < count: msg = 'The consecutive count: {} is less than master count: {}' raise DCOSException(msg.format(consecutive_count, count)) else: return response try: response = ping_for_each_master() except Exception: response = 'Unable to get ping for all {} masters in {}s'.format( count, timeout ) emitter.publish('Marathon ping response[{}x]: {}'.format( count, response )) return 0
def gen_hosts(ssh_client): dcos_client = mesos.DCOSClient() mesos_hosts = [] dns_hosts = [] for host in mesos.MesosDNSClient().hosts('master.mesos.'): mesos_hosts.append(host['ip']) summary = dcos_client.get_state_summary() for host in summary['slaves']: mesos_hosts.append(host['hostname']) scom = 'cat /etc/resolv.conf' _, query_stdout, _ = ssh_client.exec_command(scom, get_pty=True) for line in query_stdout.readlines(): if line.startswith('nameserver'): host = line.strip().split()[1] dns_hosts.append(host) return (mesos_hosts, dns_hosts)
def setup_universe_server(): # add both Unvierse servers with static packages add_app('tests/data/universe-v3-stub.json', False) add_app('tests/data/helloworld-v3-stub.json', False) assert_command(['dcos', 'package', 'repo', 'remove', 'Universe']) watch_all_deployments() # Add the two test repos to Cosmos for name, url in UNIVERSE_TEST_REPOS.items(): # wait for DNS records for the universe app to be propagated host = urlparse(url).netloc for i in range(30): for record in mesos.MesosDNSClient().hosts(host): if record['host'] == host and record['ip'] != '': break time.sleep(1) assert_command(['dcos', 'package', 'repo', 'add', name, url])
def _ssh(master, slave, option, config_file, user): """SSH into a DCOS node using the IP addresses found in master's state.json :param master: True if the user has opted to SSH into the leading master :type master: bool | None :param slave: The slave ID if the user has opted to SSH into a slave :type slave: str | None :param option: SSH option :type option: [str] :param config_file: SSH config file :type config_file: str | None :param user: SSH user :type user: str | None :rtype: int :returns: process return code """ ssh_options = util.get_ssh_options(config_file, option) if master: host = mesos.MesosDNSClient().hosts('leader.mesos.')[0]['ip'] else: summary = mesos.DCOSClient().get_state_summary() slave_obj = next((slave_ for slave_ in summary['slaves'] if slave_['id'] == slave), None) if slave_obj: host = mesos.parse_pid(slave_obj['pid'])[1] else: raise DCOSException('No slave found with ID [{}]'.format(slave)) cmd = "ssh -t {0}{1}@{2}".format( ssh_options, user, host) emitter.publish(DefaultError("Running `{}`".format(cmd))) return subprocess.call(cmd, shell=True)
def _dns_lookup(dns_name, json_): """ Returns the IP of the dns-name in the cluster :param dns_name: dns name to lookup :type dns_name: string :param json_: If true, output json. Otherwise, output a human readable table. :type json_: bool """ ips = mesos.MesosDNSClient().hosts(dns_name) if json_: emitter.publish(ips) else: table = tables.dns_table(ips) output = six.text_type(table) if output: emitter.publish(output) return 0
def _ssh(leader, slave, option, config_file, user, master_proxy, proxy_ip, command): """SSH into a DC/OS node using the IP addresses found in master's state.json :param leader: True if the user has opted to SSH into the leading master :type leader: bool | None :param slave: The slave ID if the user has opted to SSH into a slave :type slave: str | None :param option: SSH option :type option: [str] :param config_file: SSH config file :type config_file: str | None :param user: SSH user :type user: str | None :param master_proxy: If True, SSH-hop from a master :type master_proxy: bool | None :param proxy_ip: If set, SSH-hop from this IP address :type proxy_ip: str | None :param command: Command to run on the node :type command: str | None :rtype: int :returns: process return code """ ssh_options = util.get_ssh_options(config_file, option) dcos_client = mesos.DCOSClient() if leader: host = mesos.MesosDNSClient().hosts('leader.mesos.')[0]['ip'] else: summary = dcos_client.get_state_summary() slave_obj = next((slave_ for slave_ in summary['slaves'] if slave_['id'] == slave), None) if slave_obj: host = mesos.parse_pid(slave_obj['pid'])[1] else: raise DCOSException('No slave found with ID [{}]'.format(slave)) if command is None: command = '' master_public_ip = dcos_client.metadata().get('PUBLIC_IPV4') if master_proxy: if not master_public_ip: raise DCOSException(("Cannot use --master-proxy. Failed to find " "'PUBLIC_IPV4' at {}").format( dcos_client.get_dcos_url('metadata'))) proxy_ip = master_public_ip if proxy_ip: if not os.environ.get('SSH_AUTH_SOCK'): raise DCOSException( "There is no SSH_AUTH_SOCK env variable, which likely means " "you aren't running `ssh-agent`. `dcos node ssh " "--master-proxy/--proxy-ip` depends on `ssh-agent` to safely " "use your private key to hop between nodes in your cluster. " "Please run `ssh-agent`, then add your private key with " "`ssh-add`.") cmd = "ssh -A -t {0}{1}@{2} ssh -A -t {0}{1}@{3} {4}".format( ssh_options, user, proxy_ip, host, command) else: cmd = "ssh -t {0}{1}@{2} {3}".format( ssh_options, user, host, command) emitter.publish(DefaultError("Running `{}`".format(cmd))) if (not master_proxy and not proxy_ip) and master_public_ip: emitter.publish( DefaultError("If you are running this command from a separate " "network than DC/OS, consider using " "`--master-proxy` or `--proxy-ip`")) return subprocess.Subproc().call(cmd, shell=True)
def _ssh(leader, slave, option, config_file, user, master_proxy, command, flag=[], print_command=True, short_circuit=False, output=False, output_dst=None, tty=True, raw=False): """SSH into a DCOS node using the IP addresses found in master's state.json :param leader: True if the user has opted to SSH into the leading master :type leader: bool | None :param slave: The slave ID if the user has opted to SSH into a slave :type slave: str | None :param option: SSH option :type option: [str] :param config_file: SSH config file :type config_file: str | None :param user: SSH user :type user: str | None :param master_proxy: If True, SSH-hop from a master :type master_proxy: bool | None :param command: Command to run on the node :type command: str | None :param flag: SSH flags :type flag: [str] :param print_command: If True, print the raw SSH command :type print_command: bool :param short_circuit: Only use the first SSH connection made :type short_circuit: bool :param output: If True, return the output of the ssh command :type output: boolean :param output_dst: Where to send the output of SSH :type output_dst: object | None :param tty: If True, have SSH allocate a TTY :type tty: boolean :param raw: If True, return a subprocess.Popen object :type raw: boolean :rtype: int :returns: process return code | str """ ssh_options = util.get_ssh_options(config_file, option) dcos_client = mesos.DCOSClient() flagstr = " ".join(flag) if tty: flagstr += ' -t' else: flagstr += ' -T' if leader: host = mesos.MesosDNSClient().hosts('leader.mesos.')[0]['ip'] else: summary = dcos_client.get_state_summary() slave_obj = next( (slave_ for slave_ in summary['slaves'] if slave_['id'] == slave), None) if slave_obj: host = mesos.parse_pid(slave_obj['pid'])[1] else: raise DCOSException('No slave found with ID [{}]'.format(slave)) if command is None: command = '' master_public_ip = dcos_client.metadata().get('PUBLIC_IPV4') if master_proxy: if not os.environ.get('SSH_AUTH_SOCK'): raise DCOSException( "There is no SSH_AUTH_SOCK env variable, which likely means " "you aren't running `ssh-agent`. `dcos node ssh " "--master-proxy` depends on `ssh-agent` to safely use your " "private key to hop between nodes in your cluster. Please " "run `ssh-agent`, then add your private key with `ssh-add`.") if not master_public_ip: raise DCOSException(("Cannot use --master-proxy. Failed to find " "'PUBLIC_IPV4' at {}").format( dcos_client.get_dcos_url('metadata'))) cmd = "ssh -A {0} {1}{2}@{3} ssh {0} {1}{2}@{4} {5}" if short_circuit: cmd = "ssh -A {0} {1}{2}@{3} {5}" cmd = cmd.format(flagstr, ssh_options, user, master_public_ip, host, command) else: cmd = "ssh {0} {1}{2}@{3} {4}".format(flagstr, ssh_options, user, host, command) if print_command: emitter.publish(DefaultError("Running `{}`".format(cmd))) if (not master_proxy) and master_public_ip: emitter.publish( DefaultError("If you are running this command from a separate " "network than DC/OS, consider using " "`--master-proxy`")) cmd = shlex.split(cmd) if output: return subprocess.check_output(cmd) if raw: if output_dst is not None: return subprocess.Popen(cmd, stderr=output_dst, stdout=output_dst) return subprocess.Popen(cmd) if output_dst is not None: return subprocess.call(cmd, stderr=output_dst, stdout=output_dst) return subprocess.call(cmd)