instance-repo 1.3.0.dev0__tar.gz → 1.3.1__tar.gz

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.
Files changed (48) hide show
  1. {instance_repo-1.3.0.dev0 → instance_repo-1.3.1}/PKG-INFO +7 -1
  2. {instance_repo-1.3.0.dev0 → instance_repo-1.3.1}/README.md +6 -0
  3. {instance_repo-1.3.0.dev0 → instance_repo-1.3.1}/instance_repo/__init__.py +1 -1
  4. {instance_repo-1.3.0.dev0 → instance_repo-1.3.1}/instance_repo/bootstrap.py +2 -1
  5. {instance_repo-1.3.0.dev0 → instance_repo-1.3.1}/instance_repo/clients/config.py +37 -3
  6. {instance_repo-1.3.0.dev0 → instance_repo-1.3.1}/instance_repo/clients/images.py +1 -1
  7. {instance_repo-1.3.0.dev0 → instance_repo-1.3.1}/instance_repo/clients/instances.py +4 -2
  8. {instance_repo-1.3.0.dev0 → instance_repo-1.3.1}/instance_repo/clients/versions.py +4 -4
  9. {instance_repo-1.3.0.dev0 → instance_repo-1.3.1}/instance_repo/repo.py +5 -3
  10. {instance_repo-1.3.0.dev0 → instance_repo-1.3.1}/instance_repo/store/acr.py +32 -17
  11. {instance_repo-1.3.0.dev0 → instance_repo-1.3.1}/instance_repo.egg-info/PKG-INFO +7 -1
  12. {instance_repo-1.3.0.dev0 → instance_repo-1.3.1}/pyproject.toml +1 -1
  13. {instance_repo-1.3.0.dev0 → instance_repo-1.3.1}/instance_repo/_routing.py +0 -0
  14. {instance_repo-1.3.0.dev0 → instance_repo-1.3.1}/instance_repo/_site_defaults.py +0 -0
  15. {instance_repo-1.3.0.dev0 → instance_repo-1.3.1}/instance_repo/artifacts.py +0 -0
  16. {instance_repo-1.3.0.dev0 → instance_repo-1.3.1}/instance_repo/cache.py +0 -0
  17. {instance_repo-1.3.0.dev0 → instance_repo-1.3.1}/instance_repo/cli.py +0 -0
  18. {instance_repo-1.3.0.dev0 → instance_repo-1.3.1}/instance_repo/clients/__init__.py +0 -0
  19. {instance_repo-1.3.0.dev0 → instance_repo-1.3.1}/instance_repo/clients/benchmarks.py +0 -0
  20. {instance_repo-1.3.0.dev0 → instance_repo-1.3.1}/instance_repo/clients/datasets.py +0 -0
  21. {instance_repo-1.3.0.dev0 → instance_repo-1.3.1}/instance_repo/clients/reports.py +0 -0
  22. {instance_repo-1.3.0.dev0 → instance_repo-1.3.1}/instance_repo/clients/scaffold.py +0 -0
  23. {instance_repo-1.3.0.dev0 → instance_repo-1.3.1}/instance_repo/clients/splits.py +0 -0
  24. {instance_repo-1.3.0.dev0 → instance_repo-1.3.1}/instance_repo/clients/workflows.py +0 -0
  25. {instance_repo-1.3.0.dev0 → instance_repo-1.3.1}/instance_repo/concurrency.py +0 -0
  26. {instance_repo-1.3.0.dev0 → instance_repo-1.3.1}/instance_repo/content.py +0 -0
  27. {instance_repo-1.3.0.dev0 → instance_repo-1.3.1}/instance_repo/endpoints.py +0 -0
  28. {instance_repo-1.3.0.dev0 → instance_repo-1.3.1}/instance_repo/errors.py +0 -0
  29. {instance_repo-1.3.0.dev0 → instance_repo-1.3.1}/instance_repo/image.py +0 -0
  30. {instance_repo-1.3.0.dev0 → instance_repo-1.3.1}/instance_repo/layout.py +0 -0
  31. {instance_repo-1.3.0.dev0 → instance_repo-1.3.1}/instance_repo/loader.py +0 -0
  32. {instance_repo-1.3.0.dev0 → instance_repo-1.3.1}/instance_repo/models.py +0 -0
  33. {instance_repo-1.3.0.dev0 → instance_repo-1.3.1}/instance_repo/paths.py +0 -0
  34. {instance_repo-1.3.0.dev0 → instance_repo-1.3.1}/instance_repo/release.py +0 -0
  35. {instance_repo-1.3.0.dev0 → instance_repo-1.3.1}/instance_repo/retry.py +0 -0
  36. {instance_repo-1.3.0.dev0 → instance_repo-1.3.1}/instance_repo/store/__init__.py +0 -0
  37. {instance_repo-1.3.0.dev0 → instance_repo-1.3.1}/instance_repo/store/base.py +0 -0
  38. {instance_repo-1.3.0.dev0 → instance_repo-1.3.1}/instance_repo/store/oss.py +0 -0
  39. {instance_repo-1.3.0.dev0 → instance_repo-1.3.1}/instance_repo/store/registry.py +0 -0
  40. {instance_repo-1.3.0.dev0 → instance_repo-1.3.1}/instance_repo/tasktoml.py +0 -0
  41. {instance_repo-1.3.0.dev0 → instance_repo-1.3.1}/instance_repo/transport.py +0 -0
  42. {instance_repo-1.3.0.dev0 → instance_repo-1.3.1}/instance_repo/validate.py +0 -0
  43. {instance_repo-1.3.0.dev0 → instance_repo-1.3.1}/instance_repo.egg-info/SOURCES.txt +0 -0
  44. {instance_repo-1.3.0.dev0 → instance_repo-1.3.1}/instance_repo.egg-info/dependency_links.txt +0 -0
  45. {instance_repo-1.3.0.dev0 → instance_repo-1.3.1}/instance_repo.egg-info/entry_points.txt +0 -0
  46. {instance_repo-1.3.0.dev0 → instance_repo-1.3.1}/instance_repo.egg-info/requires.txt +0 -0
  47. {instance_repo-1.3.0.dev0 → instance_repo-1.3.1}/instance_repo.egg-info/top_level.txt +0 -0
  48. {instance_repo-1.3.0.dev0 → instance_repo-1.3.1}/setup.cfg +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: instance-repo
