func ProxyServer(ws *websocket.Conn) {
	cloudoneProtocol := beego.AppConfig.String("cloudoneProtocol")
	cloudoneHost := beego.AppConfig.String("cloudoneHost")
	cloudonePort := beego.AppConfig.String("cloudonePort")

	parameterMap := ws.Request().URL.Query()
	widthSlice := parameterMap["width"]
	heightSlice := parameterMap["height"]
	hostIPSlice := parameterMap["hostIP"]
	containerIDSlice := parameterMap["containerID"]
	tokenSlice := parameterMap["token"]

	if len(widthSlice) != 1 {
		errorMessage := "Parameter width is incorrect"
		ws.Write([]byte(errorMessage))
		ws.Close()
		return
	}
	width, err := strconv.Atoi(widthSlice[0])
	if err != nil {
		errorMessage := "Format of parameter width is incorrect"
		ws.Write([]byte(errorMessage))
		ws.Close()
		return
	}

	if len(heightSlice) != 1 {
		errorMessage := "Parameter height is incorrect"
		ws.Write([]byte(errorMessage))
		ws.Close()
		return
	}
	height, err := strconv.Atoi(heightSlice[0])
	if err != nil {
		errorMessage := "Format of parameter height is incorrect"
		ws.Write([]byte(errorMessage))
		ws.Close()
		return
	}

	if len(hostIPSlice) != 1 {
		errorMessage := "Parameter hostIP is incorrect"
		ws.Write([]byte(errorMessage))
		ws.Close()
		return
	}
	hostIP := hostIPSlice[0]

	if len(containerIDSlice) != 1 {
		errorMessage := "Parameter containerID is incorrect"
		ws.Write([]byte(errorMessage))
		ws.Close()
		return
	}
	containerID := containerIDSlice[0]
	// Remove docker protocol prefix docker://
	containerID = containerID[9:]

	if len(tokenSlice) != 1 {
		errorMessage := "Parameter token is incorrect"
		ws.Write([]byte(errorMessage))
		ws.Close()
		return
	}
	token := tokenSlice[0]
	headerMap := make(map[string]string)
	headerMap["token"] = token

	url := cloudoneProtocol + "://" + cloudoneHost + ":" + cloudonePort +
		"/api/v1/hosts/credentials/" + hostIP

	credential := Credential{}

	_, err = restclient.RequestGetWithStructure(url, &credential, headerMap)

	if identity.IsTokenInvalid(err) {
		ws.Write([]byte(err.Error()))
		ws.Close()
		return
	}

	if err != nil {
		ws.Write([]byte(err.Error()))
		ws.Close()
		return
	}

	interactiveMap := make(map[string]string)
	interactiveMap["[sudo]"] = credential.SSH.Password + "\n"
	interactiveMap["exit"] = "exit\n"

	// Command way
	sshCommandProxy := sshclient.CreateSSHCommandProxy(
		2*time.Second,
		credential.IP,
		credential.SSH.Port,
		credential.SSH.User,
		credential.SSH.Password,
		height,
		width,
		interactiveMap)
	i, o, _, err := sshCommandProxy.Connect()

	if err != nil {
		ws.Write([]byte(err.Error()))
		ws.Close()
		return
	}

	i <- "sudo docker exec -it " + containerID + " bash\n"

	go func() {
		for {
			data, ok := <-o
			if ok == false {
				break
			} else {
				ws.Write([]byte(data))
			}
		}
		ws.Close()
	}()

	for {
		data, _, err := ioutility.ReadText(ws, 256)
		if err == io.EOF {
			break
		} else if err != nil {
			ws.Write([]byte(err.Error()))
			break
		}

		i <- data
	}
	ws.Close()
	sshCommandProxy.Disconnect()

	// Stream way
	/*
		sshStreamProxy := sshclient.CreateSSHStreamProxy(
			2*time.Second,
			credential.IP,
			credential.SSH.Port,
			credential.SSH.User,
			credential.SSH.Password,
			height,
			width)
		w, r, _, err := sshStreamProxy.Connect()

		if err != nil {
			ws.Write([]byte(err.Error()))
			ws.Close()
			return
		}

		w.Write([]byte("sudo docker exec -it " + containerID + " bash\n"))
		w.Write([]byte(credential.SSH.Password + "\n"))

		go func() {
			// Cancatenate ssh reader to websocket writer
			io.Copy(ws, r)

			ws.Close()
		}()

		// Cancatenate websocket reader to ssh writer
		io.Copy(w, ws)

		ws.Close()
		sshStreamProxy.Disconnect()
	*/
}
Example #2
0
func ProxyServer(ws *websocket.Conn) {
	cloudoneProtocol := beego.AppConfig.String("cloudoneProtocol")
	cloudoneHost := beego.AppConfig.String("cloudoneHost")
	cloudonePort := beego.AppConfig.String("cloudonePort")
	cloudoneAnalysisProtocol := beego.AppConfig.String("cloudoneAnalysisProtocol")
	cloudoneAnalysisHost := beego.AppConfig.String("cloudoneAnalysisHost")
	cloudoneAnalysisPort := beego.AppConfig.String("cloudoneAnalysisPort")

	parameterMap := ws.Request().URL.Query()
	upgradeCloudone := getParameter(parameterMap, "upgradeCloudone")
	upgradeCloudoneImagePath := getParameter(parameterMap, "upgradeCloudoneImagePath")
	upgradeCloudoneVersion := getParameter(parameterMap, "upgradeCloudoneVersion")
	upgradeCloudoneGUI := getParameter(parameterMap, "upgradeCloudoneGUI")
	upgradeCloudoneGUIImagePath := getParameter(parameterMap, "upgradeCloudoneGUIImagePath")
	upgradeCloudoneGUIVersion := getParameter(parameterMap, "upgradeCloudoneGUIVersion")
	upgradeCloudoneAnalysis := getParameter(parameterMap, "upgradeCloudoneAnalysis")
	upgradeCloudoneAnalysisImagePath := getParameter(parameterMap, "upgradeCloudoneAnalysisImagePath")
	upgradeCloudoneAnalysisVersion := getParameter(parameterMap, "upgradeCloudoneAnalysisVersion")
	upgradeTopologyConfiguration := getParameter(parameterMap, "upgradeTopologyConfiguration")
	upgradeNamespace := getParameter(parameterMap, "upgradeNamespace")
	upgradeReplicationControllerName := getParameter(parameterMap, "upgradeReplicationControllerName")
	upgradeReplicationControllerContent := getParameter(parameterMap, "upgradeReplicationControllerContent")
	upgradeServiceName := getParameter(parameterMap, "upgradeServiceName")
	upgradeServiceContent := getParameter(parameterMap, "upgradeServiceContent")
	httpsCertFileContent := getParameter(parameterMap, "httpsCertFile")
	httpsKeyFileContent := getParameter(parameterMap, "httpsKeyFile")

	token := getParameter(parameterMap, "token")
	headerMap := make(map[string]string)
	headerMap["token"] = token

	// Configre certificate
	certificateChanged, err := configureCertificate(ws, httpsCertFileContent, httpsKeyFileContent)
	if err != nil {
		errorMessage := "Configure certificates with error " + err.Error() + "\n"
		ws.Write([]byte(errorMessage))
		ws.Close()
		return
	}
	if certificateChanged {
		upgradeCloudoneGUI = "true"
	}

	replicationControllerJsonMap := make(map[string]interface{})
	serviceJsonMap := make(map[string]interface{})
	if upgradeTopologyConfiguration == "true" {
		if upgradeReplicationControllerContent != "" {
			err := json.Unmarshal([]byte(upgradeReplicationControllerContent), &replicationControllerJsonMap)
			if err != nil {
				errorMessage := "Can't unmarshal upgradeReplicationControllerContent with error " + err.Error() + "\n"
				ws.Write([]byte(errorMessage))
				ws.Close()
				return
			}
		}
		if upgradeServiceContent != "" {
			err := json.Unmarshal([]byte(upgradeServiceContent), &serviceJsonMap)
			if err != nil {
				errorMessage := "Can't unmarshal upgradeServiceContent with error " + err.Error() + "\n"
				ws.Write([]byte(errorMessage))
				ws.Close()
				return
			}
		}
	}

	// Get credential
	url := cloudoneProtocol + "://" + cloudoneHost + ":" + cloudonePort +
		"/api/v1/hosts/credentials/"

	credentialSlice := make([]Credential, 0)

	_, err = restclient.RequestGetWithStructure(url, &credentialSlice, headerMap)

	if identity.IsTokenInvalid(err) {
		ws.Write([]byte(err.Error()))
		ws.Close()
		return
	}

	if err != nil {
		errorMessage := "Can't get credential data with error " + err.Error() + "\n"
		ws.Write([]byte(errorMessage))
		ws.Close()
		return
	}

	// Pull images
	if upgradeCloudone == "true" {
		err := UpgradeDockerImage(ws, credentialSlice, upgradeCloudoneImagePath, upgradeCloudoneVersion)
		if err != nil {
			errorMessage := "Can't upgrade image cloudone with error " + err.Error() + "\n"
			ws.Write([]byte(errorMessage))
			ws.Close()
			return
		}
	}

	if upgradeCloudoneGUI == "true" {
		err := UpgradeDockerImage(ws, credentialSlice, upgradeCloudoneGUIImagePath, upgradeCloudoneGUIVersion)
		if err != nil {
			errorMessage := "Can't upgrade image cloudone gui with error " + err.Error() + "\n"
			ws.Write([]byte(errorMessage))
			ws.Close()
			return
		}
	}

	if upgradeCloudoneAnalysis == "true" {
		err := UpgradeDockerImage(ws, credentialSlice, upgradeCloudoneAnalysisImagePath, upgradeCloudoneAnalysisVersion)
		if err != nil {
			errorMessage := "Can't upgrade image cloudone analysis with error " + err.Error() + "\n"
			ws.Write([]byte(errorMessage))
			ws.Close()
			return
		}
	}

	// Update service
	if len(serviceJsonMap) > 0 {
		url := cloudoneProtocol + "://" + cloudoneHost + ":" + cloudonePort +
			"/api/v1/services/json/" + upgradeNamespace + "/" + upgradeReplicationControllerName

		ws.Write([]byte("Start to update service\n"))

		_, err := restclient.RequestPutWithStructure(url, serviceJsonMap, nil, headerMap)

		if identity.IsTokenInvalid(err) {
			ws.Write([]byte(err.Error()))
			ws.Close()
			return
		}

		if err != nil {
			errorMessage := "Can't upgrade service with error " + err.Error() + "\n"
			ws.Write([]byte(errorMessage))
			ws.Close()
			return
		} else {
			ws.Write([]byte("The service is updated\n"))
		}
	}

	if len(replicationControllerJsonMap) > 0 {
		// Update replication controller to change all instances
		url := cloudoneProtocol + "://" + cloudoneHost + ":" + cloudonePort +
			"/api/v1/replicationcontrollers/json/" + upgradeNamespace + "/" + upgradeServiceName

		ws.Write([]byte("Stop and recreate the replication controller. Please refresh the page after tens of seconds\n"))

		_, err := restclient.RequestPutWithStructure(url, replicationControllerJsonMap, nil, headerMap)

		if identity.IsTokenInvalid(err) {
			ws.Write([]byte(err.Error()))
			ws.Close()
			return
		}

		if err != nil {
			errorMessage := "Can't upgrade replication controller with error " + err.Error() + "\n"
			ws.Write([]byte(errorMessage))
			ws.Close()
			return
		} else {
			ws.Write([]byte("The replication controller is updated\n"))
		}
	} else {
		// Only update the specific docker containers
		url := cloudoneProtocol + "://" + cloudoneHost + ":" + cloudonePort +
			"/api/v1/replicationcontrollers/" + upgradeNamespace

		replicationControllerAndRelatedPodSlice := make([]ReplicationControllerAndRelatedPod, 0)
		_, err := restclient.RequestGetWithStructure(url, &replicationControllerAndRelatedPodSlice, headerMap)

		if identity.IsTokenInvalid(err) {
			ws.Write([]byte(err.Error()))
			ws.Close()
			return
		}

		if err != nil {
			errorMessage := "Can't get replication controller and related pod data with error " + err.Error() + "\n"
			ws.Write([]byte(errorMessage))
			ws.Close()
			return
		}
		selectedReplicationControllerAndRelatedPod := ReplicationControllerAndRelatedPod{}
		for _, replicationControllerAndRelatedPod := range replicationControllerAndRelatedPodSlice {
			if replicationControllerAndRelatedPod.Name == upgradeReplicationControllerName {
				selectedReplicationControllerAndRelatedPod = replicationControllerAndRelatedPod
			}
		}

		for _, pod := range selectedReplicationControllerAndRelatedPod.PodSlice {
			usedCredential := Credential{}
			for _, credential := range credentialSlice {
				if credential.IP == pod.HostIP {
					usedCredential = credential
					break
				}
			}

			cloudoneContainer := PodContainer{}
			cloudoneAnalysisContainer := PodContainer{}
			cloudoneGUIContainer := PodContainer{}

			for _, container := range pod.ContainerSlice {
				if container.Name == "cloudone" {
					cloudoneContainer = container
				}
				if container.Name == "cloudone-analysis" {
					cloudoneAnalysisContainer = container
				}
				if container.Name == "cloudone-gui" {
					cloudoneGUIContainer = container
				}
			}

			if upgradeCloudone == "true" && cloudoneContainer.ContainerID != "" {
				containerID := cloudoneContainer.ContainerID[9:]
				ws.Write([]byte("Stop and recreate cloudone\n"))
				err := stopDockerContainer(usedCredential, containerID)
				if err != nil {
					errorMessage := "Can't stop container " + cloudoneContainer.Name + " with error " + err.Error() + "\n"
					ws.Write([]byte(errorMessage))
					ws.Close()
					return
				}
			}
			if upgradeCloudoneAnalysis == "true" && cloudoneAnalysisContainer.ContainerID != "" {
				containerID := cloudoneAnalysisContainer.ContainerID[9:]
				ws.Write([]byte("Stop and recreate cloudone_analysis\n"))
				err := stopDockerContainer(usedCredential, containerID)
				if err != nil {
					errorMessage := "Can't stop container " + cloudoneAnalysisContainer.Name + " with error " + err.Error() + "\n"
					ws.Write([]byte(errorMessage))
					ws.Close()
					return
				}
			}
			if upgradeCloudoneGUI == "true" && cloudoneGUIContainer.ContainerID != "" {
				containerID := cloudoneGUIContainer.ContainerID[9:]
				ws.Write([]byte("Stop and recreate cloudone_gui. Please refresh the page after tens of seconds\n"))
				err := stopDockerContainer(usedCredential, containerID)
				if err != nil {
					errorMessage := "Can't stop container " + cloudoneGUIContainer.Name + " with error " + err.Error() + "\n"
					ws.Write([]byte(errorMessage))
					ws.Close()
					return
				}
			}
		}

		if upgradeCloudone == "true" {
			url := cloudoneProtocol + "://" + cloudoneHost + ":" + cloudonePort +
				"/api/v1/healthchecks/"
			cloudoneJsonMap := make(map[string]interface{}, 0)
			for {
				time.Sleep(time.Second)
				_, err := restclient.RequestGetWithStructure(url, &cloudoneJsonMap, headerMap)

				if identity.IsTokenInvalid(err) {
					ws.Write([]byte(err.Error()))
					ws.Close()
					return
				}

				if err == nil {
					break
				} else {
					ws.Write([]byte("Wait for Cloudone to come up\n"))
				}
			}
		}

		if upgradeCloudoneAnalysis == "true" {
			url := cloudoneAnalysisProtocol + "://" + cloudoneAnalysisHost + ":" + cloudoneAnalysisPort +
				"/api/v1/healthchecks/"
			cloudoneAnalysisJsonMap := make(map[string]interface{}, 0)
			for {
				time.Sleep(time.Second)
				_, err := restclient.RequestGetWithStructure(url, &cloudoneAnalysisJsonMap, headerMap)

				if identity.IsTokenInvalid(err) {
					ws.Write([]byte(err.Error()))
					ws.Close()
					return
				}

				if err == nil {
					break
				} else {
					ws.Write([]byte("Wait for Cloudone Analysis to come up\n"))
				}
			}
		}
	}

	ws.Write([]byte("Upgrade is done\n"))

	ws.Close()
}