diff --git a/.github/workflows/deploy.yaml b/.github/workflows/deploy.yaml new file mode 100644 index 0000000..8801101 --- /dev/null +++ b/.github/workflows/deploy.yaml @@ -0,0 +1,18 @@ +on: + push: + branches: + - master + +jobs: + deploy: + runs-on: ubuntu-latest + steps: + - name: Checkout Repository + uses: actions/checkout@v4 + - name: Java Setup + uses: actions/setup-java@v4 + with: + distribution: 'graalvm' + java-version: '21' + - name: Gradle Build + run: ./gradlew build -Dquarkus.package.jar.enabled=false -Dquarkus.native.enabled=true -Dquarkus.container-image.build=true -Dquarkus.container-image.push=true -Dquarkus.container-image.username="${{ secrets.QUAY_UN }}" -Dquarkus.container-image.password="${{ secrets.QUAY_PW }}" \ No newline at end of file diff --git a/build.gradle.kts b/build.gradle.kts index 6fd2e23..0d60703 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -20,10 +20,12 @@ java { dependencies { implementation(enforcedPlatform(libs.quarkus.bom)) implementation("io.quarkus:quarkus-arc") - implementation("io.quarkus:quarkus-openshift") + implementation("io.quarkus:quarkus-kubernetes") + implementation("io.quarkus:quarkus-container-image-jib") implementation("io.quarkus:quarkus-openshift-client") implementation("io.quarkus:quarkus-scheduler") implementation("io.quarkus:quarkus-jackson") + implementation("io.quarkus:quarkus-smallrye-health") implementation("org.eclipse.jgit:org.eclipse.jgit:7.1.0.202411261347-r") // Lombok diff --git a/src/main/java/io/okd/operators/controller/Controller.java b/src/main/java/io/okd/operators/controller/Controller.java index 9d535ce..4c97d4c 100644 --- a/src/main/java/io/okd/operators/controller/Controller.java +++ b/src/main/java/io/okd/operators/controller/Controller.java @@ -37,20 +37,18 @@ public class Controller { private static final Path RECIPE_REPO = Paths.get("/tmp", "okd-build-controller", "repo"); private static final JsonMapper MAPPER = new JsonMapper(); -// private final Thread watchThread; - private final AtomicBoolean running = new AtomicBoolean(false); -// private final String recipesDirectory; - - @Inject - ManagedExecutor managedExecutor; @Inject OpenShiftClient client; @Inject - @ConfigProperty(name = "controller.build-repo") + @ConfigProperty(name = "controller.build-repo", defaultValue = "https://github.com/okd-project/okd-operator-pipeline.git") String buildRepo; + @Inject + @ConfigProperty(name = "controller.build-branch", defaultValue = "master") + String buildBranch; + @Inject @ConfigProperty(name = "controller.recipes.directory", defaultValue = "recipes") String recipesDirectory; @@ -71,6 +69,7 @@ void cloneRepo() throws IOException, GitAPIException { Git.cloneRepository() .setURI(this.buildRepo) .setDirectory(RECIPE_REPO.toFile()) + .setBranch(this.buildBranch) .call() .close(); } @@ -287,69 +286,75 @@ private boolean processComponent(Git git, String recipe, String version, Compone Path gitDirectory = dataDirectory.resolve("git"); - Git componentGit; - if (!RepositoryCache.FileKey.isGitRepository(gitDirectory.toFile(), FS.DETECTED)) { - if (Files.exists(gitDirectory)) { + Git componentGit = null; + try { + if (!RepositoryCache.FileKey.isGitRepository(gitDirectory.toFile(), FS.DETECTED)) { + if (Files.exists(gitDirectory)) { + try { + Files.delete(gitDirectory); + } catch (IOException e) { + throw new IllegalStateException("Failed to delete git directory", e); + } + } try { - Files.delete(gitDirectory); - } catch (IOException e) { - throw new IllegalStateException("Failed to delete git directory", e); + componentGit = Git.cloneRepository() + .setURI(component.getGitUrl()) + .setDirectory(gitDirectory.toFile()) + .setBranch(branch) + .call(); + } catch (GitAPIException e) { + throw new IllegalStateException("Failed to clone repository", e); } - } - try { - componentGit = Git.cloneRepository() - .setURI(component.getGitUrl()) - .setDirectory(gitDirectory.toFile()) - .setBranch(branch) - .call(); - } catch (GitAPIException e) { - throw new IllegalStateException("Failed to clone repository", e); - } - } else { - try { - componentGit = Git.open(gitDirectory.toFile()); + } else { + try { + componentGit = Git.open(gitDirectory.toFile()); - componentGit.pull().call(); - } catch (IOException | GitAPIException e) { - throw new IllegalStateException("Failed to open git directory", e); + componentGit.pull().call(); + } catch (IOException | GitAPIException e) { + throw new IllegalStateException("Failed to open git directory", e); + } } - } - // Check if we need to create a new PipelineRun by polling the git repo - String hash = null; - boolean runPipeline = false; - try { - List call = componentGit.branchList().setListMode(ListBranchCommand.ListMode.REMOTE).call(); - log.info("Branches: {}", call.stream().map(Ref::getName).toList()); - for (Ref ref : call) { - if (ref.getName().equals("refs/remotes/origin/" + branch)) { - hash = ref.getObjectId().getName(); - break; + // Check if we need to create a new PipelineRun by polling the git repo + String hash = null; + boolean runPipeline = false; + try { + List call = componentGit.branchList().setListMode(ListBranchCommand.ListMode.REMOTE).call(); + log.info("Branches: {}", call.stream().map(Ref::getName).toList()); + for (Ref ref : call) { + if (ref.getName().equals("refs/remotes/origin/" + branch)) { + hash = ref.getObjectId().getName(); + break; + } } - } - if (hash == null) { - log.error("Branch {} not found", branch); - throw new IllegalStateException("Branch not found"); - } + if (hash == null) { + log.error("Branch {} not found", branch); + throw new IllegalStateException("Branch not found"); + } - Path hashFile = dataDirectory.resolve("hash"); + Path hashFile = dataDirectory.resolve("hash"); - if (Files.notExists(hashFile)) { - Files.writeString(hashFile, hash); - runPipeline = true; - } else { - String existingHash = Files.readString(hashFile); - if (!existingHash.equals(hash)) { + if (Files.notExists(hashFile)) { Files.writeString(hashFile, hash); runPipeline = true; + } else { + String existingHash = Files.readString(hashFile); + if (!existingHash.equals(hash)) { + Files.writeString(hashFile, hash); + runPipeline = true; + } } + } catch (GitAPIException | IOException e) { + throw new IllegalStateException("Failed to get branch list", e); } - } catch (GitAPIException | IOException e) { - throw new IllegalStateException("Failed to get branch list", e); - } - return runPipeline; + return runPipeline; + } finally { + if (componentGit != null) { + componentGit.close(); + } + } } private void buildComponent(String recipe, String version, ComponentRecipe component, String buildVersion, diff --git a/src/main/java/io/okd/operators/controller/crds/dev/tekton/v1/PipelineRun.java b/src/main/java/io/okd/operators/controller/crds/dev/tekton/v1/PipelineRun.java index be59330..f13d009 100644 --- a/src/main/java/io/okd/operators/controller/crds/dev/tekton/v1/PipelineRun.java +++ b/src/main/java/io/okd/operators/controller/crds/dev/tekton/v1/PipelineRun.java @@ -7,6 +7,7 @@ import io.fabric8.kubernetes.api.model.HasMetadata; import io.fabric8.kubernetes.api.model.Namespaced; import io.fabric8.kubernetes.api.model.ObjectMeta; +import io.fabric8.kubernetes.api.model.apps.Deployment; import io.fabric8.kubernetes.client.CustomResource; import io.fabric8.kubernetes.model.annotation.Group; import io.fabric8.kubernetes.model.annotation.Plural; @@ -25,7 +26,7 @@ @Group("tekton.dev") @Singular("pipelinerun") @Plural("pipelineruns") -public class PipelineRun extends CustomResource implements Namespaced, HasMetadata { +public class PipelineRun implements Namespaced, HasMetadata { @JsonProperty("apiVersion") private String apiVersion = "tekton.dev/v1"; diff --git a/src/main/resources/application.properties b/src/main/resources/application.properties new file mode 100644 index 0000000..bf8e329 --- /dev/null +++ b/src/main/resources/application.properties @@ -0,0 +1,43 @@ +quarkus.application.name=operator-build-controller +quarkus.application.ui-header=Operator Build Controller + +quarkus.analytics.disabled=true +quarkus.log.file.enable=false +quarkus.banner.enabled=false + +quarkus.container-image.registry=quay.io +quarkus.container-image.group=okderators +quarkus.container-image.tag=latest + +quarkus.kubernetes.idempotent=true +quarkus.kubernetes.vcs-uri.enabled=false +quarkus.kubernetes.deployment-target=openshift +quarkus.kubernetes.part-of=operator-build-controller + +quarkus.kubernetes.readiness-probe.initial-delay=20s +quarkus.kubernetes.readiness-probe.period=45s + +quarkus.kubernetes.resources.requests.memory=256Mi +quarkus.kubernetes.resources.requests.cpu=250m +quarkus.kubernetes.resources.limits.memory=512Mi +quarkus.kubernetes.resources.limits.cpu=1000m + +# Generate Role resource with name "operator-builder" +quarkus.kubernetes.rbac.roles."operator-builder".policy-rules.0.api-groups=extensions,apps,tekton.dev +quarkus.kubernetes.rbac.roles."operator-builder".policy-rules.0.resources=configmaps,pipelineruns +quarkus.kubernetes.rbac.roles."operator-builder".policy-rules.0.verbs=get,watch,list,create,patch,update,delete + +# Generate ServiceAccount +quarkus.kubernetes.rbac.service-accounts."operator-build-controller".namespace=okd-operator-build + +# Bind Role "operator-builder" with ServiceAccount "operator-build-controller" +quarkus.kubernetes.rbac.role-bindings."operator-builder-binding".subjects."operator-build-controller".kind=ServiceAccount +quarkus.kubernetes.rbac.role-bindings."operator-builder-binding".subjects."operator-build-controller".namespace=okd-operator-build +quarkus.kubernetes.rbac.role-bindings."operator-builder-binding".role-name=operator-builder + +controller.name={CONTROLLER_NAME:operator-build-controller} +controller.build-repo={BUILD_REPO:https://github.com/okd-project/okd-operator-pipelines.git} +controller.build-branch={BUILD_BRANCH:master} +controller.recipes.directory={RECIPES_DIR:recipes} +controller.recipes.patches-directory={PATCHES_DIR:patches} +controller.data-directory={DATA_DIR:/opt/okd/recipes} diff --git a/src/main/resources/applications.properties b/src/main/resources/applications.properties deleted file mode 100644 index 0c9b408..0000000 --- a/src/main/resources/applications.properties +++ /dev/null @@ -1,5 +0,0 @@ -controller.name={CONTROLLER_NAME:okd-build-controller} -controller.build-repo={BUILD_REPO:https://github.com/okd-project/okd-operator-pipelines.git} -controller.recipes.directory={RECIPES_DIR:recipes} -controller.recipes.patches-directory={PATCHES_DIR:patches} -controller.data-directory={DATA_DIR:/opt/okd/recipes}