distribution/docs/registry/registry.go
2016-09-28 14:25:04 -07:00

186 lines
5.5 KiB
Go

package main
import (
"io/ioutil"
"os"
"os/signal"
"path"
"syscall"
"time"
"gopkg.in/yaml.v2"
log "github.com/Sirupsen/logrus"
// Register the DTR authorizer.
"github.com/docker/dhe-deploy"
_ "github.com/docker/dhe-deploy/garant/authz"
"github.com/docker/dhe-deploy/hubconfig"
"github.com/docker/dhe-deploy/hubconfig/etcd"
"github.com/docker/dhe-deploy/hubconfig/util"
"github.com/docker/dhe-deploy/manager/schema"
"github.com/docker/dhe-deploy/registry/middleware"
"github.com/docker/dhe-deploy/shared/containers"
"github.com/docker/dhe-deploy/shared/dtrutil"
// register all storage and auth drivers
_ "github.com/docker/distribution/registry/auth/htpasswd"
_ "github.com/docker/distribution/registry/auth/silly"
_ "github.com/docker/distribution/registry/auth/token"
_ "github.com/docker/distribution/registry/proxy"
_ "github.com/docker/distribution/registry/storage/driver/azure"
_ "github.com/docker/distribution/registry/storage/driver/filesystem"
_ "github.com/docker/distribution/registry/storage/driver/gcs"
_ "github.com/docker/distribution/registry/storage/driver/inmemory"
_ "github.com/docker/distribution/registry/storage/driver/middleware/cloudfront"
_ "github.com/docker/distribution/registry/storage/driver/oss"
_ "github.com/docker/distribution/registry/storage/driver/s3-aws"
_ "github.com/docker/distribution/registry/storage/driver/swift"
"github.com/docker/distribution/configuration"
"github.com/docker/distribution/context"
"github.com/docker/distribution/registry"
"github.com/docker/distribution/version"
"github.com/docker/garant"
// Metadata store
repomiddleware "github.com/docker/distribution/registry/middleware/repository"
)
const configFilePath = "/config/storage.yml"
func main() {
log.SetFormatter(new(log.JSONFormatter))
releaseRestartLock()
notifyReadOnly()
setupMiddleware()
go waitForReload()
go runGarant()
runRegistry()
}
func runGarant() {
log.Info("garant starting")
app, err := garant.NewApp("/config/garant.yml")
if err != nil {
log.Fatalf("unable to initialize token server app: %s", err)
}
log.Fatal(app.ListenAndServe())
}
func waitForReload() {
log.Info("listening for sigusr2")
c := make(chan os.Signal, 1)
signal.Notify(c, syscall.SIGUSR2)
_ = <-c
log.Info("got sigusr2! Attempting to shut down safely")
dtrKVStore := makeKVStore()
log.Info("getting restart lock")
// This will block until no other registry is restarting
err := dtrKVStore.Lock(deploy.RegistryRestartLockPath, []byte(os.Getenv(deploy.ReplicaIDEnvVar)), time.Minute)
if err != nil {
log.Fatalf("Failed to get restart lock: %s", err)
}
log.Fatal("restarting now")
}
func releaseRestartLock() {
kvStore := makeKVStore()
value, err := kvStore.Get(deploy.RegistryRestartLockPath)
if err != nil {
log.Infof("No lock found to release: %s", err)
return
}
if string(value) == os.Getenv(deploy.ReplicaIDEnvVar) {
// Unlock the key so others can restart too
// TODO: check for intermittent failures and do some retries
err := kvStore.Delete(deploy.RegistryRestartLockPath)
log.Infof("removing restart lock: %s", err)
} else {
log.Info("someone else is holding the lock, not releasing")
}
}
func notifyReadOnly() {
storageFile, err := ioutil.ReadFile(configFilePath)
if err != nil {
log.Fatalf("error reading storage.yml: %s", err)
}
var storageYML configuration.Configuration
err = yaml.Unmarshal(storageFile, &storageYML)
if err != nil {
log.Fatalf("error unmarshaling storage.yml: %s", err)
}
roMode := util.GetReadonlyMode(&storageYML.Storage)
kvStore := makeKVStore()
roModePath := path.Join(deploy.RegistryROStatePath, os.Getenv(deploy.ReplicaIDEnvVar))
if roMode {
log.Infof("registering self as being in read-only mode at key: %s", roModePath)
err := kvStore.Put(roModePath, []byte{})
if err != nil {
log.Errorf("Failed to register self as read-only: %s", err)
time.Sleep(1)
log.Fatalf("Failed to register self as read-only: %s", err)
}
} else {
// TODO: check the type of error and retry if it's an intermittent failure instead of a double delete
err = kvStore.Delete(roModePath)
log.Infof("no longer in read-only mode: %s", err)
}
}
func runRegistry() {
log.Info("registry starting")
fp, err := os.Open(configFilePath)
if err != nil {
log.Fatalf("unable to open registry config: %s", err)
}
defer fp.Close()
config, err := configuration.Parse(fp)
if err != nil {
log.Fatalf("error parsing registry config: %s", err)
}
if config.Storage.Type() == "filesystem" {
params := config.Storage["filesystem"]
params["rootdirectory"] = "/storage"
config.Storage["filesystem"] = params
}
registry, err := registry.NewRegistry(context.WithVersion(context.Background(), version.Version), config)
if err != nil {
log.Fatalf("unable to initialize registry: %s", err)
}
log.Fatal(registry.ListenAndServe())
}
// TODO: make don't call this function so many times
func makeKVStore() hubconfig.KeyValueStore {
dtrKVStore, err := etcd.NewKeyValueStore(containers.EtcdUrls(), deploy.EtcdPath)
if err != nil {
log.Fatalf("something went wrong when trying to initialize the Lock: %s", err)
}
return dtrKVStore
}
func setupMiddleware() {
replicaID := os.Getenv(deploy.ReplicaIDEnvVar)
db, err := dtrutil.GetRethinkSession(replicaID)
if err != nil {
log.WithField("error", err).Fatal("failed to connect to rethink")
}
store := schema.NewMetadataManager(db)
middleware.RegisterStore(store)
if err := repomiddleware.Register("metadata", middleware.InitMiddleware); err != nil {
log.WithField("err", err).Fatal("unable to register metadata middleware")
}
log.Info("connected to middleware")
}