Skip to content

Commit a9239a7

Browse files
committed
auth: update auth func to avoid flattening
1 parent 02cf9e5 commit a9239a7

File tree

1 file changed

+105
-52
lines changed

1 file changed

+105
-52
lines changed

src/warnet/users.py

Lines changed: 105 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,70 +1,123 @@
1+
import difflib
2+
import json
13
import os
2-
import subprocess
34
import sys
45

56
import click
6-
import yaml
7+
8+
from warnet.constants import KUBECONFIG
9+
from warnet.k8s import K8sError, open_kubeconfig, write_kubeconfig
710

811

912
@click.command()
10-
@click.argument("kube_config", type=str)
11-
def auth(kube_config: str) -> None:
12-
"""
13-
Authenticate with a warnet cluster using a kube config file
14-
"""
13+
@click.argument("auth_config", type=str)
14+
def auth(auth_config):
15+
"""Authenticate with a Warnet cluster using a kubernetes config file"""
1516
try:
16-
current_kubeconfig = os.environ.get("KUBECONFIG", os.path.expanduser("~/.kube/config"))
17-
combined_kubeconfig = (
18-
f"{current_kubeconfig}:{kube_config}" if current_kubeconfig else kube_config
19-
)
20-
os.environ["KUBECONFIG"] = combined_kubeconfig
21-
with open(kube_config) as file:
22-
content = yaml.safe_load(file)
23-
user = content["users"][0]
24-
user_name = user["name"]
25-
user_token = user["user"]["token"]
26-
current_context = content["current-context"]
27-
flatten_cmd = "kubectl config view --flatten"
28-
result_flatten = subprocess.run(
29-
flatten_cmd, shell=True, check=True, capture_output=True, text=True
30-
)
31-
except subprocess.CalledProcessError as e:
32-
click.secho("Error occurred while executing kubectl config view --flatten:", fg="red")
33-
click.secho(e.stderr, fg="red")
17+
auth_config = open_kubeconfig(auth_config)
18+
except K8sError as e:
19+
click.secho(e, fg="yellow")
20+
click.secho(f"Could not open auth_config: {auth_config}", fg="red")
3421
sys.exit(1)
3522

36-
if result_flatten.returncode == 0:
37-
with open(current_kubeconfig, "w") as file:
38-
file.write(result_flatten.stdout)
39-
click.secho(f"Authorization file written to: {current_kubeconfig}", fg="green")
40-
else:
41-
click.secho("Could not create authorization file", fg="red")
42-
click.secho(result_flatten.stderr, fg="red")
43-
sys.exit(result_flatten.returncode)
23+
is_first_config = False
24+
if not os.path.exists(KUBECONFIG):
25+
try:
26+
write_kubeconfig(auth_config, KUBECONFIG)
27+
is_first_config = True
28+
except K8sError as e:
29+
click.secho(e, fg="yellow")
30+
click.secho(f"Could not write KUBECONFIG: {KUBECONFIG}", fg="red")
31+
sys.exit(1)
4432

4533
try:
46-
update_cmd = f"kubectl config set-credentials {user_name} --token {user_token}"
47-
result_update = subprocess.run(
48-
update_cmd, shell=True, check=True, capture_output=True, text=True
49-
)
50-
if result_update.returncode != 0:
51-
click.secho("Could not update authorization file", fg="red")
52-
click.secho(result_flatten.stderr, fg="red")
53-
sys.exit(result_flatten.returncode)
54-
except subprocess.CalledProcessError as e:
55-
click.secho("Error occurred while executing kubectl config view --flatten:", fg="red")
56-
click.secho(e.stderr, fg="red")
34+
base_config = open_kubeconfig(KUBECONFIG)
35+
except K8sError as e:
36+
click.secho(e, fg="yellow")
37+
click.secho(f"Could not open KUBECONFIG: {KUBECONFIG}", fg="red")
5738
sys.exit(1)
5839

