/
main.go
135 lines (120 loc) · 3.58 KB
/
main.go
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
122
123
124
125
126
127
128
129
130
131
132
133
134
135
// Copyright 2017 Canonical Ltd.
// Licensed under the AGPLv3, see LICENCE file for details.
package main
import (
"context"
"database/sql"
"flag"
"fmt"
"log"
"os"
_ "github.com/lib/pq"
errgo "gopkg.in/errgo.v1"
mgo "github.com/juju/mgo/v2"
"github.com/canonical/candid/cmd/migrate-db/internal"
"github.com/canonical/candid/store"
"github.com/canonical/candid/store/mgostore"
"github.com/canonical/candid/store/sqlstore"
)
var (
from = flag.String("from", "legacy:mongodb://localhost/identity", "store `specification` to copy the identities from.")
to = flag.String("to", "mgo:mongodb://localhost/idm", "store `specification` to copy the identities to.")
)
func main() {
flag.Usage = usage
flag.Parse()
if err := migrate(context.Background()); err != nil {
log.Println(err)
os.Exit(1)
}
}
func usage() {
fmt.Fprintf(os.Stderr, "Usage of %s:\n", os.Args[0])
fmt.Fprint(os.Stderr, `
Migrate all of the identities from one store to another. Stores are
specified by a string containing the store type, a colon, and connection
information specific to the store type. For the -from store the valid
prefixes are:
"legacy" - old style mgo based store
"mgo" - new style mgo based store
"postgres" - postgres based store
The -to store only supports "mgo" and "postgres".
For "legacy" and "mgo" type stores the connection string is a mgo URL
(see https://godoc.org/gopkg.in/mgo.v2#Dial). For "postgres" type
stores the connection string is as documented in
https://godoc.org/github.com/lib/pq.
`)
flag.PrintDefaults()
}
func migrate(ctx context.Context) error {
var source internal.Source
type_, addr := internal.SplitStoreSpecification(*from)
switch type_ {
case "legacy":
s, err := mgo.Dial(addr)
if err != nil {
return errgo.Notef(err, "cannot connect to mongodb server")
}
defer s.Close()
source = internal.NewLegacySource(s.DB(""))
case "mgo":
s, err := mgo.Dial(addr)
if err != nil {
return errgo.Notef(err, "cannot connect to mongodb server")
}
defer s.Close()
backend, err := mgostore.NewBackend(s.DB(""))
if err != nil {
return errgo.Notef(err, "cannot initialize mgo store")
}
defer backend.Close()
source = internal.NewStoreSource(ctx, backend.Store())
case "postgres":
sqldb, err := sql.Open("postgres", addr)
if err != nil {
return errgo.Notef(err, "cannot connect to postgresql server")
}
defer sqldb.Close()
backend, err := sqlstore.NewBackend("postgres", sqldb)
if err != nil {
return errgo.Notef(err, "cannot initialize postgresql database")
}
defer backend.Close()
source = internal.NewStoreSource(ctx, backend.Store())
default:
return errgo.Newf("invalid source type %q", type_)
}
var store store.Store
type_, addr = internal.SplitStoreSpecification(*to)
switch type_ {
case "mgo":
s, err := mgo.Dial(addr)
if err != nil {
return errgo.Notef(err, "cannot connect to mongodb server")
}
defer s.Close()
backend, err := mgostore.NewBackend(s.DB(""))
if err != nil {
return errgo.Notef(err, "cannot initialize mgo store")
}
defer backend.Close()
store = backend.Store()
case "postgres":
sqldb, err := sql.Open("postgres", addr)
if err != nil {
return errgo.Notef(err, "cannot connect to postgresql server")
}
defer sqldb.Close()
backend, err := sqlstore.NewBackend("postgres", sqldb)
if err != nil {
return errgo.Notef(err, "cannot initialize postgresql database")
}
defer backend.Close()
store = backend.Store()
default:
return errgo.Newf("invalid destination type %q", type_)
}
ctx, close := store.Context(ctx)
defer close()
return errgo.Mask(internal.Copy(ctx, store, source))
}