Skip to content

Commit a91a1f3

Browse files
committed
add config argument and env var
1 parent eb9d572 commit a91a1f3

5 files changed

Lines changed: 91 additions & 45 deletions

File tree

src/mu/cli/aws.py

Lines changed: 21 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@
33

44
import click
55

6-
from ..config import Config, cli_load
6+
from ..config import Config
77
from ..libs import api_gateway, auth, ec2, ecr, ecs, gateway
88
from .core import cli
99

@@ -21,9 +21,10 @@ def aws():
2121
@click.option('--name-prefix', help='Filter on name tag')
2222
@click.option('--name-key', help='Key of tag to use for name', default='Name')
2323
@click.option('--verbose', '-v', is_flag=True)
24-
def subnets(target_env, name_prefix, name_key, verbose):
24+
@click.pass_context
25+
def subnets(ctx: click.Context, target_env, name_prefix, name_key, verbose):
2526
"""List ec2 subnets"""
26-
config: Config = cli_load(target_env)
27+
config: Config = ctx.obj['load_config'](target_env)
2728
b3_sess = auth.b3_sess(config.aws_region)
2829

2930
for name, subnet in ec2.describe_subnets(b3_sess, name_prefix, name_key).items():
@@ -36,9 +37,10 @@ def subnets(target_env, name_prefix, name_key, verbose):
3637
@click.argument('only_names', nargs=-1)
3738
@click.option('--env', 'target_env')
3839
@click.option('--verbose', '-v', is_flag=True)
39-
def security_groups(target_env, only_names, verbose):
40+
@click.pass_context
41+
def security_groups(ctx: click.Context, target_env, only_names, verbose):
4042
"""List ec2 subnets"""
41-
config: Config = cli_load(target_env)
43+
config: Config = ctx.obj['load_config'](target_env)
4244
b3_sess = auth.b3_sess(config.aws_region)
4345

4446
for name, group in ec2.describe_security_groups(b3_sess, only_names).items():
@@ -50,9 +52,10 @@ def security_groups(target_env, only_names, verbose):
5052
@aws.command()
5153
@click.option('--env', 'target_env')
5254
@click.option('--verbose', '-v', is_flag=True)
53-
def ecs_clusters(target_env, verbose):
55+
@click.pass_context
56+
def ecs_clusters(ctx: click.Context, target_env, verbose):
5457
"""List App Runner instance configurations"""
55-
config: Config = cli_load(target_env)
58+
config: Config = ctx.obj['load_config'](target_env)
5659
b3_sess = auth.b3_sess(config.aws_region)
5760

5861
ecs_ = ecs.ECS(b3_sess)
@@ -65,7 +68,7 @@ def ecs_clusters(target_env, verbose):
6568
@click.pass_context
6669
def ecr_push(ctx: click.Context, target_env: str | None):
6770
"""Push built image to ecr"""
68-
config: Config = cli_load(target_env)
71+
config: Config = ctx.obj['load_config'](target_env)
6972
repo_name = config.resource_ident
7073
print(config.aws_region)
7174
repos = ecr.Repos(auth.b3_sess(config.aws_region))
@@ -77,9 +80,10 @@ def ecr_push(ctx: click.Context, target_env: str | None):
7780
@cli.command()
7881
@click.argument('target_env', required=False)
7982
@click.option('--verbose', is_flag=True)
80-
def ecr_repos(verbose: bool, target_env: str | None):
83+
@click.pass_context
84+
def ecr_repos(ctx: click.Context, verbose: bool, target_env: str | None):
8185
"""List ECR repos in active account"""
82-
config: Config = cli_load(target_env)
86+
config: Config = ctx.obj['load_config'](target_env)
8387
b3_sess = auth.b3_sess(config.aws_region)
8488

8589
repos = ecr.Repos(b3_sess)
@@ -94,9 +98,10 @@ def ecr_repos(verbose: bool, target_env: str | None):
9498
@click.argument('repo_name', required=False)
9599
@click.option('--verbose', is_flag=True)
96100
@click.option('--env', 'target_env')
97-
def ecr_images(verbose: bool, target_env: str | None, repo_name: str | None):
101+
@click.pass_context
102+
def ecr_images(ctx: click.Context, verbose: bool, target_env: str | None, repo_name: str | None):
98103
"""List all images in a repo"""
99-
config: Config = cli_load(target_env)
104+
config: Config = ctx.obj['load_config'](target_env)
100105
b3_sess = auth.b3_sess(config.aws_region)
101106

102107
repos = ecr.Repos(b3_sess)
@@ -130,7 +135,7 @@ def ecr_tags(
130135
repo_name: str | None,
131136
):
132137
"""List ecr tags"""
133-
config: Config = cli_load(target_env)
138+
config: Config = ctx.obj['load_config'](target_env)
134139
b3_sess = auth.b3_sess(config.aws_region)
135140

