make-azure 0.4.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
make_azure/__init__.py ADDED
@@ -0,0 +1,36 @@
1
+ """Azure tasks for mkrun -- the `azure` group.
2
+
3
+ One thing: a virtual machine on Azure's free tier, in the nearest region that
4
+ will build it, optionally with a DuckDNS name, and removed with everything it
5
+ made. Sign-in is azure-identity (a browser, MFA up front, an encrypted token
6
+ cache); the rest is plain Resource Manager REST through `make.http`.
7
+
8
+ From any shell, with no task file:
9
+
10
+ uv tool install mkrun
11
+ mk --install azure
12
+ mk azure.vm box
13
+
14
+ Or in a task file, where importing is what registers it:
15
+
16
+ # Makefile.py
17
+ from make_azure import azure
18
+
19
+ The group merges with a repo's own `azure.*` tasks -- groups are namespaces,
20
+ and this package claims only its seven names.
21
+ """
22
+
23
+ from __future__ import annotations
24
+
25
+ __version__ = "0.4.0"
26
+
27
+ __all__ = ["azure", "vm"]
28
+
29
+
30
+ def __getattr__(name: str):
31
+ """Import on first access, keeping module scope import-free -- startup is a feature."""
32
+ if name in __all__:
33
+ import importlib
34
+
35
+ return importlib.import_module(f".{name}", __name__)
36
+ raise AttributeError(f"module {__name__!r} has no attribute {name!r}")
make_azure/azure.py ADDED
@@ -0,0 +1,113 @@
1
+ """The `azure` group: a free-tier virtual machine, made and removed.
2
+
3
+ mk azure.login --tenant T sign in once (a browser opens)
4
+ mk azure.account which subscription, and whether it is free
5
+ mk azure.region the nearest regions, and the one azure.vm uses
6
+ mk azure.vm box Ubuntu 24.04, SSH open, in the nearest region
7
+ mk azure.vm box --duckdns mybox ...and mybox.duckdns.org points at it
8
+ mk azure.vms what the subscription has
9
+ mk azure.dns box mybox point mybox.duckdns.org at an existing VM
10
+ mk azure.delete box the VM and everything it made
11
+ mk --dry-run azure.vm box the plan; nothing is sent, no sign-in
12
+
13
+ The work is in `make_azure.vm`, imported inside each task so `mk --list` never
14
+ loads azure-identity. No `az` CLI is involved.
15
+ """
16
+
17
+ from __future__ import annotations
18
+
19
+ from typing import Annotated
20
+
21
+ from make import arg, group
22
+
23
+ __all__ = ["azure"]
24
+
25
+ azure = group("azure")
26
+
27
+ Subscription = Annotated[str, arg(help="subscription id or name, if the sign-in reaches several")]
28
+ Size = Annotated[str, arg(help="Standard_B2ats_v2 (default), Standard_B2pts_v2 or Standard_B1s")]
29
+ Origin = Annotated[str | None, arg(help="your position, LAT,LON; default: from the time zone")]
30
+
31
+
32
+ @azure.task(name="login")
33
+ def login(
34
+ *,
35
+ tenant: Annotated[str, arg(help="tenant id or domain; needed for a personal account")] = "organizations",
36
+ ) -> None:
37
+ """Sign in with a browser, MFA included; tokens go in the encrypted cache."""
38
+ from . import vm
39
+
40
+ vm.login(tenant)
41
+
42
+
43
+ @azure.task(name="account")
44
+ def account(*, subscription: Subscription = "") -> None:
45
+ """The subscription this sign-in acts in, and whether its offer carries free services."""
46
+ from . import vm
47
+
48
+ vm.account(subscription_name=subscription)
49
+
50
+
51
+ @azure.task(name="region")
52
+ def region(
53
+ *, size: Size = "Standard_B2ats_v2", origin: Origin = None, subscription: Subscription = ""
54
+ ) -> None:
55
+ """The regions nearest to you, and the first that sells the size."""
56
+ from . import vm
57
+
58
+ vm.region(size=size, origin=origin, subscription_name=subscription)
59
+
60
+
61
+ @azure.task(name="vm", dangerous=True)
62
+ def create(
63
+ name: Annotated[str, arg(help="the VM's name; its resource group is NAME-rg")],
64
+ *,
65
+ size: Size = "Standard_B2ats_v2",
66
+ origin: Origin = None,
67
+ location: Annotated[str | None, arg(help="skip the search and use this region")] = None,
68
+ duckdns: Annotated[
69
+ str | None, arg(help="point SUBDOMAIN.duckdns.org at it (needs DUCKDNS_TOKEN)")
70
+ ] = None,
71
+ user: Annotated[str, arg(help="the login user on the VM")] = "azureuser",
72
+ no_public_ip: Annotated[bool, arg(help="private network only; avoids the billed IPv4")] = False,
73
+ paid_ok: Annotated[bool, arg(help="allow a subscription without free services")] = False,
74
+ subscription: Subscription = "",
75
+ ) -> None:
76
+ """Create a free-tier Ubuntu VM in the nearest region that will build it."""
77
+ from . import vm
78
+
79
+ vm.create(
80
+ name,
81
+ size=size,
82
+ origin=origin,
83
+ location=location,
84
+ duckdns=duckdns,
85
+ user=user,
86
+ paid_ok=paid_ok,
87
+ public_ip=not no_public_ip,
88
+ subscription_name=subscription,
89
+ )
90
+
91
+
92
+ @azure.task(name="vms")
93
+ def vms(*, subscription: Subscription = "") -> None:
94
+ """The subscription's VMs: region, size, power state, address."""
95
+ from . import vm
96
+
97
+ vm.vms(subscription_name=subscription)
98
+
99
+
100
+ @azure.task(name="dns")
101
+ def dns(name: str, subdomain: str, *, subscription: Subscription = "") -> None:
102
+ """Point SUBDOMAIN.duckdns.org at an existing VM (needs DUCKDNS_TOKEN)."""
103
+ from . import vm
104
+
105
+ vm.dns(name, subdomain, subscription_name=subscription)
106
+
107
+
108
+ @azure.task(name="delete", dangerous=True)
109
+ def delete(name: str, *, subscription: Subscription = "") -> None:
110
+ """Delete a VM's resource group: the VM, its disk, network and IP, all at once."""
111
+ from . import vm
112
+
113
+ vm.delete(name, subscription_name=subscription)