Ejemplo n.º 1
0
        public async Task <bool> DownloadArtifact(CliParams cliParams, string artifactDownloadUrl, string downloadToPath)
        {
            try
            {
                ConsoleHelper.WriteLine("Downloading build artifact.");

                var message = GetHttpRequestMessage(HttpMethod.Get, artifactDownloadUrl, cliParams);

                var response = await _httpClient.SendAsync(message);

                ConsoleHelper.WriteLine($"Download artifact response status code: {response.StatusCode}");

                if (!response.IsSuccessStatusCode)
                {
                    ConsoleHelper.WriteError("GitHub API call to download build artifact failed.  Please check your input parameters.");
                    Environment.Exit(1);
                }

                using var responseStream = await response.Content.ReadAsStreamAsync();

                using var fileStream = new FileStream(downloadToPath, FileMode.Create);

                await responseStream.CopyToAsync(fileStream);

                return(true);
            }
            catch (Exception ex)
            {
                ConsoleHelper.WriteError($"Error while downloading artifact.  Message: {ex.Message}");
                return(false);
            }
        }
Ejemplo n.º 2
0
        private async Task LaunchExternalInstaller(CliParams cliParams)
        {
            ConsoleHelper.WriteLine("Launching install script for selected reverse proxy type.");
            var resourcesPath = "Remotely.Server.Installer.Resources.";

            var fileName = cliParams.WebServer.Value switch
            {
                WebServerType.UbuntuCaddy => "Ubuntu_Caddy_Install.sh",
                WebServerType.UbuntuNginx => "Ubuntu_Nginx_Install.sh",
                WebServerType.CentOsCaddy => "CentOS_Caddy_Install.sh",
                WebServerType.CentOsNginx => "CentOS_Nginx_Install.sh",
                WebServerType.IisWindows => "IIS_Windows_Install.ps1",
                WebServerType.LinuxNginx => "LinuxArm_Nginx_Install.sh",
                _ => throw new Exception("Unrecognized reverse proxy type."),
            };

            var resourcesFile = resourcesPath + fileName;
            var filePath      = Path.Combine(Path.GetTempPath(), fileName);

            using (var mrs = Assembly.GetExecutingAssembly().GetManifestResourceStream(resourcesFile))
                using (var fileStream = new FileStream(filePath, FileMode.Create))
                {
                    await mrs.CopyToAsync(fileStream);
                }

            var scriptResult = false;
            ProcessStartInfo psi;

            if (cliParams.WebServer.Value == WebServerType.IisWindows)
            {
                psi = new ProcessStartInfo("powershell.exe")
                {
                    Arguments = $"-f \"{filePath}\" -AppPoolName Remotely -SiteName Remotely " +
                                $"-SitePath \"{cliParams.InstallDirectory}\" -HostName {cliParams.ServerUrl.Authority} -Quiet",
                    WorkingDirectory = cliParams.InstallDirectory
                };
            }
            else
            {
                Process.Start("sudo", $"chmod +x {filePath}").WaitForExit();
                psi = new ProcessStartInfo("sudo")
                {
                    Arguments        = $"\"{filePath}\" --host {cliParams.ServerUrl.Authority} --approot {cliParams.InstallDirectory}",
                    WorkingDirectory = cliParams.InstallDirectory
                };
            }

            var proc = Process.Start(psi);

            scriptResult = await Task.Run(() => proc.WaitForExit((int)TimeSpan.FromMinutes(30).TotalMilliseconds));

            if (!scriptResult)
            {
                ConsoleHelper.WriteError("Installer script is taking longer than expected.");
            }
        }