136141
repos = ecr.Repos(b3_sess)
@@ -145,9 +150,10 @@ def ecr_tags(
145150

146151
@aws.command()
147152
@click.option('--verbose', is_flag=True)
148-
def api_gateways(verbose: bool):
153+
@click.pass_context
154+
def api_gateways(ctx: click.Context, verbose: bool):
149155
"""List api gateways in active account"""
150-
config: Config = cli_load(None)
156+
config: Config = ctx.obj['load_config'](None)
151157
b3_sess = auth.b3_sess(config.aws_region)
152158

153159
apis = api_gateway.APIs(b3_sess)

src/mu/cli/core.py

Lines changed: 50 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
1+
from pathlib import Path
12
from pprint import pprint
23

34
import click
45

56
import mu.config
6-
from mu.config import Config, cli_load
7+
from mu.config import Config, default_env, load
78
from mu.libs import auth, logs, sqs, sts, utils
89
from mu.libs.lamb import Lambda
910
from mu.libs.status import Status
@@ -13,16 +14,31 @@
1314

1415

1516
@click.group()
17+
@click.option(
18+
'--config',
19+
'config_path',
20+
type=click.Path(path_type=Path),
21+
help='Path to mu config file',
22+
envvar='MU_CONFIG_PATH',
23+
)
1624
@logs.click_options
17-
def cli(log_level: str):
25+
@click.pass_context
26+
def cli(ctx: click.Context, log_level: str, config_path: Path | None):
1827
logs.init_logging(log_level)
28+
ctx.ensure_object(dict)
29+
30+
def load_config(env: str | None = None) -> Config:
31+
return load(Path.cwd(), env or default_env(), config_path)
32+
33+
ctx.obj['load_config'] = load_config
1934

2035

2136
@cli.command()
2237
@click.argument('target_env', required=False)
23-
def auth_check(target_env):
38+
@click.pass_context
39+
def auth_check(ctx: click.Context, target_env):
2440
"""Check AWS auth by displaying account info"""
25-
config: Config = cli_load(target_env)
41+
config: Config = ctx.obj['load_config'](target_env)
2642
b3_sess = auth.b3_sess(config.aws_region)
2743
ident: str = sts.caller_identity(b3_sess)
2844
print('Account:', ident['Account'])
@@ -42,9 +58,10 @@ def auth_check(target_env):
4258
@cli.command()
4359
@click.argument('target_env', required=False)
4460
@click.option('--resolve-env', is_flag=True, help='Show env after resolution (e.g. secrets)')
45-
def config(target_env: str, resolve_env: bool):
61+
@click.pass_context
62+
def config(ctx: click.Context, target_env: str, resolve_env: bool):
4663
"""Display mu config for active project"""
47-
config: Config = cli_load(target_env)
64+
config: Config = ctx.obj['load_config'](target_env)
4865

4966
sess = auth.b3_sess(config.aws_region)
5067
config.apply_sess(sess)
@@ -54,24 +71,25 @@ def config(target_env: str, resolve_env: bool):
5471

5572
@cli.command()
5673
@click.argument('envs', nargs=-1)
57-
def provision(envs: list[str]):
74+
@click.pass_context
75+
def provision(ctx: click.Context, envs: list[str]):
5876
"""Provision lambda function in environment given (or default)"""
5977
envs = envs or [None]
6078

6179
for env in envs:
62-
lamb = Lambda(cli_load(env))
80+
lamb = Lambda(ctx.obj['load_config'](env))
6381
lamb.provision()
6482

6583

6684
@cli.command()
6785
@click.argument('envs', nargs=-1)
6886
@click.option('--build', is_flag=True)
6987
@click.pass_context
70-
def deploy(ctx, envs: list[str], build: bool):
88+
def deploy(ctx: click.Context, envs: list[str], build: bool):
7189
"""Deploy local image to ecr, update lambda"""
7290
envs = envs or [mu.config.default_env()]
7391

74-
configs = [cli_load(env) for env in envs]
92+
configs = [ctx.obj['load_config'](env) for env in envs]
7593

7694
if build:
7795
service_names = [config.compose_service for config in configs]
@@ -85,18 +103,19 @@ def deploy(ctx, envs: list[str], build: bool):
85103
@cli.command()
86104
@click.argument('target_env')
87105
@click.option('--force-repo', is_flag=True)
88-
def delete(target_env: str, force_repo: bool):
106+
@click.pass_context
107+
def delete(ctx: click.Context, target_env: str, force_repo: bool):
89108
"""Delete lambda and optionally related infra"""
90-
lamb = Lambda(cli_load(target_env))
109+
lamb = Lambda(ctx.obj['load_config'](target_env))
91110
lamb.delete(target_env, force_repo=force_repo)
92111

93112

94113
@cli.command()
95114
@click.argument('target_env', required=False)
96-
def build(target_env: str):
115+
@click.pass_context
116+
def build(ctx: click.Context, target_env: str):
97117
"""Build lambda container with docker compose"""
98-
99-
conf = cli_load(target_env)
118+
conf = ctx.obj['load_config'](target_env)
100119
utils.compose_build(conf.compose_service)
101120

102121

@@ -107,10 +126,16 @@ def build(target_env: str):
107126
@click.option('--host', default='localhost:8080')
108127
@click.option('--local', is_flag=True)
109128
@click.pass_context
110-
def invoke(ctx, target_env: str, action: str, host: str, action_args: list, local: bool):
129+
def invoke(
130+
ctx: click.Context,
131+
target_env: str,
132+
action: str,
133+
host: str,
134+
action_args: list,
135+
local: bool,
136+
):
111137
"""Invoke lambda with diagnostics or given action"""
112-
113-
lamb = Lambda(cli_load(target_env))
138+
lamb = Lambda(ctx.obj['load_config'](target_env))
114139
if local:
115140
result = lamb.invoke_rei(host, action, action_args)
116141
else:
@@ -138,7 +163,7 @@ def _logs(
138163
if not first and not last:
139164
last = 10 if streams else 25
140165

141-
lamb = Lambda(cli_load(target_env))
166+
lamb = Lambda(ctx.obj['load_config'](target_env))
142167
lamb.logs(first, last, streams)
143168

144169

@@ -164,11 +189,12 @@ def sqs_list(ctx: click.Context, verbose: bool, delete: bool, name_prefix=str):
164189
@cli.command()
165190
@click.argument('action', type=click.Choice(('show', 'provision', 'delete')))
166191
@click.argument('target_env', required=False)
167-
def domain_name(target_env: str, action: str):
192+
@click.pass_context
193+
def domain_name(ctx: click.Context, target_env: str, action: str):
168194
"""Manage AWS config needed for domain name support"""
169195
from ..libs import gateway
170196

171-
config: Config = cli_load(target_env or mu.config.default_env())
197+
config: Config = ctx.obj['load_config'](target_env)
172198
assert config.domain_name
173199

174200
gw = gateway.Gateway(config)
@@ -189,8 +215,9 @@ def domain_name(target_env: str, action: str):
189215

190216
@cli.command()
191217
@click.argument('target_env', required=False)
192-
def status(target_env: str):
218+
@click.pass_context
219+
def status(ctx: click.Context, target_env: str | None):
193220
"""Check status of all infrastructure components for the app"""
194-
config = cli_load(target_env or mu.config.default_env())
221+
config = ctx.obj['load_config'](target_env)
195222

196223
print(Status.fetch(config))

src/mu/config.py

Lines changed: 8 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -173,12 +173,18 @@ def default_env():
173173
return environ.get('MU_DEFAULT_ENV') or utils.host_user()
174174

175175

176-
def load(start_at: Path, env: str) -> Config:
176+
def load(start_at: Path, env: str, mu_fpath: Path | None = None) -> Config:
177177
pp_fpath = find_upwards(start_at, 'pyproject.toml')
178178
if pp_fpath is None:
179179
raise Exception(f'No pyproject.toml found in {start_at} or parents')
180180

181-
mu_fpath = pp_fpath.with_name('mu.toml')
181+
if mu_fpath:
182+
if not mu_fpath.exists():
183+
raise Exception(f'Config file not found: {mu_fpath}')
184+
mu_fpath = mu_fpath
185+
else:
186+
mu_fpath = pp_fpath.with_name('mu.toml')
187+
182188
if mu_fpath.exists():
183189
config_fpath = mu_fpath
184190
key_prefix = ''
@@ -222,7 +228,3 @@ def load(start_at: Path, env: str) -> Config:
222228
default=(),
223229
),
224230
)
225-
226-
227-
def cli_load(env) -> Config:
228-
return load(Path.cwd(), env or default_env())

