This is an automated email from the ASF dual-hosted git repository. jianglongtao pushed a commit to branch fix-33341 in repository https://gitbox.apache.org/repos/asf/shardingsphere.git
commit e1012c49c3f65a412804e6c7ddcaaf8272cec019 Author: Raigor <[email protected]> AuthorDate: Tue Aug 20 11:30:42 2024 +0800 Add password decorator (#2) --- mode/core/pom.xml | 9 ++ .../GlobalRuleConfigurationDecorator.java | 112 +++++++++++++++++++++ .../AuthorityRuleConfigurationDecorator.java | 111 ++++++++++++++++++++ .../decorator/password/AESPasswordDecorator.java | 94 +++++++++++++++++ .../mode/decorator/password/PasswordDecorator.java | 40 ++++++++ .../mode/metadata/MetaDataContextsFactory.java | 19 +++- .../password/AESPasswordDecoratorTest.java | 39 +++++++ .../subscriber/ConfigurationChangedSubscriber.java | 13 ++- .../ral/queryable/ExportMetaDataExecutor.java | 8 +- .../ral/updatable/ImportMetaDataExecutor.java | 33 ++++++ 10 files changed, 472 insertions(+), 6 deletions(-) diff --git a/mode/core/pom.xml b/mode/core/pom.xml index e0c6d8c7f9c..3d98fe808bf 100644 --- a/mode/core/pom.xml +++ b/mode/core/pom.xml @@ -42,11 +42,20 @@ <artifactId>shardingsphere-metadata-core</artifactId> <version>${project.version}</version> </dependency> + + <dependency> + <groupId>org.bouncycastle</groupId> + <artifactId>bcpkix-jdk15on</artifactId> + </dependency> <dependency> <groupId>com.zaxxer</groupId> <artifactId>HikariCP</artifactId> <scope>compile</scope> </dependency> + <dependency> + <groupId>commons-codec</groupId> + <artifactId>commons-codec</artifactId> + </dependency> <dependency> <groupId>org.apache.shardingsphere</groupId> diff --git a/mode/core/src/main/java/com/sphereex/dbplusengine/mode/decorator/GlobalRuleConfigurationDecorator.java b/mode/core/src/main/java/com/sphereex/dbplusengine/mode/decorator/GlobalRuleConfigurationDecorator.java new file mode 100644 index 00000000000..ade1cc54674 --- /dev/null +++ b/mode/core/src/main/java/com/sphereex/dbplusengine/mode/decorator/GlobalRuleConfigurationDecorator.java @@ -0,0 +1,112 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.sphereex.dbplusengine.mode.decorator; + +import com.sphereex.dbplusengine.mode.decorator.authority.AuthorityRuleConfigurationDecorator; +import org.apache.shardingsphere.authority.config.AuthorityRuleConfiguration; +import org.apache.shardingsphere.authority.rule.AuthorityRule; +import org.apache.shardingsphere.infra.config.rule.RuleConfiguration; +import org.apache.shardingsphere.infra.instance.InstanceContext; +import org.apache.shardingsphere.infra.metadata.statistics.ShardingSphereStatistics; +import org.apache.shardingsphere.infra.rule.ShardingSphereRule; + +import java.util.Collection; +import java.util.LinkedList; +import java.util.Optional; + +/** + * Global rule configuration decorator. + */ +public final class GlobalRuleConfigurationDecorator { + + /** + * Decorate. + * + * @param instanceContext Instance context + * @param globalRuleConfigs global rule configurations + * @param statistics ShardingSphere statistics + * @return decorated rule configurations + */ + public Collection<RuleConfiguration> decorate(final InstanceContext instanceContext, final Collection<RuleConfiguration> globalRuleConfigs, + final ShardingSphereStatistics statistics) { + Collection<RuleConfiguration> result = new LinkedList<>(globalRuleConfigs); + if (!isDecorationNeeded(instanceContext, statistics)) { + return result; + } + Optional<AuthorityRuleConfiguration> authorityRuleConfig = getAuthorityRuleConfig(globalRuleConfigs); + if (!authorityRuleConfig.isPresent()) { + return result; + } + result.removeIf(each -> each instanceof AuthorityRuleConfiguration); + result.add(new AuthorityRuleConfigurationDecorator(statistics).decorate(authorityRuleConfig.get())); + return result; + } + + /** + * Restore. + * + * @param instanceContext Instance context + * @param globalRuleConfigs global rule configurations + * @param statistics ShardingSphere statistics + * @return original rule configuration + */ + public Collection<RuleConfiguration> restore(final InstanceContext instanceContext, final Collection<RuleConfiguration> globalRuleConfigs, final ShardingSphereStatistics statistics) { + Collection<RuleConfiguration> result = new LinkedList<>(globalRuleConfigs); + if (!isDecorationNeeded(instanceContext, statistics)) { + return result; + } + Optional<AuthorityRuleConfiguration> authorityRuleConfig = getAuthorityRuleConfig(globalRuleConfigs); + if (!authorityRuleConfig.isPresent()) { + return result; + } + result.removeIf(each -> each instanceof AuthorityRuleConfiguration); + result.add(new AuthorityRuleConfigurationDecorator(statistics).restore(authorityRuleConfig.get())); + return result; + } + + /** + * Restore global rules. + * + * @param globalRules global rules + * @param statistics ShardingSphere statistics + * @param instanceContext Instance context + * @return original rule configuration + */ + public Collection<ShardingSphereRule> restore(final Collection<ShardingSphereRule> globalRules, final ShardingSphereStatistics statistics, final InstanceContext instanceContext) { + Collection<ShardingSphereRule> result = new LinkedList<>(globalRules); + if (!isDecorationNeeded(instanceContext, statistics)) { + return result; + } + Optional<AuthorityRule> authorityRule = globalRules.stream().filter(each -> each instanceof AuthorityRule).map(each -> (AuthorityRule) each).findAny(); + if (!authorityRule.isPresent()) { + return result; + } + result.removeIf(each -> each instanceof AuthorityRule); + AuthorityRuleConfiguration restoredRuleConfig = new AuthorityRuleConfigurationDecorator(statistics).restore(authorityRule.get().getConfiguration()); + result.add(new AuthorityRule(restoredRuleConfig)); + return result; + } + + private boolean isDecorationNeeded(final InstanceContext instanceContext, final ShardingSphereStatistics statistics) { + return instanceContext.isCluster() && statistics.containsDatabase("shardingsphere"); + } + + private Optional<AuthorityRuleConfiguration> getAuthorityRuleConfig(final Collection<RuleConfiguration> globalRuleConfigs) { + return globalRuleConfigs.stream().filter(each -> each instanceof AuthorityRuleConfiguration).map(each -> (AuthorityRuleConfiguration) each).findAny(); + } +} diff --git a/mode/core/src/main/java/com/sphereex/dbplusengine/mode/decorator/authority/AuthorityRuleConfigurationDecorator.java b/mode/core/src/main/java/com/sphereex/dbplusengine/mode/decorator/authority/AuthorityRuleConfigurationDecorator.java new file mode 100644 index 00000000000..6e0937096fd --- /dev/null +++ b/mode/core/src/main/java/com/sphereex/dbplusengine/mode/decorator/authority/AuthorityRuleConfigurationDecorator.java @@ -0,0 +1,111 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.sphereex.dbplusengine.mode.decorator.authority; + +import com.sphereex.dbplusengine.mode.decorator.password.AESPasswordDecorator; +import org.apache.shardingsphere.authority.config.AuthorityRuleConfiguration; +import org.apache.shardingsphere.infra.metadata.statistics.ShardingSphereRowData; +import org.apache.shardingsphere.infra.metadata.statistics.ShardingSphereSchemaData; +import org.apache.shardingsphere.infra.metadata.statistics.ShardingSphereStatistics; +import org.apache.shardingsphere.infra.metadata.statistics.ShardingSphereTableData; +import org.apache.shardingsphere.infra.metadata.user.Grantee; +import org.apache.shardingsphere.infra.metadata.user.ShardingSphereUser; + +import java.util.Collection; +import java.util.LinkedList; + +/** + * Authority rule configuration decorator. + */ +public final class AuthorityRuleConfigurationDecorator { + + private final AESPasswordDecorator passwordDecorator; + + public AuthorityRuleConfigurationDecorator(final ShardingSphereStatistics shardingSphereData) { + String shardingsphereSchemaName = "shardingsphere"; + ShardingSphereSchemaData schemaData = shardingSphereData.getDatabase(shardingsphereSchemaName).getSchemaData().get(shardingsphereSchemaName); + ShardingSphereTableData tableData = schemaData.getTable("cluster_information"); + Collection<ShardingSphereRowData> rows = tableData.getRows(); + passwordDecorator = new AESPasswordDecorator(rows.iterator().next().getUniqueKey()); + } + + /** + * Decorate. + * + * @param ruleConfig rule configuration + * @return decorated rule configuration + */ + public AuthorityRuleConfiguration decorate(final AuthorityRuleConfiguration ruleConfig) { + Collection<ShardingSphereUser> users = decorateUserPassword(ruleConfig.getUsers()); + return generateAuthorityRuleConfiguration(users, ruleConfig); + } + + private Collection<ShardingSphereUser> decorateUserPassword(final Collection<ShardingSphereUser> users) { + Collection<ShardingSphereUser> result = new LinkedList<>(); + for (ShardingSphereUser each : users) { + Grantee grantee = each.getGrantee(); + result.add(new ShardingSphereUser(grantee.getUsername(), + passwordDecorator.decorate(each.getPassword()), grantee.getHostname(), each.getAuthenticationMethodName(), each.isAdmin())); + } + return result; + } + + /** + * Restore. + * + * @param ruleConfig decorated rule configuration + * @return original rule configuration + */ + public AuthorityRuleConfiguration restore(final AuthorityRuleConfiguration ruleConfig) { + Collection<ShardingSphereUser> users = restoreUserPassword(ruleConfig.getUsers()); + return generateAuthorityRuleConfiguration(users, ruleConfig); + } + + private Collection<ShardingSphereUser> restoreUserPassword(final Collection<ShardingSphereUser> users) { + Collection<ShardingSphereUser> result = new LinkedList<>(); + for (ShardingSphereUser each : users) { + Grantee grantee = each.getGrantee(); + result.add(new ShardingSphereUser(grantee.getUsername(), + passwordDecorator.restore(each.getPassword()), grantee.getHostname(), each.getAuthenticationMethodName(), each.isAdmin())); + } + return result; + } + + private AuthorityRuleConfiguration generateAuthorityRuleConfiguration(final Collection<ShardingSphereUser> users, final AuthorityRuleConfiguration ruleConfig) { + return new AuthorityRuleConfiguration(users, ruleConfig.getPrivilegeProvider(), ruleConfig.getAuthenticators(), ruleConfig.getDefaultAuthenticator()); + } + + /** + * Can be restored. + * + * @param ruleConfiguration rule configuration + * @return true or false + */ + public boolean canBeRestored(final AuthorityRuleConfiguration ruleConfiguration) { + for (ShardingSphereUser each : ruleConfiguration.getUsers()) { + try { + passwordDecorator.restore(each.getPassword()); + // CHECKSTYLE:OFF + } catch (Exception ignored) { + // CHECKSTYLE:ON + return false; + } + } + return true; + } +} diff --git a/mode/core/src/main/java/com/sphereex/dbplusengine/mode/decorator/password/AESPasswordDecorator.java b/mode/core/src/main/java/com/sphereex/dbplusengine/mode/decorator/password/AESPasswordDecorator.java new file mode 100644 index 00000000000..0b7201360c2 --- /dev/null +++ b/mode/core/src/main/java/com/sphereex/dbplusengine/mode/decorator/password/AESPasswordDecorator.java @@ -0,0 +1,94 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.sphereex.dbplusengine.mode.decorator.password; + +import lombok.SneakyThrows; +import org.apache.commons.codec.digest.DigestUtils; + +import javax.crypto.Cipher; +import javax.crypto.NoSuchPaddingException; +import javax.crypto.SecretKey; +import javax.crypto.spec.GCMParameterSpec; +import javax.crypto.spec.SecretKeySpec; +import java.nio.charset.StandardCharsets; +import java.security.GeneralSecurityException; +import java.security.InvalidAlgorithmParameterException; +import java.security.InvalidKeyException; +import java.security.NoSuchAlgorithmException; +import java.security.SecureRandom; +import java.util.Base64; + +/** + * AES password decorator. + */ +public final class AESPasswordDecorator implements PasswordDecorator { + + private static final String ALGORITHM = "AES"; + + private static final int GCM_TAG_LENGTH = 128; + + private static final int IV_LENGTH = 12; + + private static final String TRANSFORMATION = "AES/GCM/NoPadding"; + + private final SecretKey secretKey; + + public AESPasswordDecorator(final String uniqueKey) { + secretKey = new SecretKeySpec(DigestUtils.sha256(uniqueKey), ALGORITHM); + } + + @SneakyThrows(GeneralSecurityException.class) + @Override + public String decorate(final String plainText) { + if (null == plainText) { + return null; + } + SecureRandom random = new SecureRandom(); + byte[] iv = new byte[IV_LENGTH]; + random.nextBytes(iv); + Cipher cipher = getCipher(Cipher.ENCRYPT_MODE, iv); + byte[] encrypted = cipher.doFinal(plainText.getBytes(StandardCharsets.UTF_8)); + byte[] combined = new byte[iv.length + encrypted.length]; + System.arraycopy(iv, 0, combined, 0, iv.length); + System.arraycopy(encrypted, 0, combined, iv.length, encrypted.length); + return Base64.getEncoder().encodeToString(combined); + } + + @SneakyThrows(GeneralSecurityException.class) + @Override + public String restore(final String cipherText) { + if (null == cipherText) { + return null; + } + byte[] combined = Base64.getDecoder().decode(cipherText); + byte[] iv = new byte[IV_LENGTH]; + System.arraycopy(combined, 0, iv, 0, IV_LENGTH); + byte[] encrypted = new byte[combined.length - IV_LENGTH]; + System.arraycopy(combined, IV_LENGTH, encrypted, 0, combined.length - IV_LENGTH); + Cipher cipher = getCipher(Cipher.DECRYPT_MODE, iv); + byte[] decrypted = cipher.doFinal(encrypted); + return new String(decrypted, StandardCharsets.UTF_8); + } + + private Cipher getCipher(final int decryptMode, final byte[] iv) throws NoSuchPaddingException, NoSuchAlgorithmException, InvalidKeyException, InvalidAlgorithmParameterException { + GCMParameterSpec gcmParameterSpec = new GCMParameterSpec(GCM_TAG_LENGTH, iv); + Cipher result = Cipher.getInstance(TRANSFORMATION); + result.init(decryptMode, secretKey, gcmParameterSpec); + return result; + } +} diff --git a/mode/core/src/main/java/com/sphereex/dbplusengine/mode/decorator/password/PasswordDecorator.java b/mode/core/src/main/java/com/sphereex/dbplusengine/mode/decorator/password/PasswordDecorator.java new file mode 100644 index 00000000000..3e2627eee63 --- /dev/null +++ b/mode/core/src/main/java/com/sphereex/dbplusengine/mode/decorator/password/PasswordDecorator.java @@ -0,0 +1,40 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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.sphereex.dbplusengine.mode.decorator.password; + +/** + * Password decorator. + */ +public interface PasswordDecorator { + + /** + * Decorate. + * + * @param originalValue original value + * @return decorated value + */ + String decorate(String originalValue); + + /** + * Restore. + * + * @param decoratedValue decorated value + * @return original value + */ + String restore(String decoratedValue); +} diff --git a/mode/core/src/main/java/org/apache/shardingsphere/mode/metadata/MetaDataContextsFactory.java b/mode/core/src/main/java/org/apache/shardingsphere/mode/metadata/MetaDataContextsFactory.java index 1edba228140..79fdc4362c9 100644 --- a/mode/core/src/main/java/org/apache/shardingsphere/mode/metadata/MetaDataContextsFactory.java +++ b/mode/core/src/main/java/org/apache/shardingsphere/mode/metadata/MetaDataContextsFactory.java @@ -19,6 +19,7 @@ package org.apache.shardingsphere.mode.metadata; import com.google.common.base.Preconditions; import com.google.common.base.Splitter; +import com.sphereex.dbplusengine.mode.decorator.GlobalRuleConfigurationDecorator; import lombok.AccessLevel; import lombok.NoArgsConstructor; import org.apache.shardingsphere.infra.config.database.DatabaseConfiguration; @@ -33,6 +34,7 @@ import org.apache.shardingsphere.infra.metadata.ShardingSphereMetaData; import org.apache.shardingsphere.infra.metadata.database.ShardingSphereDatabase; import org.apache.shardingsphere.infra.metadata.database.resource.ResourceMetaData; import org.apache.shardingsphere.infra.metadata.database.rule.RuleMetaData; +import org.apache.shardingsphere.infra.rule.ShardingSphereRule; import org.apache.shardingsphere.infra.rule.builder.global.GlobalRulesBuilder; import org.apache.shardingsphere.infra.state.datasource.DataSourceState; import org.apache.shardingsphere.infra.state.datasource.DataSourceStateManager; @@ -99,10 +101,17 @@ public final class MetaDataContextsFactory { ResourceMetaData globalResourceMetaData = new ResourceMetaData(globalDataSources); RuleMetaData globalRuleMetaData = new RuleMetaData(GlobalRulesBuilder.buildRules(globalRuleConfigs, databases, props)); MetaDataContexts result = new MetaDataContexts(persistService, new ShardingSphereMetaData(databases, globalResourceMetaData, globalRuleMetaData, props)); + // SPEX CHANGED: BEGIN if (!isDatabaseMetaDataExisted) { - persistDatabaseConfigurations(result, param); + persistDatabaseConfigurations(instanceContext, result, param); persistMetaData(result); + } else { + Collection<ShardingSphereRule> globalRules = new GlobalRuleConfigurationDecorator().restore( + result.getMetaData().getGlobalRuleMetaData().getRules(), result.getStatistics(), instanceContext); + result.getMetaData().getGlobalRuleMetaData().getRules().clear(); + result.getMetaData().getGlobalRuleMetaData().getRules().addAll(globalRules); } + // SPEX CHANGED: END return result; } @@ -151,8 +160,12 @@ public final class MetaDataContextsFactory { return result; } - private static void persistDatabaseConfigurations(final MetaDataContexts metadataContexts, final ContextManagerBuilderParameter param) { - metadataContexts.getPersistService().persistGlobalRuleConfiguration(param.getGlobalRuleConfigs(), param.getProps()); + private static void persistDatabaseConfigurations(final InstanceContext instanceContext, final MetaDataContexts metadataContexts, final ContextManagerBuilderParameter param) { + // SPEX CHANGED: BEGIN + Collection<RuleConfiguration> globalRuleConfigs = new GlobalRuleConfigurationDecorator().decorate(instanceContext, + metadataContexts.getMetaData().getGlobalRuleMetaData().getConfigurations(), metadataContexts.getStatistics()); + metadataContexts.getPersistService().persistGlobalRuleConfiguration(globalRuleConfigs, param.getProps()); + // SPEX CHANGED: END for (Entry<String, ? extends DatabaseConfiguration> entry : param.getDatabaseConfigs().entrySet()) { String databaseName = entry.getKey(); metadataContexts.getPersistService().persistConfigurations(entry.getKey(), entry.getValue(), diff --git a/mode/core/src/test/java/org/apache/shardingsphere/mode/decorator/password/AESPasswordDecoratorTest.java b/mode/core/src/test/java/org/apache/shardingsphere/mode/decorator/password/AESPasswordDecoratorTest.java new file mode 100644 index 00000000000..85f1ebad212 --- /dev/null +++ b/mode/core/src/test/java/org/apache/shardingsphere/mode/decorator/password/AESPasswordDecoratorTest.java @@ -0,0 +1,39 @@ +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with + * this work for additional information regarding copyright ownership. + * The ASF licenses this file to You 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 org.apache.shardingsphere.mode.decorator.password; + +import com.sphereex.dbplusengine.mode.decorator.password.AESPasswordDecorator; +import org.junit.jupiter.api.Test; + +import static org.hamcrest.CoreMatchers.is; +import static org.hamcrest.MatcherAssert.assertThat; +import static org.hamcrest.Matchers.not; + +class AESPasswordDecoratorTest { + + @Test + void assertDecorateAndRestore() { + String plainText = "password"; + AESPasswordDecorator decorator = new AESPasswordDecorator("0e85e2025a653e7bf27efca5ca243c45"); + String cipherText0 = decorator.decorate(plainText); + String cipherText1 = decorator.decorate(plainText); + assertThat(cipherText0, not(cipherText1)); + assertThat(decorator.restore(cipherText0), is(plainText)); + assertThat(decorator.restore(cipherText1), is(plainText)); + } +} diff --git a/mode/type/cluster/core/src/main/java/org/apache/shardingsphere/mode/manager/cluster/coordinator/subscriber/ConfigurationChangedSubscriber.java b/mode/type/cluster/core/src/main/java/org/apache/shardingsphere/mode/manager/cluster/coordinator/subscriber/ConfigurationChangedSubscriber.java index 763d821fc5c..b01e798e91d 100644 --- a/mode/type/cluster/core/src/main/java/org/apache/shardingsphere/mode/manager/cluster/coordinator/subscriber/ConfigurationChangedSubscriber.java +++ b/mode/type/cluster/core/src/main/java/org/apache/shardingsphere/mode/manager/cluster/coordinator/subscriber/ConfigurationChangedSubscriber.java @@ -18,6 +18,8 @@ package org.apache.shardingsphere.mode.manager.cluster.coordinator.subscriber; import com.google.common.eventbus.Subscribe; +import com.sphereex.dbplusengine.mode.decorator.GlobalRuleConfigurationDecorator; +import org.apache.shardingsphere.infra.config.rule.RuleConfiguration; import org.apache.shardingsphere.mode.event.config.AlterDatabaseRuleConfigurationEvent; import org.apache.shardingsphere.mode.event.config.DropDatabaseRuleConfigurationEvent; import org.apache.shardingsphere.mode.event.config.global.AlterGlobalRuleConfigurationEvent; @@ -27,6 +29,9 @@ import org.apache.shardingsphere.mode.event.datasource.unit.RegisterStorageUnitE import org.apache.shardingsphere.mode.event.datasource.unit.UnregisterStorageUnitEvent; import org.apache.shardingsphere.mode.manager.ContextManager; +import java.util.Collection; +import java.util.Collections; + /** * Configuration changed subscriber. */ @@ -117,8 +122,12 @@ public final class ConfigurationChangedSubscriber { if (!event.getActiveVersion().equals(contextManager.getMetaDataContexts().getPersistService().getMetaDataVersionPersistService().getActiveVersionByFullPath(event.getActiveVersionKey()))) { return; } - contextManager.getConfigurationContextManager() - .alterGlobalRuleConfiguration(contextManager.getMetaDataContexts().getPersistService().getGlobalRuleService().load(event.getRuleSimpleName())); + // SPEX CHANGED: BEGIN + RuleConfiguration ruleConfig = contextManager.getMetaDataContexts().getPersistService().getGlobalRuleService().load(event.getRuleSimpleName()); + Collection<RuleConfiguration> configs = new GlobalRuleConfigurationDecorator() + .restore(contextManager.getInstanceContext(), Collections.singletonList(ruleConfig), contextManager.getMetaDataContexts().getStatistics()); + contextManager.getConfigurationContextManager().alterGlobalRuleConfiguration(configs.iterator().next()); + // SPEX CHANGED: END } /** diff --git a/proxy/backend/core/src/main/java/org/apache/shardingsphere/proxy/backend/handler/distsql/ral/queryable/ExportMetaDataExecutor.java b/proxy/backend/core/src/main/java/org/apache/shardingsphere/proxy/backend/handler/distsql/ral/queryable/ExportMetaDataExecutor.java index 1cee2a0bedb..ff83bbad6e9 100644 --- a/proxy/backend/core/src/main/java/org/apache/shardingsphere/proxy/backend/handler/distsql/ral/queryable/ExportMetaDataExecutor.java +++ b/proxy/backend/core/src/main/java/org/apache/shardingsphere/proxy/backend/handler/distsql/ral/queryable/ExportMetaDataExecutor.java @@ -17,6 +17,7 @@ package org.apache.shardingsphere.proxy.backend.handler.distsql.ral.queryable; +import com.sphereex.dbplusengine.mode.decorator.GlobalRuleConfigurationDecorator; import org.apache.commons.codec.binary.Base64; import org.apache.shardingsphere.distsql.handler.engine.query.DistSQLQueryExecutor; import org.apache.shardingsphere.distsql.statement.ral.queryable.export.ExportMetaDataStatement; @@ -75,7 +76,12 @@ public final class ExportMetaDataExecutor implements DistSQLQueryExecutor<Export ExportedMetaData exportedMetaData = new ExportedMetaData(); exportedMetaData.setDatabases(getDatabases(proxyContext)); exportedMetaData.setProps(generatePropsData(metaData.getProps().getProps())); - exportedMetaData.setRules(generateRulesData(metaData.getGlobalRuleMetaData().getConfigurations())); + // SPEX CHANGED: BEGIN + ContextManager contextManager = ProxyContext.getInstance().getContextManager(); + Collection<RuleConfiguration> globalRuleConfigs = new GlobalRuleConfigurationDecorator().decorate(contextManager.getInstanceContext(), + metaData.getGlobalRuleMetaData().getConfigurations(), contextManager.getMetaDataContexts().getStatistics()); + exportedMetaData.setRules(generateRulesData(globalRuleConfigs)); + // SPEX CHANGED: END ExportedClusterInfo exportedClusterInfo = new ExportedClusterInfo(); exportedClusterInfo.setMetaData(exportedMetaData); generateSnapshotInfo(metaData, exportedClusterInfo); diff --git a/proxy/backend/core/src/main/java/org/apache/shardingsphere/proxy/backend/handler/distsql/ral/updatable/ImportMetaDataExecutor.java b/proxy/backend/core/src/main/java/org/apache/shardingsphere/proxy/backend/handler/distsql/ral/updatable/ImportMetaDataExecutor.java index d90f79aff93..d5f3e91af2b 100644 --- a/proxy/backend/core/src/main/java/org/apache/shardingsphere/proxy/backend/handler/distsql/ral/updatable/ImportMetaDataExecutor.java +++ b/proxy/backend/core/src/main/java/org/apache/shardingsphere/proxy/backend/handler/distsql/ral/updatable/ImportMetaDataExecutor.java @@ -17,8 +17,10 @@ package org.apache.shardingsphere.proxy.backend.handler.distsql.ral.updatable; +import com.sphereex.dbplusengine.mode.decorator.authority.AuthorityRuleConfigurationDecorator; import org.apache.commons.codec.binary.Base64; import org.apache.commons.io.FileUtils; +import org.apache.shardingsphere.authority.config.AuthorityRuleConfiguration; import org.apache.shardingsphere.distsql.handler.engine.update.DistSQLUpdateExecutor; import org.apache.shardingsphere.distsql.statement.ral.updatable.ImportMetaDataStatement; import org.apache.shardingsphere.infra.config.rule.RuleConfiguration; @@ -26,8 +28,11 @@ import org.apache.shardingsphere.infra.util.json.JsonUtils; import org.apache.shardingsphere.infra.util.yaml.YamlEngine; import org.apache.shardingsphere.infra.yaml.config.swapper.rule.YamlRuleConfigurationSwapperEngine; import org.apache.shardingsphere.mode.manager.ContextManager; +import org.apache.shardingsphere.mode.metadata.MetaDataContexts; +import org.apache.shardingsphere.mode.repository.standalone.StandalonePersistRepository; import org.apache.shardingsphere.proxy.backend.config.yaml.YamlProxyDatabaseConfiguration; import org.apache.shardingsphere.proxy.backend.config.yaml.YamlProxyServerConfiguration; +import org.apache.shardingsphere.proxy.backend.context.ProxyContext; import org.apache.shardingsphere.proxy.backend.distsql.export.ExportedClusterInfo; import org.apache.shardingsphere.proxy.backend.distsql.export.ExportedMetaData; import org.apache.shardingsphere.infra.exception.generic.FileIOException; @@ -38,6 +43,7 @@ import java.io.IOException; import java.nio.charset.Charset; import java.sql.SQLException; import java.util.Collection; +import java.util.Optional; /** * Import meta data executor. @@ -73,11 +79,38 @@ public final class ImportMetaDataExecutor implements DistSQLUpdateExecutor<Impor return; } Collection<RuleConfiguration> rules = ruleConfigSwapperEngine.swapToRuleConfigurations(yamlServerConfig.getRules()); + // SPEX ADDED: BEGIN + decorateGlobalRuleConfigurations(rules); + // SPEX ADDED: END rules.forEach(each -> contextManager.getInstanceContext().getModeContextManager().alterGlobalRuleConfiguration(each)); contextManager.getInstanceContext().getModeContextManager().alterProperties(yamlServerConfig.getProps()); } + private void decorateGlobalRuleConfigurations(final Collection<RuleConfiguration> rules) { + MetaDataContexts metaDataContexts = ProxyContext.getInstance().getContextManager().getMetaDataContexts(); + if (metaDataContexts.getPersistService().getRepository() instanceof StandalonePersistRepository) { + return; + } + if (!metaDataContexts.getStatistics().containsDatabase("shardingsphere")) { + return; + } + Optional<AuthorityRuleConfiguration> ruleConfig = rules.stream() + .filter(each -> each instanceof AuthorityRuleConfiguration).map(each -> (AuthorityRuleConfiguration) each).findAny(); + if (!ruleConfig.isPresent()) { + return; + } + AuthorityRuleConfigurationDecorator authorityRuleConfigurationDecorator = new AuthorityRuleConfigurationDecorator(metaDataContexts.getStatistics()); + if (!authorityRuleConfigurationDecorator.canBeRestored(ruleConfig.get())) { + rules.removeIf(each -> each instanceof AuthorityRuleConfiguration); + AuthorityRuleConfiguration decoratedRuleConfig = authorityRuleConfigurationDecorator.decorate(ruleConfig.get()); + rules.add(decoratedRuleConfig); + } + } + private void importDatabase(final ExportedMetaData exportedMetaData) { + if (null == exportedMetaData.getDatabases() || exportedMetaData.getDatabases().isEmpty()) { + return; + } for (String each : exportedMetaData.getDatabases().values()) { YamlProxyDatabaseConfiguration yamlDatabaseConfig = YamlEngine.unmarshal(each, YamlProxyDatabaseConfiguration.class); databaseConfigImportExecutor.importDatabaseConfiguration(yamlDatabaseConfig);
