cmccabe commented on code in PR #16669: URL: https://github.com/apache/kafka/pull/16669#discussion_r1700917002
########## raft/src/main/java/org/apache/kafka/raft/DynamicVoter.java: ########## @@ -0,0 +1,188 @@ +/* + * 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.kafka.raft; + +import org.apache.kafka.common.Uuid; +import org.apache.kafka.common.feature.SupportedVersionRange; +import org.apache.kafka.common.network.ListenerName; +import org.apache.kafka.raft.internals.ReplicaKey; +import org.apache.kafka.raft.internals.VoterSet; + +import java.net.InetSocketAddress; +import java.util.Collections; +import java.util.Objects; + +/** + * The textual representation of a KIP-853 voter. + * + * Since this is used in command-line tools, format changes to the parsing logic require a KIP, + * and should be backwards compatible. + */ +public final class DynamicVoter { + private final Uuid directoryId; + private final int nodeId; + private final String host; + private final int port; + + /** + * Create a DynamicVoter object by parsing an input string. + * + * @param input The input string. + * + * @return The DynamicVoter object. + * + * @throws IllegalArgumentException If parsing fails. + */ + public static DynamicVoter parse(String input) { + input = input.trim(); + int atIndex = input.indexOf("@"); + if (atIndex < 0) { + throw new IllegalArgumentException("No @ found in dynamic voter string."); + } + if (atIndex == 0) { + throw new IllegalArgumentException("Invalid @ at beginning of dynamic voter string."); + } + String idString = input.substring(0, atIndex); + int nodeId; + try { + nodeId = Integer.parseInt(idString); + } catch (NumberFormatException e) { + throw new IllegalArgumentException("Failed to parse node id in dynamic voter string.", e); + } + if (nodeId < 0) { + throw new IllegalArgumentException("Invalid negative node id " + nodeId + + " in dynamic voter string."); + } + input = input.substring(atIndex + 1); + if (input.isEmpty()) { + throw new IllegalArgumentException("No hostname found after node id."); + } + String host; + if (input.startsWith("[")) { + int endBracketIndex = input.indexOf("]"); + if (endBracketIndex < 0) { + throw new IllegalArgumentException("Hostname began with left bracket, but no right " + + "bracket was found."); + } + host = input.substring(1, endBracketIndex); + input = input.substring(endBracketIndex + 1); + } else { + int endColonIndex = input.indexOf(":"); + if (endColonIndex < 0) { + throw new IllegalArgumentException("No colon following hostname could be found."); + } + host = input.substring(0, endColonIndex); + input = input.substring(endColonIndex); + } + if (!input.startsWith(":")) { + throw new IllegalArgumentException("Port section must start with a colon."); + } + input = input.substring(1); + int endColonIndex = input.indexOf(":"); + if (endColonIndex < 0) { + throw new IllegalArgumentException("No colon following port could be found."); + } + String portString = input.substring(0, endColonIndex); + int port; + try { + port = Integer.parseInt(portString); + } catch (NumberFormatException e) { + throw new IllegalArgumentException("Failed to parse port in dynamic voter string.", e); + } + if (port < 0 || port > 65535) { + throw new IllegalArgumentException("Invalid port " + port + " in dynamic voter string."); + } + String directoryIdString = input.substring(endColonIndex + 1); + Uuid directoryId; + try { + directoryId = Uuid.fromString(directoryIdString); + } catch (IllegalArgumentException e) { + throw new IllegalArgumentException("Failed to parse directory ID in dynamic voter string.", e); + } + return new DynamicVoter(directoryId, nodeId, host, port); + } + + /** + * Create a new KIP-853 voter. + * + * @param directoryId The directory ID. + * @param nodeId The voter ID. + * @param host The voter hostname or IP address. + * @param port The voter port. + */ + public DynamicVoter( + Uuid directoryId, + int nodeId, + String host, + int port + ) { + this.directoryId = directoryId; + this.nodeId = nodeId; + this.host = host; + this.port = port; + } + + public Uuid directoryId() { + return directoryId; + } + + public int nodeId() { + return nodeId; + } + + public String host() { + return host; + } + + public int port() { + return port; + } + + public VoterSet.VoterNode toVoterNode(String controllerListenerName) { + ReplicaKey voterKey = ReplicaKey.of(nodeId, directoryId); + Endpoints listeners = Endpoints.fromInetSocketAddresses(Collections.singletonMap( + new ListenerName(controllerListenerName), + new InetSocketAddress(host, port))); + SupportedVersionRange supportedKRaftVersion = + new SupportedVersionRange((short) 0, (short) 1); Review Comment: we can change it at that point then -- This is an automated message from the Apache Git Service. To respond to the message, please log on to GitHub and use the URL above to go to the specific comment. To unsubscribe, e-mail: [email protected] For queries about this service, please contact Infrastructure at: [email protected]
