From 7110345b097b13704eeeba4f9d7e289d55764b53 Mon Sep 17 00:00:00 2001 From: IL MARE Date: Fri, 6 Sep 2024 15:28:08 +0800 Subject: [PATCH 1/2] feat(dfa): add simple dfa for workflow cluster's status transfer (#3289) * add fsm * refactor fsm * refactor dfa --- .../oceanbase/odc/core/dfa/AbstractDfa.java | 69 ++++++++++++++++++ .../odc/core/dfa/DfaStateTransfer.java | 33 +++++++++ .../com/oceanbase/odc/core/dfa/DfaTest.java | 72 +++++++++++++++++++ .../odc/core/dfa/K8sPodStatusDfa.java | 35 +++++++++ .../odc/core/dfa/K8sPodStatusDfaTransfer.java | 45 ++++++++++++ 5 files changed, 254 insertions(+) create mode 100644 server/odc-core/src/main/java/com/oceanbase/odc/core/dfa/AbstractDfa.java create mode 100644 server/odc-core/src/main/java/com/oceanbase/odc/core/dfa/DfaStateTransfer.java create mode 100644 server/odc-core/src/test/java/com/oceanbase/odc/core/dfa/DfaTest.java create mode 100644 server/odc-core/src/test/java/com/oceanbase/odc/core/dfa/K8sPodStatusDfa.java create mode 100644 server/odc-core/src/test/java/com/oceanbase/odc/core/dfa/K8sPodStatusDfaTransfer.java diff --git a/server/odc-core/src/main/java/com/oceanbase/odc/core/dfa/AbstractDfa.java b/server/odc-core/src/main/java/com/oceanbase/odc/core/dfa/AbstractDfa.java new file mode 100644 index 0000000000..e2819e7a7e --- /dev/null +++ b/server/odc-core/src/main/java/com/oceanbase/odc/core/dfa/AbstractDfa.java @@ -0,0 +1,69 @@ +/* + * Copyright (c) 2023 OceanBase. + * + * 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.oceanbase.odc.core.dfa; + +import java.util.List; +import java.util.stream.Collectors; + +import org.apache.commons.collections4.CollectionUtils; + +import lombok.Getter; +import lombok.NonNull; +import lombok.Setter; + +/** + * {@link AbstractDfa} + * + * @author yh263208 + * @date 2024-09-04 20:21 + * @since ODC_release_4.3.2 + */ +public abstract class AbstractDfa { + + @Setter + @Getter + private STATE currentState; + private final List> dfaStateTransfers; + + public AbstractDfa(@NonNull List> dfaStateTransfers) { + this.dfaStateTransfers = dfaStateTransfers; + } + + public AbstractDfa next(INPUT input) throws Exception { + if (this.currentState == null) { + throw new IllegalStateException("Current state is not set"); + } + List> transfers = this.dfaStateTransfers.stream() + .filter(t -> t.matchesState(this.currentState)).collect(Collectors.toList()); + if (CollectionUtils.isEmpty(transfers)) { + throw new IllegalStateException("State " + this.currentState + " is the final state"); + } + transfers = transfers.stream().filter(t -> t.matchesInput(input)).collect(Collectors.toList()); + if (CollectionUtils.isEmpty(transfers)) { + throw new IllegalStateException("Unknown input " + input + " for state " + this.currentState); + } else if (transfers.size() != 1) { + throw new IllegalStateException("More than one routes for state " + + this.currentState + " and input " + input); + } + STATE nextState = transfers.get(0).next(); + onStateTransfer(currentState, nextState, input); + this.currentState = nextState; + return this; + } + + protected abstract void onStateTransfer(STATE currentState, STATE nextState, INPUT input) throws Exception; + +} diff --git a/server/odc-core/src/main/java/com/oceanbase/odc/core/dfa/DfaStateTransfer.java b/server/odc-core/src/main/java/com/oceanbase/odc/core/dfa/DfaStateTransfer.java new file mode 100644 index 0000000000..f9a7d29a7e --- /dev/null +++ b/server/odc-core/src/main/java/com/oceanbase/odc/core/dfa/DfaStateTransfer.java @@ -0,0 +1,33 @@ +/* + * Copyright (c) 2023 OceanBase. + * + * 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.oceanbase.odc.core.dfa; + +/** + * {@link DfaStateTransfer} + * + * @author yh263208 + * @date 2024-09-04 20:32 + * @since ODC_release_4.3.2 + */ +public interface DfaStateTransfer { + + STATE next(); + + boolean matchesState(STATE state); + + boolean matchesInput(INPUT input); + +} diff --git a/server/odc-core/src/test/java/com/oceanbase/odc/core/dfa/DfaTest.java b/server/odc-core/src/test/java/com/oceanbase/odc/core/dfa/DfaTest.java new file mode 100644 index 0000000000..8a9a95f22c --- /dev/null +++ b/server/odc-core/src/test/java/com/oceanbase/odc/core/dfa/DfaTest.java @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2023 OceanBase. + * + * 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.oceanbase.odc.core.dfa; + +import java.util.Arrays; + +import org.junit.Assert; +import org.junit.Test; + +/** + * Test cases for {@link AbstractDfa} + * + * @author yh263208 + * @date 2024-09-04 21:44 + * @since ODC_release_4.3.2 + */ +public class DfaTest { + + private static final String FIND_MACHINE = "Find Machine"; + private static final String POD_CREATED_SUCCEED = "Pod Created Succeed"; + private static final String IMG_PULL_ERR = "Image pull error"; + private static final String POD_DELETE = "Pod is deleting"; + private static final String POD_DELETED = "Pod is deleted"; + + @Test + public void next_stateExistsRightEvent_nextStateSucceed() throws Exception { + AbstractDfa fsm = buildFsm(); + fsm.setCurrentState("Pending"); + fsm.next(FIND_MACHINE); + Assert.assertEquals("Creating", fsm.getCurrentState()); + } + + @Test(expected = IllegalStateException.class) + public void next_illegalState_expThrown() throws Exception { + AbstractDfa fsm = buildFsm(); + fsm.setCurrentState("Abc"); + fsm.next(FIND_MACHINE); + } + + @Test + public void next_reachFinalState_expThrown() throws Exception { + AbstractDfa fsm = buildFsm(); + fsm.setCurrentState("Pending"); + fsm.next(FIND_MACHINE) + .next(POD_CREATED_SUCCEED) + .next(POD_DELETE) + .next(POD_DELETED); + } + + private AbstractDfa buildFsm() { + return new K8sPodStatusDfa(Arrays.asList( + new K8sPodStatusDfaTransfer("Pending", "Creating", FIND_MACHINE), + new K8sPodStatusDfaTransfer("Creating", "Running", POD_CREATED_SUCCEED), + new K8sPodStatusDfaTransfer("Creating", "ImgBackOff", IMG_PULL_ERR), + new K8sPodStatusDfaTransfer("Running", "Deleting", POD_DELETE), + new K8sPodStatusDfaTransfer("Deleting", "Deleted", POD_DELETED))); + } + +} diff --git a/server/odc-core/src/test/java/com/oceanbase/odc/core/dfa/K8sPodStatusDfa.java b/server/odc-core/src/test/java/com/oceanbase/odc/core/dfa/K8sPodStatusDfa.java new file mode 100644 index 0000000000..b7c2307e8c --- /dev/null +++ b/server/odc-core/src/test/java/com/oceanbase/odc/core/dfa/K8sPodStatusDfa.java @@ -0,0 +1,35 @@ +/* + * Copyright (c) 2023 OceanBase. + * + * 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.oceanbase.odc.core.dfa; + +import java.util.List; + +import lombok.NonNull; +import lombok.extern.slf4j.Slf4j; + +@Slf4j +public class K8sPodStatusDfa extends AbstractDfa { + + public K8sPodStatusDfa(@NonNull List> dfaStateTransfers) { + super(dfaStateTransfers); + } + + @Override + protected void onStateTransfer(String currentState, String nextState, String input) throws Exception { + log.info("Transfer state succeed, currentState={}, nextState={}, event={}", currentState, nextState, input); + } + +} diff --git a/server/odc-core/src/test/java/com/oceanbase/odc/core/dfa/K8sPodStatusDfaTransfer.java b/server/odc-core/src/test/java/com/oceanbase/odc/core/dfa/K8sPodStatusDfaTransfer.java new file mode 100644 index 0000000000..4cf99da31e --- /dev/null +++ b/server/odc-core/src/test/java/com/oceanbase/odc/core/dfa/K8sPodStatusDfaTransfer.java @@ -0,0 +1,45 @@ +/* + * Copyright (c) 2023 OceanBase. + * + * 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.oceanbase.odc.core.dfa; + +public class K8sPodStatusDfaTransfer implements DfaStateTransfer { + + private final String targetState; + private final String nextState; + private final String targetEvent; + + public K8sPodStatusDfaTransfer(String targetState, String nextState, String targetEvent) { + this.targetState = targetState; + this.nextState = nextState; + this.targetEvent = targetEvent; + } + + @Override + public String next() { + return this.nextState; + } + + @Override + public boolean matchesState(String s) { + return this.targetState.equals(s); + } + + @Override + public boolean matchesInput(String s) { + return this.targetEvent.equals(s); + } + +} From 624748c100bb336d5df482ec96dc49467b5b6b6f Mon Sep 17 00:00:00 2001 From: Ang <43255684+ungreat@users.noreply.github.com> Date: Fri, 6 Sep 2024 15:44:41 +0800 Subject: [PATCH 2/2] fix(web): add server restart alarm (#3296) --- .../java/com/oceanbase/odc/core/alarm/AlarmEventNames.java | 1 + .../src/main/java/com/oceanbase/odc/server/OdcServer.java | 5 +++++ 2 files changed, 6 insertions(+) diff --git a/server/odc-core/src/main/java/com/oceanbase/odc/core/alarm/AlarmEventNames.java b/server/odc-core/src/main/java/com/oceanbase/odc/core/alarm/AlarmEventNames.java index 9086b00124..a488e4aa43 100644 --- a/server/odc-core/src/main/java/com/oceanbase/odc/core/alarm/AlarmEventNames.java +++ b/server/odc-core/src/main/java/com/oceanbase/odc/core/alarm/AlarmEventNames.java @@ -26,6 +26,7 @@ private AlarmEventNames() {} public static final String SYSTEM_CONFIG_CHANGED = "SYSTEM_CONFIG_CHANGED"; public static final String REST_API_CALL_FAILED = "REST_API_CALL_FAILED"; public static final String STATEFUL_ROUTE_NOT_HEALTHY = "STATEFUL_ROUTE_NOT_HEALTHY"; + public static final String SERVER_RESTART = "SERVER_RESTART"; /** * warn diff --git a/server/odc-server/src/main/java/com/oceanbase/odc/server/OdcServer.java b/server/odc-server/src/main/java/com/oceanbase/odc/server/OdcServer.java index 76f28c4e89..c82bc84fdb 100644 --- a/server/odc-server/src/main/java/com/oceanbase/odc/server/OdcServer.java +++ b/server/odc-server/src/main/java/com/oceanbase/odc/server/OdcServer.java @@ -15,6 +15,9 @@ */ package com.oceanbase.odc.server; +import static com.oceanbase.odc.core.alarm.AlarmEventNames.SERVER_RESTART; + +import java.time.LocalDateTime; import java.util.Map; import java.util.Objects; import java.util.Properties; @@ -39,6 +42,7 @@ import com.oceanbase.odc.common.json.JsonUtils; import com.oceanbase.odc.common.security.SensitiveDataUtils; import com.oceanbase.odc.common.util.SystemUtils; +import com.oceanbase.odc.core.alarm.AlarmUtils; import com.oceanbase.odc.core.authority.interceptor.MethodAuthorizedPostProcessor; import com.oceanbase.odc.migrate.AbstractMetaDBMigrate; import com.oceanbase.odc.service.config.SystemConfigBootstrap; @@ -83,6 +87,7 @@ public static void main(String[] args) { log.info("Task executor exit."); return; } + AlarmUtils.alarm(SERVER_RESTART, LocalDateTime.now().toString()); initEnv(); System.setProperty("spring.cloud.bootstrap.enabled", "true"); PluginSpringApplication.run(OdcServer.class, args);