Skip to content

Commit

Permalink
STONEBLD-1954 assign each build attempt a unique ID
Browse files Browse the repository at this point in the history
  • Loading branch information
stuartwdouglas committed Nov 19, 2023
1 parent fb4b3f6 commit 400f948
Show file tree
Hide file tree
Showing 9 changed files with 68 additions and 50 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -27,8 +27,8 @@ public class ContainerTagCommand implements Runnable {
@CommandLine.Option(names = "--registry-prepend-tag", defaultValue = "")
String prependTag;

@CommandLine.Option(names = "--image-id", required = true)
String imageId;
@CommandLine.Option(names = "--image-digest", required = true)
String imageDigest;

@CommandLine.Parameters(split = ",")
List<String> gavs;
Expand All @@ -41,9 +41,9 @@ public void run() {

ContainerRegistryDeployer deployer = new ContainerRegistryDeployer(host, port, owner, token.orElse(""), repository,
insecure,
prependTag, imageId);
prependTag);
try {
deployer.tagArchive(gavs);
deployer.tagArchive(imageDigest, gavs);
} catch (Exception e) {
throw new RuntimeException(e);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,7 @@ public class DeployCommand implements Runnable {
private static final String DOT_POM = ".pom";
private static final String DOT = ".";
private static final Set<String> ALLOWED_CONTAMINANTS = Set.of("-tests.jar");
public static final String IMAGE_DIGEST_OUTPUT = "Image Digest: ";
final BeanManager beanManager;
final ResultsUpdater resultsUpdater;

Expand Down Expand Up @@ -133,6 +134,8 @@ public class DeployCommand implements Runnable {
@CommandLine.Option(names = "--git-identity")
String gitIdentity;

@CommandLine.Option(names = "--build-id")
String buildId;
// Testing only ; used to disable image deployment
protected boolean imageDeployment = true;

Expand Down Expand Up @@ -214,7 +217,7 @@ public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IO
+ gav.getVersion(),
"rebuilt",
Map.of("scm-uri", scmUri, "scm-commit", commit, "hermetic",
Boolean.toString(hermetic))),
Boolean.toString(hermetic), "build-id", buildId)),
Files.newOutputStream(temp), false);
Files.delete(file);
Files.move(temp, file);
Expand Down Expand Up @@ -305,6 +308,9 @@ public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) {
} else {
Log.errorf("Skipped deploying from task run %s as all artifacts were contaminated", taskRun);
}
if (imageDigest != null) {
System.out.println(IMAGE_DIGEST_OUTPUT + "sha256:" + imageDigest);
}
if (taskRun != null) {

List<Contaminates> newContaminates = new ArrayList<>();
Expand Down Expand Up @@ -383,15 +389,15 @@ public FileVisitResult preVisitDirectory(Path dir, BasicFileAttributes attrs) th
protected void doDeployment(Path sourcePath, Path logsPath, Set<String> gavs) throws Exception {
if (imageDeployment) {
ContainerRegistryDeployer deployer = new ContainerRegistryDeployer(host, port, owner, token.orElse(""), repository,
insecure, prependTag,
imageId);
deployer.deployArchive(deploymentPath, sourcePath, logsPath, gavs, new BiConsumer<String, String>() {
@Override
public void accept(String s, String hash) {
imageName = s;
imageDigest = hash;
}
});
insecure, prependTag);
deployer.deployArchive(deploymentPath, sourcePath, logsPath, gavs, imageId, buildId,
new BiConsumer<String, String>() {
@Override
public void accept(String s, String hash) {
imageName = s;
imageDigest = hash;
}
});
}
if (isNotEmpty(mvnRepo)) {
// Maven Repo Deployment
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@ public class DeployHermeticPreBuildImageCommand implements Runnable {
public void run() {
ContainerRegistryDeployer deployer = new ContainerRegistryDeployer(host, port, owner, token.orElse(""), repository,
insecure,
prependTag, "");
prependTag);
try {
deployer.deployHermeticPreBuildImage(builderImage, buildArtifactsPath, repositoryPath, imageSourcePath, imageName,
new BiConsumer<String, String>() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ public class DeployPreBuildImageCommand implements Runnable {
public void run() {
ContainerRegistryDeployer deployer = new ContainerRegistryDeployer(host, port, owner, token.orElse(""), repository,
insecure,
prependTag, "");
prependTag);
try {
deployer.deployPreBuildImage(builderImage, sourcePath, imageSourcePath, imageName,
new BiConsumer<String, String>() {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@
import java.util.List;
import java.util.Optional;
import java.util.Set;
import java.util.UUID;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import java.util.function.BiConsumer;
Expand Down Expand Up @@ -56,16 +55,14 @@ public class ContainerRegistryDeployer {

private final Credential credential;

final String imageId;

public ContainerRegistryDeployer(
String host,
int port,
String owner,
String token,
String repository,
boolean insecure,
String prependTag, String imageId) {
String prependTag) {
if (insecure) {
System.setProperty("sendCredentialsOverHttp", "true");
}
Expand All @@ -76,7 +73,6 @@ public ContainerRegistryDeployer(
this.repository = repository;
this.insecure = insecure;
this.prependTag = prependTag;
this.imageId = imageId;
String fullName = host + (port == 443 ? "" : ":" + port) + "/" + owner + "/" + repository;
this.credential = ContainerUtil.processToken(fullName, token);

Expand All @@ -86,18 +82,18 @@ public ContainerRegistryDeployer(
Log.infof("Prepend tag is %s", prependTag);
}

public void deployArchive(Path deployDir, Path sourcePath, Path logsPath, Set<String> gavs,
public void deployArchive(Path deployDir, Path sourcePath, Path logsPath, Set<String> gavs, String imageId, String buildId,
BiConsumer<String, String> imageNameHashCallback) throws Exception {
Log.debugf("Using Container registry %s:%d/%s/%s", host, port, owner, repository);

// Read the tar to get the gavs and files
DeployData imageData = new DeployData(deployDir, gavs);

// Create the image layers
createImages(imageData, sourcePath, logsPath, imageNameHashCallback);
createImages(imageData, sourcePath, logsPath, imageId, buildId, imageNameHashCallback);
}

public void tagArchive(List<String> gavNames) throws Exception {
public void tagArchive(String imageDigest, List<String> gavNames) throws Exception {
if (gavNames.isEmpty()) {
throw new RuntimeException("Empty GAV list");
}
Expand All @@ -107,7 +103,7 @@ public void tagArchive(List<String> gavNames) throws Exception {
gavs.push(Gav.parse(i));
}
Gav first = gavs.pop();
String existingImage = createImageName(imageId);
String existingImage = createImageNameFromDigest(imageDigest);
RegistryImage existingRegistryImage = RegistryImage.named(existingImage);
RegistryImage registryImage = RegistryImage.named(createImageName(first.getTag()));
if (credential != null) {
Expand Down Expand Up @@ -221,17 +217,18 @@ public FileVisitResult visitFile(Path file, BasicFileAttributes attrs) throws IO
}

private void createImages(DeployData imageData, Path sourcePath, Path logsPath,
BiConsumer<String, String> imageNameHashCallback)
String imageId, String buildId, BiConsumer<String, String> imageNameHashCallback)
throws InvalidImageReferenceException, InterruptedException, RegistryException, IOException,
CacheDirectoryCreationException, ExecutionException {

String imageName = createImageName();
String imageName = createImageName(buildId);
RegistryImage registryImage = RegistryImage.named(imageName);
if (credential != null) {
registryImage = registryImage.addCredentialRetriever(() -> Optional.of(credential));
}
Containerizer containerizer = Containerizer
.to(registryImage)
.withAdditionalTag(imageId)
.setAllowInsecureRegistries(insecure);
Log.infof("Deploying base image %s", imageName);

Expand Down Expand Up @@ -260,11 +257,6 @@ private void createImages(DeployData imageData, Path sourcePath, Path logsPath,
}
}

private String createImageName() {
String tag = imageId == null ? UUID.randomUUID().toString() : imageId;
return createImageName(tag);
}

private String createImageName(String tag) {
// As the tests utilise prependTag for uniqueness so check for that
// here to avoid reusing images when we want differentiation.
Expand All @@ -284,6 +276,15 @@ private String createImageName(String tag) {
+ ":" + tag;
}

private String createImageNameFromDigest(String digest) {
if (port == 443) {
return host + "/" + owner + "/" + repository
+ "@" + digest;
}
return host + ":" + port + "/" + owner + "/" + repository
+ "@" + digest;
}

private List<Path> getLayers(Path artifacts, Path source, Path logs) {
Log.debug("\n Container details:\n"
+ "\t layer 1 (source) " + source.toString() + "\n"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@
import java.nio.file.Paths;
import java.util.List;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

import org.junit.jupiter.api.AfterAll;
import org.junit.jupiter.api.Assertions;
Expand Down Expand Up @@ -81,6 +83,7 @@ public void testDeployArchive(QuarkusMainLauncher launcher) throws IOException {
"--image-id=test-image",
"--registry-host=" + container.getHost(),
"--registry-port=" + port,
"--build-id=test-id",
"--registry-owner=" + OWNER,
"--registry-repository=" + REPOSITORY,
"--source-path=" + source.toAbsolutePath().toString(),
Expand All @@ -92,18 +95,24 @@ public void testDeployArchive(QuarkusMainLauncher launcher) throws IOException {
Assertions.assertEquals(0, result.exitCode());
// Now we validate that the image and tags exist in the registry
ContainerRegistryDetails containerRegistryDetails = getContainerRegistryDetails();

Assertions.assertTrue(containerRegistryDetails.repoName.startsWith(OWNER + "/" + REPOSITORY));
Assertions.assertTrue(containerRegistryDetails.tags.contains("test-image"));
Assertions.assertTrue(containerRegistryDetails.tags.contains("test-id"));
Assertions.assertFalse(containerRegistryDetails.tags.contains(EXPECTED_TAG_1));
Assertions.assertFalse(containerRegistryDetails.tags.contains(EXPECTED_TAG_2));
System.out.println(result.getOutput());
Pattern p = Pattern.compile(DeployCommand.IMAGE_DIGEST_OUTPUT + "(.*)");
Matcher matcher = p.matcher(result.getOutput());
Assertions.assertTrue(matcher.find());
String digest = matcher.group(1);

result = launcher.launch("tag-container",
"--registry-host=" + container.getHost(),
"--registry-port=" + port,
"--registry-owner=" + OWNER,
"--registry-repository=" + REPOSITORY,
"--registry-insecure",
"--image-id=test-image",
"--image-digest=" + digest,
GROUP + ":" + FOO_BAR + ":" + VERSION + "," + GROUP + ":" + FOO_BAZ + ":" + VERSION);
containerRegistryDetails = getContainerRegistryDetails();
Assertions.assertTrue(containerRegistryDetails.tags.contains(EXPECTED_TAG_1));
Expand Down Expand Up @@ -184,6 +193,7 @@ private URL getRegistryURL(String path) throws IOException {

class ContainerRegistryDetails {
String repoName;
String digest;
List<String> tags;
}
}
5 changes: 3 additions & 2 deletions pkg/apis/jvmbuildservice/v1alpha1/dependencybuild_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -80,8 +80,9 @@ type DependencyBuildList struct {
}

type BuildAttempt struct {
Recipe *BuildRecipe `json:"buildRecipe,omitempty"`
Build *BuildPipelineRun `json:"build,omitempty"`
BuildId string `json:"buildId,omitempty"`
Recipe *BuildRecipe `json:"buildRecipe,omitempty"`
Build *BuildPipelineRun `json:"build,omitempty"`
}

type BuildPipelineRun struct {
Expand Down
24 changes: 11 additions & 13 deletions pkg/reconciler/dependencybuild/buildrecipeyaml.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ const (
MavenArtifactsPath = "/maven-artifacts"
PreBuildImageDigest = "PRE_BUILD_IMAGE_DIGEST"
HermeticPreBuildImageDigest = "HERMETIC_PRE_BUILD_IMAGE_DIGEST"
DeployedImageDigest = "DEPLOYED_IMAGE_DIGEST"
)

//go:embed scripts/maven-build.sh
Expand Down Expand Up @@ -53,7 +54,7 @@ var buildEntryScript string
//go:embed scripts/hermetic-entry.sh
var hermeticBuildEntryScript string

func createPipelineSpec(tool string, commitTime int64, jbsConfig *v1alpha12.JBSConfig, systemConfig *v1alpha12.SystemConfig, recipe *v1alpha12.BuildRecipe, db *v1alpha12.DependencyBuild, paramValues []pipelinev1beta1.Param, buildRequestProcessorImage string) (*pipelinev1beta1.PipelineSpec, string, error) {
func createPipelineSpec(tool string, commitTime int64, jbsConfig *v1alpha12.JBSConfig, systemConfig *v1alpha12.SystemConfig, recipe *v1alpha12.BuildRecipe, db *v1alpha12.DependencyBuild, paramValues []pipelinev1beta1.Param, buildRequestProcessorImage string, buildId string) (*pipelinev1beta1.PipelineSpec, string, error) {

// Rather than tagging with hash of json build recipe, buildrequestprocessor image and db.Name as the former two
// could change with new image versions just use db.Name (which is a hash of scm url/tag/path so should be stable)
Expand All @@ -62,7 +63,7 @@ func createPipelineSpec(tool string, commitTime int64, jbsConfig *v1alpha12.JBSC
hermeticBuildRequired := jbsConfig.Spec.HermeticBuilds == v1alpha12.HermeticBuildTypeRequired
verifyBuiltArtifactsArgs := verifyParameters(jbsConfig, recipe)

preBuildImageArgs, deployArgs, hermeticDeployArgs, tagArgs, createHermeticImageArgs := imageRegistryCommands(imageId, recipe, db, jbsConfig, hermeticBuildRequired)
preBuildImageArgs, deployArgs, hermeticDeployArgs, tagArgs, createHermeticImageArgs := imageRegistryCommands(imageId, recipe, db, jbsConfig, hermeticBuildRequired, buildId)
gitArgs := gitArgs(db, recipe)
install := additionalPackages(recipe)

Expand Down Expand Up @@ -331,7 +332,7 @@ func createPipelineSpec(tool string, commitTime int64, jbsConfig *v1alpha12.JBSC
}
tagTask := pipelinev1beta1.TaskSpec{
Workspaces: []pipelinev1beta1.WorkspaceDeclaration{{Name: WorkspaceBuildSettings}, {Name: WorkspaceSource}, {Name: WorkspaceTls}},
Params: []pipelinev1beta1.ParamSpec{{Name: "GAVS", Type: pipelinev1beta1.ParamTypeString}},
Params: []pipelinev1beta1.ParamSpec{{Name: "GAVS", Type: pipelinev1beta1.ParamTypeString}, {Name: DeployedImageDigest, Type: pipelinev1beta1.ParamTypeString}},
Steps: []pipelinev1beta1.Step{
{
Name: "tag",
Expand All @@ -350,8 +351,10 @@ func createPipelineSpec(tool string, commitTime int64, jbsConfig *v1alpha12.JBSC
}

tagDepends := artifactbuild.BuildTaskName
tagDigest := "$(tasks." + artifactbuild.BuildTaskName + ".results." + PipelineResultImageDigest + ")"
if hermeticBuildRequired {
tagDepends = artifactbuild.HermeticBuildTaskName
tagDigest = "$(tasks." + artifactbuild.HermeticBuildTaskName + ".results." + PipelineResultImageDigest + ")"
}
hermeticBuildPipelineTask := pipelinev1beta1.PipelineTask{
Name: artifactbuild.HermeticBuildTaskName,
Expand All @@ -373,7 +376,8 @@ func createPipelineSpec(tool string, commitTime int64, jbsConfig *v1alpha12.JBSC
TaskSpec: &pipelinev1beta1.EmbeddedTask{
TaskSpec: tagTask,
},
Params: []pipelinev1beta1.Param{}, Workspaces: []pipelinev1beta1.WorkspacePipelineTaskBinding{
Params: []pipelinev1beta1.Param{{Name: DeployedImageDigest, Value: pipelinev1beta1.ParamValue{Type: pipelinev1beta1.ParamTypeString, StringVal: tagDigest}}},
Workspaces: []pipelinev1beta1.WorkspacePipelineTaskBinding{
{Name: WorkspaceBuildSettings, Workspace: WorkspaceBuildSettings},
{Name: WorkspaceSource, Workspace: WorkspaceSource},
{Name: WorkspaceTls, Workspace: WorkspaceTls},
Expand Down Expand Up @@ -586,7 +590,7 @@ func gitArgs(db *v1alpha12.DependencyBuild, recipe *v1alpha12.BuildRecipe) strin
return gitArgs
}

func imageRegistryCommands(imageId string, recipe *v1alpha12.BuildRecipe, db *v1alpha12.DependencyBuild, jbsConfig *v1alpha12.JBSConfig, hermeticBuild bool) ([]string, []string, []string, []string, []string) {
func imageRegistryCommands(imageId string, recipe *v1alpha12.BuildRecipe, db *v1alpha12.DependencyBuild, jbsConfig *v1alpha12.JBSConfig, hermeticBuild bool, buildId string) ([]string, []string, []string, []string, []string) {

preBuildImageTag := imageId + "-pre-build-image"
preBuildImageArgs := []string{
Expand All @@ -607,23 +611,17 @@ func imageRegistryCommands(imageId string, recipe *v1alpha12.BuildRecipe, db *v1
"--build-info-path=$(workspaces.source.path)/build-info",
"--source-path=$(workspaces.source.path)/source",
"--task-run-name=$(context.taskRun.name)",
"--build-id=" + buildId,
"--scm-uri=" + db.Spec.ScmInfo.SCMURL,
"--scm-commit=" + db.Spec.ScmInfo.CommitHash,
}
hermeticDeployArgs := append([]string{}, deployArgs...)
hermeticDeployArgs = append(hermeticDeployArgs, "--image-id="+hermeticImageId)
deployArgs = append(deployArgs, "--image-id="+imageId)

var imageIdToTag string
if hermeticBuild {
imageIdToTag = hermeticImageId
} else {
imageIdToTag = imageId
}

tagArgs := []string{
"tag-container",
"--image-id=" + imageIdToTag, //TODO: hash
"--image-digest=$(params." + DeployedImageDigest + ")",
}
imageRegistry := jbsConfig.ImageRegistry()
registryArgs := make([]string, 0)
Expand Down
4 changes: 3 additions & 1 deletion pkg/reconciler/dependencybuild/dependencybuild.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import (
"context"
"encoding/json"
"fmt"
"github.com/google/uuid"
"github.com/redhat-appstudio/jvm-build-service/pkg/reconciler/jbsconfig"
"github.com/tektoncd/cli/pkg/cli"
"k8s.io/client-go/kubernetes"
Expand Down Expand Up @@ -468,6 +469,7 @@ func (r *ReconcileDependencyBuild) handleStateSubmitBuild(ctx context.Context, d
return reconcile.Result{}, r.client.Status().Update(ctx, db)
}
ba := v1alpha1.BuildAttempt{}
ba.BuildId = uuid.New().String()
ba.Recipe = db.Status.PotentialBuildRecipes[0]
pipelineName := currentDependencyBuildPipelineName(db)
ba.Build = &v1alpha1.BuildPipelineRun{
Expand Down Expand Up @@ -545,7 +547,7 @@ func (r *ReconcileDependencyBuild) handleStateBuilding(ctx context.Context, log
}
diagnostic := ""
// TODO: set owner, pass parameter to do verify if true, via an annoaton on the dependency build, may eed to wait for dep build to exist verify is an optional, use append on each step in build recipes
pr.Spec.PipelineSpec, diagnostic, err = createPipelineSpec(attempt.Recipe.Tool, db.Status.CommitTime, jbsConfig, &systemConfig, attempt.Recipe, db, paramValues, buildRequestProcessorImage)
pr.Spec.PipelineSpec, diagnostic, err = createPipelineSpec(attempt.Recipe.Tool, db.Status.CommitTime, jbsConfig, &systemConfig, attempt.Recipe, db, paramValues, buildRequestProcessorImage, attempt.BuildId)
if err != nil {
return reconcile.Result{}, err
}
Expand Down

0 comments on commit 400f948

Please sign in to comment.