Skip to content

Commit 07dc662

Browse files
[k8s-configuration] Update extension CLI to v2.3.0 (#9313)
1 parent 13940a9 commit 07dc662

File tree

8 files changed

+377
-6
lines changed

8 files changed

+377
-6
lines changed

src/k8s-configuration/HISTORY.rst

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,10 @@
22
33
Release History
44
===============
5+
2.3.0
6+
++++++++++++++++++
7+
* Added support for using OCIRepository as a source type in Flux configurations.
8+
59
2.2.0
610
++++++++++++++++++
711
* Introduce a new feature to add provider authentication for git repositories.

src/k8s-configuration/azext_k8s_configuration/_help.py

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -85,6 +85,13 @@
8585
--kind azblob --url https://mystorageaccount.blob.core.windows.net \\
8686
--container-name my-container --kustomization name=my-kustomization \\
8787
--account-key my-account-key
88+
- name: Create a Kubernetes v2 Flux Configuration with OCI Source Kind
89+
text: |-
90+
az k8s-configuration flux create --resource-group my-resource-group \\
91+
--cluster-name mycluster --cluster-type connectedClusters \\
92+
--name myconfig --scope cluster --namespace my-namespace \\
93+
--kind oci --url oci://ghcr.io/owner/repo/manifests/podinfo \\
94+
--kustomization name=my-kustomization --use-workload-identity
8895
"""
8996

9097
helps[
@@ -109,6 +116,11 @@
109116
az k8s-configuration flux update --resource-group my-resource-group \\
110117
--cluster-name mycluster --cluster-type connectedClusters --name myconfig \\
111118
--container-name other-container
119+
- name: Update a Flux v2 Kubernetes configuration with OCI Source Kind to use connect insecurely
120+
text: |-
121+
az k8s-configuration flux update --resource-group my-resource-group \\
122+
--cluster-name mycluster --cluster-type connectedClusters --name myconfig \\
123+
--oci-insecure
112124
"""
113125

114126
helps[

src/k8s-configuration/azext_k8s_configuration/_params.py

Lines changed: 76 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919

2020
from .action import (
2121
KustomizationAddAction,
22+
VerifyConfigAction
2223
)
2324
from . import consts
2425

@@ -65,7 +66,7 @@ def load_arguments(self, _):
6566
)
6667
c.argument(
6768
"kind",
68-
arg_type=get_enum_type([consts.GIT, consts.BUCKET, consts.AZBLOB]),
69+
arg_type=get_enum_type([consts.GIT, consts.BUCKET, consts.AZBLOB, consts.OCI]),
6970
help="Source kind to reconcile",
7071
)
7172
c.argument(
@@ -86,13 +87,13 @@ def load_arguments(self, _):
8687
)
8788
c.argument(
8889
"tag",
89-
arg_group="Git Repo Ref",
90-
help="Tag within the git source to reconcile with the cluster",
90+
arg_group="Git Repo Ref / OCI Repo Ref",
91+
help="Tag within the git or OCI source to reconcile with the cluster",
9192
)
9293
c.argument(
9394
"semver",
94-
arg_group="Git Repo Ref",
95-
help="Semver range within the git source to reconcile with the cluster",
95+
arg_group="Git Repo Ref / OCI Repo Ref",
96+
help="Semver range within the git or OCI source to reconcile with the cluster",
9697
)
9798
c.argument(
9899
"commit",
@@ -238,6 +239,76 @@ def load_arguments(self, _):
238239
options_list=["--mi-client-id", "--managed-identity-client-id"],
239240
help="The client ID of the managed identity for authentication with Azure Blob",
240241
)
242+
c.argument(
243+
"digest",
244+
arg_group="OCI Repo Ref",
245+
help="Digest of the OCI artifact to reconcile with the cluster",
246+
)
247+
c.argument(
248+
"oci_media_type",
249+
arg_group="OCI Repo Ref",
250+
options_list=["--oci-media-type", "--oci-layer-selector-media-type"],
251+
help="OCI artifact layer media type to select for extraction or copy.",
252+
)
253+
c.argument(
254+
"oci_operation",
255+
arg_group="OCI Repo Ref",
256+
arg_type=get_enum_type(["extract", "copy"]),
257+
options_list=["--oci-operation", "--oci-layer-selector-operation"],
258+
help="Operation to perform on the selected OCI artifact layer: 'extract' to extract the layer, 'copy' to copy the tarball as-is (default: extract)",
259+
)
260+
c.argument(
261+
"tls_ca_certificate",
262+
arg_group="OCI Repository Auth",
263+
help="Base64-encoded CA certificate for TLS communication with OCI repository",
264+
)
265+
c.argument(
266+
"tls_client_certificate",
267+
arg_group="OCI Repository Auth",
268+
help="Base64-encoded client certificate for TLS authentication with OCI repository",
269+
)
270+
c.argument(
271+
"tls_private_key",
272+
arg_group="OCI Repository Auth",
273+
help="Base64-encoded private key for TLS authentication with OCI repository",
274+
)
275+
c.argument(
276+
"service_account_name",
277+
arg_group="OCI Repository Auth",
278+
help="Name of the Kubernetes service account to use for accessing the OCI repository",
279+
)
280+
c.argument(
281+
"use_workload_identity",
282+
arg_group="OCI Repository Auth",
283+
arg_type=get_three_state_flag(),
284+
help="Use workload identity for authentication with OCI repository",
285+
)
286+
c.argument(
287+
"oci_insecure",
288+
arg_type=get_three_state_flag(),
289+
help="Allow connecting to an insecure (HTTP) OCI container registry.",
290+
)
291+
c.argument(
292+
"verification_provider",
293+
action=VerifyConfigAction,
294+
arg_group="OCI Repository Auth",
295+
help="Provider used for OCI verification."
296+
)
297+
c.argument(
298+
"match_oidc_identity",
299+
action=VerifyConfigAction,
300+
arg_group="OCI Repository Auth",
301+
nargs="+",
302+
help="List of OIDC identities to match for verification of OCI artifacts. Each entry should be a JSON string with 'issuer' and 'subject' fields."
303+
)
304+
c.argument(
305+
"verification_config",
306+
action=VerifyConfigAction,
307+
arg_group="OCI Repository Auth",
308+
nargs="+",
309+
help="An object containing trusted public keys of trusted authors for OCI artifacts."
310+
)
311+
241312

242313
with self.argument_context("k8s-configuration flux update") as c:
243314
c.argument(

src/k8s-configuration/azext_k8s_configuration/action.py

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
# pylint: disable=protected-access
66

77
import argparse
8+
import json
89
from azure.cli.core.azclierror import InvalidArgumentValueError
910
from .vendored_sdks.v2024_04_01_preview.models import (
1011
KustomizationDefinition,
@@ -75,3 +76,41 @@ def __call__(self, parser, namespace, values, option_string=None):
7576
),
7677
option_string,
7778
)
79+
80+
81+
class VerifyConfigAction(argparse.Action):
82+
def __call__(self, parser, namespace, values, option_string=None):
83+
# Handle verification_provider (simple string)
84+
if self.dest == "verification_provider":
85+
setattr(namespace, self.dest, values)
86+
return
87+
88+
# Handle match_oidc_identity (list of JSON strings)
89+
if self.dest == "match_oidc_identity":
90+
identities = []
91+
for entry in values:
92+
try:
93+
obj = json.loads(entry)
94+
if not isinstance(obj, dict) or "issuer" not in obj or "subject" not in obj:
95+
raise ValueError()
96+
identities.append({"issuer": obj["issuer"], "subject": obj["subject"]})
97+
except Exception:
98+
raise InvalidArgumentValueError(
99+
"Each entry for --match-oidc-identity must be a JSON string with 'issuer' and 'subject' fields."
100+
)
101+
setattr(namespace, self.dest, identities)
102+
return
103+
104+
# Handle verification_config (list of key=value)
105+
if self.dest == "verification_config":
106+
config = {}
107+
for item in values:
108+
try:
109+
key, value = item.split("=", 1)
110+
config[key] = value
111+
except Exception:
112+
raise InvalidArgumentValueError(
113+
"Each entry for --verification-config must be in key=value format."
114+
)
115+
setattr(namespace, self.dest, config)
116+
return

src/k8s-configuration/azext_k8s_configuration/consts.py

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -255,6 +255,28 @@
255255
"mi_client_id",
256256
}
257257

