Skip to content

Commit 67fb6e0

Browse files
authored
Partial support of registries.conf (unqualified-search-registries) (#434)
2 parents c170109 + 5e5f017 commit 67fb6e0

11 files changed

Lines changed: 732 additions & 122 deletions

File tree

pom.xml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -230,6 +230,10 @@
230230
<groupId>tools.jackson.core</groupId>
231231
<artifactId>jackson-databind</artifactId>
232232
</dependency>
233+
<dependency>
234+
<groupId>tools.jackson.dataformat</groupId>
235+
<artifactId>jackson-dataformat-toml</artifactId>
236+
</dependency>
233237

234238
<!-- Test dependencies -->
235239
<dependency>

src/main/java/land/oras/ContainerRef.java

Lines changed: 59 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222

2323
import java.net.URLEncoder;
2424
import java.nio.charset.StandardCharsets;
25+
import java.nio.file.Path;
2526
import java.util.Objects;
2627
import java.util.regex.Matcher;
2728
import java.util.regex.Pattern;
@@ -30,6 +31,8 @@
3031
import land.oras.utils.SupportedAlgorithm;
3132
import org.jspecify.annotations.NullMarked;
3233
import org.jspecify.annotations.Nullable;
34+
import org.slf4j.Logger;
35+
import org.slf4j.LoggerFactory;
3336

3437
/**
3538
* A referer of a container on a {@link Registry}.
@@ -38,6 +41,11 @@
3841
@OrasModel
3942
public final class ContainerRef extends Ref<ContainerRef> {
4043

44+
/**
45+
* The logger for this class.
46+
*/
47+
public static final Logger LOG = LoggerFactory.getLogger(ContainerRef.class);
48+
4149
/**
4250
* The regex pattern to parse the container name including the registry, namespace, repository, tag and digest.
4351
*/
@@ -106,20 +114,6 @@ public String getRegistry() {
106114
return registry;
107115
}
108116

109-
/**
110-
* Get the effective registry based on given target
111-
* @param target The target registry
112-
* @return The effective registry
113-
*/
114-
public String getEffectiveRegistry(Registry target) {
115-
if (isUnqualified()) {
116-
if (target.getRegistry() != null) {
117-
return target.getRegistry();
118-
}
119-
}
120-
return registry;
121-
}
122-
123117
/**
124118
* Whether the container reference is unqualified without registry
125119
* @return True if unqualified
@@ -387,6 +381,23 @@ public static ContainerRef parse(String name) {
387381
return new ContainerRef(registry, unqualified, namespace, repository, tag, digest);
388382
}
389383

384+
/**
385+
* Get the effective registry based on given target
386+
* This methods will perform HEAD request to determine the first unqualified search registry that contains the container reference if the reference is unqualified, otherwise return the registry of the reference.
387+
* This only works with Manifests and Index but now direct blob access.
388+
* See {@link #forRegistry(String)} so set correct registry when getting blobs outside high level API like {@link Registry#pullArtifact(ContainerRef, Path, boolean)}.
389+
* @param target The target registry
390+
* @return The effective registry
391+
*/
392+
public String getEffectiveRegistry(Registry target) {
393+
if (isUnqualified()) {
394+
return target.getRegistry() != null
395+
? target.getRegistry()
396+
: determineFirstUnqualifiedSearchRegistry(target);
397+
}
398+
return registry;
399+
}
400+
390401
/**
391402
* Return a copy of reference for a registry other registry
392403
* @param registry The registry
@@ -402,6 +413,13 @@ public ContainerRef forRegistry(String registry) {
402413
* @return The container reference
403414
*/
404415
public ContainerRef forRegistry(Registry registry) {
416+
if (isUnqualified() && registry.getRegistry() == null) {
417+
LOG.info(
418+
"The container reference {} was created without a registry. Will try to resolve using unqualified-search-registries in order",
419+
this);
420+
return new ContainerRef(
421+
determineFirstUnqualifiedSearchRegistry(registry), false, namespace, repository, tag, digest);
422+
}
405423
return new ContainerRef(
406424
registry.getRegistry() != null ? registry.getRegistry() : this.registry,
407425
false, // not unqualified if registry is set
@@ -411,6 +429,27 @@ public ContainerRef forRegistry(Registry registry) {
411429
digest);
412430
}
413431

432+
private String determineFirstUnqualifiedSearchRegistry(Registry registry) {
433+
// No settings, keep old behavior of defaulting to docker.io for unqualified reference
434+
if (registry.getRegistriesConf().getUnqualifiedRegistries().isEmpty()) {
435+
return Const.DEFAULT_REGISTRY;
436+
}
437+
LOG.debug(
438+
"Found registries in unqualified-search-registries: {}",
439+
registry.getRegistriesConf().getUnqualifiedRegistries());
440+
for (String searchRegistry : registry.getRegistriesConf().getUnqualifiedRegistries()) {
441+
Registry targetRegistry = registry.copy(registry, searchRegistry);
442+
LOG.debug("Checking if container {} exists in unqualified search registry {}", this, searchRegistry);
443+
if (targetRegistry.exists(this)) {
444+
LOG.debug("Found container {} in unqualified search registry {}", this, searchRegistry);
445+
return searchRegistry;
446+
}
447+
}
448+
throw new OrasException(
449+
"Container reference %s is unqualified and cannot be found in any of the unqualified search registries: %s"
450+
.formatted(this, registry.getRegistriesConf().getUnqualifiedRegistries()));
451+
}
452+
414453
@Override
415454
public boolean equals(Object o) {
416455
if (o == null || getClass() != o.getClass()) return false;
@@ -429,6 +468,12 @@ public int hashCode() {
429468

430469
@Override
431470
public String toString() {
471+
if (isUnqualified()) {
472+
if (namespace != null && !namespace.isEmpty()) {
473+
return "%s/%s:%s%s".formatted(namespace, repository, tag, digest != null ? "@" + digest : "");
474+
}
475+
return "%s:%s%s".formatted(repository, tag, digest != null ? "@" + digest : "");
476+
}
432477
if (namespace != null && !namespace.isEmpty()) {
433478
return "%s/%s/%s:%s%s".formatted(registry, namespace, repository, tag, digest != null ? "@" + digest : "");
434479
}

0 commit comments

Comments
 (0)