src/mu_tests/pkg2/mu2.toml

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
project-org = 'Starfleet'
2+
aws-region = 'us-east-2'
3+
domain-name = 'pkg2.domain2.com'

src/mu_tests/test_config.py

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,13 +38,21 @@ def test_minimal_config_defaults(self, m_host_user):
3838
assert c.function_arn == 'arn:aws:lambda:south:1234:function:starfleet-tng-func-qa'
3939

4040
@mock_patch_obj(config.utils, 'host_user')
41-
def test_mu_toml(self, m_host_user):
41+
def test_inferred_mu_toml(self, m_host_user):
4242
m_host_user.return_value = 'picard.science-station'
4343

4444
c = load('pkg2')
4545
assert c.resource_ident == 'starfleet-tng-lambda-func-qa'
4646
assert c.domain_name == 'pkg2.example.com'
4747

48+
@mock_patch_obj(config.utils, 'host_user')
49+
def test_specified_mu_toml(self, m_host_user):
50+
m_host_user.return_value = 'picard.science-station'
51+
52+
c = config.load(tests_dpath / 'pkg2', 'qa', tests_dpath / 'pkg2' / 'mu2.toml')
53+
assert c.resource_ident == 'starfleet-tng-lambda-func-qa'
54+
assert c.domain_name == 'pkg2.domain2.com'
55+
4856
def test_sqs_configs(self):
4957
conf = load('pkg-sqs')
5058
sqs = conf.aws_configs('sqs')

0 commit comments

Comments
 (0)