Skip to content
This repository was archived by the owner on Jan 23, 2026. It is now read-only.

Commit 1286919

Browse files
committed
Implement kubernetes style get command
1 parent b9760e7 commit 1286919

3 files changed

Lines changed: 112 additions & 6 deletions

File tree

  • packages
Lines changed: 92 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,100 @@
11
import asyncclick as click
2+
from jumpstarter_cli_common import OutputMode, OutputType, make_table, opt_output_all
3+
4+
from jumpstarter.config import (
5+
ClientConfigV1Alpha1,
6+
UserConfigV1Alpha1,
7+
)
8+
9+
opt_context = click.option("--context")
10+
opt_selector = click.option(
11+
"-l",
12+
"--selector",
13+
help="Selector (label query) to filter on, supports '=', '==', and '!=' (e.g. -l key1=value1,key2=value2)."
14+
" Matching objects must satisfy all of the specified label constraints.",
15+
)
16+
17+
18+
def _load_context(context: str | None) -> ClientConfigV1Alpha1:
19+
if context:
20+
config = ClientConfigV1Alpha1.load(context)
21+
else:
22+
config = UserConfigV1Alpha1.load_or_create().config.current_client
23+
if not config:
24+
raise click.BadOptionUsage(
25+
"--context",
26+
"no client context specified, and no default client context set",
27+
)
28+
return config
229

330

431
@click.group()
532
def get():
633
"""
734
Display one or many resources
835
"""
9-
pass
36+
37+
38+
@get.command(name="exporters")
39+
@opt_context
40+
@opt_selector
41+
@opt_output_all
42+
def get_exporters(context: str | None, selector: str | None, output: OutputType):
43+
"""
44+
Display one or many exporters
45+
"""
46+
config = _load_context(context)
47+
48+
exporters = config.list_exporters(filter=selector)
49+
50+
match output:
51+
case OutputMode.JSON:
52+
click.echo(exporters.dump_json())
53+
case OutputMode.YAML:
54+
click.echo(exporters.dump_yaml())
55+
case OutputMode.NAME:
56+
for exporter in exporters.exporters:
57+
click.echo(exporter.name)
58+
case _:
59+
columns = ["NAME", "LABELS"]
60+
rows = [
61+
{
62+
"NAME": exporter.name,
63+
"LABELS": ",".join(("{}={}".format(i[0], i[1]) for i in exporter.labels.items())),
64+
}
65+
for exporter in exporters.exporters
66+
]
67+
click.echo(make_table(columns, rows))
68+
69+
70+
@get.command(name="leases")
71+
@opt_context
72+
@opt_selector
73+
@opt_output_all
74+
async def get_leases(context: str | None, selector: str | None, output: OutputType):
75+
"""
76+
Display one or many leases
77+
"""
78+
config = _load_context(context)
79+
80+
leases = config.list_leases(filter=selector)
81+
82+
match output:
83+
case OutputMode.JSON:
84+
click.echo(leases.dump_json())
85+
case OutputMode.YAML:
86+
click.echo(leases.dump_yaml())
87+
case OutputMode.NAME:
88+
for lease in leases.leases:
89+
click.echo(lease.name)
90+
case _:
91+
columns = ["NAME", "CLIENT", "EXPORTER"]
92+
rows = [
93+
{
94+
"NAME": lease.name,
95+
"CLIENT": lease.client,
96+
"EXPORTER": lease.exporter,
97+
}
98+
for lease in leases.leases
99+
]
100+
click.echo(make_table(columns, rows))

packages/jumpstarter/jumpstarter/client/grpc.py

Lines changed: 19 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,11 @@
44
from datetime import timedelta
55

66
import yaml
7-
from google.protobuf import duration_pb2, field_mask_pb2
7+
from google.protobuf import duration_pb2, field_mask_pb2, json_format
88
from grpc.aio import Channel
99
from jumpstarter_protocol import kubernetes_pb2
1010
from jumpstarter_protocol.jumpstarter.client.v1 import client_pb2, client_pb2_grpc
11-
from pydantic import BaseModel, ConfigDict
11+
from pydantic import BaseModel, ConfigDict, Field, field_serializer
1212

1313

1414
def parse_identifier(identifier: str, kind: str) -> (str, str):
@@ -22,6 +22,10 @@ def parse_identifier(identifier: str, kind: str) -> (str, str):
2222
return segments[1], segments[3]
2323

2424

25+
def parse_client_identifier(identifier: str) -> (str, str):
26+
return parse_identifier(identifier, "clients")
27+
28+
2529
def parse_exporter_identifier(identifier: str) -> (str, str):
2630
return parse_identifier(identifier, "exporters")
2731

@@ -44,25 +48,35 @@ def from_protobuf(cls, data: client_pb2.Exporter) -> Exporter:
4448
class Lease(BaseModel):
4549
namespace: str
4650
name: str
51+
client: str
4752
exporter: str
4853
conditions: list[kubernetes_pb2.Condition]
4954

5055
model_config = ConfigDict(arbitrary_types_allowed=True)
5156

57+
@field_serializer("conditions")
58+
def serialize_conditions(self, conditions: list[kubernetes_pb2.Condition], _info):
59+
return [json_format.MessageToDict(condition) for condition in conditions]
60+
5261
@classmethod
5362
def from_protobuf(cls, data: client_pb2.Lease) -> Lease:
5463
namespace, name = parse_lease_identifier(data.name)
64+
65+
_, client = parse_client_identifier(data.client)
66+
_, exporter = parse_exporter_identifier(data.exporter)
67+
5568
return cls(
5669
namespace=namespace,
5770
name=name,
58-
exporter=data.exporter,
71+
client=client,
72+
exporter=exporter,
5973
conditions=data.conditions,
6074
)
6175

6276

6377
class ExporterList(BaseModel):
6478
exporters: list[Exporter]
65-
next_page_token: str | None
79+
next_page_token: str | None = Field(exclude=True)
6680

6781
@classmethod
6882
def from_protobuf(cls, data: client_pb2.ListExportersResponse) -> ExporterList:
@@ -80,7 +94,7 @@ def dump_yaml(self):
8094

8195
class LeaseList(BaseModel):
8296
leases: list[Lease]
83-
next_page_token: str | None
97+
next_page_token: str | None = Field(exclude=True)
8498

8599
@classmethod
86100
def from_protobuf(cls, data: client_pb2.ListLeasesResponse) -> LeaseList:

packages/jumpstarter/jumpstarter/config/client.py

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,7 @@ async def request_lease_async(
127127

128128
lease = Lease(
129129
channel=await self.channel(),
130+
namespace=self.metadata.namespace,
130131
name=None,
131132
metadata_filter=metadata_filter,
132133
portal=portal,

0 commit comments

Comments
 (0)