3
- Version: 1.3.0.dev0
3
+ Version: 1.3.1
4
4
  Summary: InstanceRepo SDK — 评测 Instance 统一存储客户端(SDK-only;控制面由 apiserver 承载)
5
5
  Requires-Python: >=3.10
6
6
  Description-Content-Type: text/markdown
@@ -58,6 +58,12 @@ pip install "instance-repo[oss]" # 需要数据面 OSS 读写时,附带 os
58
58
  `profile_overrides={"acr_namespace": ...}`;默认 namespace 由 repo-config 返回,但**必须由部署方
59
59
  在 ACR 企业版实例中预建**,SDK 不会创建)。
60
60
 
61
+ **公网 ACR registry(runner 不在 VPC 内网时)**:默认使用 repo-config 返回的 `registry`
62
+ (VPC 内网域名)。runner 不在对应 VPC 内时,设环境变量 `IR_ACR_PREFER_PUBLIC=1`(或
63
+ `Repo(profile_overrides={"prefer_public_registry": True})`),SDK 会改走 `public_registry`
64
+ (公网域名);公网值缺失时静默回落到 VPC 值。也可用 `IR_ACR_PUBLIC_HOST` /
65
+ `profile_overrides={"acr_public_host": ...}` 显式指定公网 registry。
66
+
61
67
  兼容别名表:
62
68
 
63
69
  | 旧名 | 新名或状态 | 优先级 | 告警 |
@@ -44,6 +44,12 @@ pip install "instance-repo[oss]" # 需要数据面 OSS 读写时,附带 os
44
44
  `profile_overrides={"acr_namespace": ...}`;默认 namespace 由 repo-config 返回,但**必须由部署方
45
45
  在 ACR 企业版实例中预建**,SDK 不会创建)。
46
46
 
47
+ **公网 ACR registry(runner 不在 VPC 内网时)**:默认使用 repo-config 返回的 `registry`
48
+ (VPC 内网域名)。runner 不在对应 VPC 内时,设环境变量 `IR_ACR_PREFER_PUBLIC=1`(或
49
+ `Repo(profile_overrides={"prefer_public_registry": True})`),SDK 会改走 `public_registry`
50
+ (公网域名);公网值缺失时静默回落到 VPC 值。也可用 `IR_ACR_PUBLIC_HOST` /
51
+ `profile_overrides={"acr_public_host": ...}` 显式指定公网 registry。
52
+
47
53
  兼容别名表:
48
54
 
49
55
  | 旧名 | 新名或状态 | 优先级 | 告警 |
@@ -18,7 +18,7 @@ from .errors import (
18
18
  TransportError,
19
19
  )
20
20
 
21
- __version__ = "1.3.0.dev0"
21
+ __version__ = "1.3.1"
22
22
 
23
23
  __all__ = [
24
24
  "Repo", "load_instances",
@@ -36,7 +36,8 @@ _logger = logging.getLogger(__name__)
36
36
  DISCOVERY_TTL_SECONDS = 3600.0
37
37
 
38
38
  #: 由自动发现填充的字段(scaffold 两项不在 repo-config 返回范围内,仍须显式提供)。
39
- DISCOVERABLE_FIELDS = ("oss_bucket", "oss_prefix", "acr_host", "acr_namespace")
39
+ DISCOVERABLE_FIELDS = ("oss_bucket", "oss_prefix", "acr_host",
40
+ "acr_public_host", "acr_namespace")
40
41
 
41
42
  _cache = TTLCache(safety=0.0)
42
43
  _lock = threading.Lock()
@@ -76,6 +76,11 @@ ENV_OSS_PREFIX = "IR_OSS_PREFIX"
76
76
  ENV_SCAFFOLD_BUCKET = "IR_SCAFFOLD_BUCKET"
77
77
  ENV_SCAFFOLD_ROOT = "IR_SCAFFOLD_ROOT"
78
78
 
79
+ # 公网 ACR registry:runner 不在 VPC 内网时,可显式切换使用公网 registry。
80
+ ENV_ACR_PUBLIC_HOST = "IR_ACR_PUBLIC_HOST"
81
+ # 是否优先使用公网 registry("1"/"true"/"on",大小写不敏感)。
82
+ ENV_ACR_PREFER_PUBLIC = "IR_ACR_PREFER_PUBLIC"
83
+
79
84
  #: v0.8 弃用的手工寻址环境变量 → 建议替代。scaffold 两项不在其中:scaffold 包不在
80
85
  #: repo-config 的返回范围内,仍须显式提供。
81
86
  DEPRECATED_ADDRESS_ENVS = {
@@ -179,6 +184,7 @@ class Profile:
179
184
  name: str
180
185
  oss_bucket: str = ""
181
186
  acr_host: str = ""
187
+ acr_public_host: str = ""
182
188
  acr_namespace: str = ""
183
189
  oss_prefix: str = DEFAULT_OSS_PREFIX
184
190
  scaffold_bucket: str = ""
@@ -197,6 +203,21 @@ class Profile:
197
203
  #: ``bootstrap.discover()`` 捕获异常时写入;``require()`` 据此在报错消息里
198
204
  #: 透传根因,避免"返回里没有 acr_host"这类误导性口径。
199
205
  discovery_error: str = ""
206
+ #: 优先使用公网 ACR registry(默认 False=走 VPC 内网)。runner 不在 VPC
207
+ #: 内网时置 True,配合 ``acr_public_host``(repo-config 的 public_registry)
208
+ #: 生效;公网值缺失时静默回落到 ``acr_host``。
209
+ prefer_public_registry: bool = False
210
+
211
+ @property
212
+ def effective_acr_host(self) -> str:
213
+ """ACR 操作实际使用的 registry host。
214
+
215
+ 默认返回 ``acr_host``(repo-config 的 registry,通常是 VPC 内网域名);
216
+ ``prefer_public_registry=True`` 且 ``acr_public_host`` 非空时返回公网域名。
217
+ """
218
+ if self.prefer_public_registry and self.acr_public_host:
219
+ return self.acr_public_host
220
+ return self.acr_host
200
221
 
201
222
  @property
202
223
  def dataset_environment(self) -> str:
@@ -240,12 +261,14 @@ def load_profile(name: str = "default", *, overrides: dict | None = None,
240
261
  storage_env, ENV_STORAGE_ENV, LEGACY_ENV_STORAGE_ENV)
241
262
  env_values = {k: os.environ.get(k, "") for k in
242
263
  (ENV_OSS_BUCKET, ENV_ACR_HOST, ENV_ACR_NAMESPACE,
264
+ ENV_ACR_PUBLIC_HOST,
243
265
  ENV_OSS_PREFIX, ENV_SCAFFOLD_BUCKET, ENV_SCAFFOLD_ROOT)}
244
266
  _warn_deprecated_envs(env_values)
245
267
  cfg = {
246
268
  "oss_bucket": env_values[ENV_OSS_BUCKET],
247
269
  "acr_host": env_values[ENV_ACR_HOST],
248
270
  "acr_namespace": env_values[ENV_ACR_NAMESPACE],
271
+ "acr_public_host": env_values[ENV_ACR_PUBLIC_HOST],
249
272
  "oss_prefix": env_values[ENV_OSS_PREFIX] or DEFAULT_OSS_PREFIX,
250
273
  "scaffold_bucket": env_values[ENV_SCAFFOLD_BUCKET],
251
274
  "scaffold_root": env_values[ENV_SCAFFOLD_ROOT],
@@ -259,19 +282,28 @@ def load_profile(name: str = "default", *, overrides: dict | None = None,
259
282
  sources["api_env"] = "env"
260
283
  else:
261
284
  sources["api_env"] = ""
285
+ prefer_public = False
262
286
  if overrides:
263
- # 只接受已知字段,避免把 api_env 之类误当数据面字段
264
- for k in ("oss_bucket", "acr_host", "acr_namespace", "oss_prefix",
265
- "scaffold_bucket", "scaffold_root", "api_base"):
287
+ # 只接受已知字段,避免把 api_env 之类误当数据面字段;
288
+ # prefer_public_registry 单独取(非寻址字段,不进 **cfg 传 Profile)。
289
+ for k in ("oss_bucket", "acr_host", "acr_namespace", "acr_public_host",
290
+ "oss_prefix", "scaffold_bucket", "scaffold_root", "api_base"):
266
291
  if k in overrides and overrides[k] is not None:
267
292
  cfg[k] = overrides[k]
268
293
  sources[k] = "explicit"
294
+ if overrides.get("prefer_public_registry") is not None:
295
+ prefer_public = bool(overrides["prefer_public_registry"])
269
296
  if cfg["api_base"]:
270
297
  cfg["api_base"] = str(cfg["api_base"]).rstrip("/")
298
+ if not prefer_public:
299
+ # 环境变量开关:IR_ACR_PREFER_PUBLIC=1/true/on(大小写不敏感)
300
+ prefer_public = os.environ.get(ENV_ACR_PREFER_PUBLIC, "").strip().lower() \
301
+ in ("1", "true", "on")
271
302
  return Profile(name=name, api_env=env,
272
303
  cluster=str(cluster_value).strip(),
273
304
  storage_env=normalize_storage_env(storage_value),
274
305
  metadata_model=(metadata_model or "").strip(),
306
+ prefer_public_registry=bool(prefer_public),
275
307
  sources=sources, **cfg)
276
308
 
277
309
 
@@ -323,6 +355,8 @@ def fetch_repo_config(transport, *, cluster: str = "", storage_env: str = "") ->
323
355
  if acr := data.get("acr"):
324
356
  if acr.get("registry"):
325
357
  result["acr_host"] = acr["registry"]
358
+ if acr.get("public_registry"):
359
+ result["acr_public_host"] = acr["public_registry"]
326
360
  if acr.get("namespace"):
327
361
  result["acr_namespace"] = acr["namespace"]
328
362
  # api_env 由 apiserver 在 repo-config 响应中下发(omitempty,旧版不返回)。
@@ -48,7 +48,7 @@ class ImageClient:
48
48
  计算**目标环境**的引用,配合 :meth:`copy` 做跨环境搬运。
49
49
  """
50
50
  host = acr_host or bootstrap.require(
51
- self._p, "acr_host", action="拼 ACR 镜像引用")
51
+ self._p, "effective_acr_host", action="拼 ACR 镜像引用")
52
52
  ns = namespace or bootstrap.require(
53
53
  self._p, "acr_namespace", action="拼 ACR 镜像引用")
54
54
  return self._layout(metadata_model).image_ref(
@@ -377,7 +377,7 @@ class InstancesClient:
377
377
  if push_image:
378
378
  # 自带 tar 且会推 ACR:docker_image 记它将被推到的 ACR 目标地址。
379
379
  # 仅在 push_image 时记——否则该 ACR 地址指向从未推送过的镜像,是假的。
380
- docker_ref = lay.image_ref(self._p.acr_host, self._p.acr_namespace,
380
+ docker_ref = lay.image_ref(self._p.effective_acr_host, self._p.acr_namespace,
381
381
  dataset, instance_id,
382
382
  version=version, split=split)
383
383
  else:
@@ -399,7 +399,7 @@ class InstancesClient:
399
399
  if image_release_dst_acr:
400
400
  from .. import release as _R # 局部导入避免循环依赖
401
401
  extend_meta = _R.image_release_meta(
402
- docker_ref, self._p.acr_host, image_release_dst_acr)
402
+ docker_ref, self._p.effective_acr_host, image_release_dst_acr)
403
403
 
404
404
  # ② 写元数据(pending) → 拿稳定 id(register=False 时跳过,用本地 id)
405
405
  meta = DatasetInstance(
@@ -702,6 +702,8 @@ class InstancesClient:
702
702
  warm(sts_prefix)
703
703
  # 推镜像时同样预热 ACR 凭据缓存(否则首轮各 worker 会并发重复签同一 host)
704
704
  if push_image and getattr(self._p, "acr_host", None):
705
+ # 签名恒用 apiserver 登记的 host(acr_host,VPC);token 实例级,
706
+ # 对公网 endpoint 同样有效(prefer_public 时连接走公网、签名仍走这里)。
705
707
  try:
706
708
  self._t.get_acr_credentials(self._p.acr_host)
707
709
  except Exception: # noqa: BLE001 — 预热失败不阻断,真正推镜像时再报
@@ -699,10 +699,10 @@ class VersionsClient:
699
699
  kw.get("split", "default"))
700
700
  kw["recorded_images"] = recorded
701
701
  for iid, img in sorted(recorded.items()):
702
- if img and not img.startswith(self._p.acr_host + "/"):
702
+ if img and not img.startswith(self._p.effective_acr_host + "/"):
703
703
  skipped.append({
704
704
  "instance_id": iid, "image": img,
705
- "reason": f"not on source ACR {self._p.acr_host}; "
705
+ "reason": f"not on source ACR {self._p.effective_acr_host}; "
706
706
  f"base/共享镜像不随数据集上架搬运",
707
707
  })
708
708
  wf = self.publish(dataset, version, instances=instances, images=images, **kw)
@@ -814,8 +814,8 @@ class VersionsClient:
814
814
  raise SchemaError("images='on' 需要 instances 列表(镜像按实例枚举)")
815
815
  image_dists = R.build_image_distributions(
816
816
  dataset, version, instances,
817
- src_acr=self._p.acr_host, src_namespace=self._p.acr_namespace,
818
- dst_acr=dst.acr_host,
817
+ src_acr=self._p.effective_acr_host, src_namespace=self._p.acr_namespace,
818
+ dst_acr=dst.effective_acr_host,
819
819
  # 目标命名空间:v0.8 之前解析了 --target-acr-namespace 却只换 host,
820
820
  # 该参数从未生效;这里真正把它传下去。为空则保留源命名空间(旧行为)。
821
821
  dst_namespace=dst.acr_namespace,
@@ -70,7 +70,9 @@ class Repo:
70
70
  self._content = OssContentStore(
71
71
  self.transport, self.profile.oss_bucket,
72
72
  bucket_factory=bucket_factory)
73
- self._image = AcrImageStore(self.transport, runner=runner)
73
+ self._image = AcrImageStore(
74
+ self.transport, runner=runner,
75
+ prefer_public=self.profile.prefer_public_registry)
74
76
  # 读路径必须与写路径对称下发 environment 与 metadata_model:
75
77
  # ingest 按 storage_env 写 pre 集合、默认 split_first,读若不下发会查 online/
76
78
  # version_first 而闭环断裂(历史真实缺陷,见 store/registry.py)。
@@ -308,8 +310,8 @@ class Repo:
308
310
  raise SchemaError(
309
311
  "rewrite_task_toml_image 需要目标 oss_bucket(用 target_overrides 提供),"
310
312
  "否则无法把改写后的 content.tgz 直传目标桶")
311
- src_acr = self.profile.acr_host
312
- dst_acr = dst.acr_host
313
+ src_acr = self.profile.effective_acr_host
314
+ dst_acr = dst.effective_acr_host
313
315
  dst_ns = dst.acr_namespace
314
316
 
315
317
  # instance_id → 本地目录(仅 harbor 目录;SWE 是 .json 文件,没有 task.toml)
@@ -192,10 +192,15 @@ def _pin_digest(ref: str, digest: str) -> str:
192
192
 
193
193
 
194
194
  class AcrImageStore(BaseImageStore):
195
- def __init__(self, transport, *, runner: Runner | None = None) -> None:
195
+ def __init__(self, transport, *, runner: Runner | None = None,
196
+ prefer_public: bool = False) -> None:
196
197
  self._t = transport
197
198
  self._injected_runner = runner is not None
198
199
  self._run = runner or _default_runner
200
+ # prefer_public:runner 不在 VPC 内网时置 True(对应 profile.prefer_public_registry)。
201
+ # 连接优先公网 endpoint;凭据签名仍用 private canonical host(apiserver acr_profiles
202
+ # 只登记 VPC host,GetAuthorizationToken 的 token 是实例级、对两个 endpoint 通用)。
203
+ self._prefer_public = prefer_public
199
204
 
200
205
  def _deadline(self) -> float:
201
206
  return time.monotonic() + _DEFAULT_OPERATION_DEADLINE_SECONDS
@@ -225,9 +230,13 @@ class AcrImageStore(BaseImageStore):
225
230
  host = _registry_host(ref)
226
231
  route = _plan_acr_route(host)
227
232
  canonical = _with_host(ref, route.private_endpoint)
228
- candidates = [canonical]
229
- if route.public_endpoint and route.public_endpoint != route.private_endpoint:
230
- candidates.append(_with_host(ref, route.public_endpoint))
233
+ if self._prefer_public and route.public_endpoint \
234
+ and route.public_endpoint != route.private_endpoint:
235
+ candidates = [_with_host(ref, route.public_endpoint), canonical]
236
+ else:
237
+ candidates = [canonical]
238
+ if route.public_endpoint and route.public_endpoint != route.private_endpoint:
239
+ candidates.append(_with_host(ref, route.public_endpoint))
231
240
  return canonical, tuple(candidates)
232
241
 
233
242
  def _net_ref(self, ref: str) -> str:
@@ -413,11 +422,14 @@ class AcrImageStore(BaseImageStore):
413
422
  def pull(self, ref: str, tar_path: Path, *, overwrite: bool = False) -> str:
414
423
  """把远端镜像拉到本地 docker-archive tar;返回实际拉取的 digest 固定引用。
415
424
 
416
- 与 OSS 下载同口径:``pull`` 是**下载动作,强制私网**——只用私网候选,不做公网回退。
425
+ 与 OSS 下载同口径:``pull`` 是**下载动作,默认强制私网**——只用私网候选,不做公网回退。
417
426
  私网端点无法确认为标准 ACR 私网地址(自定义 registry),或私网连通性失败时,抛
418
427
  ``PrivateNetworkRequired``,绝不静默走公网。
419
428
 
420
- 源引用先经私网 inspect 取得不可变 digest 并以 digest 固定后再拉,避免 tag 在
429
+ 例外:构造时 ``prefer_public=True``(IR_ACR_PREFER_PUBLIC=1,runner 不在 VPC 内网)
430
+ 时改走**公网 endpoint**(仍经标准 ACR 确认;凭据仍用 VPC host 签,token 实例级通用)。
431
+
432
+ 源引用先经 inspect 取得不可变 digest 并以 digest 固定后再拉,避免 tag 在
421
433
  inspect 与 copy 之间被覆盖、导致拉到非预期镜像。
422
434
  """
423
435
  deadline = self._deadline()
@@ -428,26 +440,29 @@ class AcrImageStore(BaseImageStore):
428
440
  "download requires private data-plane access; registry "
429
441
  f"{_registry_host(ref)} cannot be confirmed as a standard "
430
442
  "private ACR endpoint; public fallback is disabled")
431
- private_ref = _with_host(ref, route.private_endpoint)
443
+ if self._prefer_public:
444
+ data_ref = _with_host(ref, route.public_endpoint)
445
+ else:
446
+ data_ref = _with_host(ref, route.private_endpoint)
432
447
 
433
- authfile = self._authfile(private_ref, credentials=credentials)
448
+ authfile = self._authfile(data_ref, credentials=credentials)
434
449
  try:
435
- inspected = self._inspect(private_ref, authfile, deadline)
450
+ inspected = self._inspect(data_ref, authfile, deadline)
436
451
  finally:
437
452
  self._cleanup(authfile)
438
453
  if inspected.state is _InspectState.ERROR:
439
- error = self._inspect_error(private_ref, inspected, authfile)
454
+ error = self._inspect_error(data_ref, inspected, authfile)
440
455
  if _is_skopeo_connectivity_error(inspected.stderr):
441
456
  raise PrivateNetworkRequired(
442
- "download requires private data-plane access; private "
443
- f"registry {route.private_endpoint} is unreachable; "
457
+ "download data-plane access failed; registry "
458
+ f"{_registry_host(data_ref)} is unreachable; "
444
459
  "public fallback is disabled", cause=error)
445
460
  raise error
446
461
  if inspected.state is _InspectState.ABSENT:
447
- raise TransportError(f"source image manifest not found: {private_ref}")
462
+ raise TransportError(f"source image manifest not found: {data_ref}")
448
463
  if inspected.digest is None:
449
464
  raise TransportError(
450
- f"source inspect returned no immutable digest: {private_ref}")
465
+ f"source inspect returned no immutable digest: {data_ref}")
451
466
 
452
467
  target = Path(tar_path)
453
468
  if target.exists() and not overwrite:
@@ -456,7 +471,7 @@ class AcrImageStore(BaseImageStore):
456
471
  if target.parent and not target.parent.exists():
457
472
  target.parent.mkdir(parents=True, exist_ok=True)
458
473
 
459
- pinned = _pin_digest(private_ref, inspected.digest)
474
+ pinned = _pin_digest(data_ref, inspected.digest)
460
475
  authfile = self._authfile(pinned, credentials=credentials)
461
476
  try:
462
477
  command = self._run_command(
@@ -470,8 +485,8 @@ class AcrImageStore(BaseImageStore):
470
485
  "skopeo copy(reg→archive) failed", command.stderr, authfile)
471
486
  if _is_skopeo_connectivity_error(command.stderr):
472
487
  raise PrivateNetworkRequired(
473
- "download requires private data-plane access; private "
474
- f"registry {route.private_endpoint} is unreachable; "
488
+ "download data-plane access failed; registry "
489
+ f"{_registry_host(data_ref)} is unreachable; "
475
490
  "public fallback is disabled", cause=cause)
476
491
  raise cause
477
492
  finally:
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: instance-repo
3
- Version: 1.3.0.dev0
3
+ Version: 1.3.1
4
4
  Summary: InstanceRepo SDK — 评测 Instance 统一存储客户端(SDK-only;控制面由 apiserver 承载)
5
5
  Requires-Python: >=3.10
6
6
  Description-Content-Type: text/markdown
@@ -58,6 +58,12 @@ pip install "instance-repo[oss]" # 需要数据面 OSS 读写时,附带 os
58
58
  `profile_overrides={"acr_namespace": ...}`;默认 namespace 由 repo-config 返回,但**必须由部署方
59
59
  在 ACR 企业版实例中预建**,SDK 不会创建)。
60
60
 
61
+ **公网 ACR registry(runner 不在 VPC 内网时)**:默认使用 repo-config 返回的 `registry`
62
+ (VPC 内网域名)。runner 不在对应 VPC 内时,设环境变量 `IR_ACR_PREFER_PUBLIC=1`(或
63
+ `Repo(profile_overrides={"prefer_public_registry": True})`),SDK 会改走 `public_registry`
64
+ (公网域名);公网值缺失时静默回落到 VPC 值。也可用 `IR_ACR_PUBLIC_HOST` /
65
+ `profile_overrides={"acr_public_host": ...}` 显式指定公网 registry。
66
+
61
67
  兼容别名表:
62
68
 
63
69
  | 旧名 | 新名或状态 | 优先级 | 告警 |
@@ -4,7 +4,7 @@ build-backend = "setuptools.build_meta"
4
4
 
5
5
  [project]
6
6
  name = "instance-repo"
7
- version = "1.3.0.dev0"
7
+ version = "1.3.1"
8
8
  description = "InstanceRepo SDK — 评测 Instance 统一存储客户端(SDK-only;控制面由 apiserver 承载)"
9
9
  requires-python = ">=3.10"
10
10
  readme = "README.md"