View Javadoc

1   /*
2    * Licensed to the Apache Software Foundation (ASF) under one or more
3    * contributor license agreements.  See the NOTICE file distributed with
4    * this work for additional information regarding copyright ownership.
5    * The ASF licenses this file to You under the Apache License, Version 2.0
6    * (the "License"); you may not use this file except in compliance with
7    * the License.  You may obtain a copy of the License at
8    *
9    *     http://www.apache.org/licenses/LICENSE-2.0
10   *
11   * Unless required by applicable law or agreed to in writing, software
12   * distributed under the License is distributed on an "AS IS" BASIS,
13   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14   * See the License for the specific language governing permissions and
15   * limitations under the License.
16   */
17  package org.apache.accumulo.core.util.shell.commands;
18  
19  import java.io.IOException;
20  import java.util.ArrayList;
21  import java.util.List;
22  import java.util.Map;
23  import java.util.Map.Entry;
24  import java.util.Set;
25  import java.util.TreeMap;
26  
27  import jline.ConsoleReader;
28  
29  import org.apache.accumulo.core.client.AccumuloException;
30  import org.apache.accumulo.core.client.AccumuloSecurityException;
31  import org.apache.accumulo.core.client.TableNotFoundException;
32  import org.apache.accumulo.core.conf.AccumuloConfiguration;
33  import org.apache.accumulo.core.conf.Property;
34  import org.apache.accumulo.core.security.ColumnVisibility;
35  import org.apache.accumulo.core.util.BadArgumentException;
36  import org.apache.accumulo.core.util.shell.Shell;
37  import org.apache.accumulo.core.util.shell.Shell.Command;
38  import org.apache.accumulo.core.util.shell.Shell.PrintFile;
39  import org.apache.accumulo.core.util.shell.Token;
40  import org.apache.commons.cli.CommandLine;
41  import org.apache.commons.cli.Option;
42  import org.apache.commons.cli.OptionGroup;
43  import org.apache.commons.cli.Options;
44  
45  public class ConfigCommand extends Command {
46    private Option tableOpt, deleteOpt, setOpt, filterOpt, disablePaginationOpt, outputFileOpt;
47    
48    private int COL1 = 8, COL2 = 7;
49    private ConsoleReader reader;
50    
51    @Override
52    public void registerCompletion(final Token root, final Map<Command.CompletionSet,Set<String>> completionSet) {
53      final Token cmd = new Token(getName());
54      final Token sub = new Token("-" + setOpt.getOpt());
55      for (Property p : Property.values()) {
56        if (!(p.getKey().endsWith(".")) && !p.isExperimental()) {
57          sub.addSubcommand(new Token(p.toString()));
58        }
59      }
60      cmd.addSubcommand(sub);
61      root.addSubcommand(cmd);
62    }
63    
64    public int execute(final String fullCommand, final CommandLine cl, final Shell shellState) throws AccumuloException, AccumuloSecurityException,
65        TableNotFoundException, IOException, ClassNotFoundException {
66      reader = shellState.getReader();
67      
68      final String tableName = cl.getOptionValue(tableOpt.getOpt());
69      if (tableName != null && !shellState.getConnector().tableOperations().exists(tableName)) {
70        throw new TableNotFoundException(null, tableName, null);
71      }
72      if (cl.hasOption(deleteOpt.getOpt())) {
73        // delete property from table
74        String property = cl.getOptionValue(deleteOpt.getOpt());
75        if (property.contains("=")) {
76          throw new BadArgumentException("Invalid '=' operator in delete operation.", fullCommand, fullCommand.indexOf('='));
77        }
78        if (tableName != null) {
79          if (!Property.isValidTablePropertyKey(property)) {
80            Shell.log.warn("Invalid per-table property : " + property + ", still removing from zookeeper if it's there.");
81          }
82          shellState.getConnector().tableOperations().removeProperty(tableName, property);
83          Shell.log.debug("Successfully deleted table configuration option.");
84        } else {
85          if (!Property.isValidZooPropertyKey(property)) {
86            Shell.log.warn("Invalid per-table property : " + property + ", still removing from zookeeper if it's there.");
87          }
88          shellState.getConnector().instanceOperations().removeProperty(property);
89          Shell.log.debug("Successfully deleted system configuration option");
90        }
91      } else if (cl.hasOption(setOpt.getOpt())) {
92        // set property on table
93        String property = cl.getOptionValue(setOpt.getOpt()), value = null;
94        if (!property.contains("=")) {
95          throw new BadArgumentException("Missing '=' operator in set operation.", fullCommand, fullCommand.indexOf(property));
96        }
97        final String pair[] = property.split("=", 2);
98        property = pair[0];
99        value = pair[1];
100       
101       if (tableName != null) {
102         if (!Property.isValidTablePropertyKey(property)) {
103           throw new BadArgumentException("Invalid per-table property.", fullCommand, fullCommand.indexOf(property));
104         }
105         if (property.equals(Property.TABLE_DEFAULT_SCANTIME_VISIBILITY.getKey())) {
106           new ColumnVisibility(value); // validate that it is a valid expression
107         }
108         shellState.getConnector().tableOperations().setProperty(tableName, property, value);
109         Shell.log.debug("Successfully set table configuration option.");
110       } else {
111         if (!Property.isValidZooPropertyKey(property)) {
112           throw new BadArgumentException("Property cannot be modified in zookeeper", fullCommand, fullCommand.indexOf(property));
113         }
114         shellState.getConnector().instanceOperations().setProperty(property, value);
115         Shell.log.debug("Successfully set system configuration option");
116       }
117     } else {
118       // display properties
119       final TreeMap<String,String> systemConfig = new TreeMap<String,String>();
120       systemConfig.putAll(shellState.getConnector().instanceOperations().getSystemConfiguration());
121       
122       final String outputFile = cl.getOptionValue(outputFileOpt.getOpt());
123       final PrintFile printFile = outputFile == null ? null : new PrintFile(outputFile);
124       
125       final TreeMap<String,String> siteConfig = new TreeMap<String,String>();
126       siteConfig.putAll(shellState.getConnector().instanceOperations().getSiteConfiguration());
127       
128       final TreeMap<String,String> defaults = new TreeMap<String,String>();
129       for (Entry<String,String> defaultEntry : AccumuloConfiguration.getDefaultConfiguration()) {
130         defaults.put(defaultEntry.getKey(), defaultEntry.getValue());
131       }
132       Iterable<Entry<String,String>> acuconf = shellState.getConnector().instanceOperations().getSystemConfiguration().entrySet();
133       if (tableName != null) {
134         acuconf = shellState.getConnector().tableOperations().getProperties(tableName);
135       }
136       final TreeMap<String,String> sortedConf = new TreeMap<String,String>();
137       for (Entry<String,String> propEntry : acuconf) {
138         sortedConf.put(propEntry.getKey(), propEntry.getValue());
139       }
140       
141       for (Entry<String,String> propEntry : acuconf) {
142         final String key = propEntry.getKey();
143         // only show properties with similar names to that
144         // specified, or all of them if none specified
145         if (cl.hasOption(filterOpt.getOpt()) && !key.contains(cl.getOptionValue(filterOpt.getOpt()))) {
146           continue;
147         }
148         if (tableName != null && !Property.isValidTablePropertyKey(key)) {
149           continue;
150         }
151         COL2 = Math.max(COL2, propEntry.getKey().length() + 3);
152       }
153       
154       final ArrayList<String> output = new ArrayList<String>();
155       printConfHeader(output);
156       
157       for (Entry<String,String> propEntry : sortedConf.entrySet()) {
158         final String key = propEntry.getKey();
159         
160         // only show properties with similar names to that
161         // specified, or all of them if none specified
162         if (cl.hasOption(filterOpt.getOpt()) && !key.contains(cl.getOptionValue(filterOpt.getOpt()))) {
163           continue;
164         }
165         if (tableName != null && !Property.isValidTablePropertyKey(key)) {
166           continue;
167         }
168         String siteVal = siteConfig.get(key);
169         String sysVal = systemConfig.get(key);
170         String curVal = propEntry.getValue();
171         String dfault = defaults.get(key);
172         boolean printed = false;
173         
174         if (dfault != null && key.toLowerCase().contains("password")) {
175           siteVal = sysVal = dfault = curVal = curVal.replaceAll(".", "*");
176         }
177         if (sysVal != null) {
178           if (defaults.containsKey(key)) {
179             printConfLine(output, "default", key, dfault);
180             printed = true;
181           }
182           if (!defaults.containsKey(key) || !defaults.get(key).equals(siteVal)) {
183             printConfLine(output, "site", printed ? "   @override" : key, siteVal == null ? "" : siteVal);
184             printed = true;
185           }
186           if (!siteConfig.containsKey(key) || !siteVal.equals(sysVal)) {
187             printConfLine(output, "system", printed ? "   @override" : key, sysVal == null ? "" : sysVal);
188             printed = true;
189           }
190         }
191         
192         // show per-table value only if it is different (overridden)
193         if (tableName != null && !curVal.equals(sysVal)) {
194           printConfLine(output, "table", printed ? "   @override" : key, curVal);
195         }
196       }
197       printConfFooter(output);
198       shellState.printLines(output.iterator(), !cl.hasOption(disablePaginationOpt.getOpt()), printFile);
199       if (printFile != null) {
200         printFile.close();
201       }
202     }
203     return 0;
204   }
205   
206   private void printConfHeader(List<String> output) {
207     printConfFooter(output);
208     output.add(String.format("%-" + COL1 + "s | %-" + COL2 + "s | %s", "SCOPE", "NAME", "VALUE"));
209     printConfFooter(output);
210   }
211   
212   private void printConfLine(List<String> output, String s1, String s2, String s3) {
213     if (s2.length() < COL2) {
214       s2 += " " + Shell.repeat(".", COL2 - s2.length() - 1);
215     }
216     output.add(String.format("%-" + COL1 + "s | %-" + COL2 + "s | %s", s1, s2,
217         s3.replace("\n", "\n" + Shell.repeat(" ", COL1 + 1) + "|" + Shell.repeat(" ", COL2 + 2) + "|" + " ")));
218   }
219   
220   private void printConfFooter(List<String> output) {
221     int col3 = Math.max(1, Math.min(Integer.MAX_VALUE, reader.getTermwidth() - COL1 - COL2 - 6));
222     output.add(String.format("%" + COL1 + "s-+-%" + COL2 + "s-+-%-" + col3 + "s", Shell.repeat("-", COL1), Shell.repeat("-", COL2), Shell.repeat("-", col3)));
223   }
224   
225   @Override
226   public String description() {
227     return "prints system properties and table specific properties";
228   }
229   
230   @Override
231   public Options getOptions() {
232     final Options o = new Options();
233     final OptionGroup og = new OptionGroup();
234     
235     tableOpt = new Option(Shell.tableOption, "table", true, "table to display/set/delete properties for");
236     deleteOpt = new Option("d", "delete", true, "delete a per-table property");
237     setOpt = new Option("s", "set", true, "set a per-table property");
238     filterOpt = new Option("f", "filter", true, "show only properties that contain this string");
239     disablePaginationOpt = new Option("np", "no-pagination", false, "disables pagination of output");
240     outputFileOpt = new Option("o", "output", true, "local file to write the scan output to");
241 
242     tableOpt.setArgName("table");
243     deleteOpt.setArgName("property");
244     setOpt.setArgName("property=value");
245     filterOpt.setArgName("string");
246     outputFileOpt.setArgName("file");
247     
248     og.addOption(deleteOpt);
249     og.addOption(setOpt);
250     og.addOption(filterOpt);
251     
252     o.addOption(tableOpt);
253     o.addOptionGroup(og);
254     o.addOption(disablePaginationOpt);
255     o.addOption(outputFileOpt);
256     
257     return o;
258   }
259   
260   @Override
261   public int numArgs() {
262     return 0;
263   }
264 }