Agents auto-update via downloaded script. Pauses for random seconds based on total device count before downloading (to even out the bandwidth).

This commit is contained in:
Jared Goodwin 2020-01-23 17:43:48 -08:00
parent 372f1e18a0
commit d82da3dea9
10 changed files with 108 additions and 155 deletions

View File

@ -108,11 +108,6 @@ namespace Remotely.Agent
SetWorkingDirectory();
var argDict = ProcessArgs(args);
if (argDict.ContainsKey("update"))
{
Services.GetRequiredService<Updater>().CoreUpdate();
}
if (!IsDebug && OSUtils.IsWindows)
{
_ = Task.Run(() =>

View File

@ -181,7 +181,7 @@ namespace Remotely.Agent.Services
IsServerVerified = true;
if (!Program.IsDebug)
{
Updater.CheckForCoreUpdates();
Task.Run(Updater.CheckForUpdates);
}
}
else

View File

@ -22,52 +22,46 @@ namespace Remotely.Agent.Services
private ConfigService ConfigService { get; }
public void CheckForCoreUpdates()
public async Task CheckForUpdates()
{
try
{
var wc = new WebClient();
var response = new HttpClient().GetAsync(ConfigService.GetConnectionInfo().Host + $"/API/CoreVersion/").Result;
var connectionInfo = ConfigService.GetConnectionInfo();
var response = new HttpClient().GetAsync(connectionInfo.Host + $"/API/AgentUpdate/CurrentVersion").Result;
var latestVersion = response.Content.ReadAsStringAsync().Result;
var thisVersion = FileVersionInfo.GetVersionInfo("Remotely_Agent.dll").FileVersion.ToString().Trim();
if (thisVersion != latestVersion)
{
Logger.Write($"Service Updater: Downloading update. Current Version: {thisVersion}. Latest Version: {latestVersion}.");
var fileName = OSUtils.CoreZipFileName;
var tempFile = Path.Combine(Path.GetTempPath(), fileName);
var tempFolder = Path.Combine(Path.GetTempPath(), "Remotely_Update");
if (File.Exists(tempFile))
{
File.Delete(tempFile);
}
if (Directory.Exists(tempFolder))
{
Directory.Delete(tempFolder, true);
}
wc.DownloadFile(new Uri(ConfigService.GetConnectionInfo().Host + $"/Downloads/{fileName}"), tempFile);
Logger.Write($"Service Updater: Update found. Current Version: {thisVersion}. Latest Version: {latestVersion}.");
Logger.Write($"Service Updater: Extracting files.");
var updateWindow = int.Parse(wc.DownloadString(connectionInfo.Host + $"/API/AgentUpdate/UpdateWindow"));
var waitTime = new Random().Next(1, updateWindow);
Logger.Write($"Waiting {waitTime} seconds before updating.");
await Task.Delay(TimeSpan.FromSeconds(waitTime));
Logger.Write($"Service Updater: Downloading installer.");
if (OSUtils.IsWindows)
{
ZipFile.ExtractToDirectory(tempFile, tempFolder, true);
Logger.Write($"Service Updater: Launching extracted process to perform update.");
var psi = new ProcessStartInfo()
{
FileName = Path.Combine(Path.GetTempPath(), "Remotely_Update", OSUtils.ClientExecutableFileName),
Arguments = "-update true",
Verb = "RunAs"
};
Process.Start(psi);
var filePath = Path.Combine(Path.GetTempPath(), "RemotelyUpdate.ps1");
wc.DownloadFile(
ConfigService.GetConnectionInfo().Host + $"/API/ClientDownloads/{connectionInfo.OrganizationID}/{OSUtils.PlatformString}",
filePath);
Process.Start("powershell.exe", $"-f \"{filePath}\"");
}
else if (OSUtils.IsLinux)
{
Process.Start("sudo", "apt-get install unzip").WaitForExit();
Process.Start("sudo", $"unzip -o {tempFile} -d /usr/local/bin/Remotely/").WaitForExit();
Process.Start("sudo", "chmod +x /usr/local/bin/Remotely/Remotely_Agent").WaitForExit();
Process.Start("sudo", "chmod +x /usr/local/bin/Remotely/ScreenCast/Remotely_ScreenCast.Linux").WaitForExit();
Logger.Write($"Service Updater: Update complete. Restarting service.");
Process.Start("sudo", "systemctl restart remotely-agent");
var filePath = Path.Combine(Path.GetTempPath(), "RemotelyUpdate.sh");
wc.DownloadFile(
ConfigService.GetConnectionInfo().Host + $"/API/ClientDownloads/{connectionInfo.OrganizationID}/{OSUtils.PlatformString}",
filePath);
Process.Start("sudo", $"chmod +x {filePath}").WaitForExit();
Process.Start("sudo", $"{filePath} & disown");
}
}
}
@ -76,108 +70,5 @@ namespace Remotely.Agent.Services
Logger.Write(ex);
}
}
public void CoreUpdate()
{
try
{
Logger.Write("Service Updater: Starting update.");
var ps = PowerShell.Create();
if (OSUtils.IsWindows)
{
ps.AddScript(@"Get-Service | Where-Object {$_.Name -like ""Remotely_Service""} | Stop-Service -Force");
ps.Invoke();
ps.Commands.Clear();
}
else if (OSUtils.IsLinux)
{
Process.Start("sudo", "systemctl stop remotely-agent");
}
foreach (var proc in Process.GetProcesses().Where(x =>
(x.ProcessName.Contains("Remotely_Agent") ||
x.ProcessName.Contains("Remotely_ScreenCast") ||
x.ProcessName.Contains("Remotely_Desktop"))
&& x.Id != Process.GetCurrentProcess().Id))
{
proc.Kill();
}
string targetDir = "";
if (OSUtils.IsWindows)
{
targetDir = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFiles), "Remotely");
}
else if (OSUtils.IsLinux)
{
targetDir = "/usr/local/bin/Remotely";
}
Logger.Write("Service Updater: Copying new files.");
var fileList = Directory.GetFiles(Path.Combine(Path.GetTempPath(), "Remotely_Update"));
foreach (var file in fileList)
{
try
{
var targetPath = Path.Combine(targetDir, Path.GetFileName(file));
File.Copy(file, targetPath, true);
}
catch (Exception ex)
{
Logger.Write(ex);
continue;
}
}
var subdirList = Directory.GetDirectories(Path.Combine(Path.GetTempPath(), "Remotely_Update"));
foreach (var subdir in subdirList)
{
try
{
var targetPath = Path.Combine(targetDir, Path.GetFileName(subdir.TrimEnd(Path.DirectorySeparatorChar)));
if (Directory.Exists(targetPath))
{
Directory.Delete(targetPath, true);
while (Directory.Exists(targetPath))
{
Thread.Sleep(100);
}
}
Directory.Move(subdir, targetPath);
}
catch (Exception ex)
{
Logger.Write(ex);
continue;
}
}
Logger.Write("Service Updater: Update completed.");
}
catch (Exception ex)
{
Logger.Write(ex);
}
finally
{
Logger.Write("Service Updater: Starting service.");
if (OSUtils.IsWindows)
{
var ps = PowerShell.Create();
ps.AddScript("Start-Service -Name \"Remotely_Service\"");
ps.Invoke();
}
else if (OSUtils.IsLinux)
{
Process.Start("sudo", "systemctl restart remotely-agent").WaitForExit();
}
Environment.Exit(0);
}
}
}
}

View File

@ -0,0 +1,41 @@
using Microsoft.AspNetCore.Hosting;
using Microsoft.AspNetCore.Mvc;
using Remotely.Server.Services;
using System;
using System.Diagnostics;
using System.IO;
using System.IO.Compression;
namespace Remotely.Server.API
{
[Route("api/[controller]")]
public class AgentUpdateController : Controller
{
public AgentUpdateController(IWebHostEnvironment hostingEnv, DataService dataService)
{
this.HostingEnv = hostingEnv;
DataService = dataService;
}
private IWebHostEnvironment HostingEnv { get; }
private DataService DataService { get; }
// GET: api/<controller>
[HttpGet("[action]")]
public string CurrentVersion()
{
var filePath = Path.Combine(HostingEnv.ContentRootPath, "CurrentVersion.txt");
if (!System.IO.File.Exists(filePath))
{
return "0.0.0.0";
}
return System.IO.File.ReadAllText(filePath).Trim();
}
[HttpGet("[action]")]
public int UpdateWindow()
{
return DataService.GetDeviceCount() * 10;
}
}
}

View File

@ -28,9 +28,20 @@ namespace Remotely.Server.API
[Authorize]
[HttpGet("{platformID}")]
public ActionResult Get(string platformID)
public async Task<ActionResult> Get(string platformID)
{
var user = DataService.GetUserByName(User.Identity.Name);
return await GetInstallFile(user.OrganizationID, platformID);
}
[HttpGet("{organizationID}/{platformID}")]
public async Task<ActionResult> Get(string organizationID, string platformID)
{
return await GetInstallFile(organizationID, platformID);
}
private async Task<ActionResult> GetInstallFile(string organizationID, string platformID)
{
var fileContents = new List<string>();
string fileName;
byte[] fileBytes;
@ -41,32 +52,32 @@ namespace Remotely.Server.API
{
fileName = $"Install-{platformID}.ps1";
fileContents.AddRange(System.IO.File.ReadAllLines(Path.Combine(HostEnv.WebRootPath, "Downloads", $"{fileName}")));
fileContents.AddRange(await System.IO.File.ReadAllLinesAsync(Path.Combine(HostEnv.WebRootPath, "Downloads", $"{fileName}")));
var hostIndex = fileContents.IndexOf("[string]$HostName = $null");
var orgIndex = fileContents.IndexOf("[string]$Organization = $null");
fileContents[hostIndex] = $"[string]$HostName = \"{Request.Scheme}://{Request.Host}\"";
fileContents[orgIndex] = $"[string]$Organization = \"{user.Organization.ID}\"";
fileContents[orgIndex] = $"[string]$Organization = \"{organizationID}\"";
fileBytes = System.Text.Encoding.UTF8.GetBytes(string.Join(Environment.NewLine, fileContents));
break;
}
case "Linux-x64":
{
fileName = "Install-Linux-x64.sh";
fileContents.AddRange(System.IO.File.ReadAllLines(Path.Combine(HostEnv.WebRootPath, "Downloads", $"{fileName}")));
fileContents.AddRange(await System.IO.File.ReadAllLinesAsync(Path.Combine(HostEnv.WebRootPath, "Downloads", $"{fileName}")));
var hostIndex = fileContents.IndexOf("HostName=");
var orgIndex = fileContents.IndexOf("Organization=");
fileContents[hostIndex] = $"HostName=\"{Request.Scheme}://{Request.Host}\"";
fileContents[orgIndex] = $"Organization=\"{user.Organization.ID}\"";
fileContents[orgIndex] = $"Organization=\"{organizationID}\"";
fileBytes = System.Text.Encoding.UTF8.GetBytes(string.Join("\n", fileContents));
break;
}
default:
return BadRequest();
}

View File

@ -7,6 +7,7 @@ using System.IO.Compression;
namespace Remotely.Server.API
{
// TODO: Delete after a few versions.
[Route("api/[controller]")]
public class CoreVersionController : Controller
{

View File

@ -114,7 +114,7 @@
<strong>Local Install:</strong>
<span data-toggle="modal" data-target="#localInstallInfo" class="fas fa-question-circle pointer"></span>
<br />
<span class="label label-default code">sudo [path]/Install-Linux-x64.sh --path [path]/Remotely-Win10-x86.zip</span>
<span class="label label-default code">sudo [path]/Install-Linux-x64.sh --path [path]/Remotely-Linux.zip</span>
</p>
<p>
<strong>Uninstall:</strong>

View File

@ -129,6 +129,7 @@ namespace Remotely.Server.Services
RemotelyContext.SaveChanges();
return true;
}
public string AddSharedFile(IFormFile file, string organizationID)
{
var expirationDate = DateTime.Now.AddDays(-AppConfig.DataRetentionInDays);
@ -209,6 +210,7 @@ namespace Remotely.Server.Services
RemotelyContext.DeviceGroups.Remove(deviceGroup);
RemotelyContext.SaveChanges();
}
public void DeleteInvite(string requesterUserName, string inviteID)
{
var requester = RemotelyContext.Users
@ -277,6 +279,7 @@ namespace Remotely.Server.Services
.Where(x => x.OrganizationID == orgID)
.OrderByDescending(x => x.TimeStamp);
}
public IEnumerable<Device> GetAllDevicesForUser(string userID)
{
var user = RemotelyContext.Users.FirstOrDefault(x => x.Id == userID);
@ -294,6 +297,7 @@ namespace Remotely.Server.Services
.Where(x => x.OrganizationID == orgID)
.OrderByDescending(x => x.TimeStamp);
}
public ICollection<InviteLink> GetAllInviteLinks(string userName)
{
return RemotelyContext.Users
@ -336,6 +340,10 @@ namespace Remotely.Server.Services
return AppConfig.DefaultPrompt;
}
public int GetDeviceCount()
{
return RemotelyContext.Devices.Count();
}
public Device GetDeviceForUser(string userID, string deviceID)
{
var user = RemotelyContext.Users.FirstOrDefault(x => x.Id == userID);

View File

@ -4,8 +4,6 @@ Organization=
GUID=$(cat /proc/sys/kernel/random/uuid)
systemctl stop remotely-agent
rm -r -f /usr/local/bin/Remotely
rm -f /etc/systemd/system/remotely-agent.service
systemctl daemon-reload
if [ "$1" = "--uninstall" ]; then
@ -27,6 +25,14 @@ apt-get -y install libc6-dev
apt-get -y install libgdiplus
apt-get -y install libxtst-dev
apt-get -y install xclip
apt-get -y install jq
if [ -f "/usr/local/bin/Remotely/ConnectionInfo.json" ]; then
GUID=`cat "/usr/local/bin/Remotely/ConnectionInfo.json" | jq -r '.DeviceID'`
fi
rm -r -f /usr/local/bin/Remotely
rm -f /etc/systemd/system/remotely-agent.service
mkdir -p /usr/local/bin/Remotely/
cd /usr/local/bin/Remotely/

View File

@ -56,7 +56,7 @@ namespace Remotely.Shared.Services
}
}
public static string CoreZipFileName
public static string PlatformString
{
get
{
@ -64,17 +64,17 @@ namespace Remotely.Shared.Services
{
if (Environment.Is64BitOperatingSystem)
{
return "Remotely-Win10-x64.zip";
return "Win10-x64";
}
else
{
return "Remotely-Win10-x86.zip";
return "Win10-x86";
}
}
else if (OSUtils.IsLinux)
else if (IsLinux)
{
return "Remotely-Linux.zip";
return "Linux-x64";
}
else
{