Ejemplo n.º 3
0
        public async Task PerformInstall(CliParams cliParams)
        {
            var latestBuild = await _githubApi.GetLatestBuildArtifact(cliParams);

            var latestBuildId = latestBuild?.id;

            if (cliParams.CreateNew == true)
            {
                var dispatchResult = await _githubApi.TriggerDispatch(cliParams);

                if (!dispatchResult)
                {
                    ConsoleHelper.WriteError("GitHub API call to trigger build action failed.  Do you have " +
                                             "Actions enabled on your forked Remotely repo on the Actions tab?  If not, enable them and try again. " +
                                             "Otherwise, please check your input parameters.");
                    return;
                }

                ConsoleHelper.WriteLine("Build action triggered successfully.  Waiting for build completion.");

                while (latestBuild?.id == latestBuildId)
                {
                    await Task.Delay(TimeSpan.FromMinutes(1));

                    ConsoleHelper.WriteLine("Waiting for GitHub build completion.");
                    latestBuild = await _githubApi.GetLatestBuildArtifact(cliParams);
                }
            }
            else if (latestBuild is null)
            {
                ConsoleHelper.WriteError("There are no existing build artifacts, and --create-new was not specified.  Exiting.");
                return;
            }

            var filePath = Path.Combine(Path.GetTempPath(), "Remotely_Artifact.zip");

            var downloadResult = await _githubApi.DownloadArtifact(cliParams, latestBuild.archive_download_url, filePath);

            if (!downloadResult)
            {
                ConsoleHelper.WriteError("Downloading the build artifact was not successful.");
                return;
            }


            ConsoleHelper.WriteLine("Extracting artifact files.");
            if (Directory.Exists(cliParams.InstallDirectory))
            {
                Directory.Delete(cliParams.InstallDirectory, true);
            }
            Directory.CreateDirectory(cliParams.InstallDirectory);
            ZipFile.ExtractToDirectory(filePath, cliParams.InstallDirectory);

            await LaunchExternalInstaller(cliParams);
        }
Ejemplo n.º 4
0
        public async Task <bool> TriggerDispatch(CliParams cliParams)
        {
            try
            {
                ConsoleHelper.WriteLine("Trigger GitHub Actions build.");


                var message = GetHttpRequestMessage(
                    HttpMethod.Post,
                    $"{_apiHost}/repos/{cliParams.GitHubUsername}/Remotely/actions/workflows/build.yml/dispatches",
                    cliParams);

                var rid = EnvironmentHelper.IsLinux ?
                          "linux-x64" :
                          "win-x64";

                var body = new
                {
                    @ref   = cliParams.Reference,
                    inputs = new
                    {
                        serverUrl = cliParams.ServerUrl.ToString(),
                        rid       = rid
                    }
                };
                message.Content = new StringContent(JsonSerializer.Serialize(body));

                var response = await _httpClient.SendAsync(message);

                ConsoleHelper.WriteLine($"Dispatch response status code: {response.StatusCode}");

                return(response.IsSuccessStatusCode);
            }
            catch (Exception ex)
            {
                ConsoleHelper.WriteError($"Error: {ex.Message}");
            }
            return(false);
        }
Ejemplo n.º 5
0
        public async Task <Artifact> GetLatestBuildArtifact(CliParams cliParams)
        {
            try
            {
                var message = GetHttpRequestMessage(HttpMethod.Get,
                                                    $"{_apiHost}/repos/{cliParams.GitHubUsername}/Remotely/actions/artifacts",
                                                    cliParams);

                var response = await _httpClient.SendAsync(message);

                ConsoleHelper.WriteLine($"Get artifacts response status code: {response.StatusCode}");

                if (!response.IsSuccessStatusCode)
                {
                    ConsoleHelper.WriteError("GitHub API call to get build artifacts failed.  Please check your input parameters.");
                    Environment.Exit(1);
                }

                var payload = await response.Content.ReadFromJsonAsync <ArtifactsResponsePayload>();

                if (payload?.artifacts?.Any() != true)
                {
                    return(null);
                }

                return(payload.artifacts
                       .OrderByDescending(x => x.created_at)
                       .FirstOrDefault(x => x.name.Equals("Server", StringComparison.OrdinalIgnoreCase)));
            }
            catch (Exception ex)
            {
                ConsoleHelper.WriteError("Error while trying to retrieve build artifacts." +
                                         $"Error: {ex.Message}");
                Environment.Exit(1);
            }

            return(null);
        }
Ejemplo n.º 6
0
        private HttpRequestMessage GetHttpRequestMessage(HttpMethod method, string url, CliParams cliParams)
        {
            var message = new HttpRequestMessage(method, url);

            var base64Auth = Convert.ToBase64String(Encoding.UTF8.GetBytes($"{cliParams.GitHubUsername}:{cliParams.GitHubPat}"));

            message.Headers.Authorization = new AuthenticationHeaderValue("Basic", base64Auth);
            message.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/vnd.github.v3+json"));

            return(message);
        }
