Skip to content

Commit

Permalink
Merge branch 'master' into master
Browse files Browse the repository at this point in the history
  • Loading branch information
seeker89 committed Mar 16, 2019
2 parents a44d565 + cb92017 commit 8157122
Show file tree
Hide file tree
Showing 13 changed files with 119 additions and 35 deletions.
23 changes: 23 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,8 @@ usage: seal interactive [-h] --kubeconfig KUBECONFIG
[--remote-user REMOTE_USER]
[--ssh-allow-missing-host-keys]
[--ssh-path-to-private-key SSH_PATH_TO_PRIVATE_KEY]
[--ssh-password SSH_PASSWORD]
[--use-private-ip]

optional arguments:
-h, --help show this help message and exit
Expand Down Expand Up @@ -95,6 +97,9 @@ SSH settings:
Allow connection to hosts not present in known_hosts
--ssh-path-to-private-key SSH_PATH_TO_PRIVATE_KEY
Path to ssh private key
--ssh-password SSH_PASSWORD
ssh password
--use-private-ip Use the private IP of each node (vs public IP)
```
Expand Down Expand Up @@ -123,6 +128,8 @@ usage: seal autonomous [-h] --kubeconfig KUBECONFIG
[--remote-user REMOTE_USER]
[--ssh-allow-missing-host-keys]
[--ssh-path-to-private-key SSH_PATH_TO_PRIVATE_KEY]
[--ssh-password SSH_PASSWORD]
[--use-private-ip]
--policy-file POLICY_FILE
[--stdout-collector | --prometheus-collector]
[--prometheus-host PROMETHEUS_HOST]
Expand Down Expand Up @@ -157,6 +164,9 @@ SSH settings:
Allow connection to hosts not present in known_hosts
--ssh-path-to-private-key SSH_PATH_TO_PRIVATE_KEY
Path to ssh private key
--ssh-password SSH_PASSWORD
ssh password
--use-private-ip Use the private IP of each node (vs public IP)
Policy settings:
--policy-file POLICY_FILE
Expand Down Expand Up @@ -259,6 +269,8 @@ usage: seal label [-h] --kubeconfig KUBECONFIG
(-i INVENTORY_FILE | --inventory-kubernetes)
[--remote-user REMOTE_USER] [--ssh-allow-missing-host-keys]
[--ssh-path-to-private-key SSH_PATH_TO_PRIVATE_KEY]
[--ssh-password SSH_PASSWORD]
[--use-private-ip]
[--kubernetes-namespace KUBERNETES_NAMESPACE]
[--min-seconds-between-runs MIN_SECONDS_BETWEEN_RUNS]
[--max-seconds-between-runs MAX_SECONDS_BETWEEN_RUNS]
Expand Down Expand Up @@ -294,6 +306,9 @@ SSH settings:
Allow connection to hosts not present in known_hosts
--ssh-path-to-private-key SSH_PATH_TO_PRIVATE_KEY
Path to ssh private key
--ssh-password SSH_PASSWORD
ssh password
--use-private-ip Use the private IP of each node (vs public IP)
Kubernetes options:
--kubernetes-namespace KUBERNETES_NAMESPACE
Expand Down Expand Up @@ -336,6 +351,8 @@ usage: seal demo [-h] --kubeconfig KUBECONFIG
(-i INVENTORY_FILE | --inventory-kubernetes)
[--remote-user REMOTE_USER] [--ssh-allow-missing-host-keys]
[--ssh-path-to-private-key SSH_PATH_TO_PRIVATE_KEY]
[--ssh-password SSH_PASSWORD]
[--use-private-ip]
[--kubernetes-namespace KUBERNETES_NAMESPACE]
[--min-seconds-between-runs MIN_SECONDS_BETWEEN_RUNS]
[--max-seconds-between-runs MAX_SECONDS_BETWEEN_RUNS]
Expand Down Expand Up @@ -372,6 +389,9 @@ SSH settings:
Allow connection to hosts not present in known_hosts
--ssh-path-to-private-key SSH_PATH_TO_PRIVATE_KEY
Path to ssh private key
--ssh-password SSH_PASSWORD
ssh password
--use-private-ip Use the private IP of each node (vs public IP)
Kubernetes options:
--kubernetes-namespace KUBERNETES_NAMESPACE
Expand Down Expand Up @@ -437,6 +457,7 @@ seal \
--ssh-allow-missing-host-keys \
--remote-user docker \
--ssh-path-to-private-key `minikube ssh-key` \
--ssh-password `minikube ssh-password` \
--override-ssh-host `minikube ip`
```
Expand All @@ -453,6 +474,7 @@ seal \
--ssh-allow-missing-host-keys \
--remote-user docker \
--ssh-path-to-private-key `minikube ssh-key` \
--ssh-password `minikube ssh-password` \
--override-ssh-host `minikube ip`
```
Expand All @@ -471,6 +493,7 @@ seal \
--ssh-allow-missing-host-keys \
--remote-user docker \
--ssh-path-to-private-key `minikube ssh-key` \
--ssh-password `minikube ssh-password` \
--override-ssh-host `minikube ip` \
--host 0.0.0.0 \
--port 30100
Expand Down
33 changes: 27 additions & 6 deletions powerfulseal/cli/__main__.py
Original file line number Diff line number Diff line change
Expand Up @@ -62,18 +62,30 @@ def add_ssh_options(parser):
action='store_true',
help='Allow connection to hosts not present in known_hosts',
)
args_ssh.add_argument(
'--ssh-path-to-private-key',
default=os.environ.get("PS_PRIVATE_KEY"),
help='Path to ssh private key',
)
args_ssh.add_argument(
'--override-ssh-host',
help=(
'If you\'d like to execute all commands on a different host '
'(for example for minikube) you can override it here'
)
)
args_ssh.add_argument(
'--use-private-ip',
default=False,
action='store_true',
help='Use the private IP of each node (vs public IP)',
)
ssh_options = args_ssh.add_mutually_exclusive_group()
ssh_options.add_argument(
'--ssh-path-to-private-key',
default=os.environ.get("PS_PRIVATE_KEY"),
help='Path to ssh private key',
)
ssh_options.add_argument(
'--ssh-password',
default=os.environ.get("PS_SSH_PASSWORD"),
help='ssh password',
)

def add_inventory_options(parser):
# Inventory
Expand Down Expand Up @@ -200,7 +212,6 @@ def check_valid_port(value):
return parsed



def parse_args(args):
parser = ArgumentParser(
config_file_parser_class=YAMLConfigFileParser,
Expand Down Expand Up @@ -395,6 +406,9 @@ def main(argv):
logger.addHandler(stdout_handler)
coloredlogs.install(logger=logger)

my_verb = args.verbose
logger.info("modules %s : verbosity %s : log level %s : handler level %s ", __name__, my_verb, logging.getLevelName(logger.getEffectiveLevel()), logging.getLevelName(log_level) )

##########################################################################
# KUBERNETES
##########################################################################
Expand Down Expand Up @@ -441,11 +455,15 @@ def main(argv):
##########################################################################
# SSH EXECUTOR
##########################################################################
if args.use_private_ip:
logger.info("Using each node's private IP address")
executor = RemoteExecutor(
user=args.remote_user,
ssh_allow_missing_host_keys=args.ssh_allow_missing_host_keys,
ssh_path_to_private_key=args.ssh_path_to_private_key,
override_host=args.override_ssh_host,
ssh_password=args.ssh_password,
use_private_ip=args.use_private_ip,
)

##########################################################################
Expand All @@ -463,6 +481,9 @@ def main(argv):
while True:
try:
cmd.cmdloop()
except GeneratorExit:
print("Exiting")
sys.exit(0)
except KeyboardInterrupt:
print()
print("Ctrl-c again to quit")
Expand Down
7 changes: 7 additions & 0 deletions powerfulseal/cli/pscmd.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
"node": "blue",
"pod": "blue",
"ip": "yellow",
"extIp": "yellow",
}
# couple of helpers
def colour_output(output, extras=None):
Expand Down Expand Up @@ -115,6 +116,12 @@ def completedefault(self, text, line, begidx, endidx):

return suggestions

###########################################################################
# CLI control
###########################################################################
def do_exit(self, line):
"Exit CLI"
raise GeneratorExit

###########################################################################
# NODE (MACHINE) RELATED FUNCTIONALITY
Expand Down
14 changes: 6 additions & 8 deletions powerfulseal/clouddrivers/aws_driver.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ def create_connection_from_config():
return conn

def get_all_ips(instance):
""" Returns the private and public ip address of an AWS EC2 instances
""" Returns the public and private ip addresses of an AWS EC2 instances
"""
output = []
output.append(instance.private_ip_address)
Expand All @@ -27,12 +27,13 @@ def get_all_ips(instance):
def server_status_to_state(status):
return MAPPING_STATES_STATUS.get(status['Name'].upper(), NodeState.UNKNOWN)

def create_node_from_server(server, ip):
def create_node_from_server(server):
""" Translate AWS EC2 Instance representation into a Node object.
"""
return Node(
id=server.id,
ip=ip,
ip=server.private_ip_address,
extIp=server.public_ip_address,
az=server.placement['AvailabilityZone'],
name="",
state=server_status_to_state(server.state),
Expand All @@ -49,9 +50,6 @@ def __init__(self, cloud=None, conn=None, logger=None):
self.instances = []

def sync(self):
""" Downloads a fresh set of nodes form the API.
"""
self.logger.info("Synchronizing remote nodes")
""" Downloads a fresh set of nodes form the API.
"""
self.logger.info("Synchronizing remote nodes")
Expand All @@ -65,11 +63,11 @@ def get_by_ip(self, ip):
for server in self.remote_servers:
addresses = get_all_ips(server)
if not addresses:
self.logger.warning("No addresses found: %s", server)
self.logger.warning("No ip addresses found: %s", server)
else:
for addr in addresses:
if addr == ip:
return create_node_from_server(server, ip)
return create_node_from_server(server)
return None

def stop(self, node):
Expand Down
4 changes: 4 additions & 0 deletions powerfulseal/clouddrivers/driver.py
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,10 @@ class AbstractDriver():
"""
Abstract class representing a cloud driver.
All concrete drivers should implement this.
NOTE: node.extIp should be an accessible IP.
It should the same as node.ip if there is
no separate public IP.
"""

@abc.abstractmethod
Expand Down
1 change: 1 addition & 0 deletions powerfulseal/clouddrivers/no_cloud_driver.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ def get_by_ip(self, ip):
return Node(
id="fake-{ip}".format(ip=ip),
ip=ip,
extIp=ip,
az="nope",
name="local-{ip}".format(ip=ip),
state=NodeState.UNKNOWN
Expand Down
2 changes: 2 additions & 0 deletions powerfulseal/clouddrivers/open_stack_driver.py
Original file line number Diff line number Diff line change
Expand Up @@ -51,10 +51,12 @@ def server_status_to_state(status):

def create_node_from_server(server):
""" Translate OpenStack server representation into a Node object.
Same IP for private (ip) and public IPs (extIp)
"""
return Node(
id=server.id,
ip=get_all_ips(server)[-1],
extIp=get_all_ips(server)[-1],
az=server.availability_zone,
name=server.name,
state=server_status_to_state(server.status),
Expand Down
37 changes: 27 additions & 10 deletions powerfulseal/execute/remote_executor.py
Original file line number Diff line number Diff line change
Expand Up @@ -28,38 +28,55 @@ class RemoteExecutor(object):

def __init__(self, nodes=None, user="cloud-user",
ssh_allow_missing_host_keys=False, ssh_path_to_private_key=None,
override_host=None, logger=None):
ssh_password=None, override_host=None, use_private_ip=False, logger=None):
self.nodes = nodes or []
self.user = user
self.missing_host_key = (spur.ssh.MissingHostKey.accept
if ssh_allow_missing_host_keys
else spur.ssh.MissingHostKey.raise_error)
self.ssh_path_to_private_key = ssh_path_to_private_key
self.ssh_password = ssh_password
self.override_host = override_host
self.use_private_ip = use_private_ip
self.logger = logger or logging.getLogger(__name__)

def execute(self, cmd, nodes=None, debug=False):
def execute(self, cmd, nodes=None, use_private_ip=None, debug=False):
nodes = nodes or self.nodes
use_private_ip = use_private_ip or self.use_private_ip
results = dict()
cmd_full = self.PREFIX + [cmd]
for node in nodes:
shell = spur.SshShell(
hostname=self.override_host or node.ip,
username=self.user,
missing_host_key=self.missing_host_key,
private_key_file=self.ssh_path_to_private_key,
)
hostip = node.extIp
if use_private_ip:
hostip = node.ip
if self.override_host:
hostip = self.override_host
if self.ssh_password is not None:
shell = spur.SshShell(
hostname=hostip,
username=self.user,
missing_host_key=self.missing_host_key,
password=self.ssh_password,
)
else:
shell = spur.SshShell(
hostname=hostip,
username=self.user,
missing_host_key=self.missing_host_key,
private_key_file=self.ssh_path_to_private_key,
)

self.logger.info("Executing '%s' on %s" % (cmd_full, node.name))
try:
with shell:
output = shell.run(cmd_full)
results[node.ip] = {
results[hostip] = {
"ret_code": output.return_code,
"stdout": output.output.decode(),
"stderr": output.stderr_output.decode(),
}
except Exception as e:
results[node.ip] = {
results[hostip] = {
"ret_code": 1,
"error": str(e),
}
Expand Down
6 changes: 4 additions & 2 deletions powerfulseal/node/node.py
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,12 @@ class Node(object):
"""


def __init__(self, id, name=None, ip=None, az=None,
def __init__(self, id, name=None, ip=None, extIp=None, az=None,
groups=None, no=None, state=None):
self.id = id
self.name = name
self.ip = ip
self.extIp = extIp
self.az = az
self.groups = groups or []
self.no = no
Expand All @@ -49,13 +50,14 @@ def __init__(self, id, name=None, ip=None, az=None,

def __str__(self):
return (
"[node no={no} id={id} ip={ip} az={az} groups={groups} name={name} "
"[node no={no} id={id} ip={ip} extIp={extIp} az={az} groups={groups} name={name} "
"state={state}]"
).format(
no=self.no,
id=self.id,
name=self.name,
ip=self.ip,
extIp=self.extIp,
az=self.az,
groups=self.groups,
state=str(self.state)
Expand Down
Loading

0 comments on commit 8157122

Please sign in to comment.