Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,7 @@ class PromoteHelper {
private final String token;
private final String imageTag;
private final @Nullable String additionalTag;
private final @Nullable String replacementTag;

/**
* Promote the staged flex template image using MOSS promote API.
Expand All @@ -52,16 +53,26 @@ class PromoteHelper {
* @param imageTag - image tag
* @param additionalTag - additional destination tag, used by repo managements, e.g.
* public-image-latest
* @param replacementTag - tag to put on original holder of additionalTag, used by repo
* managements, e.g. no-new-use-public-image-
* @param sourceDigest - source image digest, e.g. sha256:xxxxx
*/
public PromoteHelper(
String sourcePath,
String targetPath,
String imageTag,
@Nullable String additionalTag,
@Nullable String replacementTag,
String sourceDigest)
throws IOException, InterruptedException {
this(sourcePath, targetPath, imageTag, additionalTag, sourceDigest, accessToken());
this(
sourcePath,
targetPath,
imageTag,
additionalTag,
replacementTag,
sourceDigest,
accessToken());
}

@VisibleForTesting
Expand All @@ -70,30 +81,39 @@ public PromoteHelper(
String targetPath,
String imageTag,
@Nullable String additionalTag,
@Nullable String replacementTag,
String sourceDigest,
String token) {
this.sourceSpec = new ArtifactRegImageSpec(sourcePath);
this.targetSpec = new ArtifactRegImageSpec(targetPath);
this.imageTag = imageTag;
this.additionalTag = additionalTag;
this.replacementTag = replacementTag;
this.sourceDigest = sourceDigest;
this.token = token;
this.targetPath = targetPath;
}

/** Promote the artifact. */
public void promote() throws IOException, InterruptedException {
String originalDigest = null;
if (additionalTag != null) {
originalDigest = getDigestFromTag(additionalTag);
}
String[] promoteArtifactCmd = getPromoteFlexTemplateImageCmd();
// promote API returns a long-running-operation
String responseRLO = TemplatesStageMojo.runCommandCapturesOutput(promoteArtifactCmd, null);
JsonElement parsed = JsonParser.parseString(responseRLO);
String operation = parsed.getAsJsonObject().get("name").getAsString();
waitForComplete(operation);
addTag(imageTag);
addTag(imageTag, sourceDigest);
// override latest (for pull default tag) and additionalTag (for vul scan, if present)
addTag("latest");
addTag("latest", sourceDigest);
if (additionalTag != null) {
addTag(additionalTag);
addTag(additionalTag, sourceDigest);
}
if (originalDigest != null && !originalDigest.isEmpty()) {
addTag(replacementTag, originalDigest);
}
}

Expand Down Expand Up @@ -157,7 +177,7 @@ private void waitForComplete(String operation) {
}

/** Add tag after promotion. */
private void addTag(String tag) throws IOException, InterruptedException {
private void addTag(String tag, String digest) throws IOException, InterruptedException {
// TODO: remove this once copy tag is supported by promote API
String[] command;
if (targetSpec.repository.endsWith("gcr.io")) {
Expand All @@ -169,7 +189,7 @@ private void addTag(String tag) throws IOException, InterruptedException {
"images",
"add-tag",
"-q",
String.format("%s@%s", targetPath, sourceDigest),
String.format("%s@%s", targetPath, digest),
String.format("%s:%s", targetPath, tag)
};
} else {
Expand All @@ -180,13 +200,65 @@ private void addTag(String tag) throws IOException, InterruptedException {
"docker",
"tags",
"add",
String.format("%s@%s", targetPath, sourceDigest),
String.format("%s@%s", targetPath, digest),
String.format("%s:%s", targetPath, tag)
};
}
TemplatesStageMojo.runCommandCapturesOutput(command, null);
}

/**
* Get the digest of an image with a specific tag.
*
* @param tag - The tag of the image to retrieve.
* @return The digest of the image.
*/
@VisibleForTesting
String getDigestFromTag(String tag) throws IOException, InterruptedException {
String[] command;
String imageReference = String.format("%s:%s", targetPath, tag);

if (targetSpec.repository.endsWith("gcr.io")) {
// gcr.io repository needs to use `gcloud container` to list tags
command =
new String[] {
"gcloud",
"container",
"images",
"list-tags",
targetPath, // This is the image name, e.g., us.gcr.io/my-project/my-image
"--filter=tags:" + tag,
"--format",
"get(digest)"
};
} else {
// Artifact Registry repository needs to use `gcloud artifacts docker images describe`
command =
new String[] {
"gcloud",
"artifacts",
"docker",
"images",
"describe",
imageReference, // This is the full image reference including tag, e.g.,
// us-central1-docker.pkg.dev/my-project/my-repo/my-image:tag
"--format",
"get(image_summary.digest)"
};
}

String response = "";
try {
response = TemplatesStageMojo.runCommandCapturesOutput(command, null);
} catch (Exception e) {
// Swallow exceptions here - usually this means that the image does not exist with the tag
return "";
}
// The response is expected to be just the digest, e.g., "sha256:..."
// Trim any leading/trailing whitespace.
return response.trim();
}

private static class QueryOperationRunnable implements dev.failsafe.function.CheckedRunnable {
String[] command;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,8 @@
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.time.Duration;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
Expand Down Expand Up @@ -550,14 +552,18 @@ protected String stageFlexTemplate(
// resolve tag to apply
ImageSpecMetadata metadata = imageSpec.getMetadata();
String trackTag = "public-image-latest";
String dateSuffix =
LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyy-MM-dd-HH"));
String deprecatedTag = "no-new-use-public-image-newer-available-" + dateSuffix;
if (metadata.isHidden()) {
trackTag = "no-new-use-public-image-latest";
} else if (metadata.getName().contains("[Deprecated]")) {
trackTag = "deprecated-public-image-latest";
}
// promote image
PromoteHelper promoteHelper =
new PromoteHelper(imagePath, targetImagePath, stagePrefix, trackTag, digest);
new PromoteHelper(
imagePath, targetImagePath, stagePrefix, trackTag, deprecatedTag, digest);
promoteHelper.promote();

if (!stageImageOnly) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ public void testPromoteFlexTemplateImage() {
"us-docker.pkg.dev/target-project/target-repo/some-prefix/io_to_io",
"2020_10_10_rc00",
null,
null,
"sha256:123",
"fake-token");
String[] cmds = helper.getPromoteFlexTemplateImageCmd();
Expand Down
Loading