diff --git a/.github/workflows/ci-integration-test-legacy.yml b/.github/workflows/ci-integration-test-legacy.yml index cfc823ecc..3548b21fa 100644 --- a/.github/workflows/ci-integration-test-legacy.yml +++ b/.github/workflows/ci-integration-test-legacy.yml @@ -21,7 +21,7 @@ jobs: matrix: os: [ubuntu-latest] java: [8] - cpversion: [5.5.3, 6.0.2, 6.1.0] + cpversion: [6.1.2, 6.2.0] runs-on: ${{ matrix.os }} diff --git a/.github/workflows/ci-integration-test-main.yml b/.github/workflows/ci-integration-test-main.yml index b728f0e27..8621726fe 100644 --- a/.github/workflows/ci-integration-test-main.yml +++ b/.github/workflows/ci-integration-test-main.yml @@ -19,7 +19,7 @@ jobs: matrix: os: [ubuntu-latest] java: [11.0.x] - cpversion: [5.5.3, 6.0.2, 6.1.0] + cpversion: [6.1.2, 6.2.0] runs-on: ${{ matrix.os }} diff --git a/.github/workflows/nightly-artifacts-build.yml b/.github/workflows/nightly-artifacts-build.yml index 860374480..55a6cd9e7 100644 --- a/.github/workflows/nightly-artifacts-build.yml +++ b/.github/workflows/nightly-artifacts-build.yml @@ -12,14 +12,6 @@ jobs: runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 - - name: Import private GPG key - id: import_gpg - uses: crazy-max/ghaction-import-gpg@v3 - with: - gpg-private-key: ${{ secrets.GPG_PRIVATE_KEY }} - passphrase: ${{ secrets.GPG_PASSPHRASE }} - - name: Import public GPG Key - run: rpm --import release/keys/public.key - uses: docker/setup-buildx-action@v1 - name: Set up the JDK uses: actions/setup-java@v1 @@ -70,11 +62,21 @@ jobs: restore-keys: ${{ runner.os }}-m2 - name: Build with Maven run: mvn -B package --file pom.xml + - name: Import private GPG key + id: import_gpg + uses: crazy-max/ghaction-import-gpg@v4 + with: + gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }} + passphrase: ${{ secrets.GPG_PASSPHRASE }} + git_user_signingkey: true + git_commit_gpgsign: true + - name: Import public GPG Key + run: rpm --import release/keys/public.key - name: Build the rpm run: mvn rpm:rpm - name: Sign rpm run: | - rpm --define "_gpg_name $GPG_KEY_NAME" --addsign target/rpm/julie-ops/RPMS/noarch/*.rpm + rpm --define "_gpg_name ${{ steps.import_gpg.outputs.keyid }}" --addsign target/rpm/julie-ops/RPMS/noarch/*.rpm rpm --checksig target/rpm/julie-ops/RPMS/noarch/*.rpm env: GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }} @@ -82,7 +84,7 @@ jobs: - name: Sign deb run: | sudo apt-get install dpkg-sig -y - dpkg-sig -k $GPG_KEY_NAME --sign builder $FILE target/*.deb + dpkg-sig -k ${{ steps.import_gpg.outputs.keyid }} --sign builder $FILE target/*.deb env: GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }} GPG_KEY_NAME: ${{ steps.import_gpg.outputs.email }} diff --git a/.github/workflows/release-artifacts-build-legacy.yml b/.github/workflows/release-artifacts-build-legacy.yml index 95724106e..8013002be 100644 --- a/.github/workflows/release-artifacts-build-legacy.yml +++ b/.github/workflows/release-artifacts-build-legacy.yml @@ -22,8 +22,29 @@ jobs: restore-keys: ${{ runner.os }}-m2 - name: Build with Maven run: mvn -B package --file pom.xml + - name: Import private GPG key + id: import_gpg + uses: crazy-max/ghaction-import-gpg@v4 + with: + gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }} + passphrase: ${{ secrets.GPG_PASSPHRASE }} + git_user_signingkey: true + git_commit_gpgsign: true + - name: Import public GPG Key + run: rpm --import release/keys/public.key - name: Build the rpm run: mvn rpm:rpm + - name: Sign rpm + run: | + rpm --define "_gpg_name ${{ steps.import_gpg.outputs.keyid }}" --addsign target/rpm/julie-ops/RPMS/noarch/*.rpm + rpm --checksig target/rpm/julie-ops/RPMS/noarch/*.rpm + - name: Sign deb + run: | + sudo apt-get install dpkg-sig -y + dpkg-sig -k ${{ steps.import_gpg.outputs.keyid }} --sign builder $FILE target/*.deb + env: + GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }} + GPG_KEY_NAME: ${{ steps.import_gpg.outputs.email }} - uses: actions/upload-artifact@v2 with: name: RPM package diff --git a/.github/workflows/release-artifacts-build.yml b/.github/workflows/release-artifacts-build.yml index 203c337b8..4cfd33661 100644 --- a/.github/workflows/release-artifacts-build.yml +++ b/.github/workflows/release-artifacts-build.yml @@ -12,10 +12,12 @@ jobs: - uses: actions/checkout@v2 - name: Import private GPG key id: import_gpg - uses: crazy-max/ghaction-import-gpg@v3 + uses: crazy-max/ghaction-import-gpg@v4 with: - gpg-private-key: ${{ secrets.GPG_PRIVATE_KEY }} + gpg_private_key: ${{ secrets.GPG_PRIVATE_KEY }} passphrase: ${{ secrets.GPG_PASSPHRASE }} + git_user_signingkey: true + git_commit_gpgsign: true - name: Import public GPG Key run: rpm --import release/keys/public.key - name: Set up the JDK @@ -34,7 +36,7 @@ jobs: run: mvn rpm:rpm - name: Sign rpm run: | - rpm --define "_gpg_name $GPG_KEY_NAME" --addsign target/rpm/julie-ops/RPMS/noarch/*.rpm + rpm --define "_gpg_name ${{ steps.import_gpg.outputs.keyid }}" --addsign target/rpm/julie-ops/RPMS/noarch/*.rpm rpm --checksig target/rpm/julie-ops/RPMS/noarch/*.rpm env: GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }} @@ -42,7 +44,7 @@ jobs: - name: Sign deb run: | sudo apt-get install dpkg-sig -y - dpkg-sig -k $GPG_KEY_NAME --sign builder $FILE target/*.deb + dpkg-sig -k ${{ steps.import_gpg.outputs.keyid }} --sign builder $FILE target/*.deb env: GPG_PASSPHRASE: ${{ secrets.GPG_PASSPHRASE }} GPG_KEY_NAME: ${{ steps.import_gpg.outputs.email }} diff --git a/release/keys/public.key b/release/keys/public.key index a3a63568f..864e2665b 100644 --- a/release/keys/public.key +++ b/release/keys/public.key @@ -1,19 +1,52 @@ -----BEGIN PGP PUBLIC KEY BLOCK----- -mQENBF8q4tcBCADUXVN8G0smSfgHz7EmgN2Ou69kFjMfvP2t7Yncj6X1xS1YlurB -IfQ5rRw9ZVX5mvbqyQ9/GNrqFK23sdxrusiWImewDBzHRQLnXPmqaukjZJ8eM+s7 -UTktAYlvkHsVnX5xDp7FTZF6Vrfz76b44NjeBk0cjTSRIXPpnLW+Ok67qgSC3lFW -AnKGw465UR0Y5pffcum7Dbi0wjgQspLhlptCja2wNl/vdCM7OW6svQuhLEx3Jft7 -o7s+Fu7ijiwaX6KucR8zY4Zkf/R+s4ieI3/erlWH0nBM8CgxZ2xTfuy1ZBUJpJeM -kGC4ZkgF2gHJuIvvrdqo/pVwLIlAN3WUR5bJABEBAAG0Q0thZmthIFRvcG9sb2d5 -IEJ1aWxkZXIgcmVsZWFzZSBtYW5hZ2VyIDxwZXJlLnVyYm9uK2thZmthQGdtYWls -LmNvbT6JAVQEEwEIAD4WIQRK1j1naDqX0UkkfsM5NBZpYTTokgUCXyri1wIbAwUJ -A8JnAAULCQgHAgYVCgkICwIEFgIDAQIeAQIXgAAKCRA5NBZpYTTokhEpCACBZDB5 -2TxB2FI+fg8RzoxxGu8Ft8BiLX227gi2+ACGGH9OBoZ9FhdYP0GCGr0ewXIgzdtW -z6XOLf2t6ZxfAvqY2W9YaCch9j+niSjkbphOtMndxJ7zydXBxzWdx4sUHnfdV4vn -FbyjjA1QClTuAVtoZGnd9fsUp96H7KBMB2LuQK7JhtJ2xS5SXh4st1dO/RqvM+6y -N91Olrae7gyZuzktWlVBZ+6jtRyJy7vG/YmkLtw8Nfu0tJL4/CUvBUaTPiKDJyXr -p9cNxQdvbs4dX5QuGWU59m3avAmNg0F1qcEOtIrVuzgJhanZZ74EN7e5ko/0wuOt -aIKV/zo6WAGFiB0I -=4uCQ +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 +CRNminCORZgJISzle5IG4NSu +=2myt -----END PGP PUBLIC KEY BLOCK----- diff --git a/src/main/java/com/purbon/kafka/topology/KSqlArtefactManager.java b/src/main/java/com/purbon/kafka/topology/KSqlArtefactManager.java index 991d74ef2..b14aa60dc 100644 --- a/src/main/java/com/purbon/kafka/topology/KSqlArtefactManager.java +++ b/src/main/java/com/purbon/kafka/topology/KSqlArtefactManager.java @@ -84,15 +84,9 @@ private Collection getClustersState() throws IOException { .map( artefact -> { if (artefact instanceof KsqlStreamArtefact) { - return new KsqlStreamArtefact( - artefact.getPath(), - null, - artefact.getName()); + return new KsqlStreamArtefact(artefact.getPath(), null, artefact.getName()); } else if (artefact instanceof KsqlTableArtefact) { - return new KsqlTableArtefact( - artefact.getPath(), - null, - artefact.getName()); + return new KsqlTableArtefact(artefact.getPath(), null, artefact.getName()); } else { LOGGER.error("KSQL Artefact of wrong type " + artefact.getClass()); return null; diff --git a/src/main/java/com/purbon/kafka/topology/backend/AbstractBackend.java b/src/main/java/com/purbon/kafka/topology/backend/BackendHelper.java similarity index 74% rename from src/main/java/com/purbon/kafka/topology/backend/AbstractBackend.java rename to src/main/java/com/purbon/kafka/topology/backend/BackendHelper.java index 44db6db92..863339fae 100644 --- a/src/main/java/com/purbon/kafka/topology/backend/AbstractBackend.java +++ b/src/main/java/com/purbon/kafka/topology/backend/BackendHelper.java @@ -5,17 +5,15 @@ import java.util.regex.Matcher; import java.util.regex.Pattern; -public abstract class AbstractBackend implements Backend { +class BackendHelper { - private final String expression = + private static final String expression = "^\"?\\'(\\S+)\\',\\s*\\'(\\S+)\\',\\s*\\'(\\S+)\\',\\s*\\'(\\S+)\\',\\s*\\'(.+)\\',\\s*\\'(\\S+)\\'\"?$"; - private Pattern regexp; + private static Pattern regexp = Pattern.compile(expression); - public AbstractBackend() { - this.regexp = Pattern.compile(expression); - } + private BackendHelper() {} - protected TopologyAclBinding buildAclBinding(String line) throws IOException { + static TopologyAclBinding buildAclBinding(String line) throws IOException { // 'TOPIC', 'topicB', '*', 'READ', 'User:Connect1', 'LITERAL' Matcher matches = regexp.matcher(line); diff --git a/src/main/java/com/purbon/kafka/topology/backend/BackendState.java b/src/main/java/com/purbon/kafka/topology/backend/BackendState.java index 30d561688..7f81f254f 100644 --- a/src/main/java/com/purbon/kafka/topology/backend/BackendState.java +++ b/src/main/java/com/purbon/kafka/topology/backend/BackendState.java @@ -83,6 +83,11 @@ public String asJson() throws JsonProcessingException { return JSON.asString(this); } + @JsonIgnore + public String asPrettyJson() throws JsonProcessingException { + return JSON.asPrettyString(this); + } + public void clear() { bindings.clear(); accounts.clear(); diff --git a/src/main/java/com/purbon/kafka/topology/backend/FileBackend.java b/src/main/java/com/purbon/kafka/topology/backend/FileBackend.java index 7db8404da..e5e603c63 100644 --- a/src/main/java/com/purbon/kafka/topology/backend/FileBackend.java +++ b/src/main/java/com/purbon/kafka/topology/backend/FileBackend.java @@ -4,8 +4,6 @@ import com.purbon.kafka.topology.BackendController.Mode; import com.purbon.kafka.topology.utils.JSON; -import java.io.BufferedReader; -import java.io.FileReader; import java.io.FileWriter; import java.io.IOException; import java.nio.file.Files; @@ -14,7 +12,7 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -public class FileBackend extends AbstractBackend { +public class FileBackend implements Backend { private static final Logger LOGGER = LogManager.getLogger(FileBackend.class); @@ -43,7 +41,7 @@ public void createOrOpen(Mode mode) { @Override public void save(BackendState state) throws IOException { - writeLine(state.asJson()); + writeText(state.asPrettyJson()); } @Override @@ -52,16 +50,20 @@ public BackendState load() throws IOException { if (Files.size(filePath) == 0) { // if we are loading when there is no file or is empty. return new BackendState(); } - try (BufferedReader reader = new BufferedReader(new FileReader(filePath.toFile()))) { - String backendStateAsJsonString = reader.readLine(); - return (BackendState) JSON.toObject(backendStateAsJsonString, BackendState.class); + return load(filePath); + } + + BackendState load(Path stateFilePath) throws IOException { + String backendStateAsJsonString = Files.readString(stateFilePath); + if (OldFileBackendLoader.isControlTag(backendStateAsJsonString.split("\\r?\\n")[0])) { + return new OldFileBackendLoader().load(stateFilePath.toFile()); } + return (BackendState) JSON.toObject(backendStateAsJsonString, BackendState.class); } - private void writeLine(String line) throws IOException { + private void writeText(String text) throws IOException { try { - writer.write(line); - writer.write("\n"); + writer.write(text); } catch (IOException e) { LOGGER.error(e); throw e; diff --git a/src/main/java/com/purbon/kafka/topology/backend/GCPBackend.java b/src/main/java/com/purbon/kafka/topology/backend/GCPBackend.java index 2a45df5a0..5b384ce0d 100644 --- a/src/main/java/com/purbon/kafka/topology/backend/GCPBackend.java +++ b/src/main/java/com/purbon/kafka/topology/backend/GCPBackend.java @@ -11,7 +11,7 @@ import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; -public class GCPBackend extends AbstractBackend { +public class GCPBackend implements Backend { private static final Logger LOGGER = LogManager.getLogger(GCPBackend.class); diff --git a/src/main/java/com/purbon/kafka/topology/backend/OldFileBackendLoader.java b/src/main/java/com/purbon/kafka/topology/backend/OldFileBackendLoader.java new file mode 100644 index 000000000..5fd5a1389 --- /dev/null +++ b/src/main/java/com/purbon/kafka/topology/backend/OldFileBackendLoader.java @@ -0,0 +1,71 @@ +package com.purbon.kafka.topology.backend; + +import com.fasterxml.jackson.core.JsonProcessingException; +import com.purbon.kafka.topology.model.cluster.ServiceAccount; +import com.purbon.kafka.topology.roles.TopologyAclBinding; +import com.purbon.kafka.topology.utils.JSON; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.io.IOException; +import java.util.*; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; + +class OldFileBackendLoader { + + private static final Logger LOGGER = LogManager.getLogger(OldFileBackendLoader.class); + static final String SERVICE_ACCOUNTS_TAG = "ServiceAccounts"; + static final String TOPICS_TAG = "Topics"; + static final String ACLS_TAG = "acls"; + + BackendState load(File file) throws IOException { + BackendState state = new BackendState(); + try (BufferedReader in = new BufferedReader(new FileReader(file))) { + String type = null; + String line; + while ((line = in.readLine()) != null) { + if (type == null || isControlTag(line)) { + type = line; + continue; + } + if (type.equalsIgnoreCase(SERVICE_ACCOUNTS_TAG)) { + final ServiceAccount serviceAccount = parseServiceAccount(line); + if (serviceAccount != null) { + state.addAccounts(Collections.singleton(serviceAccount)); + } + } else if (type.equalsIgnoreCase(ACLS_TAG)) { + state.addBindings(Collections.singleton(parseAcl(line))); + } else if (type.equalsIgnoreCase(TOPICS_TAG)) { + state.addTopics(Collections.singleton(parseTopic(line))); + } else { + throw new IOException("Binding type \"" + type + "\" not supported."); + } + } + } + return state; + } + + private ServiceAccount parseServiceAccount(final String line) { + try { + return (ServiceAccount) JSON.toObject(line, ServiceAccount.class); + } catch (JsonProcessingException e) { + LOGGER.error(e); + return null; + } + } + + private TopologyAclBinding parseAcl(final String line) throws IOException { + return BackendHelper.buildAclBinding(line); + } + + private String parseTopic(final String line) { + return line.trim(); + } + + static boolean isControlTag(String line) { + return line.equalsIgnoreCase(SERVICE_ACCOUNTS_TAG) + || line.equalsIgnoreCase(TOPICS_TAG) + || line.equalsIgnoreCase(ACLS_TAG); + } +} diff --git a/src/main/java/com/purbon/kafka/topology/backend/RedisBackend.java b/src/main/java/com/purbon/kafka/topology/backend/RedisBackend.java index e4e5748c2..89602d36d 100644 --- a/src/main/java/com/purbon/kafka/topology/backend/RedisBackend.java +++ b/src/main/java/com/purbon/kafka/topology/backend/RedisBackend.java @@ -9,7 +9,7 @@ import org.apache.logging.log4j.Logger; import redis.clients.jedis.Jedis; -public class RedisBackend extends AbstractBackend { +public class RedisBackend implements Backend { private static final Logger LOGGER = LogManager.getLogger(RedisBackend.class); @@ -71,7 +71,7 @@ private Set loadBindings() throws IOException { long count = jedis.scard(JULIE_OPS_BINDINGS); for (long i = 0; i < count; i++) { String elem = jedis.spop(JULIE_OPS_BINDINGS); - TopologyAclBinding binding = buildAclBinding(elem); + TopologyAclBinding binding = BackendHelper.buildAclBinding(elem); bindings.add(binding); } return bindings; diff --git a/src/main/java/com/purbon/kafka/topology/backend/S3Backend.java b/src/main/java/com/purbon/kafka/topology/backend/S3Backend.java index e6a985671..e35f273c7 100644 --- a/src/main/java/com/purbon/kafka/topology/backend/S3Backend.java +++ b/src/main/java/com/purbon/kafka/topology/backend/S3Backend.java @@ -17,7 +17,7 @@ import software.amazon.awssdk.services.s3.S3ClientBuilder; import software.amazon.awssdk.services.s3.model.*; -public class S3Backend extends AbstractBackend { +public class S3Backend implements Backend { private static final Logger LOGGER = LogManager.getLogger(S3Backend.class); diff --git a/src/main/java/com/purbon/kafka/topology/model/Artefact.java b/src/main/java/com/purbon/kafka/topology/model/Artefact.java index 2c97c1a13..ac38433cb 100644 --- a/src/main/java/com/purbon/kafka/topology/model/Artefact.java +++ b/src/main/java/com/purbon/kafka/topology/model/Artefact.java @@ -1,8 +1,6 @@ package com.purbon.kafka.topology.model; import com.fasterxml.jackson.annotation.JsonInclude; - -import java.util.Locale; import java.util.Objects; @JsonInclude(JsonInclude.Include.NON_NULL) diff --git a/src/main/java/com/purbon/kafka/topology/utils/JSON.java b/src/main/java/com/purbon/kafka/topology/utils/JSON.java index 6fe7548f8..fecdf16a3 100644 --- a/src/main/java/com/purbon/kafka/topology/utils/JSON.java +++ b/src/main/java/com/purbon/kafka/topology/utils/JSON.java @@ -37,6 +37,10 @@ public static String asString(Object account) throws JsonProcessingException { return mapper.writeValueAsString(account); } + public static String asPrettyString(Object account) throws JsonProcessingException { + return mapper.writerWithDefaultPrettyPrinter().writeValueAsString(account); + } + public static Object toObjectList(String jsonString, Class objectClazz) throws JsonProcessingException { CollectionType collectionType = diff --git a/src/test/java/com/purbon/kafka/topology/backend/FileBackendTest.java b/src/test/java/com/purbon/kafka/topology/backend/FileBackendTest.java index fdc56c06a..297759fd9 100644 --- a/src/test/java/com/purbon/kafka/topology/backend/FileBackendTest.java +++ b/src/test/java/com/purbon/kafka/topology/backend/FileBackendTest.java @@ -93,6 +93,15 @@ public void shouldParseStateFileSuccessfully() throws IOException { assertThat(backend.getAccounts()).hasSize(0); } + @Test + public void shouldParseOldStyleStateFileSuccessfully() throws IOException { + File file = TestUtils.getResourceFile("/old-style-state-file.txt"); + final BackendState state = new FileBackend().load(file.toPath()); + assertThat(state.getTopics()).hasSize(2); + assertThat(state.getBindings()).hasSize(3); + assertThat(state.getAccounts()).hasSize(0); + } + private void verifyStoreAndLoadWithPrincipal(final String principal) throws IOException { TopologyAclBinding binding = TopologyAclBinding.build( diff --git a/src/test/java/com/purbon/kafka/topology/integration/KsqlManagerIT.java b/src/test/java/com/purbon/kafka/topology/integration/KsqlManagerIT.java index 94114818d..50059eaf4 100644 --- a/src/test/java/com/purbon/kafka/topology/integration/KsqlManagerIT.java +++ b/src/test/java/com/purbon/kafka/topology/integration/KsqlManagerIT.java @@ -73,7 +73,7 @@ public void testCreateAndUpdatePathWithRemoveClusterState() throws IOException { props.put(TOPOLOGY_STATE_FROM_CLUSTER, "true"); props.put(TOPOLOGY_TOPIC_STATE_FROM_CLUSTER, "false"); props.put(ALLOW_DELETE_KSQL_ARTEFACTS, "true"); - props.put(PLATFORM_SERVER_KSQL, "http://"+client.getServer()); + props.put(PLATFORM_SERVER_KSQL, "http://" + client.getServer()); File file = TestUtils.getResourceFile("/descriptor-ksql.yaml"); diff --git a/src/test/resources/old-style-state-file.txt b/src/test/resources/old-style-state-file.txt new file mode 100644 index 000000000..17019dcc7 --- /dev/null +++ b/src/test/resources/old-style-state-file.txt @@ -0,0 +1,8 @@ +acls +'CLUSTER', 'example-cluster', '*', 'IDEMPOTENT_WRITE', 'SPIFFE:spiffe://foo.example.com/ns/foo/sa/bar', 'LITERAL' +'TOPIC', 'topic1', '*', 'DESCRIBE', 'User:CN=foo.example.com', 'LITERAL' +'TOPIC', 'topic1', '*', 'READ', 'User:CN=foo.example.com', 'LITERAL' +ServiceAccounts +Topics +topic1 +topic2