summaryrefslogtreecommitdiff
path: root/python/londiste.py
blob: e7e4f95ea01e4d7eabe9ecbe092c717fb9f108a0 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
#! /usr/bin/env python

"""Londiste launcher.
"""

import sys, os, os.path, optparse, skytools

# python 2.3 will try londiste.py first...
if os.path.exists(os.path.join(sys.path[0], 'londiste.py')) \
    and not os.path.exists(os.path.join(sys.path[0], 'londiste')):
    del sys.path[0]

import londiste

command_usage = """
%prog [options] INI CMD [subcmd args]

Node Initialization:
  init-root   NODE_NAME NODE_CONSTR
  init-branch NODE_NAME NODE_CONSTR --provider=<constr>
  init-leaf   NODE_NAME NODE_CONSTR --provider=<constr>
    Initializes node.  Given connstr is kept as global connstring
    for that node.  Those commands ignore node_db in .ini.
    The --provider connstr is used only for initial set info
    fetching, later actual provider's connect string is used.

Node Administration:
  status                Show set state
  members               Show members in set
  rename-node OLD NEW   Rename a node
  change-provider NODE NEWSRC   
  pause NODE
  resume NODE

  switchover NEWROOT
  failover NEWROOT
  tag-dead NODE ..      Tag node as dead
  tag-alive NODE ..     Tag node as alive

Replication Daemon:
  worker                replay events to subscriber

Replication Administration:
  add TBL ...           add table to queue
  remove TBL ...        remove table from queue
  add-seq SEQ ...       add sequence to provider
  remove-seq SEQ ...    remove sequence from provider
  tables                show all tables on provider
  seqs                  show all sequences on provider
  missing               list tables subscriber has not yet attached to
  resync TBL ...        do full copy again

Replication Extra:
  check                 compare table structure on both sides
  fkeys                 print out fkey drop/create commands
  compare [TBL ...]     compare table contents on both sides
  repair [TBL ...]      repair data on subscriber

Internal Commands:
  copy                  copy table logic
"""

cmd_handlers = (
    (('init-root', 'init-branch', 'init-leaf', 'members', 'tag-dead', 'tag-alive',
      'change-provider', 'rename-node', 'status', 'pause', 'resume',
      'switchover', 'failover'), londiste.LondisteSetup),
    (('add', 'remove', 'add-seq', 'remove-seq', 'tables', 'seqs',
      'missing', 'resync', 'check', 'fkeys'), londiste.LondisteSetup),
    (('worker', 'replay'), londiste.Replicator),
    (('compare',), londiste.Comparator),
    (('repair',), londiste.Repairer),
    (('copy',), londiste.CopyTable),
)

class Londiste(skytools.DBScript):
    def __init__(self, args):
        skytools.DBScript.__init__(self, 'londiste', args)

        if len(self.args) < 2:
            print "need command"
            sys.exit(1)
        cmd = self.args[1]
        self.script = None
        for names, cls in cmd_handlers:
            if cmd in names:
                self.script = cls(args)
                break
        if not self.script:
            print "Unknown command '%s', use --help for help" % cmd
            sys.exit(1)

    def start(self):
        self.script.start()

    def init_optparse(self, parser=None):
        p = skytools.DBScript.init_optparse(self, parser)
        p.set_usage(command_usage.strip())

        g = optparse.OptionGroup(p, "expert options")
        g.add_option("--all", action="store_true",
                help = "add: include add possible tables")
        g.add_option("--force", action="store_true",
                help = "add: ignore table differences, repair: ignore lag")
        g.add_option("--expect-sync", action="store_true", dest="expect_sync",
                help = "add: no copy needed", default=False)
        g.add_option("--skip-truncate", action="store_true", dest="skip_truncate",
                help = "add: keep old data", default=False)
        g.add_option("--provider",
                help = "init: upstream node temp connect string")
        g.add_option("--create",
                help = "add: create table/seq if not exist (seq,pkey,full,indexes,fkeys)")
        p.add_option_group(g)

        return p
    def opt_create_cb(self, option, opt_str, value, parser):
        print opt_str, '=', value

if __name__ == '__main__':
    script = Londiste(sys.argv[1:])
    script.start()