blob: 2cc2d2f520c58da91efd80c0ac1db11097231d86 [file] [log] [blame]
// Copyright (C) 2022 The Android Open Source Project
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
package com.google.gerrit.k8s.operator.gitgc;
import com.google.common.flogger.FluentLogger;
import com.google.gerrit.k8s.operator.cluster.GerritCluster;
import io.fabric8.kubernetes.api.model.Container;
import io.fabric8.kubernetes.api.model.ContainerBuilder;
import io.fabric8.kubernetes.api.model.EnvVar;
import io.fabric8.kubernetes.api.model.EnvVarBuilder;
import io.fabric8.kubernetes.api.model.Volume;
import io.fabric8.kubernetes.api.model.VolumeMount;
import io.fabric8.kubernetes.api.model.batch.v1.CronJob;
import io.fabric8.kubernetes.api.model.batch.v1.CronJobBuilder;
import io.fabric8.kubernetes.api.model.batch.v1.JobTemplateSpec;
import io.fabric8.kubernetes.api.model.batch.v1.JobTemplateSpecBuilder;
import io.javaoperatorsdk.operator.api.reconciler.Context;
import io.javaoperatorsdk.operator.processing.dependent.kubernetes.CRUDKubernetesDependentResource;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Map;
public class GitGarbageCollectionCronJob
extends CRUDKubernetesDependentResource<CronJob, GitGarbageCollection> {
private static final FluentLogger logger = FluentLogger.forEnclosingClass();
public GitGarbageCollectionCronJob() {
super(CronJob.class);
}
@Override
protected CronJob desired(GitGarbageCollection gitGc, Context<GitGarbageCollection> context) {
String ns = gitGc.getMetadata().getNamespace();
String name = gitGc.getMetadata().getName();
GerritCluster gerritCluster =
client
.resources(GerritCluster.class)
.inNamespace(ns)
.withName(gitGc.getSpec().getCluster())
.get();
if (gerritCluster == null) {
throw new IllegalStateException("The Gerrit cluster could not be found.");
}
logger.atInfo().log("Reconciling GitGc with name: %s/%s", ns, name);
Map<String, String> gitGcLabels =
gerritCluster.getLabels("GitGc", this.getClass().getSimpleName());
List<Container> initContainers = new ArrayList<>();
List<Volume> volumes =
List.of(gerritCluster.getGitRepositoriesVolume(), gerritCluster.getLogsVolume());
if (gerritCluster.getSpec().getStorageClasses().getNfsWorkaround().isEnabled()) {
initContainers.add(createNfsImapdInitContainer(gerritCluster));
if (gerritCluster.getSpec().getStorageClasses().getNfsWorkaround().getIdmapdConfig()
!= null) {
volumes.add(gerritCluster.getNfsImapdConfigVolume());
}
}
JobTemplateSpec gitGcJobTemplate =
new JobTemplateSpecBuilder()
.withNewSpec()
.withNewTemplate()
.withNewMetadata()
.withAnnotations(
Map.of(
"sidecar.istio.io/inject",
"false",
"cluster-autoscaler.kubernetes.io/safe-to-evict",
"false"))
.withLabels(gitGcLabels)
.endMetadata()
.withNewSpec()
.withTolerations(gitGc.getSpec().getTolerations())
.withAffinity(gitGc.getSpec().getAffinity())
.addAllToImagePullSecrets(gerritCluster.getSpec().getImagePullSecrets())
.withRestartPolicy("OnFailure")
.withNewSecurityContext()
.withFsGroup(100L)
.endSecurityContext()
.addToContainers(buildGitGcContainer(gitGc, gerritCluster))
.withVolumes(volumes)
.endSpec()
.endTemplate()
.endSpec()
.build();
return new CronJobBuilder()
.withApiVersion("batch/v1")
.withNewMetadata()
.withNamespace(ns)
.withName(name)
.withLabels(gitGcLabels)
.withAnnotations(
Collections.singletonMap("app.kubernetes.io/managed-by", "gerrit-operator"))
.addNewOwnerReference()
.withApiVersion(gitGc.getApiVersion())
.withKind(gitGc.getKind())
.withName(name)
.withUid(gitGc.getMetadata().getUid())
.endOwnerReference()
.endMetadata()
.withNewSpec()
.withSchedule(gitGc.getSpec().getSchedule())
.withConcurrencyPolicy("Forbid")
.withJobTemplate(gitGcJobTemplate)
.endSpec()
.build();
}
private Container createNfsImapdInitContainer(GerritCluster gerritCluster) {
List<VolumeMount> volumeMounts = List.of(gerritCluster.getLogsVolumeMount());
if (gerritCluster.getSpec().getStorageClasses().getNfsWorkaround().isEnabled()
&& gerritCluster.getSpec().getStorageClasses().getNfsWorkaround().getIdmapdConfig()
!= null) {
volumeMounts.add(gerritCluster.getNfsImapdConfigVolumeMount());
}
return new ContainerBuilder()
.withName("nfs-init")
.withImagePullPolicy(gerritCluster.getSpec().getImagePullPolicy())
.withImage(gerritCluster.getSpec().getBusyBox().getBusyBoxImage())
.withCommand(List.of("sh", "-c"))
.withArgs("chown -R 1000:100 /var/mnt/logs")
.withEnv(getPodNameEnvVar())
.withVolumeMounts(volumeMounts)
.build();
}
private static EnvVar getPodNameEnvVar() {
return new EnvVarBuilder()
.withName("POD_NAME")
.withNewValueFrom()
.withNewFieldRef()
.withFieldPath("metadata.name")
.endFieldRef()
.endValueFrom()
.build();
}
private Container buildGitGcContainer(GitGarbageCollection gitGc, GerritCluster gerritCluster) {
List<VolumeMount> volumeMounts =
List.of(gerritCluster.getGitRepositoriesVolumeMount(), gerritCluster.getLogsVolumeMount());
if (gerritCluster.getSpec().getStorageClasses().getNfsWorkaround().isEnabled()
&& gerritCluster.getSpec().getStorageClasses().getNfsWorkaround().getIdmapdConfig()
!= null) {
volumeMounts.add(gerritCluster.getNfsImapdConfigVolumeMount());
}
ContainerBuilder gitGcContainerBuilder =
new ContainerBuilder()
.withName("git-gc")
.withImagePullPolicy(gerritCluster.getSpec().getImagePullPolicy())
.withImage(gitGc.getSpec().getImage())
.withResources(gitGc.getSpec().getResources())
.withEnv(getPodNameEnvVar())
.withVolumeMounts(volumeMounts);
ArrayList<String> args = new ArrayList<>();
for (String project : gitGc.getSpec().getProjects()) {
args.add("-p");
args.add(project);
}
for (String project : gitGc.getStatus().getExcludedProjects()) {
args.add("-s");
args.add(project);
}
gitGcContainerBuilder.addAllToArgs(args);
return gitGcContainerBuilder.build();
}
}