Skip to content

Commit 73d9cf5

Browse files
Merge pull request redhat-appstudio#230 from stuartwdouglas/in-repo-registry-based-tests
Move in-repo tests to use container image based storage
2 parents acf6e56 + 40c6de6 commit 73d9cf5

File tree

9 files changed

+150
-41
lines changed

9 files changed

+150
-41
lines changed

deploy/overlays/dev-template/config.yaml

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,4 @@ metadata:
66
namespace: test-jvm-namespace
77
data:
88
registry.owner: QUAY_USERNAME
9-
deployer: ContainerRegistryDeployer
9+
enable-localstack: false

java-components/sidecar/pom.xml

+4
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,10 @@
4141
<groupId>io.quarkus</groupId>
4242
<artifactId>quarkus-arc</artifactId>
4343
</dependency>
44+
<dependency>
45+
<groupId>io.quarkus</groupId>
46+
<artifactId>quarkus-jaxb</artifactId>
47+
</dependency>
4448
<dependency>
4549
<groupId>io.quarkiverse.amazonservices</groupId>
4650
<artifactId>quarkus-amazon-s3</artifactId>

java-components/sidecar/src/main/java/com/redhat/hacbs/sidecar/resources/DeployResource.java

+9-4
Original file line numberDiff line numberDiff line change
@@ -56,11 +56,12 @@ public class DeployResource {
5656
Set<String> allowedSources;
5757

5858
public DeployResource(BeanManager beanManager,
59-
@ConfigProperty(name = "deployer", defaultValue = "S3Deployer") String deployer,
59+
@ConfigProperty(name = "deployer") Optional<String> deployer,
60+
@ConfigProperty(name = "registry.token") Optional<String> token,
6061
@ConfigProperty(name = "ignored-artifacts", defaultValue = "") Optional<Set<String>> doNotDeploy,
6162
@ConfigProperty(name = "allowed-sources", defaultValue = "") Optional<Set<String>> allowedSources) {
6263
this.beanManager = beanManager;
63-
this.deployer = getDeployer(deployer);
64+
this.deployer = getDeployer(deployer, token);
6465
this.doNotDeploy = doNotDeploy.orElse(Set.of());
6566
this.allowedSources = allowedSources.orElse(Set.of());
6667
Log.debugf("Using %s deployer", deployer);
@@ -159,10 +160,14 @@ public void deployArchive(InputStream data) throws Exception {
159160
}
160161
}
161162

162-
private Deployer getDeployer(String name) {
163-
Bean<Deployer> bean = (Bean<Deployer>) beanManager.getBeans(name).iterator().next();
163+
private Deployer getDeployer(Optional<String> name, Optional<String> registryToken) {
164+
//if the registry token is defined and not the deployer we default to the container
165+
//registry deployer
166+
String actualName = name.orElse(registryToken.isPresent() ? "ContainerRegistryDeployer" : "S3Deployer");
167+
Bean<Deployer> bean = (Bean<Deployer>) beanManager.getBeans(actualName).iterator().next();
164168
CreationalContext<Deployer> ctx = beanManager.createCreationalContext(bean);
165169
return (Deployer) beanManager.getReference(bean, Deployer.class, ctx);
170+
166171
}
167172

168173
private void flushLogs() {

java-components/sidecar/src/main/java/com/redhat/hacbs/sidecar/resources/deploy/containerregistry/ContainerRegistryDeployer.java

+37-3
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
import org.apache.commons.compress.archivers.tar.TarArchiveInputStream;
2727
import org.eclipse.microprofile.config.inject.ConfigProperty;
2828

29+
import com.fasterxml.jackson.databind.ObjectMapper;
2930
import com.google.cloud.tools.jib.api.CacheDirectoryCreationException;
3031
import com.google.cloud.tools.jib.api.Containerizer;
3132
import com.google.cloud.tools.jib.api.InvalidImageReferenceException;
@@ -55,6 +56,8 @@ public class ContainerRegistryDeployer implements Deployer {
5556
private final String username;
5657
private final String password;
5758

59+
static final ObjectMapper MAPPER = new ObjectMapper();
60+
5861
public ContainerRegistryDeployer(
5962
@ConfigProperty(name = "registry.host", defaultValue = "quay.io") String host,
6063
@ConfigProperty(name = "registry.port", defaultValue = "443") int port,
@@ -74,13 +77,44 @@ public ContainerRegistryDeployer(
7477
this.doNotDeploy = doNotDeploy.orElse(Set.of());
7578
if (token.isPresent()) {
7679
var decoded = new String(Base64.getDecoder().decode(token.get()), StandardCharsets.UTF_8);
77-
int pos = decoded.indexOf(":");
78-
username = decoded.substring(0, pos);
79-
password = decoded.substring(pos + 1);
80+
if (decoded.startsWith("{")) {
81+
//we assume this is a .dockerconfig file
82+
try (var parser = MAPPER.createParser(decoded)) {
83+
DockerConfig config = parser.readValueAs(DockerConfig.class);
84+
boolean found = false;
85+
String tmpUser = null;
86+
String tmpPw = null;
87+
for (var i : config.getAuths().entrySet()) {
88+
if (host.contains(i.getKey())) { //TODO: is contains enough?
89+
found = true;
90+
var decodedAuth = new String(Base64.getDecoder().decode(i.getValue().getAuth()),
91+
StandardCharsets.UTF_8);
92+
int pos = decodedAuth.indexOf(":");
93+
tmpUser = decodedAuth.substring(0, pos);
94+
tmpPw = decodedAuth.substring(pos + 1);
95+
break;
96+
}
97+
}
98+
if (!found) {
99+
throw new RuntimeException("Unable to find a host matching " + host
100+
+ " in provided dockerconfig, hosts provided: " + config.getAuths().keySet());
101+
}
102+
username = tmpUser;
103+
password = tmpPw;
104+
} catch (IOException e) {
105+
throw new RuntimeException(e);
106+
}
107+
} else {
108+
int pos = decoded.indexOf(":");
109+
username = decoded.substring(0, pos);
110+
password = decoded.substring(pos + 1);
111+
}
80112
} else {
113+
Log.errorf("No token configured");
81114
username = null;
82115
password = null;
83116
}
117+
Log.infof("Using username %s to publish to %s/%s/%s", username, host, owner, repository);
84118

85119
}
86120

Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
package com.redhat.hacbs.sidecar.resources.deploy.containerregistry;
2+
3+
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
4+
5+
@JsonIgnoreProperties(ignoreUnknown = true)
6+
public class DockerAuthEntry {
7+
8+
private String auth;
9+
10+
public String getAuth() {
11+
return auth;
12+
}
13+
14+
public DockerAuthEntry setAuth(String auth) {
15+
this.auth = auth;
16+
return this;
17+
}
18+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package com.redhat.hacbs.sidecar.resources.deploy.containerregistry;
2+
3+
import java.util.Map;
4+
5+
import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
6+
7+
@JsonIgnoreProperties(ignoreUnknown = true)
8+
public class DockerConfig {
9+
10+
private Map<String, DockerAuthEntry> auths;
11+
12+
public Map<String, DockerAuthEntry> getAuths() {
13+
return auths;
14+
}
15+
16+
public DockerConfig setAuths(Map<String, DockerAuthEntry> auths) {
17+
this.auths = auths;
18+
return this;
19+
}
20+
}

java-components/sidecar/src/main/java/com/redhat/hacbs/sidecar/resources/deploy/s3/S3Deployer.java

+1-1
Original file line numberDiff line numberDiff line change
@@ -77,4 +77,4 @@ public void deployArchive(Path tarGzFile) throws Exception {
7777
}
7878
}
7979
}
80-
}
80+
}

openshift-with-appstudio-test/e2e/util.go

+20-7
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@ import (
77
"net/http"
88
"os"
99
"path/filepath"
10+
"strconv"
1011
"strings"
1112
"testing"
1213
"time"
@@ -188,32 +189,42 @@ func setup(t *testing.T, ta *testArgs) *testArgs {
188189
if err != nil {
189190
debugAndFailTest(ta, err.Error())
190191
}
192+
owner := os.Getenv("QUAY_E2E_ORGANIZATION")
193+
if owner == "" {
194+
owner = "redhat-appstudio-qe"
195+
}
191196
cm := corev1.ConfigMap{ObjectMeta: metav1.ObjectMeta{Name: "jvm-build-config", Namespace: ta.ns},
192197
Data: map[string]string{
193198
"enable-rebuilds": "true",
199+
"enable-localstack": "false",
194200
"maven-repository-300-jboss": "https://repository.jboss.org/nexus/content/groups/public/",
195201
"maven-repository-301-gradleplugins": "https://plugins.gradle.org/m2",
196202
"maven-repository-302-confluent": "https://packages.confluent.io/maven",
197203
"maven-repository-303-gradle": "https://repo.gradle.org/artifactory/libs-releases",
198204
"maven-repository-304-eclipselink": "https://download.eclipse.org/rt/eclipselink/maven.repo",
199205
"maven-repository-305-redhat": "https://maven.repository.redhat.com/ga",
200206
"maven-repository-306-jitpack": "https://jitpack.io",
201-
"maven-repository-307-jsweet": "https://repository.jsweet.org/artifactory/libs-release-local"}}
207+
"maven-repository-307-jsweet": "https://repository.jsweet.org/artifactory/libs-release-local",
208+
"registry.host": "quay.io",
209+
"registry.prepend-tag": strconv.FormatInt(time.Now().UnixMilli(), 10),
210+
"registry.owner": owner,
211+
"registry.repository": "test-images"}}
202212
_, err = kubeClient.CoreV1().ConfigMaps(ta.ns).Create(context.TODO(), &cm, metav1.CreateOptions{})
203213
if err != nil {
204214
debugAndFailTest(ta, err.Error())
205215
}
216+
secret := corev1.Secret{ObjectMeta: metav1.ObjectMeta{Name: "jvm-build-secrets", Namespace: ta.ns},
217+
StringData: map[string]string{"registry.token": os.Getenv("QUAY_TOKEN")}}
218+
_, err = kubeClient.CoreV1().Secrets(ta.ns).Create(context.TODO(), &secret, metav1.CreateOptions{})
219+
if err != nil {
220+
debugAndFailTest(ta, err.Error())
221+
}
206222
err = wait.PollImmediate(1*time.Second, 1*time.Minute, func() (done bool, err error) {
207223
_, err = kubeClient.AppsV1().Deployments(ta.ns).Get(context.TODO(), configmap.CacheDeploymentName, metav1.GetOptions{})
208224
if err != nil {
209225
ta.Logf(fmt.Sprintf("get of cache: %s", err.Error()))
210226
return false, nil
211227
}
212-
_, err = kubeClient.AppsV1().Deployments(ta.ns).Get(context.TODO(), configmap.LocalstackDeploymentName, metav1.GetOptions{})
213-
if err != nil {
214-
ta.Logf(fmt.Sprintf("get of localstack: %s", err.Error()))
215-
return false, nil
216-
}
217228
return true, nil
218229
})
219230
if err != nil {
@@ -268,7 +279,9 @@ func streamRemoteYamlToTektonObj(url string, obj runtime.Object, ta *testArgs) r
268279
if err != nil {
269280
debugAndFailTest(ta, err.Error())
270281
}
271-
defer resp.Body.Close()
282+
defer func(Body io.ReadCloser) {
283+
_ = Body.Close()
284+
}(resp.Body)
272285
bytes, err := io.ReadAll(resp.Body)
273286
if err != nil {
274287
debugAndFailTest(ta, err.Error())

pkg/reconciler/configmap/configmap.go

+40-25
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,7 @@ const (
4040
CacheDeploymentName = "jvm-build-workspace-artifact-cache"
4141
LocalstackDeploymentName = "jvm-build-workspace-localstack"
4242
EnableRebuilds = "enable-rebuilds"
43+
EnableLocalstack = "enable-localstack"
4344
SystemConfigMapName = "jvm-build-system-config"
4445
SystemConfigMapNamespace = "jvm-build-service"
4546
SystemCacheImage = "image.cache"
@@ -117,19 +118,23 @@ func (r *ReconcileConfigMap) Reconcile(ctx context.Context, request reconcile.Re
117118
return reconcile.Result{}, nil
118119
}
119120
enabled := configMap.Data[EnableRebuilds] == "true"
121+
//for now we default it to always be created
122+
//but allow it to be disabled
123+
//our in repo tests don't need it anymore
124+
localstack := configMap.Data[EnableLocalstack] != "false"
120125

121126
systemConfigMap := corev1.ConfigMap{}
122127
err = r.client.Get(ctx, types.NamespacedName{Name: SystemConfigMapName, Namespace: SystemConfigMapNamespace}, &systemConfigMap)
123128
if err != nil {
124129
return reconcile.Result{}, nil
125130
}
126131
log.Info("Setup Cache %s", "name", request.Name)
127-
if err = r.setupCache(ctx, request, enabled, configMap, systemConfigMap); err != nil {
132+
if err = r.setupCache(ctx, request, enabled, configMap, systemConfigMap, localstack); err != nil {
128133
return reconcile.Result{}, err
129134
}
130-
if enabled {
135+
if enabled && localstack {
131136
log.Info("Setup Rebuilds %s", "name", request.Name)
132-
err := r.setupRebuilds(ctx, log, request)
137+
err := r.setupLocalstack(ctx, log, request)
133138
if err != nil {
134139
return reconcile.Result{}, err
135140
}
@@ -138,7 +143,7 @@ func (r *ReconcileConfigMap) Reconcile(ctx context.Context, request reconcile.Re
138143
return reconcile.Result{}, nil
139144
}
140145

141-
func (r *ReconcileConfigMap) setupCache(ctx context.Context, request reconcile.Request, rebuildsEnabled bool, configMap corev1.ConfigMap, systemConfigMap corev1.ConfigMap) error {
146+
func (r *ReconcileConfigMap) setupCache(ctx context.Context, request reconcile.Request, rebuildsEnabled bool, configMap corev1.ConfigMap, systemConfigMap corev1.ConfigMap, localstack bool) error {
142147
//first setup the storage
143148
deploymentName := types.NamespacedName{Namespace: request.Namespace, Name: CacheDeploymentName}
144149

@@ -277,26 +282,30 @@ func (r *ReconcileConfigMap) setupCache(ctx context.Context, request reconcile.R
277282
if rebuildsEnabled {
278283
repos = append(repos, Repo{name: "rebuilt", position: 100})
279284

280-
cache.Spec.Template.Spec.Containers[0].Env = append(cache.Spec.Template.Spec.Containers[0].Env, corev1.EnvVar{
281-
Name: "QUARKUS_S3_ENDPOINT_OVERRIDE",
282-
Value: "http://" + LocalstackDeploymentName + "." + request.Namespace + ".svc.cluster.local:4572",
283-
})
284-
cache.Spec.Template.Spec.Containers[0].Env = append(cache.Spec.Template.Spec.Containers[0].Env, corev1.EnvVar{
285-
Name: "QUARKUS_S3_AWS_REGION",
286-
Value: "us-east-1",
287-
})
288-
cache.Spec.Template.Spec.Containers[0].Env = append(cache.Spec.Template.Spec.Containers[0].Env, corev1.EnvVar{
289-
Name: "QUARKUS_S3_AWS_CREDENTIALS_TYPE",
290-
Value: "static",
291-
})
292-
cache.Spec.Template.Spec.Containers[0].Env = append(cache.Spec.Template.Spec.Containers[0].Env, corev1.EnvVar{
293-
Name: "QUARKUS_S3_AWS_CREDENTIALS_STATIC_PROVIDER_ACCESS_KEY_ID",
294-
Value: "accesskey",
295-
})
296-
cache.Spec.Template.Spec.Containers[0].Env = append(cache.Spec.Template.Spec.Containers[0].Env, corev1.EnvVar{
297-
Name: "QUARKUS_S3_AWS_CREDENTIALS_STATIC_PROVIDER_SECRET_ACCESS_KEY",
298-
Value: "secretkey",
299-
})
285+
if localstack {
286+
//TODO: localstack should eventually go away altogether
287+
//for now it is convenient for testing
288+
cache.Spec.Template.Spec.Containers[0].Env = append(cache.Spec.Template.Spec.Containers[0].Env, corev1.EnvVar{
289+
Name: "QUARKUS_S3_ENDPOINT_OVERRIDE",
290+
Value: "http://" + LocalstackDeploymentName + "." + request.Namespace + ".svc.cluster.local:4572",
291+
})
292+
cache.Spec.Template.Spec.Containers[0].Env = append(cache.Spec.Template.Spec.Containers[0].Env, corev1.EnvVar{
293+
Name: "QUARKUS_S3_AWS_REGION",
294+
Value: "us-east-1",
295+
})
296+
cache.Spec.Template.Spec.Containers[0].Env = append(cache.Spec.Template.Spec.Containers[0].Env, corev1.EnvVar{
297+
Name: "QUARKUS_S3_AWS_CREDENTIALS_TYPE",
298+
Value: "static",
299+
})
300+
cache.Spec.Template.Spec.Containers[0].Env = append(cache.Spec.Template.Spec.Containers[0].Env, corev1.EnvVar{
301+
Name: "QUARKUS_S3_AWS_CREDENTIALS_STATIC_PROVIDER_ACCESS_KEY_ID",
302+
Value: "accesskey",
303+
})
304+
cache.Spec.Template.Spec.Containers[0].Env = append(cache.Spec.Template.Spec.Containers[0].Env, corev1.EnvVar{
305+
Name: "QUARKUS_S3_AWS_CREDENTIALS_STATIC_PROVIDER_SECRET_ACCESS_KEY",
306+
Value: "secretkey",
307+
})
308+
}
300309
if configMap.Data["registry.owner"] != "" {
301310
cache.Spec.Template.Spec.Containers[0].Env = append(cache.Spec.Template.Spec.Containers[0].Env, corev1.EnvVar{
302311
Name: "REGISTRY_OWNER",
@@ -327,6 +336,12 @@ func (r *ReconcileConfigMap) setupCache(ctx context.Context, request reconcile.R
327336
ValueFrom: &corev1.EnvVarSource{ConfigMapKeyRef: &corev1.ConfigMapKeySelector{LocalObjectReference: corev1.LocalObjectReference{Name: UserConfigMapName}, Key: "registry.insecure"}},
328337
})
329338
}
339+
if configMap.Data["registry.prepend-tag"] != "" {
340+
cache.Spec.Template.Spec.Containers[0].Env = append(cache.Spec.Template.Spec.Containers[0].Env, corev1.EnvVar{
341+
Name: "REGISTRY_PREPEND_TAG",
342+
ValueFrom: &corev1.EnvVarSource{ConfigMapKeyRef: &corev1.ConfigMapKeySelector{LocalObjectReference: corev1.LocalObjectReference{Name: UserConfigMapName}, Key: "registry.prepend-tag"}},
343+
})
344+
}
330345
//TODO: ensure this exists
331346
cache.Spec.Template.Spec.Containers[0].Env = append(cache.Spec.Template.Spec.Containers[0].Env, corev1.EnvVar{
332347
Name: "REGISTRY_TOKEN",
@@ -384,7 +399,7 @@ func (r *ReconcileConfigMap) setupCache(ctx context.Context, request reconcile.R
384399

385400
}
386401

387-
func (r *ReconcileConfigMap) setupRebuilds(ctx context.Context, log logr.Logger, request reconcile.Request) error {
402+
func (r *ReconcileConfigMap) setupLocalstack(ctx context.Context, log logr.Logger, request reconcile.Request) error {
388403
//setup localstack
389404
//this is 100% temporary and needs to go away ASAP
390405
localstack := v1.Deployment{}

0 commit comments

Comments
 (0)