nvharikrishna commented on code in PR #4149:
URL: https://github.com/apache/cassandra/pull/4149#discussion_r2230036164


##########
src/java/org/apache/cassandra/tools/nodetool/CMSAdmin.java:
##########
@@ -269,4 +271,76 @@ public void execute(NodeProbe probe)
             probe.getCMSOperationsProxy().resumeDropAccordTable(tableId);
         }
     }
+
+    @Command(name = "dumpclustermetadata", description = "Dumps Cluster 
Metadata into a file")

Review Comment:
   What abut just `dump` ? 



##########
src/java/org/apache/cassandra/tools/CMSOfflineTool.java:
##########
@@ -0,0 +1,434 @@
+/*
+ * 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.cassandra.tools;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import io.airlift.airline.Cli;
+import io.airlift.airline.Command;
+import io.airlift.airline.Help;
+import io.airlift.airline.Option;
+import io.airlift.airline.OptionType;
+import io.airlift.airline.ParseException;
+import org.apache.cassandra.config.DatabaseDescriptor;
+import org.apache.cassandra.dht.IPartitioner;
+import org.apache.cassandra.dht.Range;
+import org.apache.cassandra.dht.Token;
+import org.apache.cassandra.io.util.File;
+import org.apache.cassandra.io.util.FileInputStreamPlus;
+import org.apache.cassandra.io.util.FileOutputStreamPlus;
+import org.apache.cassandra.locator.InetAddressAndPort;
+import org.apache.cassandra.locator.MetaStrategy;
+import org.apache.cassandra.locator.Replica;
+import org.apache.cassandra.schema.KeyspaceMetadata;
+import org.apache.cassandra.schema.ReplicationParams;
+import org.apache.cassandra.tcm.ClusterMetadata;
+import org.apache.cassandra.tcm.ClusterMetadataService;
+import org.apache.cassandra.tcm.membership.Directory;
+import org.apache.cassandra.tcm.membership.Location;
+import org.apache.cassandra.tcm.membership.NodeAddresses;
+import org.apache.cassandra.tcm.membership.NodeId;
+import org.apache.cassandra.tcm.membership.NodeVersion;
+import org.apache.cassandra.tcm.ownership.DataPlacement;
+import org.apache.cassandra.tcm.ownership.ReplicaGroups;
+import org.apache.cassandra.tcm.serialization.VerboseMetadataSerializer;
+import org.apache.cassandra.tcm.serialization.Version;
+import org.apache.cassandra.utils.FBUtilities;
+
+import static com.google.common.base.Throwables.getStackTraceAsString;
+import static 
org.apache.cassandra.tcm.transformations.cms.PrepareCMSReconfiguration.needsReconfiguration;
+
+/**
+ * Offline tool to print or update cluster metadata dump.
+ */
+public class CMSOfflineTool
+{
+
+    private static final String TOOL_NAME = "cmsofflinetool";
+    private final Output output;
+
+    public CMSOfflineTool(Output output)
+    {
+        this.output = output;
+    }
+
+    public static void main(String[] args) throws IOException
+    {
+        //noinspection UseOfSystemOutOrSystemErr
+        System.exit(new CMSOfflineTool(new Output(System.out, 
System.err)).execute(args));
+    }
+
+    public int execute(String... args)
+    {
+
+        Cli.CliBuilder<ClusterMetadataToolRunnable> builder = 
Cli.builder(TOOL_NAME);
+
+        List<Class<? extends ClusterMetadataToolRunnable>> commands = new 
ArrayList<>()
+        {{
+            add(ClusterMetadataToolHelp.class);
+            add(AddToCMS.class);
+            add(AssignTokens.class);
+            add(Describe.class);
+            add(ForceJoin.class);
+            add(ForgetNode.class);
+            add(PrintDataPlacements.class);
+            add(PrintDirectoryCmd.class);
+        }};
+
+        builder.withDescription("Offline tool to print or update cluster 
metadata dump")
+               .withDefaultCommand(ClusterMetadataToolHelp.class)
+               .withCommands(commands);
+
+        Cli<ClusterMetadataToolRunnable> parser = builder.build();
+        int status = 0;
+        try
+        {
+            ClusterMetadataToolRunnable parse = parser.parse(args);
+            parse.run(output);
+        }
+        catch (ParseException pe)
+        {
+            status = 1;
+            badUse(pe);
+        }
+        catch (Exception e)
+        {
+            status = 2;
+            err(e);
+        }
+        return status;
+    }
+
+
+    private void badUse(Exception e)
+    {
+        output.err.println(TOOL_NAME + ": " + e.getMessage());
+        output.err.printf("See '%s help' or '%s help <command>'.%n", 
TOOL_NAME, TOOL_NAME);
+    }
+
+    private void err(Exception e)
+    {
+        output.err.println("error: " + e.getMessage());
+        output.err.println("-- StackTrace --");
+        output.err.println(getStackTraceAsString(e));
+    }
+
+
+    interface ClusterMetadataToolRunnable
+    {
+        void run(Output output) throws IOException;
+    }
+
+    public static abstract class ClusterMetadataToolCmd implements 
ClusterMetadataToolRunnable
+    {
+        @Option(type = OptionType.COMMAND, name = { "-f", "--file" }, 
description = "Cluster metadata dump file path", required = true)
+        protected String metadataDumpPath;
+
+        @Option(type = OptionType.COMMAND, name = { "-sv", 
"--serialization-version" }, description = "Serialization version to use")
+        private Version serializationVersion;
+
+
+        public ClusterMetadata parseClusterMetadata() throws IOException
+        {
+            File file = new File(metadataDumpPath);
+            if (!file.exists())
+            {
+                throw new IllegalArgumentException("Cluster metadata dump file 
" + metadataDumpPath + " does not exist");
+            }
+
+            Version serializationVersion = 
NodeVersion.CURRENT.serializationVersion();
+            // Make sure the partitioner we use to manipulate the metadata is 
the same one used to generate it
+            IPartitioner partitioner;
+            try (FileInputStreamPlus fisp = new 
FileInputStreamPlus(metadataDumpPath))
+            {
+                // skip over the prefix specifying the metadata version
+                fisp.readUnsignedVInt32();
+                partitioner = ClusterMetadata.Serializer.getPartitioner(fisp, 
serializationVersion);
+            }
+            DatabaseDescriptor.toolInitialization();
+            DatabaseDescriptor.setPartitionerUnsafe(partitioner);
+            ClusterMetadataService.initializeForTools(false);
+
+            return 
ClusterMetadataService.deserializeClusterMetadata(metadataDumpPath);
+        }
+
+        public void writeMetadata(Output output, ClusterMetadata metadata, 
String outputFilePath) throws IOException
+        {
+            Path p = outputFilePath != null ?
+                     Files.createFile(Path.of(outputFilePath)) :
+                     Files.createTempFile("clustermetadata", "dump");
+
+
+            try (FileOutputStreamPlus out = new FileOutputStreamPlus(p))
+            {
+                VerboseMetadataSerializer.serialize(ClusterMetadata.serializer,
+                                                    metadata,
+                                                    out,
+                                                    getSerializationVersion());
+                output.out.println("Updated cluster metadata written to file " 
+ p.toAbsolutePath());
+            }
+        }
+
+        Version getSerializationVersion()
+        {
+            return serializationVersion != null ? serializationVersion : 
NodeVersion.CURRENT.serializationVersion();
+        }
+    }
+
+    public static class ClusterMetadataToolHelp extends Help implements 
ClusterMetadataToolRunnable
+    {
+
+        @Override
+        public void run(Output output)
+        {
+            run();
+        }
+    }
+
+    @Command(name = "addtocms", description = "Makes a node as CMS member")
+    public static class AddToCMS extends ClusterMetadataToolCmd
+    {
+        @Option(name = { "-ip", "--ip-address" }, description = "IP address of 
node to make CMS", required = true)
+        private String ipAddress;
+
+        @Option(type = OptionType.COMMAND, name = { "-o", "--output-file" }, 
description = "Ouput file path for storing the updated Cluster Metadata")
+        private String outputFilePath;
+
+        @Override
+        public void run(Output output) throws IOException
+        {
+            ClusterMetadata metadata = parseClusterMetadata();
+            InetAddressAndPort nodeAddress = 
InetAddressAndPort.getByNameUnchecked(ipAddress);
+            metadata = makeCMS(metadata, nodeAddress);
+            writeMetadata(output, metadata, outputFilePath);
+        }
+
+        ClusterMetadata makeCMS(ClusterMetadata metadata, InetAddressAndPort 
endpoint)
+        {
+            ReplicationParams metaParams = ReplicationParams.meta(metadata);
+            DataPlacement.Builder builder = 
metadata.placements.get(metaParams).unbuild();
+
+            Replica newCMS = MetaStrategy.replica(endpoint);
+            builder.withReadReplica(metadata.epoch, newCMS)
+                   .withWriteReplica(metadata.epoch, newCMS);
+            return 
metadata.transformer().with(metadata.placements.unbuild().with(metaParams,
+                                                                               
   builder.build())
+                                                                  .build())
+                           .build().metadata;
+        }
+    }
+
+    @Command(name = "assigntokens", description = "Assigns a token for given 
instance")
+    public static class AssignTokens extends ClusterMetadataToolCmd
+    {
+        @Option(name = { "-ip", "--ip-address" }, description = "IP address of 
endpoint. Port can be specified as well.", required = true)

Review Comment:
   Done



##########
src/java/org/apache/cassandra/tools/nodetool/CMSAdmin.java:
##########
@@ -269,4 +271,76 @@ public void execute(NodeProbe probe)
             probe.getCMSOperationsProxy().resumeDropAccordTable(tableId);
         }
     }
+
+    @Command(name = "dumpclustermetadata", description = "Dumps Cluster 
Metadata into a file")
+    public static class DumpClusterMetadata extends NodeTool.NodeToolCmd
+    {
+
+        @Option(title = "Epoch", name = { "-e", "--epoch" }, required = false,
+        description = "Epoch at which cluster metadata should be dumped")
+        private Long epoch;
+
+        @Option(title = "Transform Epoch", name = { "-te", "--transform-epoch" 
}, required = false,
+        description = "The epoch to which the cluster meta data should be 
transformed before dumping")

Review Comment:
   done



##########
src/java/org/apache/cassandra/tools/CMSOfflineTool.java:
##########
@@ -0,0 +1,434 @@
+/*
+ * 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.cassandra.tools;
+
+import java.io.IOException;
+import java.nio.file.Files;
+import java.nio.file.Path;
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Set;
+import java.util.stream.Collectors;
+
+import io.airlift.airline.Cli;
+import io.airlift.airline.Command;
+import io.airlift.airline.Help;
+import io.airlift.airline.Option;
+import io.airlift.airline.OptionType;
+import io.airlift.airline.ParseException;
+import org.apache.cassandra.config.DatabaseDescriptor;
+import org.apache.cassandra.dht.IPartitioner;
+import org.apache.cassandra.dht.Range;
+import org.apache.cassandra.dht.Token;
+import org.apache.cassandra.io.util.File;
+import org.apache.cassandra.io.util.FileInputStreamPlus;
+import org.apache.cassandra.io.util.FileOutputStreamPlus;
+import org.apache.cassandra.locator.InetAddressAndPort;
+import org.apache.cassandra.locator.MetaStrategy;
+import org.apache.cassandra.locator.Replica;
+import org.apache.cassandra.schema.KeyspaceMetadata;
+import org.apache.cassandra.schema.ReplicationParams;
+import org.apache.cassandra.tcm.ClusterMetadata;
+import org.apache.cassandra.tcm.ClusterMetadataService;
+import org.apache.cassandra.tcm.membership.Directory;
+import org.apache.cassandra.tcm.membership.Location;
+import org.apache.cassandra.tcm.membership.NodeAddresses;
+import org.apache.cassandra.tcm.membership.NodeId;
+import org.apache.cassandra.tcm.membership.NodeVersion;
+import org.apache.cassandra.tcm.ownership.DataPlacement;
+import org.apache.cassandra.tcm.ownership.ReplicaGroups;
+import org.apache.cassandra.tcm.serialization.VerboseMetadataSerializer;
+import org.apache.cassandra.tcm.serialization.Version;
+import org.apache.cassandra.utils.FBUtilities;
+
+import static com.google.common.base.Throwables.getStackTraceAsString;
+import static 
org.apache.cassandra.tcm.transformations.cms.PrepareCMSReconfiguration.needsReconfiguration;
+
+/**
+ * Offline tool to print or update cluster metadata dump.
+ */
+public class CMSOfflineTool
+{
+
+    private static final String TOOL_NAME = "cmsofflinetool";
+    private final Output output;
+
+    public CMSOfflineTool(Output output)
+    {
+        this.output = output;
+    }
+
+    public static void main(String[] args) throws IOException
+    {
+        //noinspection UseOfSystemOutOrSystemErr
+        System.exit(new CMSOfflineTool(new Output(System.out, 
System.err)).execute(args));
+    }
+
+    public int execute(String... args)
+    {
+

Review Comment:
   done



##########
src/java/org/apache/cassandra/tools/nodetool/CMSAdmin.java:
##########
@@ -269,4 +271,76 @@ public void execute(NodeProbe probe)
             probe.getCMSOperationsProxy().resumeDropAccordTable(tableId);
         }
     }
+
+    @Command(name = "dumpclustermetadata", description = "Dumps Cluster 
Metadata into a file")
+    public static class DumpClusterMetadata extends NodeTool.NodeToolCmd
+    {
+
+        @Option(title = "Epoch", name = { "-e", "--epoch" }, required = false,
+        description = "Epoch at which cluster metadata should be dumped")
+        private Long epoch;
+
+        @Option(title = "Transform Epoch", name = { "-te", "--transform-epoch" 
}, required = false,
+        description = "The epoch to which the cluster meta data should be 
transformed before dumping")
+        private Long transformEpoch;
+
+        @Option(title = "Searialization Version", name = { "-sv", 
"--serialization-version" }, required = false,
+        description = "Searialization Version")

Review Comment:
   done



##########
src/java/org/apache/cassandra/tools/nodetool/CMSAdmin.java:
##########
@@ -269,4 +271,76 @@ public void execute(NodeProbe probe)
             probe.getCMSOperationsProxy().resumeDropAccordTable(tableId);
         }
     }
+
+    @Command(name = "dumpclustermetadata", description = "Dumps Cluster 
Metadata into a file")
+    public static class DumpClusterMetadata extends NodeTool.NodeToolCmd
+    {
+
+        @Option(title = "Epoch", name = { "-e", "--epoch" }, required = false,
+        description = "Epoch at which cluster metadata should be dumped")
+        private Long epoch;
+
+        @Option(title = "Transform Epoch", name = { "-te", "--transform-epoch" 
}, required = false,
+        description = "The epoch to which the cluster meta data should be 
transformed before dumping")
+        private Long transformEpoch;
+
+        @Option(title = "Searialization Version", name = { "-sv", 
"--serialization-version" }, required = false,
+        description = "Searialization Version")
+        private Version version;
+
+        protected void execute(NodeProbe probe)
+        {
+            if (epoch == null && transformEpoch == null && version == null)
+            {
+                try
+                {
+                    String fileLocation = 
probe.getCMSOperationsProxy().dumpClusterMetadata();
+                    printCMSDumpLocation(probe, fileLocation);
+                }
+                catch (IOException e)
+                {
+                    throw new RuntimeException(e);
+                }
+            }
+            else if (epoch != null && transformEpoch != null && version != 
null)
+            {
+                try
+                {
+                    String fileLocation = 
probe.getCMSOperationsProxy().dumpClusterMetadata(epoch,
+                                                                               
             transformEpoch,
+                                                                               
             version.name());
+                    printCMSDumpLocation(probe, fileLocation);
+                }
+                catch (IOException e)
+                {
+                    throw new RuntimeException(e);
+                }
+            }
+            else
+            {
+                List<String> invalidArgs = new ArrayList<>(2);
+                if (null == epoch)
+                {

Review Comment:
   done



##########
src/java/org/apache/cassandra/tools/nodetool/CMSAdmin.java:
##########
@@ -269,4 +271,76 @@ public void execute(NodeProbe probe)
             probe.getCMSOperationsProxy().resumeDropAccordTable(tableId);
         }
     }
+
+    @Command(name = "dumpclustermetadata", description = "Dumps Cluster 
Metadata into a file")
+    public static class DumpClusterMetadata extends NodeTool.NodeToolCmd
+    {
+
+        @Option(title = "Epoch", name = { "-e", "--epoch" }, required = false,
+        description = "Epoch at which cluster metadata should be dumped")
+        private Long epoch;
+
+        @Option(title = "Transform Epoch", name = { "-te", "--transform-epoch" 
}, required = false,
+        description = "The epoch to which the cluster meta data should be 
transformed before dumping")
+        private Long transformEpoch;
+
+        @Option(title = "Searialization Version", name = { "-sv", 
"--serialization-version" }, required = false,

Review Comment:
   done



-- 
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: pr-unsubscr...@cassandra.apache.org

For queries about this service, please contact Infrastructure at:
us...@infra.apache.org


---------------------------------------------------------------------
To unsubscribe, e-mail: pr-unsubscr...@cassandra.apache.org
For additional commands, e-mail: pr-h...@cassandra.apache.org

Reply via email to