Example #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")
}
			redisRunner.Start(redisArgs)
		})

		AfterEach(func() {
			redisRunner.Stop()
		})

		Describe("turning on appendonly", func() {
			It("turns on appendonly", func() {
				client, err := client.Connect(
					client.Host(host),
					client.Port(port),
				)
				Ω(err).ShouldNot(HaveOccurred())

				err = client.EnableAOF()
				Ω(err).ShouldNot(HaveOccurred())

				conn, err := redisclient.Dial("tcp", ":6480")
				Ω(err).ShouldNot(HaveOccurred())
				defer conn.Close()

				response, err := redisclient.Strings(conn.Do("CONFIG", "GET", "appendonly"))
				Ω(err).ShouldNot(HaveOccurred())

				Ω(response[1]).Should(Equal("yes"))
			})
		})

		Describe(".Info", func() {
			var redis client.Client