forked from TrueCloudLab/distribution
186 lines
5.5 KiB
Go
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")
|
|
}
|