LogCabin
Examples/Reconfigure.cc
Go to the documentation of this file.
00001 /* Copyright (c) 2012 Stanford University
00002  *
00003  * Permission to use, copy, modify, and distribute this software for any
00004  * purpose with or without fee is hereby granted, provided that the above
00005  * copyright notice and this permission notice appear in all copies.
00006  *
00007  * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR(S) DISCLAIM ALL WARRANTIES
00008  * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
00009  * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL AUTHORS BE LIABLE FOR
00010  * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
00011  * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
00012  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
00013  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
00014  */
00015 
00016 /**
00017  * \file
00018  * Changes the membership of a LogCabin cluster.
00019  */
00020 
00021 #include <getopt.h>
00022 #include <iostream>
00023 #include <string>
00024 
00025 #include <LogCabin/Client.h>
00026 #include <LogCabin/Debug.h>
00027 
00028 namespace {
00029 
00030 using LogCabin::Client::Cluster;
00031 using LogCabin::Client::Configuration;
00032 using LogCabin::Client::ConfigurationResult;
00033 using LogCabin::Client::Result;
00034 using LogCabin::Client::Server;
00035 using LogCabin::Client::Status;
00036 
00037 /**
00038  * Parses argv for the main function.
00039  */
00040 class OptionParser {
00041   public:
00042     OptionParser(int& argc, char**& argv)
00043         : argc(argc)
00044         , argv(argv)
00045         , cluster("logcabin:5254")
00046         , logPolicy("")
00047         , servers()
00048     {
00049         while (true) {
00050             static struct option longOptions[] = {
00051                {"cluster",  required_argument, NULL, 'c'},
00052                {"help",  no_argument, NULL, 'h'},
00053                {"verbose",  no_argument, NULL, 'v'},
00054                {"verbosity",  required_argument, NULL, 256},
00055                {0, 0, 0, 0}
00056             };
00057             int c = getopt_long(argc, argv, "c:hv", longOptions, NULL);
00058 
00059             // Detect the end of the options.
00060             if (c == -1)
00061                 break;
00062 
00063             switch (c) {
00064                 case 'c':
00065                     cluster = optarg;
00066                     break;
00067                 case 'h':
00068                     usage();
00069                     exit(0);
00070                 case 'v':
00071                     logPolicy = "VERBOSE";
00072                     break;
00073                 case 256:
00074                     logPolicy = optarg;
00075                     break;
00076                 case '?':
00077                 default:
00078                     // getopt_long already printed an error message.
00079                     usage();
00080                     exit(1);
00081             }
00082         }
00083 
00084         // Additional command line arguments are required.
00085         if (optind == argc) {
00086             usage();
00087             exit(1);
00088         }
00089         // For now, first argument must be the command "set".
00090         if (std::string("set") == argv[optind]) {
00091             ++optind;
00092             while (optind < argc) {
00093                 servers.push_back(argv[optind]);
00094                 ++optind;
00095             }
00096         } else {
00097             std::cerr << "Invalid command: " << argv[optind] << std::endl;
00098             usage();
00099             exit(1);
00100         }
00101     }
00102 
00103     void usage() {
00104         std::cout
00105             << "Changes the membership of a LogCabin cluster."
00106             << std::endl
00107             << std::endl
00108             << "This program was released in LogCabin v1.0.0."
00109             << std::endl
00110             << std::endl
00111 
00112             << "Usage: " << argv[0] << " [options] set <server>..."
00113             << std::endl
00114             << std::endl
00115 
00116             << "Options:"
00117             << std::endl
00118 
00119             << "  -c <addresses>, --cluster=<addresses>  "
00120             << "Network addresses of the LogCabin"
00121             << std::endl
00122             << "                                         "
00123             << "servers, including both the old and"
00124             << std::endl
00125             << "                                         "
00126             << "the new servers, comma-separated"
00127             << std::endl
00128             << "                                         "
00129             << "[default: logcabin:5254]"
00130             << std::endl
00131 
00132             << "  -h, --help                             "
00133             << "Print this usage information"
00134             << std::endl
00135 
00136             << "  -v, --verbose                  "
00137             << "Same as --verbosity=VERBOSE (added in v1.1.0)"
00138             << std::endl
00139 
00140             << "  --verbosity=<policy>           "
00141             << "Set which log messages are shown."
00142             << std::endl
00143             << "                                 "
00144             << "Comma-separated LEVEL or PATTERN@LEVEL rules."
00145             << std::endl
00146             << "                                 "
00147             << "Levels: SILENT ERROR WARNING NOTICE VERBOSE."
00148             << std::endl
00149             << "                                 "
00150             << "Patterns match filename prefixes or suffixes."
00151             << std::endl
00152             << "                                 "
00153             << "Example: Client@NOTICE,Test.cc@SILENT,VERBOSE."
00154             << std::endl
00155             << "                                 "
00156             << "(added in v1.1.0)"
00157             << std::endl;
00158     }
00159 
00160     int& argc;
00161     char**& argv;
00162     std::string cluster;
00163     std::string logPolicy;
00164     std::vector<std::string> servers;
00165 };
00166 
00167 void
00168 printConfiguration(const std::pair<uint64_t, Configuration>& configuration)
00169 {
00170     std::cout << "Configuration " << configuration.first << ":" << std::endl;
00171     for (auto it = configuration.second.begin();
00172          it != configuration.second.end();
00173          ++it) {
00174         std::cout << "- " << it->serverId << ": " << it->addresses
00175                   << std::endl;
00176     }
00177     std::cout << std::endl;
00178 }
00179 
00180 
00181 } // anonymous namespace
00182 
00183 int
00184 main(int argc, char** argv)
00185 {
00186     OptionParser options(argc, argv);
00187     LogCabin::Client::Debug::setLogPolicy(
00188         LogCabin::Client::Debug::logPolicyFromString(
00189             options.logPolicy));
00190     Cluster cluster(options.cluster);
00191 
00192     std::pair<uint64_t, Configuration> configuration =
00193         cluster.getConfiguration();
00194     uint64_t id = configuration.first;
00195     std::cout << "Current configuration:" << std::endl;
00196     printConfiguration(configuration);
00197 
00198     std::cout << "Attempting to change cluster membership to the following:"
00199               << std::endl;
00200     Configuration servers;
00201     for (auto it = options.servers.begin();
00202          it != options.servers.end();
00203          ++it) {
00204         Server info;
00205         Result result = cluster.getServerInfo(*it,
00206                                               /* timeout = 2s */ 2000000000UL,
00207                                               info);
00208         switch (result.status) {
00209             case Status::OK:
00210                 std::cout << info.serverId << ": "
00211                           << info.addresses
00212                           << " (given as " << *it << ")"
00213                           << std::endl;
00214                 servers.emplace_back(info.serverId, info.addresses);
00215                 break;
00216             case Status::TIMEOUT:
00217                 std::cout << "Could not fetch server info from "
00218                           << *it << " (" << result.error << "). Aborting."
00219                           << std::endl;
00220                 return 1;
00221             default:
00222                 std::cout << "Unknown error from "
00223                           << *it << " (" << result.error << "). Aborting."
00224                           << std::endl;
00225                 return 1;
00226         }
00227     }
00228     std::cout << std::endl;
00229 
00230     ConfigurationResult result = cluster.setConfiguration(id, servers);
00231     std::cout << "Membership change result: ";
00232     if (result.status == ConfigurationResult::OK) {
00233         std::cout << "OK" << std::endl;
00234     } else if (result.status == ConfigurationResult::CHANGED) {
00235         std::cout << "CHANGED (" << result.error << ")" << std::endl;
00236     } else if (result.status == ConfigurationResult::BAD) {
00237         std::cout << "BAD SERVERS (" << result.error << "):" << std::endl;
00238         for (auto it = result.badServers.begin();
00239              it != result.badServers.end();
00240              ++it) {
00241             std::cout << "- " << it->serverId << ": " << it->addresses
00242                       << std::endl;
00243         }
00244     }
00245     std::cout << std::endl;
00246 
00247     std::cout << "Current configuration:" << std::endl;
00248     printConfiguration(cluster.getConfiguration());
00249 
00250     if (result.status == ConfigurationResult::OK)
00251         return 0;
00252     else
00253         return 1;
00254 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines