Exemplo n.º 1
0
        private async Task<SiteExtensionInfo> TryInstallExtension(string id, string version, string feedUrl, SiteExtensionInfo.SiteExtensionType type, ITracer tracer)
        {
            SiteExtensionInfo info = null;
            HttpStatusCode status = HttpStatusCode.OK;  // final status when success
            bool alreadyInstalled = false;

            if (_preInstalledExtensionDictionary.ContainsKey(id))
            {
                tracer.Trace("Pre-installed site extension found: {0}, not going to perform new installation.", id);
                info = EnablePreInstalledExtension(_preInstalledExtensionDictionary[id], tracer);
                alreadyInstalled = true;
            }
            else
            {
                try
                {
                    // Check if site extension already installed (id, version, feedUrl), if already install return right away
                    if (await this.IsSiteExtensionInstalled(id, version, feedUrl))
                    {
                        // package already installed, return package from local repo.
                        tracer.Trace("Package {0} with version {1} from {2} already installed.", id, version, feedUrl);
                        info = await GetLocalExtension(id);
                        alreadyInstalled = true;
                    }
                    else
                    {
                        JsonSettings siteExtensionSettings = GetSettingManager(id);
                        feedUrl = (string.IsNullOrEmpty(feedUrl) ? siteExtensionSettings.GetValue(_feedUrlSetting) : feedUrl);
                        SourceRepository remoteRepo = GetRemoteRepository(feedUrl);
                        UIPackageMetadata localPackage = null;
                        UIPackageMetadata repoPackage = null;

                        if (this.IsInstalledToWebRoot(id))
                        {
                            // override WebRoot type from setting
                            // WebRoot is a special type that install package to wwwroot, when perform update we need to update new content to wwwroot even if type is not specified
                            type = SiteExtensionInfo.SiteExtensionType.WebRoot;
                        }

                        if (string.IsNullOrWhiteSpace(version))
                        {
                            using (tracer.Step("Version is null, search latest package by id: {0}, will not search for unlisted package.", id))
                            {
                                repoPackage = await remoteRepo.GetLatestPackageById(id);
                            }
                        }
                        else
                        {
                            using (tracer.Step("Search package by id: {0} and version: {1}, will also search for unlisted package.", id, version))
                            {
                                repoPackage = await remoteRepo.GetPackageByIdentity(id, version);
                            }
                        }

                        if (repoPackage != null)
                        {
                            using (tracer.Step("Install package: {0}.", id))
                            {
                                string installationDirectory = GetInstallationDirectory(id);
                                localPackage = await InstallExtension(repoPackage, installationDirectory, feedUrl, type, tracer);
                                siteExtensionSettings.SetValues(new KeyValuePair<string, JToken>[] {
                                    new KeyValuePair<string, JToken>(_versionSetting, localPackage.Identity.Version.ToNormalizedString()),
                                    new KeyValuePair<string, JToken>(_feedUrlSetting, feedUrl),
                                    new KeyValuePair<string, JToken>(_installUtcTimestampSetting, DateTime.UtcNow.ToString("u")),
                                    new KeyValuePair<string, JToken>(_packageType, Enum.GetName(typeof(SiteExtensionInfo.SiteExtensionType), type))
                                });
                            }
                        }

                        info = await ConvertLocalPackageToSiteExtensionInfo(localPackage, checkLatest: true, tracer: tracer);
                    }
                }
                catch (FileNotFoundException ex)
                {
                    _analytics.UnexpectedException(
                        ex,
                        method: "PUT",
                        path: string.Format(CultureInfo.InvariantCulture, "/api/siteextensions/{0}", id),
                        result: Constants.SiteExtensionProvisioningStateFailed,
                        message: string.Format(CultureInfo.InvariantCulture, "{{\"version\": {0}, \"feed_url\": {1}}}", version, feedUrl),
                        trace: false);

                    tracer.TraceError(ex);
                    info = new SiteExtensionInfo();
                    info.Id = id;
                    info.ProvisioningState = Constants.SiteExtensionProvisioningStateFailed;
                    info.Comment = ex.ToString();
                    status = HttpStatusCode.NotFound;
                }
                catch (WebException ex)
                {
                    _analytics.UnexpectedException(
                        ex,
                        method: "PUT",
                        path: string.Format(CultureInfo.InvariantCulture, "/api/siteextensions/{0}", id),
                        result: Constants.SiteExtensionProvisioningStateFailed,
                        message: string.Format(CultureInfo.InvariantCulture, "{{\"version\": {0}, \"feed_url\": {1}}}", version, feedUrl),
                        trace: false);

                    tracer.TraceError(ex);
                    info = new SiteExtensionInfo();
                    info.Id = id;
                    info.ProvisioningState = Constants.SiteExtensionProvisioningStateFailed;
                    info.Comment = ex.ToString();
                    status = HttpStatusCode.BadRequest;
                }
                catch (InvalidEndpointException ex)
                {
                    _analytics.UnexpectedException(ex, trace: false);

                    tracer.TraceError(ex);
                    info = new SiteExtensionInfo();
                    info.Id = id;
                    info.ProvisioningState = Constants.SiteExtensionProvisioningStateFailed;
                    info.Comment = ex.ToString();
                    status = HttpStatusCode.BadRequest;
                }
                catch (Exception ex)
                {
                    _analytics.UnexpectedException(
                        ex,
                        method: "PUT",
                        path: string.Format(CultureInfo.InvariantCulture, "/api/siteextensions/{0}", id),
                        result: Constants.SiteExtensionProvisioningStateFailed,
                        message: string.Format(CultureInfo.InvariantCulture, "{{\"version\": {0}, \"feed_url\": {1}}}", version, feedUrl),
                        trace: false);

                    tracer.TraceError(ex);
                    info = new SiteExtensionInfo();
                    info.Id = id;
                    info.ProvisioningState = Constants.SiteExtensionProvisioningStateFailed;
                    info.Comment = ex.ToString();
                    status = HttpStatusCode.BadRequest;
                }
            }

            if (info == null)
            {
                // treat this as an error case since no result return from repo
                _analytics.UnexpectedException(
                        new FileNotFoundException(id),
                        method: "PUT",
                        path: string.Format(CultureInfo.InvariantCulture, "/api/siteextensions/{0}", id),
                        result: Constants.SiteExtensionProvisioningStateFailed,
                        message: string.Format(CultureInfo.InvariantCulture, "{{\"version\": {0}, \"feed_url\": {1}}}", version, feedUrl),
                        trace: false);

                info = new SiteExtensionInfo();
                info.ProvisioningState = Constants.SiteExtensionProvisioningStateFailed;
                info.Comment = string.Format(Constants.SiteExtensionProvisioningStateNotFoundMessageFormat, id);
                status = HttpStatusCode.NotFound;
            }
            else if (!string.Equals(Constants.SiteExtensionProvisioningStateFailed, info.ProvisioningState, StringComparison.OrdinalIgnoreCase))
            {
                info.ProvisioningState = Constants.SiteExtensionProvisioningStateSucceeded;
                info.Comment = null;
            }

            using (tracer.Step("Update arm settings for {0} installation. Status: {1}", id, status))
            {
                SiteExtensionStatus armSettings = new SiteExtensionStatus(_environment.SiteExtensionSettingsPath, id, tracer);
                armSettings.ReadSiteExtensionInfo(info);
                armSettings.Status = status;
                armSettings.Operation = alreadyInstalled ? null : Constants.SiteExtensionOperationInstall;
            }

            return info;
        }
Exemplo n.º 2
0
        public async Task<bool> UninstallExtension(string id)
        {
            ITracer tracer = _traceFactory.GetTracer();

            string installationDirectory = GetInstallationDirectory(id);

            SiteExtensionInfo info = await GetLocalExtension(id, checkLatest: false);

            if (info == null || !FileSystemHelpers.DirectoryExists(info.LocalPath))
            {
                tracer.TraceError("Site extension {0} not found.", id);
                throw new DirectoryNotFoundException(installationDirectory);
            }

            if (IsInstalledToWebRoot(id))
            {
                // special handling for package that install in wwwroot instead of under site extension folder
                tracer.Trace("Clear all content in wwwroot");
                OperationManager.Attempt(() => FileSystemHelpers.DeleteDirectoryContentsSafe(_environment.WebRootPath));
            }
            else
            {
                // default action for site extension uninstall

                // only site extension has below infomation
                var externalCommandFactory = new ExternalCommandFactory(_environment, _settings, installationDirectory);

                string uninstallScript = Path.Combine(installationDirectory, _uninstallScriptName);

                if (FileSystemHelpers.FileExists(uninstallScript))
                {
                    using (tracer.Step("Execute uninstall.cmd"))
                    {
                        OperationManager.Attempt(() =>
                        {
                            Executable exe = externalCommandFactory.BuildCommandExecutable(uninstallScript,
                                installationDirectory,
                                _settings.GetCommandIdleTimeout(), NullLogger.Instance);
                            exe.ExecuteWithProgressWriter(NullLogger.Instance, _traceFactory.GetTracer(), String.Empty);
                        });
                    }
                }

                using (tracer.Step("Remove site extension job"))
                {
                    OperationManager.Attempt(() => CleanupSiteExtensionJobs(id));
                }
            }

            using (tracer.Step("Delete site extension package, directory and arm settings"))
            {
                OperationManager.Attempt(() => FileSystemHelpers.DeleteFileSafe(GetNuGetPackageFile(info.Id, info.Version)));
                OperationManager.Attempt(() => FileSystemHelpers.DeleteDirectorySafe(installationDirectory));
                SiteExtensionStatus armSettings = new SiteExtensionStatus(_environment.SiteExtensionSettingsPath, id, tracer);
                await armSettings.RemoveStatus();
            }

            return await GetLocalExtension(id, checkLatest: false) == null;
        }
Exemplo n.º 3
0
        // <inheritdoc />
        public async Task<SiteExtensionInfo> GetLocalExtension(string id, bool checkLatest = true)
        {
            ITracer tracer = _traceFactory.GetTracer();
            SiteExtensionInfo info = GetPreInstalledExtension(id);
            if (info != null && info.ExtensionUrl != null)
            {
                tracer.Trace("Pre-installed site extension found: {0}", id);
            }
            else
            {
                UIPackageMetadata package = null;
                using (tracer.Step("{0} is not a pre-installed package. Now querying from local repo.", id))
                {
                    package = await _localRepository.GetLatestPackageById(id);
                }

                if (package == null)
                {
                    tracer.Trace("No package found from local repo with id: {0}.", id);
                    return null;
                }

                using (tracer.Step("Converting NuGet object to SiteExtensionInfo"))
                {
                    info = await ConvertLocalPackageToSiteExtensionInfo(package, checkLatest, tracer: tracer);
                }
            }

            SiteExtensionStatus armSettings = new SiteExtensionStatus(_environment.SiteExtensionSettingsPath, id, tracer);
            armSettings.FillSiteExtensionInfo(info);
            return info;
        }
Exemplo n.º 4
0
        // <inheritdoc />
        public async Task<SiteExtensionInfo> InstallExtension(string id, string version, string feedUrl, SiteExtensionInfo.SiteExtensionType type, ITracer tracer)
        {
            try
            {
                using (tracer.Step("Installing '{0}' version '{1}' from '{2}'", id, version, feedUrl))
                {
                    var installationLock = SiteExtensionInstallationLock.CreateLock(_environment.SiteExtensionSettingsPath, id, enableAsync: true);
                    // hold on to lock till action complete (success or fail)
                    return await installationLock.LockOperationAsync<SiteExtensionInfo>(async () =>
                    {
                        return await TryInstallExtension(id, version, feedUrl, type, tracer);
                    }, "Installing SiteExtension", TimeSpan.Zero);
                }
            }
            catch (Exception ex)
            {
                _analytics.UnexpectedException(
                        ex,
                        method: "PUT",
                        path: string.Format(CultureInfo.InvariantCulture, "/api/siteextensions/{0}", id),
                        result: Constants.SiteExtensionProvisioningStateFailed,
                        message: string.Format(CultureInfo.InvariantCulture, "{{\"version\": {0}, \"feed_url\": {1}}}", version, feedUrl),
                        trace: false);

                // handle unexpected exception
                tracer.TraceError(ex);

                var info = new SiteExtensionInfo();
                info.Id = id;

                SiteExtensionStatus armStatus = new SiteExtensionStatus(_environment.SiteExtensionSettingsPath, id, tracer);
                armStatus.Operation = Constants.SiteExtensionOperationInstall;
                armStatus.ProvisioningState = Constants.SiteExtensionProvisioningStateFailed;
                armStatus.Status = HttpStatusCode.BadRequest;
                armStatus.FillSiteExtensionInfo(info);
                tracer.Trace("Update arm settings for {0} installation. Status: {1}", id, armStatus.Status);
                return info;
            }
        }
Exemplo n.º 5
0
        /// <summary>
        /// <para>Scan every site extensions, check if there is any successful installation</para>
        /// <para>Looking for below cases:</para>
        /// <para>if not install to webroot, trigger restart; if install to webroot and with applicationHost.xdt file, trigger restart.</para>
        /// </summary>
        /// <param name="siteExtensionStatusRoot">should be $ROOT\site\siteextensions</param>
        /// <param name="siteExtensionRoot">should be $ROOT\SiteExtensions</param>
        public static bool IsAnyInstallationRequireRestart(string siteExtensionStatusRoot, string siteExtensionRoot, ITracer tracer, IAnalytics analytics)
        {
            try
            {
                using (tracer.Step("Checking if there is any installation require site restart ..."))
                {
                    string[] packageDirs = FileSystemHelpers.GetDirectories(siteExtensionStatusRoot);
                    // folder name is the package id
                    foreach (var dir in packageDirs)
                    {
                        try
                        {
                            DirectoryInfo dirInfo = new DirectoryInfo(dir);
                            var statusSettings = new SiteExtensionStatus(siteExtensionStatusRoot, dirInfo.Name, tracer);
                            if (statusSettings.IsSiteExtensionRequireRestart(siteExtensionRoot))
                            {
                                return true;
                            }
                        }
                        catch (Exception ex)
                        {
                            analytics.UnexpectedException(ex, trace: false);
                            tracer.TraceError(ex, "Failed to query {0} under {1}, continus to check others ...", _statusSettingsFileName, dir);
                        }
                    }
                }
            }
            catch (Exception ex)
            {
                analytics.UnexpectedException(ex, trace: false);
                tracer.TraceError(ex, "Not able to query directory under {0}", siteExtensionStatusRoot);
            }

            return false;
        }
Exemplo n.º 6
0
        public async Task<IEnumerable<SiteExtensionInfo>> GetLocalExtensions(string filter, bool checkLatest)
        {
            ITracer tracer = _traceFactory.GetTracer();
            IEnumerable<SiteExtensionInfo> preInstalledExtensions = GetPreInstalledExtensions(filter, showEnabledOnly: true);
            IEnumerable<UIPackageMetadata> searchResult = null;
            List<SiteExtensionInfo> siteExtensionInfos = new List<SiteExtensionInfo>();

            foreach (var item in preInstalledExtensions)
            {
                SiteExtensionStatus armSettings = new SiteExtensionStatus(_environment.SiteExtensionSettingsPath, item.Id, tracer);
                armSettings.FillSiteExtensionInfo(item, defaultProvisionState: Constants.SiteExtensionProvisioningStateSucceeded);
            }

            using (tracer.Step("Search packages locally with filter: {0}", filter))
            {
                searchResult = await _localRepository.Search(filter);
                siteExtensionInfos = await ConvertNuGetPackagesToSiteExtensionInfos(
                    searchResult,
                    async (uiPackage) =>
                    {
                        SiteExtensionInfo info = await ConvertLocalPackageToSiteExtensionInfo(uiPackage, checkLatest, tracer);
                        SiteExtensionStatus armSettings = new SiteExtensionStatus(_environment.SiteExtensionSettingsPath, info.Id, tracer);
                        armSettings.FillSiteExtensionInfo(info, defaultProvisionState: Constants.SiteExtensionProvisioningStateSucceeded);
                        return info;
                    });
            }

            return preInstalledExtensions.Concat(siteExtensionInfos);
        }
Exemplo n.º 7
0
        public async Task<HttpResponseMessage> GetLocalExtension(string id, bool checkLatest = true)
        {
            var tracer = _traceFactory.GetTracer();

            SiteExtensionInfo extension = null;
            HttpResponseMessage responseMessage = null;
            if (ArmUtils.IsArmRequest(Request))
            {
                tracer.Trace("Incoming GetLocalExtension is arm request.");
                SiteExtensionStatus armSettings = new SiteExtensionStatus(_environment.SiteExtensionSettingsPath, id, tracer);

                if (string.Equals(Constants.SiteExtensionOperationInstall, armSettings.Operation, StringComparison.OrdinalIgnoreCase))
                {
                    bool isInstallationLockHeld = IsInstallationLockHeldSafeCheck(id);
                    if (!isInstallationLockHeld
                        && string.Equals(Constants.SiteExtensionProvisioningStateSucceeded, armSettings.ProvisioningState, StringComparison.OrdinalIgnoreCase))
                    {
                        tracer.Trace("Package {0} was just installed.", id);
                        extension = await _manager.GetLocalExtension(id, checkLatest);
                        if (extension == null)
                        {
                            using (tracer.Step("Status indicate {0} installed, but not able to find it from local repo.", id))
                            {
                                // should NOT happen
                                extension = new SiteExtensionInfo { Id = id };
                                responseMessage = Request.CreateResponse(HttpStatusCode.NotFound);
                                // package is gone, remove setting file
                                await armSettings.RemoveStatus();
                            }
                        }
                        else
                        {
                            if (SiteExtensionInstallationLock.IsAnyPendingLock(_environment.SiteExtensionSettingsPath, tracer))
                            {
                                using (tracer.Step("{0} finsihed installation. But there is other installation on-going, fake the status to be Created, so that we can restart once for all.", id))
                                {
                                    // if there is other pending installation, fake the status
                                    extension.ProvisioningState = Constants.SiteExtensionProvisioningStateCreated;
                                    responseMessage = Request.CreateResponse(HttpStatusCode.Created, ArmUtils.AddEnvelopeOnArmRequest<SiteExtensionInfo>(extension, Request));
                                }
                            }
                            else
                            {
                                // it is important to call "SiteExtensionStatus.IsAnyInstallationRequireRestart" before "UpdateArmSettingsForSuccessInstallation"
                                // since "IsAnyInstallationRequireRestart" is depending on properties inside site extension status files 
                                // while "UpdateArmSettingsForSuccessInstallation" will override some of the values
                                bool requireRestart = SiteExtensionStatus.IsAnyInstallationRequireRestart(_environment.SiteExtensionSettingsPath, _siteExtensionRoot, tracer, _analytics);
                                // clear operation, since opeation is done
                                if (UpdateArmSettingsForSuccessInstallation())
                                {
                                    using (tracer.Step("{0} finsihed installation and batch update lock aquired. Will notify Antares GEO to restart website.", id))
                                    {
                                        responseMessage = Request.CreateResponse(armSettings.Status, ArmUtils.AddEnvelopeOnArmRequest<SiteExtensionInfo>(extension, Request));

                                        // Notify GEO to restart website if necessary
                                        if (requireRestart)
                                        {
                                            responseMessage.Headers.Add(Constants.SiteOperationHeaderKey, Constants.SiteOperationRestart);
                                        }
                                    }
                                }
                                else
                                {
                                    tracer.Trace("Not able to aquire batch update lock, there must be another batch update on-going. return Created status to user to let them poll again.");
                                    responseMessage = Request.CreateResponse(HttpStatusCode.Created, ArmUtils.AddEnvelopeOnArmRequest<SiteExtensionInfo>(extension, Request));
                                }
                            }
                        }
                    }
                    else if (!isInstallationLockHeld && !armSettings.IsTerminalStatus())
                    {
                        // no background thread is working on instalation
                        // app-pool must be recycled
                        using (tracer.Step("{0} installation cancelled, background thread must be dead.", id))
                        {
                            extension = new SiteExtensionInfo { Id = id };
                            extension.ProvisioningState = Constants.SiteExtensionProvisioningStateCanceled;
                            responseMessage = Request.CreateResponse(HttpStatusCode.OK, ArmUtils.AddEnvelopeOnArmRequest<SiteExtensionInfo>(extension, Request));
                        }
                    }
                    else
                    {
                        // on-going or failed, return status from setting
                        using (tracer.Step("Installation {0}", armSettings.Status))
                        {
                            extension = new SiteExtensionInfo { Id = id };
                            armSettings.FillSiteExtensionInfo(extension);
                            responseMessage = Request.CreateResponse(armSettings.Status, ArmUtils.AddEnvelopeOnArmRequest<SiteExtensionInfo>(extension, Request));
                        }
                    }
                }

                // normal GET request
                if (responseMessage == null)
                {
                    using (tracer.Step("ARM get : {0}", id))
                    {
                        extension = await _manager.GetLocalExtension(id, checkLatest);
                    }

                    if (extension == null)
                    {
                        extension = new SiteExtensionInfo { Id = id };
                        responseMessage = Request.CreateResponse(HttpStatusCode.NotFound);
                    }
                    else
                    {
                        armSettings.FillSiteExtensionInfo(extension);
                        responseMessage = Request.CreateResponse(HttpStatusCode.OK, ArmUtils.AddEnvelopeOnArmRequest<SiteExtensionInfo>(extension, Request));
                    }
                }
            }
            else
            {
                using (tracer.Step("Get: {0}, is not a ARM request.", id))
                {
                    extension = await _manager.GetLocalExtension(id, checkLatest);
                }

                if (extension == null)
                {
                    throw new HttpResponseException(Request.CreateErrorResponse(HttpStatusCode.NotFound, id));
                }

                responseMessage = Request.CreateResponse(HttpStatusCode.OK, extension);
            }

            return responseMessage;
        }
Exemplo n.º 8
0
        // <inheritdoc />
        public async Task<SiteExtensionInfo> GetLocalExtension(string id, bool checkLatest = true)
        {
            ITracer tracer = _traceFactory.GetTracer();
            UIPackageMetadata package = null;
            using (tracer.Step("Now querying from local repo for package '{0}'.", id))
            {
                package = await _localRepository.GetLatestPackageById(id);
            }

            if (package == null)
            {
                tracer.Trace("No package found from local repo with id: {0}.", id);
                return null;
            }

            SiteExtensionInfo info;
            using (tracer.Step("Converting NuGet object to SiteExtensionInfo"))
            {
                info = await ConvertLocalPackageToSiteExtensionInfo(package, checkLatest, tracer: tracer);
            }

            SiteExtensionStatus armSettings = new SiteExtensionStatus(_environment.SiteExtensionSettingsPath, id, tracer);
            armSettings.FillSiteExtensionInfo(info);
            return info;
        }
Exemplo n.º 9
0
        private async Task<SiteExtensionInfo> InitInstallSiteExtension(string id, SiteExtensionInfo.SiteExtensionType type)
        {
            SiteExtensionStatus settings = new SiteExtensionStatus(_environment.SiteExtensionSettingsPath, id, _traceFactory.GetTracer());
            settings.ProvisioningState = Constants.SiteExtensionProvisioningStateCreated;
            settings.Operation = Constants.SiteExtensionOperationInstall;
            settings.Status = HttpStatusCode.Created;
            settings.Type = type;
            settings.Comment = null;

            SiteExtensionInfo info = new SiteExtensionInfo();
            info.Id = id;
            settings.FillSiteExtensionInfo(info);
            return await Task.FromResult(info);
        }
Exemplo n.º 10
0
        /// <summary>
        /// <para>1. list all package</para>
        /// <para>2. for each package: if operation is 'install' and provisionState is 'success' and no installation lock</para>
        /// <para>      Update operation to null</para>
        /// </summary>
        private bool UpdateArmSettingsForSuccessInstallation()
        {
            var tracer = _traceFactory.GetTracer();
            using (tracer.Step("Checking if there is any installation finsihed recently, if there is one, update its status."))
            {
                var batchUpdateLock = SiteExtensionBatchUpdateStatusLock.CreateLock(_environment.SiteExtensionSettingsPath);

                bool isAnyUpdate = false;

                bool islocked = batchUpdateLock.TryLockOperation(() =>
                {
                    string[] packageDirs = FileSystemHelpers.GetDirectories(_environment.SiteExtensionSettingsPath);
                    foreach (var dir in packageDirs)
                    {
                        var dirInfo = new DirectoryInfo(dir);   // arm setting folder name is same as package id
                        SiteExtensionStatus armSettings = new SiteExtensionStatus(_environment.SiteExtensionSettingsPath, dirInfo.Name, tracer);
                        if (string.Equals(armSettings.Operation, Constants.SiteExtensionOperationInstall, StringComparison.OrdinalIgnoreCase)
                            && string.Equals(armSettings.ProvisioningState, Constants.SiteExtensionProvisioningStateSucceeded, StringComparison.OrdinalIgnoreCase))
                        {
                            try
                            {
                                armSettings.Operation = null;
                                isAnyUpdate = true;
                                tracer.Trace("Updated {0}", dir);
                            }
                            catch (Exception ex)
                            {
                                tracer.TraceError(ex);
                                // no-op
                            }
                        }
                    }

                }, TimeSpan.FromSeconds(5));

                return islocked && isAnyUpdate;
            }
        }
Exemplo n.º 11
0
 /// <summary>
 /// Log to MDS when installation/uninstallation finsihed
 /// </summary>
 private void LogEndEvent(string id, TimeSpan duration, ITracer tracer, string defaultResult = null)
 {
     SiteExtensionStatus armStatus = new SiteExtensionStatus(_environment.SiteExtensionSettingsPath, id, tracer);
     string filePath = Path.Combine(_environment.RootPath, "SiteExtensions", id, "SiteExtensionSettings.json");
     var jsonSetting = new JsonSettings(filePath);
     _analytics.SiteExtensionEvent(
         Request.Method.Method,
         Request.RequestUri.AbsolutePath,
         armStatus.ProvisioningState ?? defaultResult,
         duration.TotalMilliseconds.ToString(),
         jsonSetting.ToString());
 }
Exemplo n.º 12
0
        public async Task<HttpResponseMessage> InstallExtension(string id, SiteExtensionInfo requestInfo)
        {
            var startTime = DateTime.UtcNow;
            var tracer = _traceFactory.GetTracer();

            if (IsInstallationLockHeldSafeCheck(id))
            {
                tracer.Trace("{0} is installing with another request, reject current request with Conflict status.", id);
                throw new HttpResponseException(Request.CreateErrorResponse(HttpStatusCode.Conflict, id));
            }

            if (requestInfo == null)
            {
                requestInfo = new SiteExtensionInfo();
            }

            tracer.Trace("Installing {0}, version: {1} from feed: {2}", id, requestInfo.Version, requestInfo.FeedUrl);
            SiteExtensionInfo result = await InitInstallSiteExtension(id, requestInfo.Type);

            if (ArmUtils.IsArmRequest(Request))
            {
                // create a context free tracer
                ITracer backgroundTracer = NullTracer.Instance;
                IDictionary<string, string> traceAttributes = new Dictionary<string, string>();

                if (tracer.TraceLevel == TraceLevel.Off)
                {
                    backgroundTracer = NullTracer.Instance;
                }

                if (tracer.TraceLevel > TraceLevel.Off)
                {
                    backgroundTracer = new XmlTracer(_environment.TracePath, tracer.TraceLevel);
                    traceAttributes = new Dictionary<string, string>()
                    {
                        {"url", Request.RequestUri.AbsolutePath},
                        {"method", Request.Method.Method}
                    };

                    foreach (var item in Request.Headers)
                    {
                        if (!traceAttributes.ContainsKey(item.Key))
                        {
                            traceAttributes.Add(item.Key, string.Join(",", item.Value));
                        }
                    }
                }

                AutoResetEvent installationSignal = new AutoResetEvent(false);

                // trigger installation, but do not wait. Expecting poll for status
                ThreadPool.QueueUserWorkItem((object stateInfo) =>
                {
                    using (backgroundTracer.Step(XmlTracer.BackgroundTrace, attributes: traceAttributes))
                    {
                        try
                        {
                            using (backgroundTracer.Step("Background thread started for {0} installation", id))
                            {
                                _manager.InstallExtension(id, requestInfo.Version, requestInfo.FeedUrl, requestInfo.Type, backgroundTracer).Wait();
                            }
                        }
                        finally
                        {
                            installationSignal.Set();

                            // will be a few millionseconds off if task finshed within 15 seconds.
                            LogEndEvent(id, (DateTime.UtcNow - startTime), backgroundTracer);
                        }
                    }
                });

                SiteExtensionStatus armSettings = new SiteExtensionStatus(_environment.SiteExtensionSettingsPath, id, tracer);
                if (installationSignal.WaitOne(TimeSpan.FromSeconds(15)))
                {
                    if (!armSettings.IsRestartRequired(_siteExtensionRoot))
                    {
                        // only skip polling if current installation doesn`t require restart, to avoid making race condition common
                        // TODO: re-visit if we want to skip polling for case that need to restart
                        tracer.Trace("Installation finish quick and not require restart, skip async polling, invoking GET to return actual status to caller.");
                        return await GetLocalExtension(id);
                    }
                }

                // do not log end event here, since it is not done yet
                return Request.CreateResponse(HttpStatusCode.Created, ArmUtils.AddEnvelopeOnArmRequest<SiteExtensionInfo>(result, Request));
            }
            else
            {
                result = await _manager.InstallExtension(id, requestInfo.Version, requestInfo.FeedUrl, requestInfo.Type, tracer);

                if (string.Equals(Constants.SiteExtensionProvisioningStateFailed, result.ProvisioningState, StringComparison.OrdinalIgnoreCase))
                {
                    SiteExtensionStatus armSettings = new SiteExtensionStatus(_environment.SiteExtensionSettingsPath, id, tracer);
                    throw new HttpResponseException(Request.CreateErrorResponse(armSettings.Status, result.Comment));
                }

                var response = Request.CreateResponse(HttpStatusCode.OK, result);
                LogEndEvent(id, (DateTime.UtcNow - startTime), tracer);
                return response;
            }
        }
Exemplo n.º 13
0
        private async Task <SiteExtensionInfo> TryInstallExtension(string id, string version, string feedUrl, SiteExtensionInfo.SiteExtensionType type, ITracer tracer)
        {
            SiteExtensionInfo info   = null;
            HttpStatusCode    status = HttpStatusCode.OK; // final status when success
            bool alreadyInstalled    = false;

            if (_preInstalledExtensionDictionary.ContainsKey(id))
            {
                tracer.Trace("Pre-installed site extension found: {0}, not going to perform new installation.", id);
                info             = EnablePreInstalledExtension(_preInstalledExtensionDictionary[id], tracer);
                alreadyInstalled = true;
            }
            else
            {
                try
                {
                    // Check if site extension already installed (id, version, feedUrl), if already install return right away
                    if (await this.IsSiteExtensionInstalled(id, version, feedUrl))
                    {
                        // package already installed, return package from local repo.
                        tracer.Trace("Package {0} with version {1} from {2} already installed.", id, version, feedUrl);
                        info = await GetLocalExtension(id);

                        alreadyInstalled = true;
                    }
                    else
                    {
                        JsonSettings siteExtensionSettings = GetSettingManager(id);
                        feedUrl = (string.IsNullOrEmpty(feedUrl) ? siteExtensionSettings.GetValue(_feedUrlSetting) : feedUrl);
                        SourceRepository  remoteRepo   = GetRemoteRepository(feedUrl);
                        UIPackageMetadata localPackage = null;
                        UIPackageMetadata repoPackage  = null;

                        if (string.IsNullOrWhiteSpace(version))
                        {
                            using (tracer.Step("Version is null, search latest package by id: {0}, will not search for unlisted package.", id))
                            {
                                repoPackage = await remoteRepo.GetLatestPackageById(id);
                            }
                        }
                        else
                        {
                            using (tracer.Step("Search package by id: {0} and version: {1}, will also search for unlisted package.", id, version))
                            {
                                repoPackage = await remoteRepo.GetPackageByIdentity(id, version);
                            }
                        }

                        if (repoPackage != null)
                        {
                            using (tracer.Step("Install package: {0}.", id))
                            {
                                string installationDirectory = GetInstallationDirectory(id);
                                localPackage = await InstallExtension(repoPackage, installationDirectory, feedUrl, type, tracer);

                                siteExtensionSettings.SetValues(new KeyValuePair <string, JToken>[] {
                                    new KeyValuePair <string, JToken>(_versionSetting, localPackage.Identity.Version.ToNormalizedString()),
                                    new KeyValuePair <string, JToken>(_feedUrlSetting, feedUrl),
                                    new KeyValuePair <string, JToken>(_installUtcTimestampSetting, DateTime.UtcNow.ToString("u")),
                                    new KeyValuePair <string, JToken>(_packageType, Enum.GetName(typeof(SiteExtensionInfo.SiteExtensionType), type))
                                });
                            }
                        }

                        info = await ConvertLocalPackageToSiteExtensionInfo(localPackage, checkLatest : true, tracer : tracer);
                    }
                }
                catch (FileNotFoundException ex)
                {
                    _analytics.UnexpectedException(
                        ex,
                        method: "PUT",
                        path: string.Format(CultureInfo.InvariantCulture, "/api/siteextensions/{0}", id),
                        result: Constants.SiteExtensionProvisioningStateFailed,
                        message: string.Format(CultureInfo.InvariantCulture, "{{\"version\": {0}, \"feed_url\": {1}}}", version, feedUrl),
                        trace: false);

                    tracer.TraceError(ex);
                    info    = new SiteExtensionInfo();
                    info.Id = id;
                    info.ProvisioningState = Constants.SiteExtensionProvisioningStateFailed;
                    info.Comment           = string.Format(Constants.SiteExtensionProvisioningStateNotFoundMessageFormat, id);
                    status = HttpStatusCode.NotFound;
                }
                catch (WebException ex)
                {
                    _analytics.UnexpectedException(
                        ex,
                        method: "PUT",
                        path: string.Format(CultureInfo.InvariantCulture, "/api/siteextensions/{0}", id),
                        result: Constants.SiteExtensionProvisioningStateFailed,
                        message: string.Format(CultureInfo.InvariantCulture, "{{\"version\": {0}, \"feed_url\": {1}}}", version, feedUrl),
                        trace: false);

                    tracer.TraceError(ex);
                    info    = new SiteExtensionInfo();
                    info.Id = id;
                    info.ProvisioningState = Constants.SiteExtensionProvisioningStateFailed;
                    info.Comment           = string.Format(Constants.SiteExtensionProvisioningStateDownloadFailureMessageFormat, id);
                    status = HttpStatusCode.BadRequest;
                }
                catch (InvalidEndpointException ex)
                {
                    _analytics.UnexpectedException(ex, trace: false);

                    tracer.TraceError(ex);
                    info    = new SiteExtensionInfo();
                    info.Id = id;
                    info.ProvisioningState = Constants.SiteExtensionProvisioningStateFailed;
                    info.Comment           = ex.Message;
                    status = HttpStatusCode.BadRequest;
                }
                catch (Exception ex)
                {
                    _analytics.UnexpectedException(
                        ex,
                        method: "PUT",
                        path: string.Format(CultureInfo.InvariantCulture, "/api/siteextensions/{0}", id),
                        result: Constants.SiteExtensionProvisioningStateFailed,
                        message: string.Format(CultureInfo.InvariantCulture, "{{\"version\": {0}, \"feed_url\": {1}}}", version, feedUrl),
                        trace: false);

                    tracer.TraceError(ex);
                    info    = new SiteExtensionInfo();
                    info.Id = id;
                    info.ProvisioningState = Constants.SiteExtensionProvisioningStateFailed;
                    info.Comment           = string.Format(Constants.SiteExtensionProvisioningStateInvalidPackageMessageFormat, id);
                    status = HttpStatusCode.BadRequest;
                }
            }

            if (info == null)
            {
                // treat this as an error case since no result return from repo
                _analytics.UnexpectedException(
                    new FileNotFoundException(id),
                    method: "PUT",
                    path: string.Format(CultureInfo.InvariantCulture, "/api/siteextensions/{0}", id),
                    result: Constants.SiteExtensionProvisioningStateFailed,
                    message: string.Format(CultureInfo.InvariantCulture, "{{\"version\": {0}, \"feed_url\": {1}}}", version, feedUrl),
                    trace: false);

                info = new SiteExtensionInfo();
                info.ProvisioningState = Constants.SiteExtensionProvisioningStateFailed;
                info.Comment           = string.Format(Constants.SiteExtensionProvisioningStateNotFoundMessageFormat, id);
                status = HttpStatusCode.NotFound;
            }
            else if (!string.Equals(Constants.SiteExtensionProvisioningStateFailed, info.ProvisioningState, StringComparison.OrdinalIgnoreCase))
            {
                info.ProvisioningState = Constants.SiteExtensionProvisioningStateSucceeded;
                info.Comment           = null;
            }

            using (tracer.Step("Update arm settings for {0} installation. Status: {1}", id, status))
            {
                SiteExtensionStatus armSettings = new SiteExtensionStatus(_environment.SiteExtensionSettingsPath, id, tracer);
                armSettings.ReadSiteExtensionInfo(info);
                armSettings.Status    = status;
                armSettings.Operation = alreadyInstalled ? null : Constants.SiteExtensionOperationInstall;
            }

            return(info);
        }
Exemplo n.º 14
0
        private async Task <SiteExtensionInfo> TryInstallExtension(string id, string version, string feedUrl, SiteExtensionInfo.SiteExtensionType type, ITracer tracer, string installationArgs)
        {
            SiteExtensionInfo info   = null;
            HttpStatusCode    status = HttpStatusCode.OK; // final status when success
            bool alreadyInstalled    = false;

            try
            {
                // Check if site extension already installed (id, version, feedUrl), if already install with correct installation arguments then return right away
                if (await IsSiteExtensionInstalled(id, installationArgs))
                {
                    // package already installed, return package from local repo.
                    tracer.Trace("Package {0} with version {1} from {2} with installation arguments '{3}' already installed.", id, version, feedUrl, installationArgs);
                    info = await GetLocalExtension(id);

                    alreadyInstalled = true;
                }
                else
                {
                    JsonSettings siteExtensionSettings = GetSettingManager(id);
                    feedUrl = (string.IsNullOrEmpty(feedUrl) ? siteExtensionSettings.GetValue(_feedUrlSetting) : feedUrl);
                    IEnumerable <SourceRepository> remoteRepos = GetRemoteRepositories(feedUrl);

                    using (tracer.Step("Search package by id: {0} and version: {1}, will also search for unlisted package.", id, version))
                    {
                        info = await FeedExtensionsV2.GetPackageByIdentity(id, version);
                    }

                    if (info != null)
                    {
                        using (tracer.Step("Install package: {0}.", id))
                        {
                            string installationDirectory = GetInstallationDirectory(id);
                            info = await InstallExtension(info, installationDirectory, type, tracer, installationArgs);

                            siteExtensionSettings.SetValues(new KeyValuePair <string, JToken>[] {
                                new KeyValuePair <string, JToken>(_versionSetting, info.Version),
                                new KeyValuePair <string, JToken>(_feedUrlSetting, feedUrl),
                                new KeyValuePair <string, JToken>(_installUtcTimestampSetting, DateTime.UtcNow.ToString("u")),
                                new KeyValuePair <string, JToken>(_packageType, Enum.GetName(typeof(SiteExtensionInfo.SiteExtensionType), type)),
                                new KeyValuePair <string, JToken>(_installationArgs, installationArgs)
                            });
                        }
                    }
                }

                if (info != null)
                {
                    await SetLocalInfo(info);
                }
            }
            catch (FileNotFoundException ex)
            {
                _analytics.UnexpectedException(
                    ex,
                    method: "PUT",
                    path: string.Format(CultureInfo.InvariantCulture, "/api/siteextensions/{0}", id),
                    result: Constants.SiteExtensionProvisioningStateFailed,
                    message: string.Format(CultureInfo.InvariantCulture, "{{\"version\": {0}, \"feed_url\": {1}}}", version, feedUrl),
                    trace: false);

                tracer.TraceError(ex);
                info    = new SiteExtensionInfo();
                info.Id = id;
                info.ProvisioningState = Constants.SiteExtensionProvisioningStateFailed;
                info.Comment           = ex.ToString();
                status = HttpStatusCode.NotFound;
            }
            catch (WebException ex)
            {
                _analytics.UnexpectedException(
                    ex,
                    method: "PUT",
                    path: string.Format(CultureInfo.InvariantCulture, "/api/siteextensions/{0}", id),
                    result: Constants.SiteExtensionProvisioningStateFailed,
                    message: string.Format(CultureInfo.InvariantCulture, "{{\"version\": {0}, \"feed_url\": {1}}}", version, feedUrl),
                    trace: false);

                tracer.TraceError(ex);
                info    = new SiteExtensionInfo();
                info.Id = id;
                info.ProvisioningState = Constants.SiteExtensionProvisioningStateFailed;
                info.Comment           = ex.ToString();
                status = HttpStatusCode.BadRequest;
            }
            catch (InvalidEndpointException ex)
            {
                _analytics.UnexpectedException(ex, trace: false);

                tracer.TraceError(ex);
                info    = new SiteExtensionInfo();
                info.Id = id;
                info.ProvisioningState = Constants.SiteExtensionProvisioningStateFailed;
                info.Comment           = ex.ToString();
                status = HttpStatusCode.BadRequest;
            }
            catch (Exception ex)
            {
                _analytics.UnexpectedException(
                    ex,
                    method: "PUT",
                    path: string.Format(CultureInfo.InvariantCulture, "/api/siteextensions/{0}", id),
                    result: Constants.SiteExtensionProvisioningStateFailed,
                    message: string.Format(CultureInfo.InvariantCulture, "{{\"version\": {0}, \"feed_url\": {1}}}", version, feedUrl),
                    trace: false);

                tracer.TraceError(ex);
                info    = new SiteExtensionInfo();
                info.Id = id;
                info.ProvisioningState = Constants.SiteExtensionProvisioningStateFailed;
                info.Comment           = ex.ToString();
                status = HttpStatusCode.BadRequest;
            }

            if (info == null)
            {
                // treat this as an error case since no result return from repo
                _analytics.UnexpectedException(
                    new FileNotFoundException(id),
                    method: "PUT",
                    path: string.Format(CultureInfo.InvariantCulture, "/api/siteextensions/{0}", id),
                    result: Constants.SiteExtensionProvisioningStateFailed,
                    message: string.Format(CultureInfo.InvariantCulture, "{{\"version\": {0}, \"feed_url\": {1}}}", version, feedUrl),
                    trace: false);

                info = new SiteExtensionInfo();
                info.ProvisioningState = Constants.SiteExtensionProvisioningStateFailed;
                info.Comment           = string.Format(Constants.SiteExtensionProvisioningStateNotFoundMessageFormat, id);
                status = HttpStatusCode.NotFound;
            }
            else if (!string.Equals(Constants.SiteExtensionProvisioningStateFailed, info.ProvisioningState, StringComparison.OrdinalIgnoreCase))
            {
                info.ProvisioningState = Constants.SiteExtensionProvisioningStateSucceeded;
                info.Comment           = null;
            }

            using (tracer.Step("Update arm settings for {0} installation. Status: {1}", id, status))
            {
                SiteExtensionStatus armSettings = new SiteExtensionStatus(_environment.SiteExtensionSettingsPath, id, tracer);
                armSettings.ReadSiteExtensionInfo(info);
                armSettings.Status    = status;
                armSettings.Operation = alreadyInstalled ? null : Constants.SiteExtensionOperationInstall;
            }

            return(info);
        }
Exemplo n.º 15
0
        private async Task <SiteExtensionInfo> TryInstallExtension(string id, string version, string feedUrl, SiteExtensionInfo.SiteExtensionType type, ITracer tracer, string installationArgs)
        {
            SiteExtensionInfo info   = null;
            HttpStatusCode    status = HttpStatusCode.OK; // final status when success
            bool alreadyInstalled    = false;

            try
            {
                // Check if site extension already installed (id, version, feedUrl), if already install with correct installation arguments then return right away
                if (await this.IsSiteExtensionInstalled(id, version, feedUrl, installationArgs))
                {
                    // package already installed, return package from local repo.
                    tracer.Trace("Package {0} with version {1} from {2} with installation arguments '{3}' already installed.", id, version, feedUrl, installationArgs);
                    info = await GetLocalExtension(id);

                    alreadyInstalled = info != null;
                }

                if (!alreadyInstalled)
                {
                    JsonSettings siteExtensionSettings = GetSettingManager(id);
                    feedUrl = (string.IsNullOrEmpty(feedUrl) ? siteExtensionSettings.GetValue(_feedUrlSetting) : feedUrl);
                    IEnumerable <SourceRepository> remoteRepos = GetRemoteRepositories(feedUrl);
                    UIPackageMetadata localPackage             = null;
                    UIPackageMetadata repoPackage = null;
                    SourceRepository  remoteRepo  = null;

                    if (this.IsInstalledToWebRoot(id))
                    {
                        // override WebRoot type from setting
                        // WebRoot is a special type that install package to wwwroot, when perform update we need to update new content to wwwroot even if type is not specified
                        type = SiteExtensionInfo.SiteExtensionType.WebRoot;
                    }

                    if (string.IsNullOrWhiteSpace(version))
                    {
                        using (tracer.Step("Version is null, search latest package by id: {0}, will not search for unlisted package.", id))
                        {
                            foreach (SourceRepository rr in remoteRepos)
                            {
                                repoPackage = await rr.GetLatestPackageByIdFromSrcRepo(id);

                                if (repoPackage != null)
                                {
                                    remoteRepo = rr;
                                    break;
                                }
                            }
                        }
                    }
                    else
                    {
                        using (tracer.Step("Search package by id: {0} and version: {1}, will also search for unlisted package.", id, version))
                        {
                            foreach (SourceRepository rr in remoteRepos)
                            {
                                repoPackage = await rr.GetPackageByIdentity(id, version);

                                if (repoPackage != null)
                                {
                                    remoteRepo = rr;
                                    break;
                                }
                            }
                        }
                    }

                    if (repoPackage != null)
                    {
                        Debug.Assert(remoteRepo != null, "remote SourceRepository should not be null!");
                        using (tracer.Step("Install package: {0}.", id))
                        {
                            string installationDirectory = GetInstallationDirectory(id);
                            localPackage = await InstallExtension(repoPackage, installationDirectory, remoteRepo, type, tracer, installationArgs);

                            siteExtensionSettings.SetValues(new KeyValuePair <string, JToken>[] {
                                new KeyValuePair <string, JToken>(_versionSetting, localPackage.Identity.Version.ToNormalizedString()),
                                new KeyValuePair <string, JToken>(_feedUrlSetting, feedUrl),
                                new KeyValuePair <string, JToken>(_installUtcTimestampSetting, DateTime.UtcNow.ToString("u")),
                                new KeyValuePair <string, JToken>(_packageType, Enum.GetName(typeof(SiteExtensionInfo.SiteExtensionType), type)),
                                new KeyValuePair <string, JToken>(_installationArgs, installationArgs)
                            });
                        }
                    }

                    info = await ConvertLocalPackageToSiteExtensionInfo(localPackage, checkLatest : true, tracer : tracer);
                }
            }
            catch (FileNotFoundException ex)
            {
                _analytics.UnexpectedException(
                    ex,
                    method: "PUT",
                    path: string.Format(CultureInfo.InvariantCulture, "/api/siteextensions/{0}", id),
                    result: Constants.SiteExtensionProvisioningStateFailed,
                    message: string.Format(CultureInfo.InvariantCulture, "{{\"version\": {0}, \"feed_url\": {1}}}", version, feedUrl),
                    trace: false);

                tracer.TraceError(ex);
                info    = new SiteExtensionInfo();
                info.Id = id;
                info.ProvisioningState = Constants.SiteExtensionProvisioningStateFailed;
                info.Comment           = ex.ToString();
                status = HttpStatusCode.NotFound;
            }
            catch (WebException ex)
            {
                _analytics.UnexpectedException(
                    ex,
                    method: "PUT",
                    path: string.Format(CultureInfo.InvariantCulture, "/api/siteextensions/{0}", id),
                    result: Constants.SiteExtensionProvisioningStateFailed,
                    message: string.Format(CultureInfo.InvariantCulture, "{{\"version\": {0}, \"feed_url\": {1}}}", version, feedUrl),
                    trace: false);

                tracer.TraceError(ex);
                info    = new SiteExtensionInfo();
                info.Id = id;
                info.ProvisioningState = Constants.SiteExtensionProvisioningStateFailed;
                info.Comment           = ex.ToString();
                status = HttpStatusCode.BadRequest;
            }
            catch (InvalidEndpointException ex)
            {
                _analytics.UnexpectedException(ex, trace: false);

                tracer.TraceError(ex);
                info    = new SiteExtensionInfo();
                info.Id = id;
                info.ProvisioningState = Constants.SiteExtensionProvisioningStateFailed;
                info.Comment           = ex.ToString();
                status = HttpStatusCode.BadRequest;
            }
            catch (Exception ex)
            {
                _analytics.UnexpectedException(
                    ex,
                    method: "PUT",
                    path: string.Format(CultureInfo.InvariantCulture, "/api/siteextensions/{0}", id),
                    result: Constants.SiteExtensionProvisioningStateFailed,
                    message: string.Format(CultureInfo.InvariantCulture, "{{\"version\": {0}, \"feed_url\": {1}}}", version, feedUrl),
                    trace: false);

                tracer.TraceError(ex);
                info    = new SiteExtensionInfo();
                info.Id = id;
                info.ProvisioningState = Constants.SiteExtensionProvisioningStateFailed;
                info.Comment           = ex.ToString();
                status = HttpStatusCode.BadRequest;
            }

            if (info == null)
            {
                // treat this as an error case since no result return from repo
                _analytics.UnexpectedException(
                    new FileNotFoundException(id),
                    method: "PUT",
                    path: string.Format(CultureInfo.InvariantCulture, "/api/siteextensions/{0}", id),
                    result: Constants.SiteExtensionProvisioningStateFailed,
                    message: string.Format(CultureInfo.InvariantCulture, "{{\"version\": {0}, \"feed_url\": {1}}}", version, feedUrl),
                    trace: false);

                info = new SiteExtensionInfo();
                info.ProvisioningState = Constants.SiteExtensionProvisioningStateFailed;
                info.Comment           = string.Format(Constants.SiteExtensionProvisioningStateNotFoundMessageFormat, id);
                status = HttpStatusCode.NotFound;
            }
            else if (!string.Equals(Constants.SiteExtensionProvisioningStateFailed, info.ProvisioningState, StringComparison.OrdinalIgnoreCase))
            {
                info.ProvisioningState = Constants.SiteExtensionProvisioningStateSucceeded;
                info.Comment           = null;
            }

            using (tracer.Step("Update arm settings for {0} installation. Status: {1}", id, status))
            {
                SiteExtensionStatus armSettings = new SiteExtensionStatus(_environment.SiteExtensionSettingsPath, id, tracer);
                armSettings.ReadSiteExtensionInfo(info);
                armSettings.Status    = status;
                armSettings.Operation = alreadyInstalled ? null : Constants.SiteExtensionOperationInstall;
            }

            return(info);
        }