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 "gopkg.in/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))
}
|