258+
OCI_REPO_REQUIRED_PARAMS = {"url"}
259+
OCI_REPO_VALID_PARAMS = {
260+
"url",
261+
"tag",
262+
"semver",
263+
"digest",
264+
"sync_interval",
265+
"timeout",
266+
"local_auth_ref",
267+
"oci_media_type",
268+
"oci_operation",
269+
"tls_ca_certificate",
270+
"tls_client_certificate",
271+
"tls_private_key",
272+
"service_account_name",
273+
"use_workload_identity",
274+
"oci_insecure",
275+
"verification_provider",
276+
"match_oidc_identity",
277+
"verification_config",
278+
}
279+
258280
DEPENDENCY_KEYS = ["dependencies", "depends_on", "dependsOn", "depends"]
259281
SYNC_INTERVAL_KEYS = ["interval", "sync_interval", "syncInterval"]
260282
RETRY_INTERVAL_KEYS = ["retryInterval", "retry_interval"]
@@ -266,6 +288,7 @@
266288
VALID_GIT_URL_REGEX = r"^(((http|https|ssh)://)|(git@))"
267289
VALID_BUCKET_URL_REGEX = r"^(((http|https)://))"
268290
VALID_AZUREBLOB_URL_REGEX = r"^(((http|https)://))"
291+
VALID_OCI_URL_REGEX = r"^oci://.*$"
269292

270293
VALID_KUBERNETES_DNS_SUBDOMAIN_NAME_REGEX = r"^[a-z0-9]([\.\-a-z0-9]*[a-z0-9])?$"
271294
VALID_KUBERNETES_DNS_NAME_REGEX = r"^[a-z0-9]([\-a-z0-9]*[a-z0-9])?$"
@@ -274,8 +297,10 @@
274297
BUCKET = "bucket"
275298
BUCKET_CAPS = "Bucket"
276299
AZBLOB = "azblob"
300+
OCI = "oci"
277301
AZURE_BLOB = "AzureBlob"
278302
GIT_REPOSITORY = "GitRepository"
303+
OCI_REPOSITORY = "OCIRepository"
279304

280305
CONNECTED_CLUSTER_TYPE = "connectedclusters"
281306
MANAGED_CLUSTER_TYPE = "managedclusters"

0 commit comments

Comments
 (0)