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") } } }
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") } }
func isCertificateExist(keyFilePath, certFilePath string) (isExist bool) { if utils.FileExist(keyFilePath) && utils.FileExist(certFilePath) { return true } return false }
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) } } } }