Skip to content

Commit

Permalink
custom args, list formatting
Browse files Browse the repository at this point in the history
  • Loading branch information
jiri_otoupal authored and jiri_otoupal committed Mar 6, 2024
1 parent 86150b8 commit 929d0a6
Show file tree
Hide file tree
Showing 6 changed files with 67 additions and 28 deletions.
13 changes: 5 additions & 8 deletions abst/__version__.py
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,16 @@
"CLI Command making OCI Bastion and kubernetes usage simple and fast"
)

__version__ = "2.3.23"
__version__ = "2.3.24"
__author__ = "Jiri Otoupal"
__author_email__ = "jiri-otoupal@ips-database.eu"
__license__ = "MIT"
__url__ = "https://github.com/jiri-otoupal/abst"
__pypi_repo__ = "https://pypi.org/project/abst/"

__version_name__ = "Octopus X0"
__version_name__ = "Formatted Giraffe"
__change_log__ = """
* Added alias to context, now you can use 'ctx'\n
* Sharing and Pasting now works for sets too, you can use set_name/context for both\n
* When pasting, it will ask if you want to change IP and for bastion name renaming\n
* Removed unused packages\n
* Fixed filename .json search\n
* Abst is filtering not json files from context search\n
* Added new option to context config so user can input custom ssh arguments to 'ssh-custom-arguments' key in context\n
* Listing context will show last usage time\n
* Changed formatting of 'abst context list' and 'abst parallel list'\n
"""
29 changes: 23 additions & 6 deletions abst/bastion_support/oci_bastion.py
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,13 @@ def __init__(self, context_name=None, region=None, direct_json_path=None):
self.response: Optional[dict] = None
self._current_status = None
self.direct_json_path = direct_json_path
self.__mark_used__()

def __mark_used__(self):
cfg_path = Bastion.get_creds_path_resolve(self.context_name)
context_cfg = Bastion.load_json(cfg_path)
context_cfg["last-time-used"] = datetime.datetime.now().isoformat()
Bastion.write_creds_json(context_cfg, cfg_path)

@property
def current_status(self):
Expand Down Expand Up @@ -134,6 +141,7 @@ def create_managed_loop(self, shell: bool = False):
port = target_details["target_resource_port"]
private_key_path = creds.get("private-key-path", conf.get("private-key-path",
"No supplied private key"))
user_custom_options = creds.get("ssh-custom-arguments", "")

if private_key_path == "No supplied private key":
rich.print("[red]No private key in credentials and config specified[/red]")
Expand All @@ -151,7 +159,7 @@ def create_managed_loop(self, shell: bool = False):
creds[
"resource-os-username"],
ip, port,
shell)
shell, user_custom_options)
logging.info(f"SSH tunnel exited with code {exit_code}")
if exit_code == 0:
print(f"User requested termination {self.get_print_name()}")
Expand Down Expand Up @@ -215,10 +223,11 @@ def create_forward_loop(self, shell: bool = False, force: bool = False):

self.current_status = "digging tunnel"

user_custom_args = creds.get("ssh-custom-arguments", "")
ssh_tunnel_arg_str = self.run_ssh_tunnel_port_forward(bid, host, ip, port,
shell,
creds.get("local-port", 22),
ssh_pub_key_path, force)
ssh_pub_key_path, force, user_custom_args)

while status := (sdata := self.get_bastion_state())[
"lifecycle_state"] == "ACTIVE" and \
Expand All @@ -236,11 +245,15 @@ def create_forward_loop(self, shell: bool = False, force: bool = False):

def run_ssh_tunnel_managed_session(self, bid, host, private_key_path, username,
ip, port,
shell):
shell, custom_user_options: str = ""):
if custom_user_options:
print(
"[yellow][WARNING] Having custom ssh arguments can prevent your ssh command from working[/yellow]")

print(f"Bastion {self.get_print_name()} initialized")
print(f"Initializing SSH Tunnel for {self.get_print_name()}")

