On 07/05/2015 01:38 AM, Alex Wang wrote: > This commit adds ovn-sbctl to ovn family by using the db-ctl-base > library. > > Signed-off-by: Alex Wang <al...@nicira.com> > Acked-by: Ben Pfaff <b...@nicira.com> > > --- > PATCH->V2: > - change command add/del-ch to add/del-chassis. > - refine the manual based on comments from Ben. > --- > manpages.mk | 12 + > ovn/.gitignore | 2 + > ovn/automake.mk | 9 + > ovn/ovn-sbctl.8.in | 160 ++++++++++ > ovn/ovn-sbctl.c | 837 > ++++++++++++++++++++++++++++++++++++++++++++++++++++ > tests/automake.mk | 5 +- > tests/ovn-sbctl.at | 61 ++++ > tests/testsuite.at | 1 + > 8 files changed, 1085 insertions(+), 2 deletions(-) > create mode 100644 ovn/ovn-sbctl.8.in > create mode 100644 ovn/ovn-sbctl.c > create mode 100644 tests/ovn-sbctl.at > > diff --git a/manpages.mk b/manpages.mk > index 3cec260..032cb26 100644 > --- a/manpages.mk > +++ b/manpages.mk > @@ -1,5 +1,17 @@ > # Generated automatically -- do not modify! -*- buffer-read-only: t -*- > > +ovn/ovn-sbctl.8: \ > + ovn/ovn-sbctl.8.in \ > + lib/db-ctl-base.man \ > + lib/table.man \ > + ovsdb/remote-active.man \ > + ovsdb/remote-passive.man > +ovn/ovn-sbctl.8.in: > +lib/db-ctl-base.man: > +lib/table.man: > +ovsdb/remote-active.man: > +ovsdb/remote-passive.man: > + > ovsdb/ovsdb-client.1: \ > ovsdb/ovsdb-client.1.in \ > lib/common-syn.man \ > diff --git a/ovn/.gitignore b/ovn/.gitignore > index 4c13616..2d4835a 100644 > --- a/ovn/.gitignore > +++ b/ovn/.gitignore > @@ -7,3 +7,5 @@ > /ovn-sb.pic > /ovn-nbctl > /ovn-nbctl.8 > +/ovn-sbctl > +/ovn-sbctl.8
This isn't really related to this patch, but maybe we should create a ovn/utilities/ directory for ovn-nbctl, ovn-sbctl, and whatever else we come up with. > diff --git a/ovn/ovn-sbctl.8.in b/ovn/ovn-sbctl.8.in > new file mode 100644 > index 0000000..1cf9b7d > --- /dev/null > +++ b/ovn/ovn-sbctl.8.in > @@ -0,0 +1,160 @@ > +.\" -*- nroff -*- How about doing this in the XML format? It seems much easier to read and edit that way. > new file mode 100644 > index 0000000..8c82d03 > --- /dev/null > +++ b/ovn/ovn-sbctl.c > @@ -0,0 +1,837 @@ > +/* > + * Copyright (c) 2009, 2010, 2011, 2012, 2013, 2014, 2015 Nicira, Inc. Presumably just 2015? Though these days I personally prefer not including this line at all since it's not necessary, and is rarely accurate in a collaborative open source project. Keeping it is consistent with the rest of OVS, though ... > + * > + * Licensed 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. > + */ > + > +#include <config.h> > + > +#include <ctype.h> > +#include <errno.h> > +#include <float.h> > +#include <getopt.h> > +#include <inttypes.h> > +#include <signal.h> > +#include <stdarg.h> > +#include <stdlib.h> > +#include <string.h> > +#include <unistd.h> > + > +#include "db-ctl-base.h" > + > +#include "command-line.h" > +#include "compiler.h" > +#include "dynamic-string.h" > +#include "fatal-signal.h" > +#include "json.h" > +#include "ovsdb-data.h" > +#include "ovsdb-idl.h" > +#include "poll-loop.h" > +#include "process.h" > +#include "sset.h" > +#include "shash.h" > +#include "ovn/lib/ovn-sb-idl.h" > +#include "table.h" > +#include "timeval.h" > +#include "util.h" > +#include "openvswitch/vlog.h" > + > +VLOG_DEFINE_THIS_MODULE(sbctl); > + > +struct sbctl_context; > + > +/* --db: The database server to contact. */ > +static const char *db; > + > +/* --oneline: Write each command's output as a single line? */ > +static bool oneline; > + > +/* --dry-run: Do not commit any changes. */ > +static bool dry_run; > + > +/* --timeout: Time to wait for a connection to 'db'. */ > +static int timeout; > + > +/* Format for table output. */ > +static struct table_style table_style = TABLE_STYLE_DEFAULT; > + > +static void sbctl_cmd_init(void); > +OVS_NO_RETURN static void usage(void); > +static void parse_options(int argc, char *argv[], struct shash > *local_options); > +static void run_prerequisites(struct ctl_command[], size_t n_commands, > + struct ovsdb_idl *); > +static void do_sbctl(const char *args, struct ctl_command *, size_t n, > + struct ovsdb_idl *); > + > +int > +main(int argc, char *argv[]) > +{ > + extern struct vlog_module VLM_reconnect; > + struct ovsdb_idl *idl; > + struct ctl_command *commands; > + struct shash local_options; > + unsigned int seqno; > + size_t n_commands; > + char *args; > + > + set_program_name(argv[0]); > + fatal_ignore_sigpipe(); > + vlog_set_levels(NULL, VLF_CONSOLE, VLL_WARN); > + vlog_set_levels(&VLM_reconnect, VLF_ANY_DESTINATION, VLL_WARN); > + sbrec_init(); > + > + sbctl_cmd_init(); > + > + /* Log our arguments. This is often valuable for debugging systems. */ > + args = process_escape_args(argv); > + VLOG(ctl_might_write_to_db(argv) ? VLL_INFO : VLL_DBG, "Called as %s", > args); > + > + /* Parse command line. */ > + shash_init(&local_options); > + parse_options(argc, argv, &local_options); > + commands = ctl_parse_commands(argc - optind, argv + optind, > &local_options, > + &n_commands); > + > + if (timeout) { > + time_alarm(timeout); > + } > + > + /* Initialize IDL. */ > + idl = the_idl = ovsdb_idl_create(db, &sbrec_idl_class, false, false); > + run_prerequisites(commands, n_commands, idl); > + > + /* Execute the commands. > + * > + * 'seqno' is the database sequence number for which we last tried to > + * execute our transaction. There's no point in trying to commit more > than > + * once for any given sequence number, because if the transaction fails > + * it's because the database changed and we need to obtain an up-to-date > + * view of the database before we try the transaction again. */ > + seqno = ovsdb_idl_get_seqno(idl); > + for (;;) { > + ovsdb_idl_run(idl); > + if (!ovsdb_idl_is_alive(idl)) { > + int retval = ovsdb_idl_get_last_error(idl); > + ctl_fatal("%s: database connection failed (%s)", > + db, ovs_retval_to_string(retval)); > + } > + > + if (seqno != ovsdb_idl_get_seqno(idl)) { > + seqno = ovsdb_idl_get_seqno(idl); > + do_sbctl(args, commands, n_commands, idl); > + } > + > + if (seqno == ovsdb_idl_get_seqno(idl)) { > + ovsdb_idl_wait(idl); > + poll_block(); > + } > + } > +} > + > +static void > +parse_options(int argc, char *argv[], struct shash *local_options) > +{ > + enum { > + OPT_DB = UCHAR_MAX + 1, > + OPT_ONELINE, > + OPT_NO_SYSLOG, > + OPT_DRY_RUN, > + OPT_PEER_CA_CERT, > + OPT_LOCAL, > + OPT_COMMANDS, > + OPT_OPTIONS, > + VLOG_OPTION_ENUMS, > + TABLE_OPTION_ENUMS > + }; > + static const struct option global_long_options[] = { > + {"db", required_argument, NULL, OPT_DB}, > + {"no-syslog", no_argument, NULL, OPT_NO_SYSLOG}, > + {"dry-run", no_argument, NULL, OPT_DRY_RUN}, > + {"oneline", no_argument, NULL, OPT_ONELINE}, > + {"timeout", required_argument, NULL, 't'}, > + {"help", no_argument, NULL, 'h'}, > + {"commands", no_argument, NULL, OPT_COMMANDS}, > + {"options", no_argument, NULL, OPT_OPTIONS}, > + {"version", no_argument, NULL, 'V'}, > + VLOG_LONG_OPTIONS, > + TABLE_LONG_OPTIONS, > + {NULL, 0, NULL, 0}, > + }; > + const int n_global_long_options = ARRAY_SIZE(global_long_options) - 1; > + char *tmp, *short_options; > + > + struct option *options; > + size_t allocated_options; > + size_t n_options; > + size_t i; > + > + tmp = ovs_cmdl_long_options_to_short_options(global_long_options); > + short_options = xasprintf("+%s", tmp); > + free(tmp); > + > + /* We want to parse both global and command-specific options here, but > + * getopt_long() isn't too convenient for the job. We copy our global > + * options into a dynamic array, then append all of the command-specific > + * options. */ > + options = xmemdup(global_long_options, sizeof global_long_options); > + allocated_options = ARRAY_SIZE(global_long_options); > + n_options = n_global_long_options; > + ctl_add_cmd_options(&options, &n_options, &allocated_options, OPT_LOCAL); > + table_style.format = TF_LIST; > + > + for (;;) { > + int idx; > + int c; > + > + c = getopt_long(argc, argv, short_options, options, &idx); > + if (c == -1) { > + break; > + } > + > + switch (c) { > + case OPT_DB: > + db = optarg; > + break; > + > + case OPT_ONELINE: > + oneline = true; > + break; > + > + case OPT_NO_SYSLOG: > + vlog_set_levels(&VLM_sbctl, VLF_SYSLOG, VLL_WARN); > + break; > + > + case OPT_DRY_RUN: > + dry_run = true; > + break; > + > + case OPT_LOCAL: > + if (shash_find(local_options, options[idx].name)) { > + ctl_fatal("'%s' option specified multiple times", > + options[idx].name); > + } > + shash_add_nocopy(local_options, > + xasprintf("--%s", options[idx].name), > + optarg ? xstrdup(optarg) : NULL); > + break; > + > + case 'h': > + usage(); > + > + case OPT_COMMANDS: > + ctl_print_commands(); > + > + case OPT_OPTIONS: > + ctl_print_options(global_long_options); > + > + case 'V': > + ovs_print_version(0, 0); > + printf("DB Schema %s\n", sbrec_get_db_version()); > + exit(EXIT_SUCCESS); > + > + case 't': > + timeout = strtoul(optarg, NULL, 10); > + if (timeout < 0) { > + ctl_fatal("value %s on -t or --timeout is invalid", > + optarg); > + } > + break; > + > + VLOG_OPTION_HANDLERS > + TABLE_OPTION_HANDLERS(&table_style) > + > + case '?': > + exit(EXIT_FAILURE); > + > + default: > + abort(); > + } > + } > + free(short_options); > + > + if (!db) { > + db = ctl_default_db(); > + } > + > + for (i = n_global_long_options; options[i].name; i++) { > + free(CONST_CAST(char *, options[i].name)); > + } > + free(options); > +} > + > +static void > +usage(void) > +{ > + printf("\ > +%s: ovs-vswitchd management utility\n\ > +usage: %s [OPTIONS] COMMAND [ARG...]\n\ > +\n\ > +SouthBound DB commands:\n\ > + show print overview of database contents\n\ > +\n\ > +Chassis commands:\n\ > + add-chassis CHASSIS create a new chassis named CHASSIS\n\ > + del-chassis CHASSIS delete CHASSIS and all of its encaps,\n\ > + and gateway_ports\n\ > +\n\ > +Binding commands:\n\ > + bind-lport LPORT CHASSIS bind logical port LPORT to CHASSIS\n\ > + unbind-lport LPORT delete the binding of logical port LPORT\n\ I'm trying to think of when any of these commands would be used. add-chassis and bind-lport are always done by ovn-controller. I could see del-chassis needed in some cases where ovn-controller didn't exit cleanly and an administrator is trying to do some cleanup. I suppose unbind-port could be used in cleanup, too. Are these commands just for test automation with ovn-controller out of the picture? If so, maybe the help output could make it clear that the commands should never be needed? I'm just asking because I want to avoid making OVN confusing by exposing things to administrators that should never really be used. -- Russell Bryant _______________________________________________ dev mailing list dev@openvswitch.org http://openvswitch.org/mailman/listinfo/dev