func RunInstallCommands()

in agent/plugins/configurecontainers/windowscontainerutil/windowscontainerutil.go [43:307]


func RunInstallCommands(context context.T, orchestrationDirectory string, out iohandler.IOHandler) {
	var err error
	var command string
	var platformVersion string
	var parameters []string
	var requireReboot bool

	var isNanoServer bool
	var output string

	log := context.Log()
	platformVersion, err = dep.PlatformVersion(log)
	if err != nil {
		log.Error("Error detecting platform version", err)
		out.MarkAsFailed(fmt.Errorf("Error detecting platform version: %v", err))
		return
	}
	log.Debug("Platform Version:", platformVersion)
	if !strings.HasPrefix(platformVersion, "10") {
		out.MarkAsFailed(errors.New("ConfigureDocker is only supported on Microsoft Windows Server 2016 and above."))
		return
	}

	isNanoServer, err = dep.IsPlatformNanoServer(log)
	if err != nil {
		log.Error("Error detecting if Nano Server", err)
		out.MarkAsFailed(fmt.Errorf("Error detecting if Nano Server: %v", err))
		return
	}
	if isNanoServer {
		command = "(Get-PackageProvider -ListAvailable).Name"
		parameters = make([]string, 0)
		output, err = dep.UpdateUtilExeCommandOutput(context, 120, log, command, parameters, "", "", "", "", true)
		if err != nil {
			log.Error("Error getting package providers", err)
			out.MarkAsFailed(fmt.Errorf("Error getting package providers: %v", err))
			return
		}
		log.Debug("Get-PackageProvider output:", output)
		packageInstalled := strings.Contains(output, "NanoServerPackage")

		if !packageInstalled {
			out.AppendInfo("Installing Nano Server package provider.")
			command = `Install-PackageProvider -Name Nuget -MinimumVersion 2.8.5.201 -Force`
			parameters = make([]string, 0)
			output, err = dep.UpdateUtilExeCommandOutput(context, 60, log, command, parameters, "", "", "", "", true)
			if err != nil {
				log.Error("Error installing Nuget package provider", err)
				out.MarkAsFailed(fmt.Errorf("Error installing Nuget package provider: %v", err))
				return
			}
			log.Debug("Install Package provider output:", output)

			command = `Save-Module -Path "$env:programfiles\WindowsPowerShell\Modules\" -Name NanoServerPackage -minimumVersion 1.0.1.0`
			parameters = make([]string, 0)
			output, err = dep.UpdateUtilExeCommandOutput(context, 60, log, command, parameters, "", "", "", "", true)
			if err != nil {
				log.Error("Error saving module", err)
				out.MarkAsFailed(fmt.Errorf("Error saving Nano server package: %v", err))
				return
			}
			log.Debug("Save-Module output:", output)

			command = `Import-PackageProvider NanoServerPackage`
			parameters = make([]string, 0)
			output, err = dep.UpdateUtilExeCommandOutput(context, 30, log, command, parameters, "", "", "", "", true)
			if err != nil {
				log.Error("Error importing package", err)
				out.MarkAsFailed(fmt.Errorf("Error importing package: %v", err))
				return
			}
			log.Debug("Import-PackageProvider output:", output)
		}

		//Install containers package
		command = "(Get-Package -providername NanoServerPackage).Name"
		parameters = make([]string, 0)
		output, err = dep.UpdateUtilExeCommandOutput(context, 30, log, command, parameters, "", "", "", "", true)
		if err != nil {
			log.Error("Error getting microsoft-nanoserver-containers-package", err)
			out.MarkAsFailed(fmt.Errorf("Error getting microsoft-nanoserver-containers-package: %v", err))
			return
		}
		log.Debug("Get-Package output:", output)
		packageInstalled = strings.Contains(output, "Microsoft-NanoServer-Containers-Package")

		if !packageInstalled {
			out.AppendInfo("Installing containers package.")
			command = "Install-NanoServerPackage microsoft-nanoserver-containers-package"
			parameters = make([]string, 0)
			output, err = dep.UpdateUtilExeCommandOutput(context, 30, log, command, parameters, "", "", "", "", true)
			if err != nil {
				log.Error("Error installing microsoft-nanoserver-containers-package", err)
				out.MarkAsFailed(fmt.Errorf("Error installing microsoft-nanoserver-containers-package: %v", err))
				return
			}
			log.Debug("Install-NanoServerPackage output:", output)
			requireReboot = true
		}
	} else {
		//install windows containers feature
		command = "(Get-WindowsFeature -Name containers).Installed"
		parameters = make([]string, 0)
		output, err = dep.UpdateUtilExeCommandOutput(context, 30, log, command, parameters, "", "", "", "", true)
		if err != nil {
			log.Error("Error getting containers feature", err)
			out.MarkAsFailed(fmt.Errorf("Error getting containers feature: %v", err))
			return
		}
		log.Debug("Get-WindowsFeature output:", output)
		packageInstalled := strings.Contains(output, "True")

		if !packageInstalled {
			out.AppendInfo("Installing Windows containers feature.")
			command = "(Install-WindowsFeature -Name containers).RestartNeeded"
			parameters = make([]string, 0)
			output, err = dep.UpdateUtilExeCommandOutput(context, 30, log, command, parameters, "", "", "", "", true)
			if err != nil {
				log.Error("Error installing Windows containers feature", err)
				out.MarkAsFailed(fmt.Errorf("Error installing Windows containers feature: %v", err))
				return
			}
			log.Debug("Install-WindowsFeature output:", output)
			requireReboot = strings.Contains(output, "Yes")
		}
	}

	//Create docker config if it does not exist
	daemonConfigPath := PROGRAM_DATA_DIRECTORY + "\\docker\\config\\daemon.json"
	daemonConfigContent := `{}`

	if err := dep.SetDaemonConfig(daemonConfigPath, daemonConfigContent); err != nil {
		log.Error("Error writing Docker daemon config file", err)
		out.MarkAsFailed(fmt.Errorf("Error writing Docker daemon config file: %v", err))
		return
	}

	//Download docker
	var downloadOutput artifact.DownloadOutput
	downloadOutput, err = dep.ArtifactDownload(context, artifact.DownloadInput{SourceURL: DOCKER_DOWNLOAD_URL, DestinationDirectory: appconfig.DownloadRoot})
	if err != nil {
		log.Errorf("Failed to download Docker Engine file from %v: %v", DOCKER_DOWNLOAD_URL, err)
		out.MarkAsFailed(fmt.Errorf("Failed to download Docker Engine file from %v: %v", DOCKER_DOWNLOAD_URL, err))
		return
	}
	log.Debugf("Zip file downloaded to %v", downloadOutput.LocalFilePath)

	_, installedErr := os.Stat(DOCKER_INSTALLED_DIRECTORY)
	if downloadOutput.IsUpdated || installedErr != nil {
		out.AppendInfo("Unzipping Docker to program files directory.")
		//uncompress docker zip
		fileutil.Uncompress(log, downloadOutput.LocalFilePath, PROGRAM_FILES_DIRECTORY)
	}

	// delete downloaded file, if it exists
	pluginutil.CleanupFile(log, downloadOutput.LocalFilePath)

	//Set this process's path environment variable to include Docker
	if !strings.Contains(strings.ToLower(os.Getenv("path")), strings.ToLower(DOCKER_INSTALLED_DIRECTORY)) {
		out.AppendInfo("Setting process path variable to include docker directory")
		//set envvariable for this process
		os.Setenv("path", DOCKER_INSTALLED_DIRECTORY+";"+os.Getenv("path"))

	}
	log.Debug("Path set to ", os.Getenv("path"))

	//set path env variable for machine to include Docker
	var currentSystemPathValue string
	currentSystemPathValue, _, err = dep.LocalRegistryKeyGetStringValue(`System\CurrentControlSet\Control\Session Manager\Environment`, "Path")
	if err != nil {
		log.Error("Error getting current machine registry key value", err)
		out.MarkAsFailed(fmt.Errorf("Error getting current machine registry key value: %v", err))
		return
	}
	log.Debug("System Path set to ", currentSystemPathValue)
	if !strings.Contains(strings.ToLower(currentSystemPathValue), strings.ToLower(DOCKER_INSTALLED_DIRECTORY)) {
		out.AppendInfo("Setting machine path variable to include docker directory")
		command = "setx"
		parameters = []string{"-m", "path", os.Getenv("path")}
		var setPathOutput string
		setPathOutput, err = dep.UpdateUtilExeCommandOutput(context, 10, log, command, parameters, "", "", "", "", false)
		if err != nil {
			log.Error("Error setting machine path environment variable", err)
			out.MarkAsFailed(fmt.Errorf("Error setting machine path environment variable: %v", err))
			return
		}
		log.Debug("setx path output:", setPathOutput)
	}

	//reboot if needed
	if requireReboot {
		out.AppendInfo("Rebooting machine to complete install")
		log.Debug("require reboot is true")
		out.SetStatus(contracts.ResultStatusSuccessAndReboot)
		return
	}

	//Check if docker daemon registered
	var dockerServiceStatusOutput string
	command = "(Get-Service docker).Status"
	parameters = make([]string, 0)
	dockerServiceStatusOutput, err = dep.UpdateUtilExeCommandOutput(context, 120, log, command, parameters, "", "", "", "", true)
	if err != nil {
		log.Error("Error getting Docker service status", err)
		out.MarkAsFailed(fmt.Errorf("Error getting Docker service status: %v", err))
		return
	}
	log.Debug("Get-Service output:", dockerServiceStatusOutput)

	ServiceRunning := strings.HasPrefix(dockerServiceStatusOutput, "Running")

	//Register Service
	if len(strings.TrimSpace(dockerServiceStatusOutput)) == 0 {
		out.AppendInfo("Registering dockerd.")

		command = `dockerd`
		log.Debug("dockerd cmd:", command)
		parameters = []string{"--register-service"}
		dockerServiceStatusOutput, err = dep.UpdateUtilExeCommandOutput(context, 120, log, command, parameters, DOCKER_INSTALLED_DIRECTORY, "", "", "", false)
		if err != nil {
			log.Error("Error registering Docker service", err)
			out.MarkAsFailed(fmt.Errorf("Error registering Docker service: %v", err))
			return
		}
		log.Debug("dockerd output:", dockerServiceStatusOutput)
		//set service to delayed start
		out.AppendInfo("set dockerd service configuration.")
		command = "sc.exe"
		parameters = []string{"config", "docker", "start=delayed-auto"}
		dockerServiceStatusOutput, err = dep.UpdateUtilExeCommandOutput(context, 10, log, command, parameters, "", "", "", "", false)
		if err != nil {
			log.Error("Error setting delayed start for Docker service", err)
			out.MarkAsFailed(fmt.Errorf("Error setting delayed start for Docker service: %v", err))
			return
		}
		log.Debug("sc output:", dockerServiceStatusOutput)
		//sleep 10 sec after registering
		time.Sleep(10 * time.Second)
	}
	err = dep.LocalRegistryKeySetDWordValue(`SYSTEM\CurrentControlSet\services\docker`, "AutoStartDelay", 240)
	if err != nil {
		log.Error("Error opening registry key to set Docker delayed start", err)
		out.MarkAsFailed(fmt.Errorf("Error opening registry key to set Docker delayed start: %v", err))
		return
	}

	//Start service
	if !ServiceRunning {
		out.AppendInfo("Starting Docker service.")
		command = "Start-Service docker"
		parameters = make([]string, 0)
		dockerServiceStatusOutput, err = dep.UpdateUtilExeCommandOutput(context, 300, log, command, parameters, "", "", "", "", true)
		if err != nil {

			log.Error("Error starting Docker service", err)
			out.MarkAsFailed(fmt.Errorf("Error starting Docker service: %v", err))
			return
		}
		log.Debug("start-service output:", dockerServiceStatusOutput)
	}
	out.AppendInfo("Installation complete")
	log.Debug("require reboot:", requireReboot)
	out.SetStatus(contracts.ResultStatusSuccess)
	return
}