-
-
Notifications
You must be signed in to change notification settings - Fork 2
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
kubectl command wrapper #172
Merged
Changes from 7 commits
Commits
Show all changes
12 commits
Select commit
Hold shift + click to select a range
dc283e2
kubectl command wrapper
Franr 3e59d38
EOL
Franr e03b6f1
get fresh credentials when spawning the shell too
Franr ee28e60
no need to override these methods
Franr aecb690
development environment explanation
Franr a4351a7
kc alias
Franr ce64aed
configure command
Franr 7afad25
refresh credentials on each run
Franr 0c7ae64
don't assume the position of the aws eks command
Franr da23afb
refresh_aws_credentials to support both SSO and MFA
Franr cc668a8
tests!
Franr 779485d
doc for the command
Franr File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -13,4 +13,6 @@ leverage.egg-info | |
**/__pycache__* | ||
.pytest_cache | ||
coverage | ||
.coverage | ||
.coverage | ||
|
||
.idea |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,80 @@ | ||
import os | ||
import pwd | ||
from pathlib import Path | ||
|
||
from click.exceptions import Exit | ||
from docker.types import Mount | ||
|
||
from leverage import logger | ||
from leverage._utils import chain_commands, EmptyEntryPoint | ||
from leverage.container import TerraformContainer | ||
|
||
|
||
class KubeCtlContainer(TerraformContainer): | ||
"""Container specifically tailored to run kubectl commands.""" | ||
|
||
KUBECTL_CLI_BINARY = "/usr/local/bin/kubectl" | ||
KUBECTL_CONFIG_PATH = Path("/root/.kube") | ||
KUBECTL_CONFIG_FILE = KUBECTL_CONFIG_PATH / Path("config") | ||
|
||
def __init__(self, client): | ||
super().__init__(client) | ||
|
||
self.entrypoint = self.KUBECTL_CLI_BINARY | ||
|
||
host_config_path = str(Path.home() / Path(f".kube/{self.project}")) | ||
self.container_config["host_config"]["Mounts"].append( | ||
# the container is expecting a file named "config" here | ||
Mount( | ||
source=host_config_path, | ||
target=str(self.KUBECTL_CONFIG_PATH), | ||
type="bind", | ||
) | ||
) | ||
|
||
def start_shell(self): | ||
with EmptyEntryPoint(self): | ||
self._start() | ||
|
||
def configure(self): | ||
logger.info("Retrieving k8s cluster information...") | ||
with EmptyEntryPoint(self): | ||
add_eks_cluster_cmd = self._get_eks_kube_config() | ||
|
||
# generate the command that will: configure the new cluster, and also set the proper user on the new config file | ||
change_owner_cmd = self._change_kube_file_owner_cmd() | ||
full_cmd = chain_commands([add_eks_cluster_cmd, change_owner_cmd]) | ||
|
||
logger.info("Configuring context...") | ||
with EmptyEntryPoint(self): | ||
exit_code, output = self._exec(full_cmd) | ||
if exit_code: | ||
logger.error(output) | ||
raise Exit(exit_code) | ||
|
||
logger.info("Done.") | ||
|
||
def _get_eks_kube_config(self) -> str: | ||
self.check_for_layer_location() | ||
|
||
exit_code, output = self._exec(f"{self.TF_BINARY} output") | ||
if exit_code: | ||
logger.error(output) | ||
raise Exit(exit_code) | ||
|
||
aws_eks_cmd = output.split("\n")[10] | ||
# assuming the cluster container is on the primary region | ||
return aws_eks_cmd + f" --region {self.common_conf['region_primary']}" | ||
|
||
def _change_kube_file_owner_cmd(self) -> str: | ||
user_id = os.getuid() | ||
user = pwd.getpwuid(user_id) | ||
group_id = user.pw_gid | ||
|
||
return f"chown {user_id}:{group_id} {self.KUBECTL_CONFIG_FILE}" | ||
|
||
def check_for_layer_location(self): | ||
super(KubeCtlContainer, self).check_for_layer_location() | ||
if self.cwd.parts[-1] != "cluster": | ||
logger.error("This command can only run at the [bold]cluster layer[/bold].") | ||
raise Exit(1) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
from leverage._internals import pass_state | ||
from leverage._internals import pass_container | ||
from leverage.container import get_docker_client | ||
from leverage.containers.kubectl import KubeCtlContainer | ||
|
||
import click | ||
|
||
from leverage.modules.utils import _handle_subcommand | ||
|
||
CONTEXT_SETTINGS = {"ignore_unknown_options": True} | ||
|
||
|
||
@click.group(invoke_without_command=True, context_settings={"ignore_unknown_options": True}) | ||
@click.argument("args", nargs=-1, type=click.UNPROCESSED) | ||
@pass_state | ||
@click.pass_context | ||
def kubectl(context, state, args): | ||
"""Run Kubectl commands in a custom containerized environment.""" | ||
state.container = KubeCtlContainer(get_docker_client()) | ||
state.container.ensure_image() | ||
_handle_subcommand(context=context, cli_container=state.container, args=args) | ||
|
||
|
||
@kubectl.command(context_settings=CONTEXT_SETTINGS) | ||
@pass_container | ||
def shell(kctl: KubeCtlContainer): | ||
"""Spawn a shell with the kubectl credentials pre-configured.""" | ||
kctl.start_shell() | ||
|
||
|
||
@kubectl.command(context_settings=CONTEXT_SETTINGS) | ||
@pass_container | ||
def configure(kctl: KubeCtlContainer): | ||
kctl.configure() |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,34 @@ | ||
from click.exceptions import Exit | ||
|
||
|
||
def _handle_subcommand(context, cli_container, args, caller_name=None): | ||
"""Decide if command corresponds to a wrapped one or not and run accordingly. | ||
|
||
Args: | ||
context (click.context): Current context | ||
cli_container (LeverageContainer): Container where commands will be executed | ||
args (tuple(str)): Arguments received by Leverage | ||
caller_name (str, optional): Calling command. Defaults to None. | ||
|
||
Raises: | ||
Exit: Whenever container execution returns a non-zero exit code | ||
""" | ||
caller_pos = args.index(caller_name) if caller_name is not None else 0 | ||
|
||
# Find if one of the wrapped subcommand was invoked | ||
wrapped_subcommands = context.command.commands.keys() | ||
subcommand = next((arg for arg in args[caller_pos:] if arg in wrapped_subcommands), None) | ||
|
||
if subcommand is None: | ||
# Pass command to the container directly | ||
exit_code = cli_container.start(" ".join(args)) | ||
if not exit_code: | ||
raise Exit(exit_code) | ||
|
||
else: | ||
# Invoke wrapped command | ||
subcommand = context.command.commands.get(subcommand) | ||
if not subcommand.params: | ||
context.invoke(subcommand) | ||
else: | ||
context.forward(subcommand) |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Love the use of context managers, very elegant solution!