Ejemplo n.º 1
0
func main() {
	fmt.Println("Starting redis restore")

	if len(os.Args) != 3 {
		log.Fatalf("usage: restore <instance_id> <rdb_path>")
	}

	instanceID := os.Args[1]
	rdbPath := os.Args[2]

	logger := lager.NewLogger("redis-restore")
	logger.RegisterSink(lager.NewWriterSink(os.Stdout, lager.DEBUG))
	logger.RegisterSink(lager.NewWriterSink(os.Stderr, lager.ERROR))

	startStep("Loading config")
	config, err := restoreconfig.Load(restoreConfigPath())
	if err != nil {
		finishStepFatal("Could not load config")
	}
	finishStep("OK")

	monitExecutablePath := config.MonitExecutablePath
	instanceDirPath := config.InstanceDataDir(instanceID)

	startStep("Checking instance directory and backup file")
	if _, err := os.Stat(instanceDirPath); os.IsNotExist(err) {
		finishStepFatal("Instance not found")
	}

	if _, err := os.Stat(rdbPath); os.IsNotExist(err) {
		log.Fatalf("RDB file not found")
	}
	finishStep("OK")

	commandRunner := system.OSCommandRunner{
		Logger: logger,
	}

	startStep("Disabling Redis process watcher")
	if config.DedicatedInstance {
		finishStep("Skipped")
	} else {
		err = stopViaMonit(monitExecutablePath, "process-watcher")
		if err != nil {
			finishStep("ERROR")
			logger.Fatal("stop-process-watcher", err)
		}
		finishStep("OK")
	}

	processKiller := &process.ProcessKiller{}

	processController := &redis.OSProcessController{
		CommandRunner:             commandRunner,
		InstanceInformer:          &config,
		Logger:                    logger,
		ProcessChecker:            &process.ProcessChecker{},
		ProcessKiller:             processKiller,
		PingFunc:                  redis.PingServer,
		WaitUntilConnectableFunc:  availability.Check,
		RedisServerExecutablePath: config.RedisServerExecutablePath,
	}

	instance := &redis.Instance{ID: instanceID, Host: "localhost", Port: 6379}

	pidfilePath := config.InstancePidFilePath(instanceID)

	startStep("Stopping Redis")
	if config.DedicatedInstance {
		if err = unmonit(monitExecutablePath, "redis"); err == nil {
			err = processKiller.KillProvidedPID(redisPIDProvider(instanceDirPath))
		}
	} else {
		err = processController.Kill(instance)
	}

	if err != nil {
		finishStep("ERROR")
		logger.Fatal("killing-redis", err)
	}
	finishStep("OK")

	startStep("Copying backup file to instance directory")
	err = copyRdbFileIntoInstance(rdbPath, instanceDirPath)
	if err != nil {
		finishStep("ERROR")
		logger.Fatal("copy-rdb", err)
	}
	finishStep("OK")

	startStep("Starting Redis from backup file")
	err = processController.StartAndWaitUntilReadyWithConfig(
		instance,
		[]string{
			"--pidfile", pidfilePath,
			"--daemonize", "yes",
			"--dir", instanceDirPath,
			"--bind", "127.0.0.1",
		},
		time.Duration(config.StartRedisTimeoutSeconds)*time.Second,
	)
	if err != nil {
		finishStep("ERROR")
		logger.Fatal("starting-redis", err)
	}
	finishStep("OK")

	startStep("Waiting for redis to finish loading data into memory")
	client, err := client.Connect(
		client.Host(instance.Host),
		client.Port(instance.Port),
	)

	if err != nil {
		finishStep("ERROR")
		logger.Fatal("connecting-to-redis", err)
	}

	err = client.WaitUntilRedisNotLoading(config.StartRedisTimeoutSeconds * 1000)
	if err != nil {
		finishStep("ERROR")
		logger.Fatal("starting-redis", err)
	}
	finishStep("OK")

	startStep("Enabling appendonly mode")
	err = client.EnableAOF()
	if err != nil {
		finishStep("ERROR")
		logger.Fatal("enabling-aof", err)
	}
	finishStep("OK")

	startStep("Waiting for appendonly rewrite to finish")
	for {
		aofRewriteInProgress, err := client.InfoField("aof_rewrite_in_progress")
		if err != nil {
			finishStep("ERROR")
			logger.Fatal("querying-aof-progress", err)
		}

		if aofRewriteInProgress == "0" {
			break
		}

		time.Sleep(time.Millisecond * aofRewriteInProgressCheckIntervalMilliseconds)
	}

	aofRewriteStatus, err := client.InfoField("aof_last_bgrewrite_status")
	if err != nil {
		logger.Fatal("getting-aof-write-status", err)
	}

	if aofRewriteStatus != "ok" {
		logger.Fatal(
			"verifying-aof-write-status",
			fmt.Errorf("Invalid AOF write status: %s", aofRewriteStatus),
		)
	}

	finishStep("OK")

	startStep("Stopping Redis")
	err = processController.Kill(instance)
	if err != nil {
		finishStep("ERROR")
		logger.Fatal("killing-redis", err)
	}
	finishStep("OK")

	startStep("Setting correct permissions on appendonly file")
	aofPath := path.Join(instanceDirPath, "appendonly.aof")
	err = chownAof("vcap", aofPath)
	if err != nil {
		finishStep("ERROR")
		logger.Fatal("chown-aof", err)
	}
	finishStep("OK")

	startStep("Restarting Redis process watcher/redis")
	if config.DedicatedInstance {
		err = startViaMonit(monitExecutablePath, "redis")
	} else {
		err = startViaMonit(monitExecutablePath, "process-watcher")
	}

	if err != nil {
		finishStep("ERROR")
		logger.Fatal("start redis/process watcher", err)
	}
	finishStep("OK")

	fmt.Println("Restore completed successfully")
}
Ejemplo n.º 2
0
			It("returns a map that contains expected entries", func() {
				info, _ := redis.Info()
				Expect(info["aof_enabled"]).To(Equal("0"))
			})
		})

		Describe("querying info fields", func() {
			Context("when the field exits", func() {
				It("returns the value", func() {
					client, err := client.Connect(
						client.Host(host),
						client.Port(port),
					)
					Ω(err).ShouldNot(HaveOccurred())

					result, err := client.InfoField("aof_enabled")
					Ω(err).ShouldNot(HaveOccurred())
					Ω(result).To(Equal("0"))
				})
			})

			Context("when the field does not exist", func() {
				It("returns an error", func() {
					client, err := client.Connect(
						client.Host(host),
						client.Port(port),
					)
					Ω(err).ShouldNot(HaveOccurred())

					_, err = client.InfoField("made_up_field")
					Ω(err).Should(MatchError("Unknown field: made_up_field"))