59-
with open(current_kubeconfig) as file:
60-
contents = yaml.safe_load(file)
40+
if not is_first_config:
41+
for category in ["clusters", "users", "contexts"]:
42+
if category in auth_config:
43+
merge_entries(category, base_config, auth_config)
6144

62-
with open(current_kubeconfig, "w") as file:
63-
contents["current-context"] = current_context
64-
yaml.safe_dump(contents, file)
45+
new_current_context = auth_config.get("current-context")
46+
base_config["current-context"] = new_current_context
6547

66-
with open(current_kubeconfig) as file:
67-
contents = yaml.safe_load(file)
48+
# Check if the new current context has an explicit namespace
49+
context_entry = next(
50+
(ctx for ctx in base_config["contexts"] if ctx["name"] == new_current_context), None
51+
)
52+
if context_entry and "namespace" not in context_entry["context"]:
6853
click.secho(
69-
f"\nwarnet's current context is now set to: {contents['current-context']}", fg="green"
54+
f"Warning: The context '{new_current_context}' does not have an explicit namespace.",
55+
fg="yellow",
7056
)
57+
58+
try:
59+
write_kubeconfig(base_config, KUBECONFIG)
60+
click.secho(f"Updated kubeconfig with authorization data: {KUBECONFIG}", fg="green")
61+
except K8sError as e:
62+
click.secho(e, fg="yellow")
63+
click.secho(f"Could not write KUBECONFIG: {KUBECONFIG}", fg="red")
64+
sys.exit(1)
65+
66+
try:
67+
base_config = open_kubeconfig(KUBECONFIG)
68+
click.secho(
69+
f"Warnet's current context is now set to: {base_config['current-context']}", fg="green"
70+
)
71+
except K8sError as e:
72+
click.secho(f"Error reading from {KUBECONFIG}: {e}", fg="red")
73+
sys.exit(1)
74+
75+
76+
def merge_entries(category, base_config, auth_config):
77+
name = "name"
78+
base_list = base_config.setdefault(category, [])
79+
auth_list = auth_config[category]
80+
base_entry_names = {entry[name] for entry in base_list} # Extract existing names
81+
for auth_entry in auth_list:
82+
if auth_entry[name] in base_entry_names:
83+
existing_entry = next(
84+
base_entry for base_entry in base_list if base_entry[name] == auth_entry[name]
85+
)
86+
if existing_entry != auth_entry:
87+
# Show diff between existing and new entry
88+
existing_entry_str = json.dumps(existing_entry, indent=2, sort_keys=True)
89+
auth_entry_str = json.dumps(auth_entry, indent=2, sort_keys=True)
90+
diff = difflib.unified_diff(
91+
existing_entry_str.splitlines(),
92+
auth_entry_str.splitlines(),
93+
fromfile="Existing Entry",
94+
tofile="New Entry",
95+
lineterm="",
96+
)
97+
click.echo("Differences between existing and new entry:\n")
98+
click.echo("\n".join(diff))
99+
100+
if click.confirm(
101+
f"The '{category}' section key '{auth_entry[name]}' already exists and differs. Overwrite?",
102+
default=False,
103+
):
104+
# Find and replace the existing entry
105+
base_list[:] = [
106+
base_entry if base_entry[name] != auth_entry[name] else auth_entry
107+
for base_entry in base_list
108+
]
109+
click.secho(
110+
f"Overwrote '{category}' section key '{auth_entry[name]}'", fg="yellow"
111+
)
112+
else:
113+
click.secho(
114+
f"Skipped '{category}' section key '{auth_entry[name]}'", fg="yellow"
115+
)
116+
else:
117+
click.secho(
118+
f"Entry for '{category}' section key '{auth_entry[name]}' is identical. No changes made.",
119+
fg="blue",
120+
)
121+
else:
122+
base_list.append(auth_entry)
123+
click.secho(f"Added new '{category}' section key '{auth_entry[name]}'", fg="green")

0 commit comments

Comments
 (0)