Ejemplo n.º 7
0
        public async Task PerformInstall(CliParams cliParams)
        {
            var zipPath = Path.Combine(Path.GetTempPath(), "Remotely_Server.zip");

            if (cliParams.UsePrebuiltPackage == true)
            {
                ConsoleHelper.WriteLine("Downloading pre-built server package.");

                int progress = 0;

                var releaseFile = cliParams.WebServer == WebServerType.IisWindows ?
                                  "https://github.com/lucent-sea/Remotely/releases/latest/download/Remotely_Server_Win-x64.zip" :
                                  "https://github.com/lucent-sea/Remotely/releases/latest/download/Remotely_Server_Linux-x64.zip";

                using var webClient = new WebClient();
                webClient.DownloadProgressChanged += (sender, args) =>
                {
                    var newProgress = args.ProgressPercentage / 5 * 5;
                    if (newProgress != progress)
                    {
                        progress = newProgress;
                        ConsoleHelper.WriteLine($"Progress: {progress}%");
                    }
                };
                await webClient.DownloadFileTaskAsync(releaseFile, zipPath);
            }
            else
            {
                var latestBuild = await _githubApi.GetLatestBuildArtifact(cliParams);

                var latestBuildId = latestBuild?.id;

                if (cliParams.CreateNew == true)
                {
                    var dispatchResult = await _githubApi.TriggerDispatch(cliParams);

                    if (!dispatchResult)
                    {
                        ConsoleHelper.WriteError("GitHub API call to trigger build action failed.  Do you have " +
                                                 "Actions enabled on your forked Remotely repo on the Actions tab?  If not, enable them and try again. " +
                                                 "Otherwise, please check your input parameters.");
                        return;
                    }

                    ConsoleHelper.WriteLine("Build action triggered successfully.  Waiting for build completion.");

                    while (latestBuild?.id == latestBuildId)
                    {
                        await Task.Delay(TimeSpan.FromMinutes(1));

                        ConsoleHelper.WriteLine("Waiting for GitHub build completion.");
                        latestBuild = await _githubApi.GetLatestBuildArtifact(cliParams);
                    }
                }
                else if (latestBuild is null)
                {
                    ConsoleHelper.WriteError("There are no existing build artifacts, and --create-new was not specified.  Exiting.");
                    return;
                }

                var downloadResult = await _githubApi.DownloadArtifact(cliParams, latestBuild.archive_download_url, zipPath);

                if (!downloadResult)
                {
                    ConsoleHelper.WriteError("Downloading the build artifact was not successful.");
                    return;
                }
            }

            // Files in use can't be overwritten in Windows.  Stop the
            // website process first.
            if (cliParams.WebServer == WebServerType.IisWindows)
            {
                var initialW3wpCount = Process.GetProcessesByName("w3wp").Length;
                Process.Start("powershell.exe", "-Command & \"{ Stop-WebAppPool -Name Remotely -ErrorAction SilentlyContinue }\"").WaitForExit();
                Process.Start("powershell.exe", "-Command & \"{ Stop-Website -Name Remotely -ErrorAction SilentlyContinue }\"").WaitForExit();
                ConsoleHelper.WriteLine("Waiting for w3wp processes to close...");
                TaskHelper.DelayUntil(() => Process.GetProcessesByName("w3wp").Length < initialW3wpCount, TimeSpan.FromMinutes(5), 100);
            }

            ConsoleHelper.WriteLine("Extracting files.");
            Directory.CreateDirectory(cliParams.InstallDirectory);
            ZipFile.ExtractToDirectory(zipPath, cliParams.InstallDirectory, true);

            await LaunchExternalInstaller(cliParams);
        }
