func NatTunnel(url, ngrokPath, ngrokLogPath, ngrokConfPath, uuid string) {
	if isNodeReachable(url, uuid) {
		Logger.Printf("Node %s is publicly reachable", Conf.CertCommonName)
		return
	} else {
		Logger.Printf("Node %s is NOT publicly reachable", Conf.CertCommonName)
	}

	if !utils.FileExist(ngrokPath) {
		Logger.Println("Cannot find ngrok binary at", ngrokPath)
		DownloadNgrok(NgrokBinaryURL, ngrokPath)
	}

	updateNgrokHost(url)
	createNgrokConfFile(ngrokConfPath)

	var cmd *exec.Cmd

	if !utils.FileExist(ngrokConfPath) {
		SendError(errors.New("Cannot find ngrok conf"), "Cannot find ngrok conf file", nil)
		Logger.Println("Cannot find NAT tunnel configuration")
		return
	}
	cmd = exec.Command(ngrokPath,
		"-config", ngrokConfPath,
		"-log", "stdout",
		"-proto", "tcp",
		DockerHostPort)

	os.RemoveAll(ngrokLogPath)
	logFile, err := os.OpenFile(ngrokLogPath, os.O_WRONLY|os.O_CREATE|os.O_APPEND, 0666)
	if err != nil {
		SendError(err, "Failed to open ngrok log file", nil)
		Logger.Println(err)
	} else {
		defer logFile.Close()
		cmd.Stdout = logFile
	}

	go monitorTunnels(url, ngrokLogPath)
	Logger.Println("Starting NAT tunnel")

	runNgrok(cmd)

	for {
		if ScheduledShutdown {
			Logger.Println("Scheduling for shutting down, do not restart the tunnel")
			break
		} else {
			Logger.Println("Restarting NAT tunnel in 10 seconds")
			time.Sleep(10 * time.Second)
			runNgrok(cmd)
		}
	}
}
func getDockerStartOpt(dockerBinPath, keyFilePath, certFilePath, caFilePath string) []string {
	ver := GetDockerClientVersion(dockerBinPath)
	v, err := semver.Make(ver)
	if err != nil {
		Logger.Println("Cannot get semantic version of", ver)
	}
	v1_7, err := semver.Make("1.7.0")
	v1_8, err := semver.Make("1.8.0")

	daemonOpt := "daemon"
	if v.LT(v1_8) {
		daemonOpt = "-d"
	}

	userlandProxyOpt := ""
	if v.GTE(v1_7) {
		userlandProxyOpt = " --userland-proxy=false"
	}

	debugOpt := ""
	if *FlagDebugMode {
		debugOpt = " -D"
	}

	bindOpt := fmt.Sprintf(" -H %s -H %s", DockerDefaultHost, Conf.DockerHost)

	var certOpt string
	if *FlagStandalone && !utils.FileExist(caFilePath) {
		certOpt = fmt.Sprintf(" --tlscert %s --tlskey %s --tls", certFilePath, keyFilePath)
		fmt.Fprintln(os.Stderr, "WARNING: standalone mode activated but no CA certificate found - client authentication disabled")
	} else {
		certOpt = fmt.Sprintf(" --tlscert %s --tlskey %s --tlscacert %s --tlsverify", certFilePath, keyFilePath, caFilePath)
	}

	extraOpt := ""
	if Conf.DockerOpts != "" {
		extraOpt = " " + Conf.DockerOpts
	}

	optStr := fmt.Sprintf("%s%s%s%s%s%s", daemonOpt, debugOpt, bindOpt, userlandProxyOpt, certOpt, extraOpt)

	optSlice, err := shlex.Split(optStr)
	if err != nil {
		optSlice = strings.Split(optStr, " ")
	}
	return optSlice
}
func UpdateDocker(dockerBinPath, dockerNewBinPath, dockerNewBinSigPath, keyFilePath, certFilePath, caFilePath string) {
	if utils.FileExist(dockerNewBinPath) {
		Logger.Printf("New Docker binary (%s) found", dockerNewBinPath)
		Logger.Println("Updating docker...")
		if verifyDockerSig(dockerNewBinPath, dockerNewBinSigPath) {
			Logger.Println("Stopping docker daemon")
			ScheduleToTerminateDocker = true
			StopDocker()
			Logger.Println("Removing old docker binary")
			if err := os.RemoveAll(dockerBinPath); err != nil {
				SendError(err, "Failed to remove the old docker binary", nil)
				Logger.Println("Cannot remove old docker binary:", err)
			}
			Logger.Println("Renaming new docker binary")
			if err := os.Rename(dockerNewBinPath, dockerBinPath); err != nil {
				SendError(err, "Failed to rename the docker binary", nil)
				Logger.Println("Cannot rename docker binary:", err)
			}
			Logger.Println("Removing the signature file", dockerNewBinSigPath)
			if err := os.RemoveAll(dockerNewBinSigPath); err != nil {
				SendError(err, "Failed to remove the docker sig file", nil)
				Logger.Println(err)
			}
			CreateDockerSymlink(dockerBinPath, DockerSymbolicLink)
			ScheduleToTerminateDocker = false
			StartDocker(dockerBinPath, keyFilePath, certFilePath, caFilePath)
			Logger.Println("Docker binary updated successfully")
		} else {
			Logger.Println("Cannot verify signature. Rejecting update")
			Logger.Println("Removing the invalid docker binary", dockerNewBinPath)
			if err := os.RemoveAll(dockerNewBinPath); err != nil {
				SendError(err, "Failed to remove the invalid docker binary", nil)
				Logger.Println(err)
			}
			Logger.Println("Removing the invalid signature file", dockerNewBinSigPath)
			if err := os.RemoveAll(dockerNewBinSigPath); err != nil {
				SendError(err, "Failed to remove the invalid docker sig file", nil)
				Logger.Println(err)
			}
			Logger.Println("Failed to update docker binary")
		}
	}
}
Beispiel #4
0
func PrepareFiles(configFilePath, dockerBinPath, keyFilePath, certFilePath string) {
	Logger.Println("Checking if config file exists")
	if !utils.FileExist(configFilePath) {
		LoadDefaultConf()
		if err := SaveConf(configFilePath, Conf); err != nil {
			SendError(err, "Failed to save config to the conf file", nil)
			Logger.Fatalln(err)
		}
	}

	Logger.Println("Loading Configuration file")
	conf, err := LoadConf(configFilePath)
	if err != nil {
		SendError(err, "Failed to load configuration file", nil)
		Logger.Fatalln("Failed to load configuration file:", err)
	} else {
		Conf = *conf
	}

	if *FlagDockerHost != "" {
		Logger.Printf("Override 'DockerHost' from command line flag: %s\n", *FlagDockerHost)
		Conf.DockerHost = *FlagDockerHost
	}
	if *FlagHost != "" {
		Logger.Printf("Override 'Host' from command line flag: %s\n", *FlagHost)
		Conf.Host = *FlagHost
	}
	if *FlagToken != "" {
		Logger.Printf("Override 'Token' from command line flag: %s\n", *FlagToken)
		Conf.Token = *FlagToken
	}
	if *FlagUUID != "" {
		Logger.Printf("Override 'UUID' from command line flag: %s\n", *FlagUUID)
		Conf.UUID = *FlagUUID
	}
	if *FlagDockerOpts != "" {
		Logger.Printf("Override 'DockerOpts' from command line flag: %s\n", *FlagDockerOpts)
		Conf.DockerOpts = *FlagDockerOpts
	}
}
func DownloadNgrok(url, ngrokBinPath string) {
	if !utils.FileExist(ngrokBinPath) {
		Logger.Println("Downloading NAT tunnel binary ...")
		downloadFile(url, ngrokBinPath, "ngrok")
	}
}
func DownloadDocker(url, dockerBinPath string) {
	if !utils.FileExist(dockerBinPath) {
		Logger.Println("Downloading docker binary...")
		downloadFile(url, dockerBinPath, "docker")
	}
}
Beispiel #7
0
func isCertificateExist(keyFilePath, certFilePath string) (isExist bool) {
	if utils.FileExist(keyFilePath) && utils.FileExist(certFilePath) {
		return true
	}
	return false
}
Beispiel #8
0
func main() {
	dockerBinPath := path.Join(DockerDir, DockerBinaryName)
	dockerNewBinPath := path.Join(DockerDir, DockerNewBinaryName)
	dockerNewBinSigPath := path.Join(DockerDir, DockerNewBinarySigName)
	configFilePath := path.Join(AgentHome, ConfigFileName)
	keyFilePath := path.Join(AgentHome, KeyFileName)
	certFilePath := path.Join(AgentHome, CertFileName)
	caFilePath := path.Join(AgentHome, CAFileName)
	ngrokPath := path.Join(DockerDir, NgrokBinaryName)
	ngrokLogPath := path.Join(LogDir, NgrokLogName)
	ngrokConfPath := path.Join(AgentHome, NgrokConfName)

	_ = os.MkdirAll(AgentHome, 0755)
	_ = os.MkdirAll(DockerDir, 0755)
	_ = os.MkdirAll(LogDir, 0755)

	ParseFlag()

	if *FlagVersion {
		fmt.Println(VERSION)
		return
	}
	SetLogger(path.Join(LogDir, AgentLogFileName))
	Logger.Print("Running dockercloud-agent: version ", VERSION)
	CreatePidFile(AgentPidFile)

	PrepareFiles(configFilePath, dockerBinPath, keyFilePath, certFilePath)
	SetConfigFile(configFilePath)

	regUrl := utils.JoinURL(Conf.Host, RegEndpoint)
	if Conf.UUID == "" {
		os.RemoveAll(keyFilePath)
		os.RemoveAll(certFilePath)
		os.RemoveAll(caFilePath)

		if !*FlagStandalone {
			Logger.Printf("Registering in Docker Cloud via POST: %s", regUrl)
			RegPost(regUrl, caFilePath, configFilePath)
		}
	}

	if *FlagStandalone {
		commonName := Conf.CertCommonName
		if commonName == "" {
			commonName = "*"
		}
		CreateCerts(keyFilePath, certFilePath, commonName)
	} else {
		CreateCerts(keyFilePath, certFilePath, Conf.CertCommonName)
	}

	if utils.FileExist(dockerBinPath) {
		DockerClientVersion = GetDockerClientVersion(dockerBinPath)
	}

	if !*FlagStandalone {
		Logger.Printf("Registering in Docker Cloud via PATCH: %s",
			regUrl+Conf.UUID)
		err := RegPatch(regUrl, caFilePath, certFilePath, configFilePath)
		if err != nil {
			Logger.Printf("PATCH error %s :either UUID (%s) or Token is invalid", err.Error(), Conf.UUID)
			Conf.UUID = ""
			SaveConf(configFilePath, Conf)

			os.RemoveAll(keyFilePath)
			os.RemoveAll(certFilePath)
			os.RemoveAll(caFilePath)

			Logger.Printf("Registering in Docker Cloud via POST: %s", regUrl)
			RegPost(regUrl, caFilePath, configFilePath)

			CreateCerts(keyFilePath, certFilePath, Conf.CertCommonName)
			DownloadDocker(DockerBinaryURL, dockerBinPath)

			Logger.Printf("Registering in Docker Cloud via PATCH: %s",
				regUrl+Conf.UUID)
			if err = RegPatch(regUrl, caFilePath, certFilePath, configFilePath); err != nil {
				SendError(err, "Registion HTTP error", nil)
			}
		}
	}

	if err := SaveConf(configFilePath, Conf); err != nil {
		SendError(err, "Failed to save config to the conf file", nil)
		Logger.Fatalln(err)
	}

	DownloadDocker(DockerBinaryURL, dockerBinPath)
	CreateDockerSymlink(dockerBinPath, DockerSymbolicLink)
	HandleSig()
	syscall.Setpriority(syscall.PRIO_PROCESS, os.Getpid(), RenicePriority)

	Logger.Println("Initializing docker daemon")
	StartDocker(dockerBinPath, keyFilePath, certFilePath, caFilePath)

	if !*FlagStandalone {
		if *FlagSkipNatTunnel {
			Logger.Println("Skip NAT tunnel")
		} else {
			Logger.Println("Loading NAT tunnel module")
			go NatTunnel(regUrl, ngrokPath, ngrokLogPath, ngrokConfPath, Conf.UUID)
		}
	}

	if !*FlagStandalone {
		Logger.Println("Verifying the registration with Docker Cloud")
		go VerifyRegistration(regUrl)
	}

	Logger.Println("Docker server started. Entering maintenance loop")
	for {
		time.Sleep(HeartBeatInterval * time.Second)
		UpdateDocker(dockerBinPath, dockerNewBinPath, dockerNewBinSigPath, keyFilePath, certFilePath, caFilePath)

		// try to restart docker daemon if it dies somehow
		if DockerProcess == nil {
			time.Sleep(HeartBeatInterval * time.Second)
			if DockerProcess == nil && ScheduleToTerminateDocker == false {
				Logger.Println("Respawning docker daemon")
				StartDocker(dockerBinPath, keyFilePath, certFilePath, caFilePath)
			}
		}
	}
}