ssh_tunnel_arg_str = (f'ssh -i {private_key_path} {self.custom_ssh_options} '
ssh_tunnel_arg_str = (f'ssh -i {private_key_path} {self.custom_ssh_options} {custom_user_options}'
f'-o ProxyCommand="ssh -i {private_key_path} -W %h:%p -p {port} {bid}@{host} -A" -p {port} '
f'{username}@{ip} -A')
logging.info(f"Running ssh command {ssh_tunnel_arg_str}")
Expand All @@ -250,13 +263,17 @@ def run_ssh_tunnel_managed_session(self, bid, host, private_key_path, username,
return ssh_tunnel_arg_str, exit_code

def run_ssh_tunnel_port_forward(self, bid, host, ip, port, shell, local_port,
ssh_pub_key_path, force=False):
ssh_pub_key_path, force=False, custom_user_options: str = ""):
if custom_user_options:
print(
"[yellow][WARNING] Having custom ssh arguments can prevent your ssh command from working[/yellow]")

print(f"Bastion {self.get_print_name()} initialized")
print(f"Initializing SSH Tunnel for {self.get_print_name()}")
additional_args = "" if not force else self.force_ssh_options

ssh_tunnel_arg_str = (
f"ssh {self.custom_ssh_options} -N -L {local_port}:{ip}:{port} -p 22 {bid}@{host} "
f"ssh {self.custom_ssh_options} {custom_user_options} -N -L {local_port}:{ip}:{port} -p 22 {bid}@{host} "
f"-vvv -i {ssh_pub_key_path.strip('.pub')} {additional_args}")
logging.info(f"Running ssh command {ssh_tunnel_arg_str}")
exit_code = self.__run_ssh_tunnel(ssh_tunnel_arg_str, shell)
Expand Down
4 changes: 2 additions & 2 deletions abst/cfg_func.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,13 @@
from InquirerPy import inquirer

from abst.bastion_support.oci_bastion import Bastion
from abst.config import default_config_keys, default_contexts_location, default_parallel_sets_location
from abst.config import default_context_keys, default_contexts_location, default_parallel_sets_location


def __upgrade(context_name, path, _all):
if not _all:
creds_json_ro = Bastion.load_json(Bastion.get_creds_path_resolve(context_name))
missing_keys = set(default_config_keys).difference(creds_json_ro.keys())
missing_keys = set(default_context_keys).difference(creds_json_ro.keys())
res_json = dict(creds_json_ro)
for key in missing_keys:
res_json[key] = "!!! New Key !!! <- This was upgraded"
Expand Down
14 changes: 12 additions & 2 deletions abst/cli_commands/context/commands.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
import pyperclip
import rich
from InquirerPy import inquirer
from rich.tree import Tree

from abst.bastion_support.oci_bastion import Bastion
from abst.config import default_contexts_location, share_excluded_keys
Expand All @@ -28,9 +29,18 @@ def ctx():
@click.option("--debug", is_flag=True, default=False)
def _list(debug=False):
setup_calls(debug)
rich.print("Contexts:")

tree = Tree("Contexts")

for file in Path(default_contexts_location).iterdir():
rich.print(f" {file.name.replace('.json', '')}")
cfg = Bastion.load_json(file)
used_time = "" if "last-time-used" not in cfg.keys() else f"| Used: {cfg['last-time-used']}"
tree.add(f"{file.name.replace('.json', '')} {used_time}")

if not len(tree.children):
rich.print("No contexts")

rich.print(tree)


@context.command(help="Will display JSON format of context")
Expand Down
28 changes: 21 additions & 7 deletions abst/cli_commands/parallel/commands.py
Original file line number Diff line number Diff line change
@@ -1,9 +1,13 @@
from pathlib import Path

import click
import rich
from InquirerPy import inquirer
from rich.tree import Tree

from abst.bastion_support.bastion_scheduler import BastionScheduler
from abst.config import default_parallel_sets_location
from abst.bastion_support.oci_bastion import Bastion
from abst.config import default_parallel_sets_location, default_contexts_location
from abst.tools import display_scheduled
from abst.utils.misc_funcs import setup_calls

Expand Down Expand Up @@ -64,15 +68,23 @@ def create(debug, set_name):
@click.option("--debug", is_flag=True, default=False)
def _list(debug):
setup_calls(debug)
rich.print("Sets in parallel folder")
tree = Tree("Sets in parallel folder")

for _set in default_parallel_sets_location.iterdir():
if _set.name.startswith(".") and not _set.name.endswith(".json"):
continue
rich.print(f" {_set.name}")
leaf = tree.add(f"{_set.name.replace('.json', '')}")
for ctx in _set.iterdir():
cfg = Bastion.load_json(ctx)
used_time = "" if "last-time-used" not in cfg.keys() else f"| last time used {cfg['last-time-used']}"
if ctx.name.startswith("."):
continue
rich.print(f" {ctx.name.replace('.json', '')}")
leaf.add(f"{ctx.name.replace('.json', '')} {used_time}")

if not len(tree.children):
rich.print("No contexts")

rich.print(tree)


@parallel.command("remove", help="Remove Bastion from stack (Can not remove sets)")
Expand All @@ -87,13 +99,15 @@ def remove(debug, context_name):
@parallel.command("run", help="Run All Bastions in fullauto")
@click.option("--debug", is_flag=True, default=False)
@click.option("-y", is_flag=True, default=False, help="Automatically confirm")
@click.option("-f", "--force", is_flag=True, default=False, help="Will force connections ignoring security policies")
@click.option("-f", "--force", is_flag=True, default=False,
help="Will force connections ignoring security policies")
@click.argument("set_name", default=None, required=False, type=str)
def run(debug, y, force, set_name=None):
setup_calls(debug)
if force:
rich.print("[red]Running in force mode[/red][gray] this mode is less secure as it is ignoring key checking and"
" security policies involving known_hosts[/gray]")
rich.print(
"[red]Running in force mode[/red][gray] this mode is less secure as it is ignoring key checking and"
" security policies involving known_hosts[/gray]")
if set_name:
set_dir = get_set_dir(set_name)
else:
Expand Down
7 changes: 4 additions & 3 deletions abst/config.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,17 @@
default_contexts_location: Path = (Path().home().resolve() / ".abst" / "contexts")
default_parallel_sets_location: Path = (Path().home().resolve() / ".abst" / "sets")

default_config_keys: tuple = (
default_context_keys: tuple = (
"host", "bastion-id", "default-name", "ssh-pub-path", "private-key-path", "target-ip",
"local-port", "target-port", "ttl", "resource-id", "resource-os-username", "region")
"local-port", "target-port", "ttl", "resource-id", "resource-os-username", "region",
"ssh-custom-arguments")
default_stack_contents: dict = {"stack": []}
default_conf_contents: dict = {"used_context": None, "private-key-path": "~/.ssh/id_rsa",
"ssh-pub-path": "~/.ssh/id_rsa"
".pub"}

# Share Config
share_excluded_keys: tuple = ("private-key-path", "ssh-pub-path")
share_excluded_keys: tuple = ("private-key-path", "ssh-pub-path", "last-time-used")


def get_public_key(ssh_path):
Expand Down

0 comments on commit 929d0a6

Please sign in to comment.