Ejemplo n.º 8
0
        private static bool ParseCliParams(string[] args, out CliParams cliParams)
        {
            cliParams = new CliParams();

            for (var i = 0; i < args.Length; i += 2)
            {
                try
                {
                    var key = args[i].Trim();

                    if (i == args.Length - 1)
                    {
                        ConsoleHelper.WriteError("An argument is missing a value.");
                        return(false);
                    }

                    var value = args[i + 1].Trim();

                    switch (key)
                    {
                    case "--use-prebuilt":
                    case "-b":
                    {
                        if (bool.TryParse(value, out var result))
                        {
                            cliParams.UsePrebuiltPackage = result;
                            continue;
                        }
                        ConsoleHelper.WriteError("--use-prebuilt parameter is invalid.  Must be true or false.");
                        return(false);
                    }

                    case "--web-server":
                    case "-w":
                    {
                        if (int.TryParse(value, out var webServerResult))
                        {
                            cliParams.WebServer = (WebServerType)webServerResult;
                            continue;
                        }
                        ConsoleHelper.WriteError($"--web-server parameter is invalid.  Must be a " +
                                                 $"number (0 - {Enum.GetValues<WebServerType>().Length}).");
                        return(false);
                    }

                    case "--server-url":
                    case "-s":
                    {
                        if (Uri.TryCreate(value, UriKind.Absolute, out var result))
                        {
                            cliParams.ServerUrl = result;
                            continue;
                        }
                        ConsoleHelper.WriteError("--server-url parameter is invalid.  Must be a valid URL (e.g. https://app.remotely.one).");
                        return(false);
                    }

                    case "--install-directory":
                    case "-i":
                        cliParams.InstallDirectory = value;
                        continue;

                    case "--github-username":
                    case "-u":
                        cliParams.GitHubUsername = value;
                        continue;

                    case "--github-pat":
                    case "-p":
                        cliParams.GitHubPat = value;
                        continue;

                    case "--reference":
                    case "-r":
                        cliParams.Reference = value;
                        continue;

                    case "--create-new":
                    case "-c":
                    {
                        if (bool.TryParse(value, out var result))
                        {
                            cliParams.CreateNew = result;
                            continue;
                        }
                        ConsoleHelper.WriteError("--create-new parameter is invalid.  Must be true or false.");
                        return(false);
                    }

                    default:
                        return(false);
                    }
                }
                catch (Exception ex)
                {
                    ConsoleHelper.WriteError($"Error while parsing command line arguments: {ex.Message}");
                    return(false);
                }
            }
            return(true);
        }
Ejemplo n.º 9
0
        public async Task PerformInstall(CliParams cliParams)
        {
            var filePath = Path.Combine(Path.GetTempPath(), "Remotely_Server.zip");

            if (cliParams.UsePrebuiltPackage == true)
            {
                ConsoleHelper.WriteLine("Downloading pre-built server package.");

                var progress    = 0;
                var releaseFile = "https://github.com/lucent-sea/Remotely/releases/latest/download/Remotely_Server_Linux-x64.zip";
                using var webClient = new WebClient();
                webClient.DownloadProgressChanged += (sender, arg) =>
                {
                    var newProgress = arg.ProgressPercentage / 5 * 5;
                    if (newProgress != progress)
                    {
                        progress = newProgress;
                        ConsoleHelper.WriteLine($"Progress: {progress}%");
                    }
                };
                await webClient.DownloadFileTaskAsync(releaseFile, filePath);
            }
            else
            {
                var latestBuild = await _githubApi.GetLatestBuildArtifact(cliParams);

                var latestBuildId = latestBuild?.id;

                if (cliParams.CreateNew == true)
                {
                    var dispatchResult = await _githubApi.TriggerDispatch(cliParams);

                    if (!dispatchResult)
                    {
                        ConsoleHelper.WriteError("GitHub API call to trigger build action failed.  Do you have " +
                                                 "Actions enabled on your forked Remotely repo on the Actions tab?  If not, enable them and try again. " +
                                                 "Otherwise, please check your input parameters.");
                        return;
                    }

                    ConsoleHelper.WriteLine("Build action triggered successfully.  Waiting for build completion.");

                    while (latestBuild?.id == latestBuildId)
                    {
                        await Task.Delay(TimeSpan.FromMinutes(1));

                        ConsoleHelper.WriteLine("Waiting for GitHub build completion.");
                        latestBuild = await _githubApi.GetLatestBuildArtifact(cliParams);
                    }
                }
                else if (latestBuild is null)
                {
                    ConsoleHelper.WriteError("There are no existing build artifacts, and --create-new was not specified.  Exiting.");
                    return;
                }

                var downloadResult = await _githubApi.DownloadArtifact(cliParams, latestBuild.archive_download_url, filePath);

                if (!downloadResult)
                {
                    ConsoleHelper.WriteError("Downloading the build artifact was not successful.");
                    return;
                }
            }


            ConsoleHelper.WriteLine("Extracting files.");
            if (Directory.Exists(cliParams.InstallDirectory))
            {
                Directory.Delete(cliParams.InstallDirectory, true);
            }
            Directory.CreateDirectory(cliParams.InstallDirectory);
            ZipFile.ExtractToDirectory(filePath, cliParams.InstallDirectory);

            await LaunchExternalInstaller(cliParams);
        }