2 * Copyright 2008-2014 LinkedIn, Inc
4 * Licensed under the Apache License, Version 2.0 (the "License"); you may not
5 * use this file except in compliance with the License. You may obtain a copy of
8 * http://www.apache.org/licenses/LICENSE-2.0
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
12 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
13 * License for the specific language governing permissions and limitations under
17 package voldemort
.tools
.admin
;
19 import java
.io
.BufferedReader
;
21 import java
.io
.IOException
;
22 import java
.io
.InputStreamReader
;
23 import java
.util
.ArrayList
;
24 import java
.util
.Collection
;
25 import java
.util
.HashMap
;
26 import java
.util
.Iterator
;
27 import java
.util
.List
;
31 import voldemort
.VoldemortException
;
32 import voldemort
.client
.ClientConfig
;
33 import voldemort
.client
.protocol
.admin
.AdminClient
;
34 import voldemort
.client
.protocol
.admin
.AdminClientConfig
;
35 import voldemort
.cluster
.Node
;
36 import voldemort
.store
.StoreDefinition
;
37 import voldemort
.store
.metadata
.MetadataStore
;
38 import voldemort
.store
.metadata
.MetadataStore
.VoldemortState
;
39 import voldemort
.store
.quota
.QuotaUtils
;
40 import voldemort
.store
.system
.SystemStoreConstants
;
41 import voldemort
.utils
.Utils
;
42 import voldemort
.versioning
.Versioned
;
44 import com
.google
.common
.collect
.Lists
;
45 import com
.google
.common
.collect
.Maps
;
48 * Utility class for AdminCommand
51 public class AdminUtils
{
53 private static final String QUOTATYPE_ALL
= "all";
56 * Utility function that copies a string array except for the first element
58 * @param arr Original array of strings
59 * @return Copied array of strings
61 public static String
[] copyArrayCutFirst(String
[] arr
) {
63 String
[] arrCopy
= new String
[arr
.length
- 1];
64 System
.arraycopy(arr
, 1, arrCopy
, 0, arrCopy
.length
);
72 * Utility function that copies a string array and add another string to
75 * @param arr Original array of strings
77 * @return Copied array of strings
79 public static String
[] copyArrayAddFirst(String
[] arr
, String add
) {
80 String
[] arrCopy
= new String
[arr
.length
+ 1];
82 System
.arraycopy(arr
, 0, arrCopy
, 1, arr
.length
);
87 * Utility function that pauses and asks for confirmation on dangerous
90 * @param confirm User has already confirmed in command-line input
91 * @param opDesc Description of the dangerous operation
93 * @return True if user confirms the operation in either command-line input
97 public static Boolean
askConfirm(Boolean confirm
, String opDesc
) throws IOException
{
99 System
.out
.println("Confirmed " + opDesc
+ " in command-line.");
102 System
.out
.println("Are you sure you want to " + opDesc
+ "? (yes/no)");
103 BufferedReader buffer
= new BufferedReader(new InputStreamReader(System
.in
));
104 String text
= buffer
.readLine();
105 return text
.equals("yes");
110 * Utility function that gives list of values from list of value-pair
113 * @param valueList List of value-pair strings
114 * @param delim Delimiter that separates the value pair
115 * @returns The list of values; empty if no value-pair is present, The even
116 * elements are the first ones of the value pair, and the odd
117 * elements are the second ones. For example, if the list of
118 * value-pair is ["cluster.xml=file1", "stores.xml=file2"], and the
119 * pair delimiter is '=', we will then have the list of values in
120 * return: ["cluster.xml", "file1", "stores.xml", "file2"].
122 public static List
<String
> getValueList(List
<String
> valuePairs
, String delim
) {
123 List
<String
> valueList
= Lists
.newArrayList();
124 for(String valuePair
: valuePairs
) {
125 String
[] value
= valuePair
.split(delim
, 2);
126 if(value
.length
!= 2)
127 throw new VoldemortException("Invalid argument pair: " + value
);
128 valueList
.add(value
[0]);
129 valueList
.add(value
[1]);
135 * Utility function that converts a list to a map.
137 * @param list The list in which even elements are keys and odd elements are
139 * @rturn The map container that maps even elements to odd elements, e.g.
142 public static <V
> Map
<V
, V
> convertListToMap(List
<V
> list
) {
143 Map
<V
, V
> map
= new HashMap
<V
, V
>();
144 if(list
.size() % 2 != 0)
145 throw new VoldemortException("Failed to convert list to map.");
146 for(int i
= 0; i
< list
.size(); i
+= 2) {
147 map
.put(list
.get(i
), list
.get(i
+ 1));
153 * Utility function that constructs AdminClient.
155 * @param url URL pointing to the bootstrap node
156 * @return Newly constructed AdminClient
158 public static AdminClient
getAdminClient(String url
) {
159 return new AdminClient(url
, new AdminClientConfig(), new ClientConfig());
163 * Utility function that fetches nodes.
165 * @param adminClient An instance of AdminClient points to given cluster
166 * @param nodeIds List of node IDs parsed from command-line input
167 * @param allNodes Tells if all nodes are selected
168 * @return Collection of node objects selected by user
170 public static Collection
<Node
> getNodes(AdminClient adminClient
,
171 List
<Integer
> nodeIds
,
173 Collection
<Node
> nodes
= null;
175 nodes
= adminClient
.getAdminClientCluster().getNodes();
177 nodes
= new ArrayList
<Node
>();
178 for(Integer nodeId
: nodeIds
) {
179 nodes
.add(adminClient
.getAdminClientCluster().getNodeById(nodeId
));
182 if(nodes
.size() == 0) {
183 throw new VoldemortException("The cluster doesn't have any node.");
189 * Utility function that fetches stores on a node.
191 * @param adminClient An instance of AdminClient points to given cluster
192 * @param node Node to fetch stores from
193 * @param storeNames Stores read from command-line input
194 * @param allStores Tells if all stores are selected
195 * @return List of store names selected by user
197 public static List
<String
> getUserStoresOnNode(AdminClient adminClient
,
199 List
<String
> storeNames
,
201 List
<StoreDefinition
> storeDefinitionList
= adminClient
.metadataMgmtOps
.getRemoteStoreDefList(node
.getId())
204 storeNames
= Lists
.newArrayList();
205 for(StoreDefinition storeDefinition
: storeDefinitionList
) {
206 storeNames
.add(storeDefinition
.getName());
209 for(String storeName
: storeNames
) {
210 if(!storeDefinitionList
.contains(storeName
))
211 Utils
.croak("Store " + storeName
+ " does not exist!");
218 * Utility function that fetches partitions.
220 * @param adminClient An instance of AdminClient points to given cluster
221 * @param partIds List of partitions read from command-line input
222 * @param allParts Tells if all partitions are selected
223 * @return List of partitions selected by user
225 public static List
<Integer
> getPartitions(AdminClient adminClient
,
226 List
<Integer
> partIds
,
229 partIds
= Lists
.newArrayList();
230 for(Node node
: adminClient
.getAdminClientCluster().getNodes()) {
231 partIds
.addAll(node
.getPartitionIds());
238 * Utility function that fetches quota types.
240 * @param nodeIds List of IDs of nodes parsed from command-line input
241 * @param allNodes Tells if all nodes are selected
242 * @return Collection of node objects selected by user
244 public static List
<String
> getQuotaTypes(List
<String
> quotaTypes
) {
245 if(quotaTypes
.size() < 1) {
246 throw new VoldemortException("Quota type not specified.");
248 Set
<String
> validQuotaTypes
= QuotaUtils
.validQuotaTypes();
249 if(quotaTypes
.size() == 1 && quotaTypes
.get(0).equals(AdminUtils
.QUOTATYPE_ALL
)) {
250 Iterator
<String
> iter
= validQuotaTypes
.iterator();
251 quotaTypes
= Lists
.newArrayList();
252 while(iter
.hasNext()) {
253 quotaTypes
.add(iter
.next());
256 for(String quotaType
: quotaTypes
) {
257 if(!validQuotaTypes
.contains(quotaType
)) {
258 Utils
.croak("Specify a valid quota type from :" + validQuotaTypes
);
266 * Utility function that creates directory.
268 * @param dir Directory path
269 * @return File object of directory.
271 public static File
createDir(String dir
) {
273 File directory
= null;
275 directory
= new File(dir
);
276 if(!(directory
.exists() || directory
.mkdir())) {
277 Utils
.croak("Can't find or create directory " + dir
);
284 * Utility function that fetches system store definitions
286 * @return The map container that maps store names to store definitions
288 public static Map
<String
, StoreDefinition
> getSystemStoreDefs() {
289 Map
<String
, StoreDefinition
> sysStoreDefMap
= Maps
.newHashMap();
290 List
<StoreDefinition
> storesDefs
= SystemStoreConstants
.getAllSystemStoreDefs();
291 for(StoreDefinition def
: storesDefs
) {
292 sysStoreDefMap
.put(def
.getName(), def
);
294 return sysStoreDefMap
;
298 * Utility function that fetches user defined store definitions
300 * @param adminClient An instance of AdminClient points to given cluster
301 * @param node Store definitions to fetch from
302 * @return The map container that maps store names to store definitions
304 public static Map
<String
, StoreDefinition
> getUserStoreDefs(AdminClient adminClient
, Node node
) {
305 List
<StoreDefinition
> storeDefinitionList
= adminClient
.metadataMgmtOps
.getRemoteStoreDefList(node
.getId())
307 Map
<String
, StoreDefinition
> storeDefinitionMap
= Maps
.newHashMap();
308 for(StoreDefinition storeDefinition
: storeDefinitionList
) {
309 storeDefinitionMap
.put(storeDefinition
.getName(), storeDefinition
);
311 return storeDefinitionMap
;
315 * Utility function that checks the execution state of the server by
316 * checking the state of {@link VoldemortState} <br>
318 * This function checks if all nodes of the cluster are in normal state (
319 * {@link VoldemortState#NORMAL_SERVER}).
321 * @param adminClient An instance of AdminClient points to given cluster
322 * @throws VoldemortException if any node is not in normal state
324 public static void checkServerInNormalState(AdminClient adminClient
) {
325 checkServerInNormalState(adminClient
, adminClient
.getAdminClientCluster().getNodes());
329 * Utility function that checks the execution state of the server by
330 * checking the state of {@link VoldemortState} <br>
332 * This function checks if a node is in normal state (
333 * {@link VoldemortState#NORMAL_SERVER}).
335 * @param adminClient An instance of AdminClient points to given cluster
336 * @param node Node to be checked
337 * @throws VoldemortException if any node is not in normal state
339 public static void checkServerInNormalState(AdminClient adminClient
, Node node
) {
340 List
<Node
> nodes
= Lists
.newArrayList();
342 checkServerInNormalState(adminClient
, nodes
);
346 * Utility function that checks the execution state of the server by
347 * checking the state of {@link VoldemortState} <br>
349 * This function checks if the nodes are in normal state (
350 * {@link VoldemortState#NORMAL_SERVER}).
352 * @param adminClient An instance of AdminClient points to given cluster
353 * @param nodes List of nodes to be checked
354 * @throws VoldemortException if any node is not in normal state
356 public static void checkServerInNormalState(AdminClient adminClient
, Collection
<Node
> nodes
) {
357 for(Node node
: nodes
) {
358 Versioned
<String
> versioned
= adminClient
.metadataMgmtOps
.getRemoteMetadata(node
.getId(),
359 MetadataStore
.SERVER_STATE_KEY
);
360 VoldemortState state
= VoldemortState
.valueOf(versioned
.getValue());
361 if(!state
.equals(VoldemortState
.NORMAL_SERVER
)) {
362 throw new VoldemortException("Cannot execute admin operation: " + node
.getId()
363 + " (" + node
.getHost()
364 + ") is not in normal state, but in "
365 + versioned
.getValue());